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

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