@abi-software/scaffoldvuer 0.2.3-alpha-2 → 0.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (49) hide show
  1. package/.eslintrc.js +12 -12
  2. package/CHANGELOG.md +344 -316
  3. package/LICENSE +201 -201
  4. package/README.md +164 -164
  5. package/babel.config.js +14 -14
  6. package/dist/scaffoldvuer-wc.common.js +277 -34
  7. package/dist/scaffoldvuer-wc.umd.js +277 -34
  8. package/dist/scaffoldvuer-wc.umd.min.js +277 -34
  9. package/dist/scaffoldvuer.common.js +1252 -529
  10. package/dist/scaffoldvuer.common.js.map +1 -1
  11. package/dist/scaffoldvuer.css +1 -1
  12. package/dist/scaffoldvuer.umd.js +1252 -529
  13. package/dist/scaffoldvuer.umd.js.map +1 -1
  14. package/dist/scaffoldvuer.umd.min.js +1 -1
  15. package/dist/scaffoldvuer.umd.min.js.map +1 -1
  16. package/package-lock.json +18121 -18119
  17. package/package.json +89 -89
  18. package/public/index.html +17 -17
  19. package/src/App.vue +669 -669
  20. package/src/ScaffoldVuer-wc.js +13 -13
  21. package/src/app/DropZone.vue +114 -114
  22. package/src/app/ModelsInformation.js +35 -35
  23. package/src/app/ModelsTable.vue +113 -113
  24. package/src/app/TextureDemos.js +114 -114
  25. package/src/assets/_variables.scss +43 -43
  26. package/src/assets/styles.scss +7 -7
  27. package/src/components/OpacityControls.vue +123 -222
  28. package/src/components/PrimitiveControls.vue +173 -0
  29. package/src/components/ScaffoldTooltip.vue +142 -142
  30. package/src/components/ScaffoldVuer.md +44 -44
  31. package/src/components/ScaffoldVuer.vue +2007 -2007
  32. package/src/components/TextureSlidesControls.vue +272 -0
  33. package/src/components/TreeControls.vue +707 -699
  34. package/src/components/index.js +7 -7
  35. package/src/credential.json +12 -0
  36. package/src/main.js +14 -14
  37. package/src/scripts/BaseModule.js +80 -80
  38. package/src/scripts/RendererModule.js +289 -289
  39. package/src/scripts/WebGL.js +94 -94
  40. package/src/scripts/annotation.js +5 -5
  41. package/src/scripts/eventNotifier.js +66 -66
  42. package/src/scripts/graphicsHighlight.js +134 -134
  43. package/src/scripts/organsRenderer.js +587 -587
  44. package/src/scripts/search.js +182 -182
  45. package/src/scripts/utilities.js +146 -146
  46. package/styleguide.config.js +22 -22
  47. package/vue.config.js +41 -41
  48. package/src/components/test.pdf +0 -0
  49. package/src/searchControls.vue +0 -122
