Outliner.js 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223
  1. /**
  2. * Outliner.js
  3. *
  4. * @author realor
  5. */
  6. import { Panel } from './Panel.js'
  7. import { Tree } from './Tree.js'
  8. import * as THREE from '../lib/three.module.js'
  9. class Outliner extends Panel {
  10. constructor(application) {
  11. super(application)
  12. this.id = 'outliner'
  13. this.position = 'right'
  14. this.title = 'tool.outliner.label'
  15. this.tree = new Tree(this.bodyElem)
  16. this.tree.rootsElem.className = 'tree outliner'
  17. this.map = new Map()
  18. this.autoScroll = true
  19. this.tree.getNodeLabel = object => {
  20. let objectLabel = object.name
  21. if (objectLabel === null || objectLabel.trim().length === 0) {
  22. objectLabel = object.id
  23. }
  24. return objectLabel
  25. }
  26. application.addEventListener('selection', () => {
  27. this.updateSelection()
  28. })
  29. application.addEventListener('scene', event => {
  30. if (event.type === 'added') {
  31. let object = event.object
  32. let parentTreeNode = this.map.get(event.parent)
  33. if (parentTreeNode) {
  34. let treeNode = this.populateObject(object, parentTreeNode)
  35. this.createMap(treeNode)
  36. }
  37. } else if (event.type === 'removed') {
  38. let object = event.object
  39. let treeNode = this.map.get(object)
  40. if (treeNode) {
  41. this.destroyMap(treeNode)
  42. treeNode.remove()
  43. }
  44. } else if (event.type === 'nodeChanged') {
  45. for (let object of event.objects) {
  46. let treeNode = this.map.get(object)
  47. if (treeNode) {
  48. treeNode.updateLabel()
  49. this.updateNodeStyle(treeNode)
  50. }
  51. }
  52. } else if (event.type === 'structureChanged') {
  53. let objects = this.getRootObjects(event.objects)
  54. if (objects.length === 1 && objects[0] === this.application.scene) {
  55. // update all tree
  56. this.update()
  57. } else {
  58. for (let object of objects) {
  59. let treeNode = this.map.get(object)
  60. if (treeNode) {
  61. this.destroyMap(treeNode)
  62. treeNode.updateLabel()
  63. treeNode.clear()
  64. this.populateChildren(treeNode)
  65. this.createMap(treeNode)
  66. }
  67. }
  68. }
  69. this.updateSelection()
  70. } else if (event.type === 'cameraActivated') {
  71. this.clearNodeStyle('active_camera')
  72. let camera = event.object
  73. let treeNode = this.map.get(camera)
  74. if (treeNode) treeNode.addClass('active_camera')
  75. } else if (event.type === 'cut') {
  76. this.clearNodeStyle('cut')
  77. for (let object of event.objects) {
  78. let treeNode = this.map.get(object)
  79. if (treeNode) treeNode.addClass('cut')
  80. }
  81. } else if (event.type === 'pasted') {
  82. this.clearNodeStyle('cut')
  83. for (let object of event.objects) {
  84. let treeNode = this.map.get(object)
  85. if (treeNode) treeNode.expandAncestors(false)
  86. }
  87. }
  88. })
  89. if (application.scene) this.update()
  90. }
  91. update() {
  92. this.tree.clear()
  93. this.map.clear()
  94. let treeNode = this.populateObject(this.application.scene)
  95. this.createMap(treeNode)
  96. }
  97. updateSelection() {
  98. // clear previous selectes nodes
  99. this.clearNodeStyle('selected')
  100. // mark new selection
  101. const selection = this.application.selection
  102. const objects = selection.objects
  103. const lastObject = objects[objects.length - 1]
  104. for (let object of objects) {
  105. let treeNode = this.map.get(object)
  106. if (treeNode) {
  107. treeNode.addClass('selected')
  108. let makeVisible = object === lastObject && this.autoScroll
  109. treeNode.expandAncestors(makeVisible)
  110. }
  111. }
  112. this.bodyElem.scrollLeft = 0
  113. this.autoScroll = true
  114. }
  115. populateObject(object, parentTreeNode) {
  116. let onClick = event => {
  117. this.autoScroll = false
  118. this.application.userSelectObjects([object], event)
  119. }
  120. let treeNode
  121. if (parentTreeNode) {
  122. treeNode = parentTreeNode.addNode(object, onClick)
  123. } else {
  124. treeNode = this.tree.addNode(object, onClick)
  125. }
  126. this.updateNodeStyle(treeNode)
  127. this.populateChildren(treeNode)
  128. return treeNode
  129. }
  130. populateChildren(treeNode) {
  131. let object = treeNode.value
  132. for (let child of object.children) {
  133. let name = child.name || ''
  134. if (!name.startsWith(THREE.Object3D.HIDDEN_PREFIX)) {
  135. this.populateObject(child, treeNode)
  136. }
  137. }
  138. }
  139. getObjectClassNames(object) {
  140. let classList = [object.type]
  141. if (object.userData.IFC && object.userData.IFC.ifcClassName) {
  142. classList.push(object.userData.IFC.ifcClassName)
  143. }
  144. if (object.builder) {
  145. classList.push(object.builder.constructor.name)
  146. }
  147. return classList.join(' ')
  148. }
  149. updateNodeStyle(treeNode) {
  150. const object = treeNode.value
  151. if (object.visible) {
  152. treeNode.removeClass('hidden')
  153. } else {
  154. treeNode.addClass('hidden')
  155. }
  156. let expanded = treeNode.isExpanded()
  157. treeNode.itemElem.className = this.getObjectClassNames(object)
  158. if (expanded) {
  159. treeNode.expand()
  160. } else {
  161. treeNode.collapse()
  162. }
  163. }
  164. clearNodeStyle(className) {
  165. let nodes = this.tree.rootsElem.getElementsByClassName(className)
  166. nodes = [...nodes]
  167. for (let node of nodes) {
  168. node.classList.remove(className)
  169. }
  170. }
  171. getRootObjects(objects) {
  172. const set = new Set()
  173. for (let object of objects) {
  174. set.add(object)
  175. }
  176. const roots = []
  177. for (let object of set) {
  178. let ancestor = object.parent
  179. while (ancestor && !set.has(ancestor)) {
  180. ancestor = ancestor.parent
  181. }
  182. if (ancestor === null) roots.push(object)
  183. }
  184. return roots
  185. }
  186. createMap(treeNode) {
  187. this.map.set(treeNode.value, treeNode)
  188. for (let childTreeNode of treeNode.children) {
  189. this.createMap(childTreeNode)
  190. }
  191. }
  192. destroyMap(treeNode) {
  193. this.map.delete(treeNode.value)
  194. for (let childTreeNode of treeNode.children) {
  195. this.destroyMap(childTreeNode)
  196. }
  197. }
  198. }
  199. export { Outliner }