@@ -1,699 +1,707 @@
1
- <template>
2
- <div
3
- class="tree-controls"
4
- :class="{ open: drawerOpen, close: !drawerOpen }"
5
- >
6
- <div class="traditional-container">
7
- <el-row>
8
- <el-col :span="12">
9
- <div class="regions-display-text">
10
- Regions
11
- </div>
12
- </el-col>
13
- </el-row>
14
- <div class="tree-container">
15
- <el-tree
16
- ref="regionTree"
17
- node-key="id"
18
- v-loading="!isReady"
19
- show-checkbox
20
- element-loading-spinner="el-icon-loading"
21
- element-loading-background="rgba(0, 0, 0, 0.3)"
22
- :check-strictly="false"
23
- :data="treeData[0].children"
24
- :expand-on-click-node="false"
25
- :render-after-expand="false"
26
- @check="checkChanged"
27
- >
28
- <span
29
- slot-scope="{ node, data }"
30
- class="region-tree-node"
31
- :class="{
32
- activeItem: active.includes(data.id),
33
- hoverItem: hover.includes(data.id),
34
- }"
35
- @click="changeActiveByNode(data, true)"
36
- @mouseover="changeHoverByNode(data, true)"
37
- >
38
- <el-color-picker
39
- v-if="data.isPrimitives"
40
- :class="{ 'show-picker': showColourPicker }"
41
- :value="getColour(data)"
42
- size="small"
43
- :popper-class="myPopperClass"
44
- @change="setColour(data, $event)"
45
- />
46
- <span>{{ node.label }}</span>
47
- </span>
48
- </el-tree>
49
- </div>
50
- </div>
51
- <div
52
- class="drawer-button"
53
- :class="{ open: drawerOpen, close: !drawerOpen }"
54
- @click="toggleDrawer"
55
- >
56
- <i class="el-icon-arrow-left" />
57
- </div>
58
- </div>
59
- </template>
60
-
61
- <script>
62
- /* eslint-disable no-alert, no-console */
63
- import Vue from "vue";
64
- import {
65
- Checkbox,
66
- CheckboxGroup,
67
- ColorPicker,
68
- Loading,
69
- Row,
70
- Tree,
71
- } from "element-ui";
72
- import lang from "element-ui/lib/locale/lang/en";
73
- import locale from "element-ui/lib/locale";
74
- import {
75
- convertUUIDsToFullPaths,
76
- createListFromPrimitives,
77
- extractAllFullPaths,
78
- findObjectsWithNames,
79
- } from "../scripts/utilities.js";
80
-
81
- const orderBy = require("lodash/orderBy");
82
- const uniq = require("lodash/uniq");
83
- locale.use(lang);
84
- Vue.use(Checkbox);
85
- Vue.use(CheckboxGroup);
86
- Vue.use(ColorPicker);
87
- Vue.use(Loading);
88
- Vue.use(Row);
89
- Vue.use(Tree);
90
-
91
- const nameSorting = (a, b) => {
92
- const labelA = a.label.toUpperCase();
93
- const labelB = b.label.toUpperCase();
94
- if (labelA < labelB) {
95
- return -1;
96
- }
97
- if (labelA > labelB) {
98
- return 1;
99
- }
100
- return 0;
101
- };
102
-
103
- /**
104
- * A vue component for toggling visibility of various regions.
105
- */
106
- export default {
107
- name: "TreeControls",
108
- props: {
109
- /**
110
- * Enable/disable colour picker
111
- */
112
- showColourPicker: Boolean,
113
- isReady: Boolean,
114
- },
115
- data: function () {
116
- return {
117
- treeData: [{ label: "Root", regionPath: "", id: undefined, children: [] }],
118
- active: [],
119
- hover: [],
120
- myPopperClass: "hide-scaffold-colour-popup",
121
- drawerOpen: true,
122
- };
123
- },
124
- watch: {
125
- showColourPicker: {
126
- immediate: true,
127
- handler: function () {
128
- if (this.showColourPicker) this.myPopperClass = "showPicker";
129
- else this.myPopperClass = "hide-scaffold-colour-popup";
130
- },
131
- },
132
- },
133
- destroyed: function () {
134
- this.sortedPrimitiveGroups = undefined;
135
- },
136
- methods: {
137
- addTreeItem: function (parentContainer, item) {
138
- //The following block prevent duplicate graphics with the same name
139
- if (parentContainer.some(child => child.label === item.label)) {
140
- return;
141
- }
142
- parentContainer.push(item);
143
- parentContainer.sort((a, b) => {
144
- return nameSorting(a, b);
145
- });
146
- this.__nodeNumbers++;
147
- this.$nextTick(() => {
148
- this.$refs.regionTree.setChecked(item.id, true);
149
- });
150
- },
151
- // find or create new region, region id is always prefixed with
152
- // '__r/'
153
- findOrCreateRegion: function (data, paths, prefix) {
154
- //check if root region has been set
155
- if (
156
- this.rootID === undefined &&
157
- this.$module &&
158
- this.$module.scene
159
- ) {
160
- this.treeData[0].id = this.$module.scene.getRootRegion().uuid;
161
- this.treeData[0].isRegion = true;
162
- }
163
- if (paths.length > 0) {
164
- const _paths = [...paths];
165
- let childRegion = data.children.find(
166
- (child) => child.label == _paths[0]
167
- );
168
- const path = prefix + "/" + paths[0];
169
- const region = this.$module.scene.getRootRegion().findChildFromPath(path);
170
- if (!childRegion) {
171
- childRegion = {
172
- label: _paths[0],
173
- id: region.uuid,
174
- children: [],
175
- regionPath: path,
176
- isRegion: true,
177
- };
178
- this.addTreeItem(data.children, childRegion);
179
- }
180
- _paths.shift();
181
- return this.findOrCreateRegion(childRegion, _paths, path);
182
- } else {
183
- return data;
184
- }
185
- },
186
- /**
187
- * This is called when a new zinc object is read into the scene.
188
- */
189
- zincObjectAdded: function (zincObject) {
190
- // Using the new uuid, the cavaet of that is graphics with
191
- // same groupName will have different uuid. So in the tree control
192
- // We use the first uuid found for a group of primitives with same
193
- // group names to represent all of them.
194
- const region = zincObject.region;
195
- if (region) {
196
- const paths = region.getFullSeparatedPath();
197
- const regionData = this.findOrCreateRegion(this.treeData[0], paths, "");
198
- if (zincObject.groupName) {
199
- if (regionData) {
200
- if (!regionData.children) {
201
- regionData.children = [];
202
- }
203
- const child = {
204
- label: zincObject.groupName,
205
- id: region.uuid + "/" + zincObject.uuid,
206
- isPrimitives: true,
207
- regionPath: zincObject.region.getFullPath(),
208
- };
209
- this.addTreeItem(regionData.children, child);
210
- }
211
- }
212
- }
213
- },
214
- checkChanged: function (node, data) {
215
- const isRegion = node.isRegion;
216
- const isPrimitives = node.isPrimitives;
217
- const isChecked = data.checkedKeys.includes(node.id);
218
- const region = this.$module.scene
219
- .getRootRegion()
220
- .findChildFromPath(node.regionPath);
221
- if (isRegion) {
222
- isChecked ? region.showAllPrimitives() : region.hideAllPrimitives();
223
- }
224
- if (isPrimitives) {
225
- const primitives = region.findObjectsWithGroupName(node.label);
226
- primitives.forEach((primitive) => {
227
- primitive.setVisibility(isChecked);
228
- });
229
- }
230
- },
231
- updateActiveUI: function (primitives) {
232
- this.active.length = 0;
233
- createListFromPrimitives(primitives, this.active);
234
- },
235
- changeActiveByPrimitives: function (primitives, propagate) {
236
- if (primitives && primitives.length > 0) {
237
- this.updateActiveUI(primitives);
238
- this.$emit("object-selected", primitives, propagate);
239
- } else {
240
- this.removeActive(propagate);
241
- }
242
- this.removeHover(propagate);
243
- },
244
- updateHoverUI: function (primitives) {
245
- this.hover.length = 0;
246
- createListFromPrimitives(primitives, this.hover);
247
- },
248
- changeHoverByPrimitives: function (primitives, propagate) {
249
- if (primitives && primitives.length > 0) {
250
- this.updateHoverUI(primitives);
251
- this.$emit("object-hovered", primitives, propagate);
252
- } else {
253
- this.removeHover(propagate);
254
- }
255
- },
256
- /**
257
- * Select a region by its name.
258
- */
259
- changeActiveByNames: function (names, regionPath, propagate) {
260
- const rootRegion = this.$module.scene.getRootRegion();
261
- const targetObjects = findObjectsWithNames(
262
- rootRegion,
263
- names,
264
- regionPath,
265
- true
266
- );
267
- this.changeActiveByPrimitives(targetObjects, propagate);
268
- },
269
- /**
270
- * Hover a region by its name.
271
- */
272
- changeHoverByNames: function (names, regionPath, propagate) {
273
- const rootRegion = this.$module.scene.getRootRegion();
274
- const targetObjects = findObjectsWithNames(
275
- rootRegion,
276
- names,
277
- regionPath,
278
- true
279
- );
280
- this.changeHoverByPrimitives(targetObjects, propagate);
281
- },
282
- changeActiveByNode: function (node, propagate) {
283
- if (node.isPrimitives || node.isRegion) {
284
- const transverse = node.isRegion ? true : false;
285
- const targetObjects = this.getZincObjectsFromNode(node, transverse);
286
- this.changeActiveByPrimitives(targetObjects, propagate);
287
- }
288
- },
289
- changeHoverByNode: function (node, propagate) {
290
- if (node.isPrimitives) {
291
- const targetObjects = this.getZincObjectsFromNode(node, false);
292
- this.changeHoverByPrimitives(targetObjects, propagate);
293
- }
294
- },
295
- /**
296
- * Unselect the current selected region.
297
- */
298
- removeActive: function (propagate) {
299
- this.active = [];
300
- this.$emit("object-selected", [], propagate);
301
- },
302
- /**
303
- * Unselect the current hover region.
304
- */
305
- removeHover: function (propagate) {
306
- this.hover = [];
307
- this.$emit("object-hovered", [], propagate);
308
- },
309
- /**
310
- * Reset the controls.
311
- */
312
- clear: function () {
313
- this.active.length = 0;
314
- this.hover.length = 0;
315
- this.__nodeNumbers = 0;
316
- this.$refs.regionTree.updateKeyChildren(this.treeData[0].id, []);
317
- this.treeData[0].children.length = 0;
318
- this.treeData[0].id = undefined;
319
- this.$emit("object-selected", []);
320
- },
321
- getColour: function (nodeData) {
322
- //Do not need to check for primitives as this is checked on the template
323
- if (nodeData) {
324
- const targetObjects = this.getZincObjectsFromNode(nodeData, false);
325
- let graphic = targetObjects[0];
326
- if (graphic) {
327
- let hex = graphic.getColourHex();
328
- if (hex) return "#" + hex;
329
- }
330
- }
331
- return "#FFFFFF";
332
- },
333
- getZincObjectsFromNode: function (node, transverse) {
334
- const rootRegion = this.$module.scene.getRootRegion();
335
- if (node.isPrimitives) {
336
- return findObjectsWithNames(
337
- rootRegion,
338
- node.label,
339
- node.regionPath,
340
- transverse
341
- );
342
- } else if (node.isRegion) {
343
- if (node.regionPath) {
344
- let targetRegion = rootRegion.findChildFromPath(node.regionPath);
345
- if (targetRegion) {
346
- return targetRegion.getAllObjects(transverse);
347
- }
348
- }
349
- }
350
- return [];
351
- },
352
- //Set this right at the beginning.
353
- setModule: function (moduleIn) {
354
- this.$module = moduleIn;
355
- this.__nodeNumbers = 0;
356
- const objects = this.$module.scene.getRootRegion().getAllObjects(true);
357
- objects.forEach((zincObject) => {
358
- this.zincObjectAdded(zincObject);
359
- });
360
- this.$module.addOrganPartAddedCallback(this.zincObjectAdded);
361
-
362
- },
363
- setColour: function (nodeData, value) {
364
- if (nodeData && nodeData.isPrimitives) {
365
- const targetObjects = this.getZincObjectsFromNode(nodeData, false);
366
- targetObjects.forEach((primitive) => {
367
- let hexString = value.replace("#", "0x");
368
- primitive.setColourHex(hexString);
369
- });
370
- }
371
- },
372
- viewAll: function () {
373
- this.$module.viewAll();
374
- },
375
- visibilityToggle: function (item, event) {
376
- this.$module.changeOrganPartsVisibility(item, event);
377
- if (event == false) {
378
- if (this.activeRegion === item) {
379
- this.removeActive(true);
380
- }
381
- if (this.hoverRegion === item) {
382
- this.removeHover(true);
383
- }
384
- }
385
- },
386
- toggleDrawer: function () {
387
- this.drawerOpen = !this.drawerOpen;
388
- this.$emit("drawer-toggled", this.drawerOpen);
389
- },
390
- //Set visibility using full paths and add found id to the ids list
391
- //and remove item from list if remove is set to true.
392
- setTreeVisibilityWithFullPaths: function (node, list, ids, remove) {
393
- let flag = false;
394
- let nodeName = "";
395
- if (node.isRegion) {
396
- nodeName = `__r${node.regionPath}`;
397
- }
398
- if (node.isPrimitives) {
399
- nodeName = `${node.regionPath}/${node.label}`;
400
- }
401
- //Find the node in list, remove it from list if remove flag is on
402
- const index = list.indexOf(nodeName);
403
- if (index > -1) {
404
- flag = true;
405
- list.splice(index, 1);
406
- ids.push(node.id);
407
- }
408
- const region = this.$module.scene
409
- .getRootRegion()
410
- .findChildFromPath(node.regionPath);
411
- if (nodeName && (nodeName !== "__r")) {
412
- if (node.isPrimitives) {
413
- const primitives = region.findObjectsWithGroupName(node.label);
414
- primitives.forEach((primitive) => primitive.setVisibility(flag));
415
- }
416
- }
417
- if (node.children) {
418
- node.children.forEach((child) => {
419
- this.setTreeVisibilityWithFullPaths(child, list, ids, true);
420
- });
421
- }
422
- },
423
- checkAllKeys: function () {
424
- const keysList = [];
425
- const ids = [];
426
- extractAllFullPaths(this.treeData[0], keysList);
427
- this.setTreeVisibilityWithFullPaths(this.treeData[0],
428
- keysList, ids, true);
429
- this.$refs.regionTree.setCheckedKeys(ids);
430
- },
431
- getState: function () {
432
- let checkedItems = this.$refs.regionTree.getCheckedKeys();
433
- if (checkedItems.length === this.__nodeNumbers) {
434
- return { checkAll: true, version: "2.0" };
435
- } else {
436
- //We cannot use the generated uuid as the identifier for permastate,
437
- //convert it back to paths
438
- let paths = convertUUIDsToFullPaths(this.$module.scene.getRootRegion(),
439
- checkedItems);
440
- return { checkedItems: paths, version: "2.0" };
441
- }
442
- },
443
- setState: function (state) {
444
- if (state) {
445
- if (state.checkAll) {
446
- this.checkAllKeys();
447
- } else if (state.checkedItems) {
448
- let list = [];
449
- if (state.version !== "2.0") {
450
- list = state.checkedItems.map((item) => "/" + item);
451
- list.shift("__r/");
452
- } else {
453
- list.push(...state.checkedItems);
454
- }
455
- const ids = [];
456
- this.setTreeVisibilityWithFullPaths(this.treeData[0], list,
457
- ids, true);
458
- this.$refs.regionTree.setCheckedKeys(ids);
459
- }
460
- }
461
- },
462
- },
463
- };
464
- </script>
465
-
466
- <!-- Add "scoped" attribute to limit CSS to this component only -->
467
- <style scoped lang="scss">
468
- @import "~element-ui/packages/theme-chalk/src/checkbox";
469
- @import "~element-ui/packages/theme-chalk/src/color-picker";
470
- @import "~element-ui/packages/theme-chalk/src/loading";
471
- @import "~element-ui/packages/theme-chalk/src/row";
472
- @import "~element-ui/packages/theme-chalk/src/tree";
473
-
474
- .checkbox-container {
475
- display: flex;
476
- cursor: pointer;
477
- }
478
-
479
- .tree-controls {
480
- position: absolute;
481
- bottom: 0px;
482
- transition: all 1s ease;
483
-
484
- &:focus {
485
- outline: none;
486
- }
487
- &.open {
488
- left: 0px;
489
- .traditional-container {
490
- opacity: 1;
491
- }
492
- }
493
- &.close {
494
- left: -298px;
495
- .traditional-container {
496
- pointer-events: none;
497
- opacity: 0;
498
- }
499
- }
500
- }
501
-
502
- .traditional-container {
503
- transition: all 1s ease;
504
- float: left;
505
- padding-left: 16px;
506
- padding-right: 18px;
507
- max-height: calc(100% - 154px);
508
- text-align: left;
509
- overflow: none;
510
- border: 1px solid rgb(220, 223, 230);
511
- padding-top: 7px;
512
- padding-bottom: 16px;
513
- background: #ffffff;
514
- }
515
-
516
- .regions-display-text {
517
- width: 59px;
518
- height: 20px;
519
- color: rgb(48, 49, 51);
520
- font-size: 14px;
521
- font-weight: normal;
522
- line-height: 20px;
523
- margin-left: 8px;
524
- }
525
-
526
- .all-checkbox {
527
- float: right;
528
- }
529
-
530
- .tree-container {
531
- width: 260px;
532
- border: 1px solid rgb(144, 147, 153);
533
- border-radius: 4px;
534
- background: #ffffff;
535
- margin-top: 6px;
536
- scrollbar-width: thin;
537
-
538
- ::v-deep .el-tree {
539
- max-height: 240px;
540
- min-height: 130px;
541
- overflow: auto;
542
- &::-webkit-scrollbar {
543
- width: 4px;
544
- }
545
-
546
- &::-webkit-scrollbar-thumb {
547
- border-radius: 10px;
548
- box-shadow: inset 0 0 6px #c0c4cc;
549
- }
550
- }
551
-
552
- ::v-deep .el-tree-node__content {
553
- height: 22px;
554
- }
555
- }
556
-
557
- ::v-deep .el-checkbox__input {
558
- &.is-indeterminate,
559
- &.is-checked {
560
- .el-checkbox__inner {
561
- background-color: $app-primary-color;
562
- border-color: $app-primary-color;
563
- }
564
- }
565
- }
566
-
567
- ::v-deep .el-color-picker__color {
568
- border: 1px solid $app-primary-color;
569
- }
570
-
571
- ::v-deep .el-checkbox__label {
572
- padding-left: 5px;
573
- color: $app-primary-color !important;
574
- font-size: 12px;
575
- font-weight: 500;
576
- letter-spacing: 0px;
577
- line-height: 14px;
578
- }
579
-
580
- .activeItem {
581
- background-color: #bbb !important;
582
- }
583
-
584
- .region-tree-node {
585
- flex: 1;
586
- color: $app-primary-color !important;
587
- display: flex;
588
- font-size: 12px;
589
- line-height: 14px;
590
- padding-left: 0px;
591
- background-color: #fff;
592
- width: 100%;
593
-
594
- ::v-deep .el-color-picker {
595
- height: 14px !important;
596
- }
597
-
598
- ::v-deep .el-color-picker__trigger {
599
- margin-left: 8px;
600
- margin-right: 8px;
601
- padding: 0px;
602
- height: 14px;
603
- width: 14px;
604
- border: 0px;
605
- }
606
- }
607
-
608
- .hoverItem {
609
- background-color: #eee !important;
610
- }
611
-
612
- ::v-deep .el-color-picker__icon {
613
- &.el-icon-arrow-down {
614
- display: none;
615
- }
616
- }
617
-
618
- ::v-deep .show-picker {
619
- .el-color-picker__icon {
620
- &.el-icon-arrow-down {
621
- display: block;
622
- }
623
- }
624
- }
625
-
626
- ::v-deep .my-drawer {
627
- background: rgba(0, 0, 0, 0);
628
- box-shadow: none;
629
- }
630
-
631
- .drawer {
632
- ::v-deep .el-drawer:focus {
633
- outline: none;
634
- }
635
- }
636
-
637
- .open-drawer {
638
- width: 20px;
639
- height: 40px;
640
- z-index: 8;
641
- position: absolute;
642
- left: 0px;
643
- box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.06);
644
- border: solid 1px #e4e7ed;
645
- background-color: #f7faff;
646
- text-align: center;
647
- vertical-align: middle;
648
- cursor: pointer;
649
- pointer-events: auto;
650
- }
651
-
652
- .drawer-button {
653
- float: left;
654
- width: 20px;
655
- height: 40px;
656
- z-index: 8;
657
- margin-top: calc(50% - 52px);
658
- border: solid 1px $app-primary-color;
659
- background-color: #f9f2fc;
660
- text-align: center;
661
- vertical-align: middle;
662
- cursor: pointer;
663
- pointer-events: auto;
664
- }
665
-
666
- .drawer-button {
667
- i {
668
- font-weight: 600;
669
- margin-top: 12px;
670
- color: $app-primary-color;
671
- transition-delay: 0.9s;
672
- }
673
- &.open {
674
- i {
675
- transform: rotate(0deg) scaleY(2);
676
- }
677
- }
678
- &.close {
679
- i {
680
- transform: rotate(180deg) scaleY(2);
681
- }
682
- }
683
- }
684
-
685
- .drawer-button.open i {
686
- transform: rotate(0deg) scaleY(2.5);
687
- }
688
-
689
- .drawer-button.close i {
690
- transform: rotate(180deg) scaleY(2.5);
691
- }
692
- </style>
693
-
694
- <style>
695
- .hide-scaffold-colour-popup {
696
- display: none;
697
- }
698
- </style>
699
-
1
+ <template>
2
+ <div
3
+ class="tree-controls"
4
+ :class="{ open: drawerOpen, close: !drawerOpen }"
5
+ >
6
+ <div class="traditional-container">
7
+ <el-row>
8
+ <el-col :span="12">
9
+ <div class="regions-display-text">
10
+ Regions
11
+ </div>
12
+ </el-col>
13
+ </el-row>
14
+ <div class="tree-container">
15
+ <el-tree
16
+ ref="regionTree"
17
+ node-key="id"
18
+ v-loading="!isReady"
19
+ show-checkbox
20
+ element-loading-spinner="el-icon-loading"
21
+ element-loading-background="rgba(0, 0, 0, 0.3)"
22
+ :check-strictly="false"
23
+ :data="treeData[0].children"
24
+ :expand-on-click-node="false"
25
+ :render-after-expand="false"
26
+ @check="checkChanged"
27
+ >
28
+ <span
29
+ slot-scope="{ node, data }"
30
+ class="region-tree-node"
31
+ :class="{
32
+ activeItem: active.includes(data.id),
33
+ hoverItem: hover.includes(data.id),
34
+ }"
35
+ @click="changeActiveByNode(data, true)"
36
+ @mouseover="changeHoverByNode(data, true)"
37
+ >
38
+ <el-color-picker
39
+ v-if="data.isPrimitives"
40
+ :class="{ 'show-picker': showColourPicker }"
41
+ :value="getColour(data)"
42
+ size="small"
43
+ :popper-class="myPopperClass"
44
+ @change="setColour(data, $event)"
45
+ />
46
+ <span>{{ node.label }}</span>
47
+ <span v-if="data.isTextureSlides" class="node-options">
48
+ (Texture)
49
+ </span>
50
+ </span>
51
+ </el-tree>
52
+ </div>
53
+ </div>
54
+ <div
55
+ class="drawer-button"
56
+ :class="{ open: drawerOpen, close: !drawerOpen }"
57
+ @click="toggleDrawer"
58
+ >
59
+ <i class="el-icon-arrow-left" />
60
+ </div>
61
+ </div>
62
+ </template>
63
+
64
+ <script>
65
+ /* eslint-disable no-alert, no-console */
66
+ import Vue from "vue";
67
+ import {
68
+ Checkbox,
69
+ CheckboxGroup,
70
+ ColorPicker,
71
+ Loading,
72
+ Row,
73
+ Tree,
74
+ } from "element-ui";
75
+ import lang from "element-ui/lib/locale/lang/en";
76
+ import locale from "element-ui/lib/locale";
77
+ import {
78
+ convertUUIDsToFullPaths,
79
+ createListFromPrimitives,
80
+ extractAllFullPaths,
81
+ findObjectsWithNames,
82
+ } from "../scripts/utilities.js";
83
+
84
+ const orderBy = require("lodash/orderBy");
85
+ const uniq = require("lodash/uniq");
86
+ locale.use(lang);
87
+ Vue.use(Checkbox);
88
+ Vue.use(CheckboxGroup);
89
+ Vue.use(ColorPicker);
90
+ Vue.use(Loading);
91
+ Vue.use(Row);
92
+ Vue.use(Tree);
93
+
94
+ const nameSorting = (a, b) => {
95
+ const labelA = a.label.toUpperCase();
96
+ const labelB = b.label.toUpperCase();
97
+ if (labelA < labelB) {
98
+ return -1;
99
+ }
100
+ if (labelA > labelB) {
101
+ return 1;
102
+ }
103
+ return 0;
104
+ };
105
+
106
+ /**
107
+ * A vue component for toggling visibility of various regions.
108
+ */
109
+ export default {
110
+ name: "TreeControls",
111
+ props: {
112
+ /**
113
+ * Enable/disable colour picker
114
+ */
115
+ showColourPicker: Boolean,
116
+ isReady: Boolean,
117
+ },
118
+ data: function () {
119
+ return {
120
+ treeData: [{ label: "Root", regionPath: "", id: undefined, children: [] }],
121
+ active: [],
122
+ hover: [],
123
+ myPopperClass: "hide-scaffold-colour-popup",
124
+ drawerOpen: true,
125
+ };
126
+ },
127
+ watch: {
128
+ showColourPicker: {
129
+ immediate: true,
130
+ handler: function () {
131
+ if (this.showColourPicker) this.myPopperClass = "showPicker";
132
+ else this.myPopperClass = "hide-scaffold-colour-popup";
133
+ },
134
+ },
135
+ },
136
+ destroyed: function () {
137
+ this.sortedPrimitiveGroups = undefined;
138
+ },
139
+ methods: {
140
+ addTreeItem: function (parentContainer, item) {
141
+ //The following block prevent duplicate graphics with the same name
142
+ if (parentContainer.some(child => child.label === item.label)) {
143
+ return;
144
+ }
145
+ parentContainer.push(item);
146
+ parentContainer.sort((a, b) => {
147
+ return nameSorting(a, b);
148
+ });
149
+ this.__nodeNumbers++;
150
+ this.$nextTick(() => {
151
+ this.$refs.regionTree.setChecked(item.id, true);
152
+ });
153
+ },
154
+ // find or create new region, region id is always prefixed with
155
+ // '__r/'
156
+ findOrCreateRegion: function (data, paths, prefix) {
157
+ //check if root region has been set
158
+ if (
159
+ this.rootID === undefined &&
160
+ this.$module &&
161
+ this.$module.scene
162
+ ) {
163
+ this.treeData[0].id = this.$module.scene.getRootRegion().uuid;
164
+ this.treeData[0].isRegion = true;
165
+ }
166
+ if (paths.length > 0) {
167
+ const _paths = [...paths];
168
+ let childRegion = data.children.find(
169
+ (child) => child.label == _paths[0]
170
+ );
171
+ const path = prefix + "/" + paths[0];
172
+ const region = this.$module.scene.getRootRegion().findChildFromPath(path);
173
+ if (!childRegion) {
174
+ childRegion = {
175
+ label: _paths[0],
176
+ id: region.uuid,
177
+ children: [],
178
+ regionPath: path,
179
+ isRegion: true,
180
+ };
181
+ this.addTreeItem(data.children, childRegion);
182
+ }
183
+ _paths.shift();
184
+ return this.findOrCreateRegion(childRegion, _paths, path);
185
+ } else {
186
+ return data;
187
+ }
188
+ },
189
+ /**
190
+ * This is called when a new zinc object is read into the scene.
191
+ */
192
+ zincObjectAdded: function (zincObject) {
193
+ // Using the new uuid, the cavaet of that is graphics with
194
+ // same groupName will have different uuid. So in the tree control
195
+ // We use the first uuid found for a group of primitives with same
196
+ // group names to represent all of them.
197
+ const region = zincObject.region;
198
+ if (region) {
199
+ const paths = region.getFullSeparatedPath();
200
+ const regionData = this.findOrCreateRegion(this.treeData[0], paths, "");
201
+ if (zincObject.groupName) {
202
+ if (regionData) {
203
+ if (!regionData.children) {
204
+ regionData.children = [];
205
+ }
206
+ const child = {
207
+ label: zincObject.groupName,
208
+ id: region.uuid + "/" + zincObject.uuid,
209
+ isPrimitives: true,
210
+ regionPath: zincObject.region.getFullPath(),
211
+ isTextureSlides: zincObject.isTextureSlides ? true : false,
212
+ };
213
+ this.addTreeItem(regionData.children, child);
214
+ }
215
+ }
216
+ }
217
+ },
218
+ checkChanged: function (node, data) {
219
+ const isRegion = node.isRegion;
220
+ const isPrimitives = node.isPrimitives;
221
+ const isChecked = data.checkedKeys.includes(node.id);
222
+ const region = this.$module.scene
223
+ .getRootRegion()
224
+ .findChildFromPath(node.regionPath);
225
+ if (isRegion) {
226
+ isChecked ? region.showAllPrimitives() : region.hideAllPrimitives();
227
+ }
228
+ if (isPrimitives) {
229
+ const primitives = region.findObjectsWithGroupName(node.label);
230
+ primitives.forEach((primitive) => {
231
+ primitive.setVisibility(isChecked);
232
+ });
233
+ }
234
+ },
235
+ updateActiveUI: function (primitives) {
236
+ this.active.length = 0;
237
+ createListFromPrimitives(primitives, this.active);
238
+ },
239
+ changeActiveByPrimitives: function (primitives, propagate) {
240
+ if (primitives && primitives.length > 0) {
241
+ this.updateActiveUI(primitives);
242
+ this.$emit("object-selected", primitives, propagate);
243
+ } else {
244
+ this.removeActive(propagate);
245
+ }
246
+ this.removeHover(propagate);
247
+ },
248
+ updateHoverUI: function (primitives) {
249
+ this.hover.length = 0;
250
+ createListFromPrimitives(primitives, this.hover);
251
+ },
252
+ changeHoverByPrimitives: function (primitives, propagate) {
253
+ if (primitives && primitives.length > 0) {
254
+ this.updateHoverUI(primitives);
255
+ this.$emit("object-hovered", primitives, propagate);
256
+ } else {
257
+ this.removeHover(propagate);
258
+ }
259
+ },
260
+ /**
261
+ * Select a region by its name.
262
+ */
263
+ changeActiveByNames: function (names, regionPath, propagate) {
264
+ const rootRegion = this.$module.scene.getRootRegion();
265
+ const targetObjects = findObjectsWithNames(
266
+ rootRegion,
267
+ names,
268
+ regionPath,
269
+ true
270
+ );
271
+ this.changeActiveByPrimitives(targetObjects, propagate);
272
+ },
273
+ /**
274
+ * Hover a region by its name.
275
+ */
276
+ changeHoverByNames: function (names, regionPath, propagate) {
277
+ const rootRegion = this.$module.scene.getRootRegion();
278
+ const targetObjects = findObjectsWithNames(
279
+ rootRegion,
280
+ names,
281
+ regionPath,
282
+ true
283
+ );
284
+ this.changeHoverByPrimitives(targetObjects, propagate);
285
+ },
286
+ changeActiveByNode: function (node, propagate) {
287
+ if (node.isPrimitives || node.isRegion) {
288
+ const transverse = node.isRegion ? true : false;
289
+ const targetObjects = this.getZincObjectsFromNode(node, transverse);
290
+ this.changeActiveByPrimitives(targetObjects, propagate);
291
+ }
292
+ },
293
+ changeHoverByNode: function (node, propagate) {
294
+ if (node.isPrimitives) {
295
+ const targetObjects = this.getZincObjectsFromNode(node, false);
296
+ this.changeHoverByPrimitives(targetObjects, propagate);
297
+ }
298
+ },
299
+ /**
300
+ * Unselect the current selected region.
301
+ */
302
+ removeActive: function (propagate) {
303
+ this.active = [];
304
+ this.$emit("object-selected", [], propagate);
305
+ },
306
+ /**
307
+ * Unselect the current hover region.
308
+ */
309
+ removeHover: function (propagate) {
310
+ this.hover = [];
311
+ this.$emit("object-hovered", [], propagate);
312
+ },
313
+ /**
314
+ * Reset the controls.
315
+ */
316
+ clear: function () {
317
+ this.active.length = 0;
318
+ this.hover.length = 0;
319
+ this.__nodeNumbers = 0;
320
+ this.$refs.regionTree.updateKeyChildren(this.treeData[0].id, []);
321
+ this.treeData[0].children.length = 0;
322
+ this.treeData[0].id = undefined;
323
+ this.$emit("object-selected", []);
324
+ },
325
+ getColour: function (nodeData) {
326
+ //Do not need to check for primitives as this is checked on the template
327
+ if (nodeData) {
328
+ const targetObjects = this.getZincObjectsFromNode(nodeData, false);
329
+ let graphic = targetObjects[0];
330
+ if (graphic) {
331
+ let hex = graphic.getColourHex();
332
+ if (hex) return "#" + hex;
333
+ }
334
+ }
335
+ return "#FFFFFF";
336
+ },
337
+ getZincObjectsFromNode: function (node, transverse) {
338
+ const rootRegion = this.$module.scene.getRootRegion();
339
+ if (node.isPrimitives) {
340
+ return findObjectsWithNames(
341
+ rootRegion,
342
+ node.label,
343
+ node.regionPath,
344
+ transverse
345
+ );
346
+ } else if (node.isRegion) {
347
+ if (node.regionPath) {
348
+ let targetRegion = rootRegion.findChildFromPath(node.regionPath);
349
+ if (targetRegion) {
350
+ return targetRegion.getAllObjects(transverse);
351
+ }
352
+ }
353
+ }
354
+ return [];
355
+ },
356
+ //Set this right at the beginning.
357
+ setModule: function (moduleIn) {
358
+ this.$module = moduleIn;
359
+ this.__nodeNumbers = 0;
360
+ const objects = this.$module.scene.getRootRegion().getAllObjects(true);
361
+ objects.forEach((zincObject) => {
362
+ this.zincObjectAdded(zincObject);
363
+ });
364
+ this.$module.addOrganPartAddedCallback(this.zincObjectAdded);
365
+
366
+ },
367
+ setColour: function (nodeData, value) {
368
+ if (nodeData && nodeData.isPrimitives) {
369
+ const targetObjects = this.getZincObjectsFromNode(nodeData, false);
370
+ targetObjects.forEach((primitive) => {
371
+ let hexString = value.replace("#", "0x");
372
+ primitive.setColourHex(hexString);
373
+ });
374
+ }
375
+ },
376
+ viewAll: function () {
377
+ this.$module.viewAll();
378
+ },
379
+ visibilityToggle: function (item, event) {
380
+ this.$module.changeOrganPartsVisibility(item, event);
381
+ if (event == false) {
382
+ if (this.activeRegion === item) {
383
+ this.removeActive(true);
384
+ }
385
+ if (this.hoverRegion === item) {
386
+ this.removeHover(true);
387
+ }
388
+ }
389
+ },
390
+ toggleDrawer: function () {
391
+ this.drawerOpen = !this.drawerOpen;
392
+ this.$emit("drawer-toggled", this.drawerOpen);
393
+ },
394
+ //Set visibility using full paths and add found id to the ids list
395
+ //and remove item from list if remove is set to true.
396
+ setTreeVisibilityWithFullPaths: function (node, list, ids, remove) {
397
+ let flag = false;
398
+ let nodeName = "";
399
+ if (node.isRegion) {
400
+ nodeName = `__r${node.regionPath}`;
401
+ }
402
+ if (node.isPrimitives) {
403
+ nodeName = `${node.regionPath}/${node.label}`;
404
+ }
405
+ //Find the node in list, remove it from list if remove flag is on
406
+ const index = list.indexOf(nodeName);
407
+ if (index > -1) {
408
+ flag = true;
409
+ list.splice(index, 1);
410
+ ids.push(node.id);
411
+ }
412
+ const region = this.$module.scene
413
+ .getRootRegion()
414
+ .findChildFromPath(node.regionPath);
415
+ if (nodeName && (nodeName !== "__r")) {
416
+ if (node.isPrimitives) {
417
+ const primitives = region.findObjectsWithGroupName(node.label);
418
+ primitives.forEach((primitive) => primitive.setVisibility(flag));
419
+ }
420
+ }
421
+ if (node.children) {
422
+ node.children.forEach((child) => {
423
+ this.setTreeVisibilityWithFullPaths(child, list, ids, true);
424
+ });
425
+ }
426
+ },
427
+ checkAllKeys: function () {
428
+ const keysList = [];
429
+ const ids = [];
430
+ extractAllFullPaths(this.treeData[0], keysList);
431
+ this.setTreeVisibilityWithFullPaths(this.treeData[0],
432
+ keysList, ids, true);
433
+ this.$refs.regionTree.setCheckedKeys(ids);
434
+ },
435
+ getState: function () {
436
+ let checkedItems = this.$refs.regionTree.getCheckedKeys();
437
+ if (checkedItems.length === this.__nodeNumbers) {
438
+ return { checkAll: true, version: "2.0" };
439
+ } else {
440
+ //We cannot use the generated uuid as the identifier for permastate,
441
+ //convert it back to paths
442
+ let paths = convertUUIDsToFullPaths(this.$module.scene.getRootRegion(),
443
+ checkedItems);
444
+ return { checkedItems: paths, version: "2.0" };
445
+ }
446
+ },
447
+ setState: function (state) {
448
+ if (state) {
449
+ if (state.checkAll) {
450
+ this.checkAllKeys();
451
+ } else if (state.checkedItems) {
452
+ let list = [];
453
+ if (state.version !== "2.0") {
454
+ list = state.checkedItems.map((item) => "/" + item);
455
+ list.shift("__r/");
456
+ } else {
457
+ list.push(...state.checkedItems);
458
+ }
459
+ const ids = [];
460
+ this.setTreeVisibilityWithFullPaths(this.treeData[0], list,
461
+ ids, true);
462
+ this.$refs.regionTree.setCheckedKeys(ids);
463
+ }
464
+ }
465
+ },
466
+ },
467
+ };
468
+ </script>
469
+
470
+ <!-- Add "scoped" attribute to limit CSS to this component only -->
471
+ <style scoped lang="scss">
472
+ @import "~element-ui/packages/theme-chalk/src/checkbox";
473
+ @import "~element-ui/packages/theme-chalk/src/color-picker";
474
+ @import "~element-ui/packages/theme-chalk/src/loading";
475
+ @import "~element-ui/packages/theme-chalk/src/row";
476
+ @import "~element-ui/packages/theme-chalk/src/tree";
477
+
478
+ .checkbox-container {
479
+ display: flex;
480
+ cursor: pointer;
481
+ }
482
+
483
+ .tree-controls {
484
+ position: absolute;
485
+ bottom: 0px;
486
+ transition: all 1s ease;
487
+
488
+ &:focus {
489
+ outline: none;
490
+ }
491
+ &.open {
492
+ left: 0px;
493
+ .traditional-container {
494
+ opacity: 1;
495
+ }
496
+ }
497
+ &.close {
498
+ left: -298px;
499
+ .traditional-container {
500
+ pointer-events: none;
501
+ opacity: 0;
502
+ }
503
+ }
504
+ }
505
+
506
+ .traditional-container {
507
+ transition: all 1s ease;
508
+ float: left;
509
+ padding-left: 16px;
510
+ padding-right: 18px;
511
+ max-height: calc(100% - 154px);
512
+ text-align: left;
513
+ overflow: none;
514
+ border: 1px solid rgb(220, 223, 230);
515
+ padding-top: 7px;
516
+ padding-bottom: 16px;
517
+ background: #ffffff;
518
+ }
519
+
520
+ .regions-display-text {
521
+ width: 59px;
522
+ height: 20px;
523
+ color: rgb(48, 49, 51);
524
+ font-size: 14px;
525
+ font-weight: normal;
526
+ line-height: 20px;
527
+ margin-left: 8px;
528
+ }
529
+
530
+ .all-checkbox {
531
+ float: right;
532
+ }
533
+
534
+ .tree-container {
535
+ width: 260px;
536
+ border: 1px solid rgb(144, 147, 153);
537
+ border-radius: 4px;
538
+ background: #ffffff;
539
+ margin-top: 6px;
540
+ scrollbar-width: thin;
541
+
542
+ ::v-deep .el-tree {
543
+ max-height: 240px;
544
+ min-height: 130px;
545
+ overflow: auto;
546
+ &::-webkit-scrollbar {
547
+ width: 4px;
548
+ }
549
+
550
+ &::-webkit-scrollbar-thumb {
551
+ border-radius: 10px;
552
+ box-shadow: inset 0 0 6px #c0c4cc;
553
+ }
554
+ }
555
+
556
+ ::v-deep .el-tree-node__content {
557
+ height: 22px;
558
+ }
559
+ }
560
+
561
+ ::v-deep .el-checkbox__input {
562
+ &.is-indeterminate,
563
+ &.is-checked {
564
+ .el-checkbox__inner {
565
+ background-color: $app-primary-color;
566
+ border-color: $app-primary-color;
567
+ }
568
+ }
569
+ }
570
+
571
+ ::v-deep .el-color-picker__color {
572
+ border: 1px solid $app-primary-color;
573
+ }
574
+
575
+ ::v-deep .el-checkbox__label {
576
+ padding-left: 5px;
577
+ color: $app-primary-color !important;
578
+ font-size: 12px;
579
+ font-weight: 500;
580
+ letter-spacing: 0px;
581
+ line-height: 14px;
582
+ }
583
+
584
+ .activeItem {
585
+ background-color: #bbb !important;
586
+ }
587
+
588
+ .region-tree-node {
589
+ flex: 1;
590
+ color: $app-primary-color !important;
591
+ display: flex;
592
+ font-size: 12px;
593
+ line-height: 14px;
594
+ padding-left: 0px;
595
+ background-color: #fff;
596
+ width: 100%;
597
+
598
+ ::v-deep .el-color-picker {
599
+ height: 14px !important;
600
+ }
601
+
602
+ ::v-deep .el-color-picker__trigger {
603
+ margin-left: 8px;
604
+ margin-right: 8px;
605
+ padding: 0px;
606
+ height: 14px;
607
+ width: 14px;
608
+ border: 0px;
609
+ }
610
+ }
611
+
612
+ .hoverItem {
613
+ background-color: #eee !important;
614
+ }
615
+
616
+ ::v-deep .el-color-picker__icon {
617
+ &.el-icon-arrow-down {
618
+ display: none;
619
+ }
620
+ }
621
+
622
+ ::v-deep .show-picker {
623
+ .el-color-picker__icon {
624
+ &.el-icon-arrow-down {
625
+ display: block;
626
+ }
627
+ }
628
+ }
629
+
630
+ ::v-deep .my-drawer {
631
+ background: rgba(0, 0, 0, 0);
632
+ box-shadow: none;
633
+ }
634
+
635
+ .drawer {
636
+ ::v-deep .el-drawer:focus {
637
+ outline: none;
638
+ }
639
+ }
640
+
641
+ .open-drawer {
642
+ width: 20px;
643
+ height: 40px;
644
+ z-index: 8;
645
+ position: absolute;
646
+ left: 0px;
647
+ box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.06);
648
+ border: solid 1px #e4e7ed;
649
+ background-color: #f7faff;
650
+ text-align: center;
651
+ vertical-align: middle;
652
+ cursor: pointer;
653
+ pointer-events: auto;
654
+ }
655
+
656
+ .drawer-button {
657
+ float: left;
658
+ width: 20px;
659
+ height: 40px;
660
+ z-index: 8;
661
+ margin-top: calc(50% - 52px);
662
+ border: solid 1px $app-primary-color;
663
+ background-color: #f9f2fc;
664
+ text-align: center;
665
+ vertical-align: middle;
666
+ cursor: pointer;
667
+ pointer-events: auto;
668
+ }
669
+
670
+ .drawer-button {
671
+ i {
672
+ font-weight: 600;
673
+ margin-top: 12px;
674
+ color: $app-primary-color;
675
+ transition-delay: 0.9s;
676
+ }
677
+ &.open {
678
+ i {
679
+ transform: rotate(0deg) scaleY(2);
680
+ }
681
+ }
682
+ &.close {
683
+ i {
684
+ transform: rotate(180deg) scaleY(2);
685
+ }
686
+ }
687
+ }
688
+
689
+ .node-options {
690
+ text-align: right;
691
+ }
692
+
693
+ .drawer-button.open i {
694
+ transform: rotate(0deg) scaleY(2.5);
695
+ }
696
+
697
+ .drawer-button.close i {
698
+ transform: rotate(180deg) scaleY(2.5);
699
+ }
700
+ </style>
701
+
702
+ <style>
703
+ .hide-scaffold-colour-popup {
704
+ display: none;
705
+ }
706
+ </style>
707
+