@abi-software/scaffoldvuer 1.2.1-beta.0 → 1.3.0-beta.0
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.
- package/dist/scaffoldvuer.js +15081 -14342
- package/dist/scaffoldvuer.umd.cjs +183 -184
- package/dist/style.css +1 -1
- package/package.json +2 -2
- package/src/App.vue +101 -58
- package/src/components/LinesControls.vue +126 -26
- package/src/components/PointsControls.vue +145 -2
- package/src/components/PrimitiveControls.vue +10 -4
- package/src/components/ScaffoldTooltip.vue +57 -3
- package/src/components/ScaffoldTreeControls.vue +18 -0
- package/src/components/ScaffoldVuer.vue +301 -128
- package/src/components/TransformationControls.vue +78 -18
- package/src/scripts/OrgansRenderer.js +43 -5
- package/src/scripts/RendererModule.js +12 -10
- package/src/scripts/Search.js +17 -1
- package/src/scripts/Utilities.js +76 -14
- package/src/store/index.js +1 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@abi-software/scaffoldvuer",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.3.0-beta.0",
|
|
4
4
|
"license": "Apache-2.0",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -55,7 +55,7 @@
|
|
|
55
55
|
"vue": "^3.4.15",
|
|
56
56
|
"vue-router": "^4.2.5",
|
|
57
57
|
"vue3-component-svg-sprite": "^0.0.1",
|
|
58
|
-
"zincjs": "^1.8.
|
|
58
|
+
"zincjs": "^1.8.5"
|
|
59
59
|
},
|
|
60
60
|
"devDependencies": {
|
|
61
61
|
"@vitejs/plugin-vue": "^4.6.2",
|
package/src/App.vue
CHANGED
|
@@ -27,6 +27,7 @@
|
|
|
27
27
|
:view-u-r-l="viewURL"
|
|
28
28
|
:format="format"
|
|
29
29
|
:marker-labels="markerLabels"
|
|
30
|
+
:enableLocalAnnotations="true"
|
|
30
31
|
@open-map="openMap"
|
|
31
32
|
@on-ready="onReady"
|
|
32
33
|
@scaffold-selected="onSelected"
|
|
@@ -114,9 +115,6 @@
|
|
|
114
115
|
<el-col :span="auto">
|
|
115
116
|
<el-button size="small" @click="screenCapture()"> Capture </el-button>
|
|
116
117
|
</el-col>
|
|
117
|
-
<el-col :span="auto">
|
|
118
|
-
<el-button size="small" @click="changeMarkers"> Change Markers </el-button>
|
|
119
|
-
</el-col>
|
|
120
118
|
</el-row>
|
|
121
119
|
|
|
122
120
|
<el-row :gutter="20" justify="center" align="middle">
|
|
@@ -138,6 +136,25 @@
|
|
|
138
136
|
</el-col>
|
|
139
137
|
</el-row>
|
|
140
138
|
|
|
139
|
+
<el-row :gutter="20" justify="center" align="middle">
|
|
140
|
+
<el-col :span="auto">
|
|
141
|
+
<el-button size="small" @click="exportLocalAnnotations()">
|
|
142
|
+
Export Annotations
|
|
143
|
+
</el-button>
|
|
144
|
+
</el-col>
|
|
145
|
+
<el-col :span="auto">
|
|
146
|
+
<el-button size="small">
|
|
147
|
+
<label for="annotations-upload">Import Annotations</label>
|
|
148
|
+
<input
|
|
149
|
+
id="annotations-upload"
|
|
150
|
+
type="file"
|
|
151
|
+
accept="application/json"
|
|
152
|
+
@change="importLocalAnnotations"
|
|
153
|
+
/>
|
|
154
|
+
</el-button>
|
|
155
|
+
</el-col>
|
|
156
|
+
</el-row>
|
|
157
|
+
|
|
141
158
|
<el-row justify="center" align="middle">
|
|
142
159
|
<el-col>
|
|
143
160
|
<el-row :gutter="20" justify="center" align="middle">
|
|
@@ -297,6 +314,7 @@ import {
|
|
|
297
314
|
ElInputNumber as InputNumber,
|
|
298
315
|
ElPopover as Popover,
|
|
299
316
|
ElRow as Row,
|
|
317
|
+
ElUpload as Upload,
|
|
300
318
|
ElSwitch as Switch,
|
|
301
319
|
} from "element-plus";
|
|
302
320
|
import { useRoute, useRouter } from 'vue-router'
|
|
@@ -305,6 +323,18 @@ import '@abi-software/map-utilities/dist/style.css'
|
|
|
305
323
|
|
|
306
324
|
let texture_prefix = undefined;
|
|
307
325
|
|
|
326
|
+
const writeTextFile = (filename, data) => {
|
|
327
|
+
let dataStr =
|
|
328
|
+
"data:text/json;charset=utf-8," +
|
|
329
|
+
encodeURIComponent(JSON.stringify(data));
|
|
330
|
+
let hrefElement = document.createElement("a");
|
|
331
|
+
document.body.append(hrefElement);
|
|
332
|
+
hrefElement.download = filename;
|
|
333
|
+
hrefElement.href = dataStr;
|
|
334
|
+
hrefElement.click();
|
|
335
|
+
hrefElement.remove();
|
|
336
|
+
}
|
|
337
|
+
|
|
308
338
|
export default {
|
|
309
339
|
name: "app",
|
|
310
340
|
components: {
|
|
@@ -317,6 +347,7 @@ export default {
|
|
|
317
347
|
Popover,
|
|
318
348
|
Row,
|
|
319
349
|
Switch,
|
|
350
|
+
Upload,
|
|
320
351
|
ElIconFolderOpened,
|
|
321
352
|
ElIconSetting,
|
|
322
353
|
DropZone,
|
|
@@ -327,7 +358,7 @@ export default {
|
|
|
327
358
|
data: function () {
|
|
328
359
|
return {
|
|
329
360
|
consoleOn: true,
|
|
330
|
-
|
|
361
|
+
createLinesWithNormal: true,
|
|
331
362
|
url: undefined,
|
|
332
363
|
input: undefined,
|
|
333
364
|
displayUI: true,
|
|
@@ -342,7 +373,7 @@ export default {
|
|
|
342
373
|
tumbleOn: false,
|
|
343
374
|
tumbleDirection: [1.0, 0.0],
|
|
344
375
|
showColourPicker: true,
|
|
345
|
-
markerCluster:
|
|
376
|
+
markerCluster: false,
|
|
346
377
|
minimapSettings: {
|
|
347
378
|
x_offset: 16,
|
|
348
379
|
y_offset: 50,
|
|
@@ -350,22 +381,7 @@ export default {
|
|
|
350
381
|
height: 128,
|
|
351
382
|
align: "top-right",
|
|
352
383
|
},
|
|
353
|
-
markerLabels: {
|
|
354
|
-
"body proper": 9,
|
|
355
|
-
"Spinal cord": 8,
|
|
356
|
-
"lung": 11,
|
|
357
|
-
"stomach": 12,
|
|
358
|
-
"urinary bladder": 11,
|
|
359
|
-
"Brainstem": 11,
|
|
360
|
-
"heart": 9,
|
|
361
|
-
"skin epidermis": 5,
|
|
362
|
-
"Diaphragm": 7,
|
|
363
|
-
"colon": 9,
|
|
364
|
-
"vagus nerve": 3,
|
|
365
|
-
"myenteric nerve plexus": 2,
|
|
366
|
-
"esophagus": 1,
|
|
367
|
-
"urethra": 3
|
|
368
|
-
},
|
|
384
|
+
markerLabels: { },
|
|
369
385
|
render: true,
|
|
370
386
|
region: "",
|
|
371
387
|
viewURL: "",
|
|
@@ -389,7 +405,6 @@ export default {
|
|
|
389
405
|
router: useRouter(),
|
|
390
406
|
ElIconSetting: shallowRef(ElIconSetting),
|
|
391
407
|
ElIconFolderOpened: shallowRef(ElIconFolderOpened),
|
|
392
|
-
coordinatesClicked: [],
|
|
393
408
|
auto: NaN
|
|
394
409
|
};
|
|
395
410
|
},
|
|
@@ -400,6 +415,28 @@ export default {
|
|
|
400
415
|
tumbleOn: function () {
|
|
401
416
|
this.autoTumble();
|
|
402
417
|
},
|
|
418
|
+
markerCluster: function(val) {
|
|
419
|
+
if (val) {
|
|
420
|
+
this.markerLabels = {
|
|
421
|
+
"body proper": 9,
|
|
422
|
+
"Spinal cord": 8,
|
|
423
|
+
"lung": 11,
|
|
424
|
+
"stomach": 12,
|
|
425
|
+
"urinary bladder": 11,
|
|
426
|
+
"Brainstem": 11,
|
|
427
|
+
"heart": 9,
|
|
428
|
+
"skin epidermis": 5,
|
|
429
|
+
"Diaphragm": 7,
|
|
430
|
+
"colon": 9,
|
|
431
|
+
"vagus nerve": 3,
|
|
432
|
+
"myenteric nerve plexus": 2,
|
|
433
|
+
"esophagus": 1,
|
|
434
|
+
"urethra": 3
|
|
435
|
+
};
|
|
436
|
+
} else {
|
|
437
|
+
this.markerLabels = { };
|
|
438
|
+
}
|
|
439
|
+
},
|
|
403
440
|
"route.query": {
|
|
404
441
|
handler: "parseQuery",
|
|
405
442
|
deep: true,
|
|
@@ -426,15 +463,8 @@ export default {
|
|
|
426
463
|
methods: {
|
|
427
464
|
exportGLTF: function () {
|
|
428
465
|
this.$refs.scaffold.exportGLTF(false).then((data) => {
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
encodeURIComponent(JSON.stringify(data));
|
|
432
|
-
let hrefElement = document.createElement("a");
|
|
433
|
-
document.body.append(hrefElement);
|
|
434
|
-
hrefElement.download = `export.gltf`;
|
|
435
|
-
hrefElement.href = dataStr;
|
|
436
|
-
hrefElement.click();
|
|
437
|
-
hrefElement.remove();
|
|
466
|
+
const filename = 'export' + JSON.stringify(new Date()) + '.gltf';
|
|
467
|
+
writeTextFile(filename, data);
|
|
438
468
|
});
|
|
439
469
|
},
|
|
440
470
|
exportGLB: function () {
|
|
@@ -449,14 +479,26 @@ export default {
|
|
|
449
479
|
hrefElement.remove();
|
|
450
480
|
});
|
|
451
481
|
},
|
|
482
|
+
exportLocalAnnotations: function() {
|
|
483
|
+
const annotations = this.$refs.scaffold.getLocalAnnotations();
|
|
484
|
+
const filename = 'scaffoldAnnotations' + JSON.stringify(new Date()) + '.json';
|
|
485
|
+
writeTextFile(filename, annotations);
|
|
486
|
+
},
|
|
487
|
+
onReaderLoad: function(event) {
|
|
488
|
+
const annotationsList = JSON.parse(event.target.result);
|
|
489
|
+
this.$refs.scaffold.importLocalAnnotations(annotationsList);
|
|
490
|
+
},
|
|
491
|
+
importLocalAnnotations: function() {
|
|
492
|
+
const selectedFile = document.getElementById("annotations-upload").files[0];
|
|
493
|
+
const reader = new FileReader();
|
|
494
|
+
reader.onload = this.onReaderLoad;
|
|
495
|
+
reader.readAsText(selectedFile);
|
|
496
|
+
},
|
|
452
497
|
objectAdded: function (zincObject) {
|
|
453
498
|
if (this.consoleOn) {
|
|
454
499
|
console.log(zincObject)
|
|
455
500
|
console.log(this.$refs.scaffold.$module.scene.getBoundingBox())
|
|
456
501
|
}
|
|
457
|
-
if (this._objects.length === 0) {
|
|
458
|
-
zincObject.setMarkerMode("on");
|
|
459
|
-
}
|
|
460
502
|
if (zincObject.isGeometry) {
|
|
461
503
|
zincObject._lod._material.wireframe = this.wireframe;
|
|
462
504
|
}
|
|
@@ -601,40 +643,36 @@ export default {
|
|
|
601
643
|
}
|
|
602
644
|
this.scaffoldRef = this.$refs.scaffold;
|
|
603
645
|
},
|
|
604
|
-
|
|
605
|
-
if (
|
|
646
|
+
addLinesWithNormal: function (coord, normal) {
|
|
647
|
+
if (coord && normal) {
|
|
648
|
+
const newCoords = [
|
|
649
|
+
coord[0] + normal.x * 1000,
|
|
650
|
+
coord[1] + normal.y * 1000,
|
|
651
|
+
coord[2] + normal.z * 1000,
|
|
652
|
+
];
|
|
606
653
|
const returned = this.$refs.scaffold.$module.scene.createLines(
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
} else {
|
|
615
|
-
this.coordinatesClicked.push(coord);
|
|
654
|
+
"test",
|
|
655
|
+
"lines",
|
|
656
|
+
[newCoords, coord],
|
|
657
|
+
0x00ee22,
|
|
658
|
+
);
|
|
659
|
+
returned.zincObject.isEditable = true;
|
|
660
|
+
if (this.consoleOn) console.log(returned);
|
|
616
661
|
}
|
|
617
662
|
},
|
|
618
663
|
onSelected: function (data) {
|
|
619
664
|
if (data && data.length > 0 && data[0].data.group) {
|
|
620
|
-
if (this.consoleOn) console.log(data[0]);
|
|
621
|
-
if (this.
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
"points",
|
|
625
|
-
[data[0].extraData.worldCoords],
|
|
626
|
-
undefined,
|
|
627
|
-
0x0022ee,
|
|
628
|
-
);
|
|
665
|
+
if (this.consoleOn) console.log(data[0], data[0].extraData.intersected);
|
|
666
|
+
if (this.createLinesWithNormal && data[0].extraData.worldCoords &&
|
|
667
|
+
data[0].extraData.intersected?.face) {
|
|
668
|
+
this.addLinesWithNormal(data[0].extraData.worldCoords, data[0].extraData.intersected.face.normal)
|
|
629
669
|
}
|
|
630
670
|
delete this.route.query["viewURL"];
|
|
631
|
-
this.$refs.scaffold.showRegionTooltipWithAnnotations(data, false, true);
|
|
671
|
+
//this.$refs.scaffold.showRegionTooltipWithAnnotations(data, false, true);
|
|
632
672
|
if (this.onClickMarkers) this.$refs.scaffold.setMarkerModeForObjectsWithName(data[0].data.group, "on");
|
|
633
673
|
}
|
|
634
674
|
},
|
|
635
|
-
|
|
636
|
-
this.markerLabels = {"left atrium": 3, "epicardium": 4 , "stomach": 5};
|
|
637
|
-
},
|
|
675
|
+
|
|
638
676
|
onNavigated: function (data) {
|
|
639
677
|
this.zoom = data.zoom;
|
|
640
678
|
this.pos[0] = data.target[0];
|
|
@@ -828,4 +866,9 @@ body {
|
|
|
828
866
|
svg.map-icon {
|
|
829
867
|
color: $app-primary-color;
|
|
830
868
|
}
|
|
869
|
+
|
|
870
|
+
input[type="file"] {
|
|
871
|
+
display: none;
|
|
872
|
+
}
|
|
873
|
+
|
|
831
874
|
</style>
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
<el-col :offset="0" :span="6">
|
|
6
6
|
Width:
|
|
7
7
|
</el-col>
|
|
8
|
-
<el-col :offset="0" :span="
|
|
8
|
+
<el-col :offset="0" :span="12">
|
|
9
9
|
<el-slider
|
|
10
10
|
v-model="width"
|
|
11
11
|
class="my-slider"
|
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
@input="modifyWidth"
|
|
17
17
|
/>
|
|
18
18
|
</el-col>
|
|
19
|
-
<el-col :offset="0" :span="
|
|
19
|
+
<el-col :offset="0" :span="4">
|
|
20
20
|
<el-input-number
|
|
21
21
|
v-model="width"
|
|
22
22
|
:step="1"
|
|
@@ -27,24 +27,66 @@
|
|
|
27
27
|
/>
|
|
28
28
|
</el-col>
|
|
29
29
|
</el-row>
|
|
30
|
-
<
|
|
30
|
+
<template v-if="currentIndex > -1 && distance > 0">
|
|
31
31
|
<el-col :offset="0" :span="4">
|
|
32
|
-
<el-button
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
<el-col :offset="0" :span="7">
|
|
38
|
-
<el-input-number
|
|
39
|
-
v-model="unit"
|
|
40
|
-
:controls="false"
|
|
41
|
-
class="input-box number-input"
|
|
32
|
+
<el-button
|
|
33
|
+
size='small'
|
|
34
|
+
:disabled="currentIndex === 0"
|
|
35
|
+
:icon="ElIconArrowLeft"
|
|
36
|
+
@click="changeIndex(false)"
|
|
42
37
|
/>
|
|
43
38
|
</el-col>
|
|
39
|
+
<el-col :offset="4" :span="9">
|
|
40
|
+
Editing Line {{ currentIndex + 1}}
|
|
41
|
+
</el-col>
|
|
44
42
|
<el-col :offset="2" :span="2">
|
|
45
|
-
<el-button
|
|
43
|
+
<el-button
|
|
44
|
+
size='small'
|
|
45
|
+
:icon="ElIconArrowRight"
|
|
46
|
+
@click="changeIndex(true)"
|
|
47
|
+
/>
|
|
46
48
|
</el-col>
|
|
47
|
-
|
|
49
|
+
<el-row>
|
|
50
|
+
<el-col :offset="0" :span="6">
|
|
51
|
+
Move:
|
|
52
|
+
</el-col>
|
|
53
|
+
<el-col :offset="0" :span="16">
|
|
54
|
+
<el-slider
|
|
55
|
+
v-model="adjust"
|
|
56
|
+
:step="0.01"
|
|
57
|
+
:min="-3"
|
|
58
|
+
:max="3"
|
|
59
|
+
:show-tooltip="false"
|
|
60
|
+
@input="onMoveSliding()"
|
|
61
|
+
@change="reset()"
|
|
62
|
+
/>
|
|
63
|
+
</el-col>
|
|
64
|
+
</el-row>
|
|
65
|
+
<el-row>
|
|
66
|
+
<el-col :offset="0" :span="6">
|
|
67
|
+
Length:
|
|
68
|
+
</el-col>
|
|
69
|
+
<el-col :offset="0" :span="10">
|
|
70
|
+
<el-slider
|
|
71
|
+
v-model="lengthScale"
|
|
72
|
+
:step="0.01"
|
|
73
|
+
:min="-1"
|
|
74
|
+
:max="1"
|
|
75
|
+
:show-tooltip="false"
|
|
76
|
+
@input="onLengthSliding()"
|
|
77
|
+
@change="reset()"
|
|
78
|
+
/>
|
|
79
|
+
</el-col>
|
|
80
|
+
<el-col :offset="0" :span="6">
|
|
81
|
+
<el-input-number
|
|
82
|
+
v-model="newDistance"
|
|
83
|
+
:controls="false"
|
|
84
|
+
class="input-box number-input"
|
|
85
|
+
@change="onLengthInput"
|
|
86
|
+
/>
|
|
87
|
+
</el-col>
|
|
88
|
+
</el-row>
|
|
89
|
+
</template>
|
|
48
90
|
</el-main>
|
|
49
91
|
</el-container>
|
|
50
92
|
</template>
|
|
@@ -55,7 +97,8 @@
|
|
|
55
97
|
// limited support to line width
|
|
56
98
|
import { shallowRef } from 'vue';
|
|
57
99
|
import {
|
|
58
|
-
|
|
100
|
+
getLineDistance,
|
|
101
|
+
moveAndExtendLine,
|
|
59
102
|
} from "../scripts/Utilities.js";
|
|
60
103
|
import {
|
|
61
104
|
ElButton as Button,
|
|
@@ -63,15 +106,12 @@ import {
|
|
|
63
106
|
ElContainer as Container,
|
|
64
107
|
ElInputNumber as InputNumber,
|
|
65
108
|
ElMain as Main,
|
|
66
|
-
ElSelect as Select,
|
|
67
109
|
ElSlider as Slider,
|
|
68
|
-
ElOption as Option,
|
|
69
110
|
} from "element-plus";
|
|
70
|
-
import
|
|
111
|
+
import{
|
|
71
112
|
ArrowLeft as ElIconArrowLeft,
|
|
72
113
|
ArrowRight as ElIconArrowRight,
|
|
73
114
|
} from '@element-plus/icons-vue';
|
|
74
|
-
|
|
75
115
|
/**
|
|
76
116
|
* A component to control the opacity of the target object.
|
|
77
117
|
*/
|
|
@@ -83,9 +123,7 @@ export default {
|
|
|
83
123
|
Container,
|
|
84
124
|
InputNumber,
|
|
85
125
|
Main,
|
|
86
|
-
Select,
|
|
87
126
|
Slider,
|
|
88
|
-
Option,
|
|
89
127
|
ElIconArrowLeft,
|
|
90
128
|
ElIconArrowRight,
|
|
91
129
|
},
|
|
@@ -96,23 +134,85 @@ export default {
|
|
|
96
134
|
},
|
|
97
135
|
data: function () {
|
|
98
136
|
return {
|
|
137
|
+
adjust: 0,
|
|
138
|
+
pAdjust: 0,
|
|
139
|
+
lengthScale: 0,
|
|
140
|
+
newDistance: 0,
|
|
99
141
|
width: 1,
|
|
100
|
-
|
|
142
|
+
currentIndex: 0,
|
|
101
143
|
ElIconArrowLeft: shallowRef(ElIconArrowLeft),
|
|
102
144
|
ElIconArrowRight: shallowRef(ElIconArrowRight),
|
|
145
|
+
edited: false,
|
|
103
146
|
};
|
|
104
147
|
},
|
|
148
|
+
watch: {
|
|
149
|
+
"createData.faceIndex": {
|
|
150
|
+
handler: function (value) {
|
|
151
|
+
if (this._zincObject?.isLines2) {
|
|
152
|
+
this.currentIndex = value;
|
|
153
|
+
this.distance = getLineDistance(this._zincObject, this.currentIndex);
|
|
154
|
+
}
|
|
155
|
+
},
|
|
156
|
+
immediate: true,
|
|
157
|
+
},
|
|
158
|
+
},
|
|
105
159
|
mounted: function () {
|
|
106
160
|
this._zincObject = undefined;
|
|
107
161
|
},
|
|
108
162
|
methods: {
|
|
109
|
-
|
|
110
|
-
|
|
163
|
+
changeIndex: function(increment) {
|
|
164
|
+
if (increment) {
|
|
165
|
+
const dist = getLineDistance(this._zincObject, this.currentIndex + 1);
|
|
166
|
+
if (dist > 0) {
|
|
167
|
+
this.currentIndex++;
|
|
168
|
+
this.reset();
|
|
169
|
+
}
|
|
170
|
+
} else {
|
|
171
|
+
this.currentIndex--;
|
|
172
|
+
this.reset();
|
|
173
|
+
}
|
|
174
|
+
},
|
|
175
|
+
onLengthInput: function() {
|
|
176
|
+
if (this.newDistance !== 0) {
|
|
177
|
+
this.distance = this.newDistance;
|
|
178
|
+
this.edited = moveAndExtendLine(
|
|
179
|
+
this._zincObject, this.currentIndex, this.newDistance, true) || this.edited;
|
|
180
|
+
} else {
|
|
181
|
+
this.newDistance = this.distance;
|
|
182
|
+
}
|
|
183
|
+
},
|
|
184
|
+
onLengthSliding: function() {
|
|
185
|
+
this.newDistance = Math.pow(10, this.lengthScale) * this.distance;
|
|
186
|
+
this.edited = moveAndExtendLine(
|
|
187
|
+
this._zincObject, this.currentIndex, this.newDistance, true) || this.edited;
|
|
188
|
+
},
|
|
189
|
+
onMoveSliding: function() {
|
|
190
|
+
const diff = (this.adjust - this.pAdjust) * this.distance;
|
|
191
|
+
this.edited = moveAndExtendLine(
|
|
192
|
+
this._zincObject, this.currentIndex, diff, false) || this.edited;
|
|
193
|
+
this.pAdjust = this.adjust;
|
|
194
|
+
},
|
|
195
|
+
reset: function() {
|
|
196
|
+
this.adjust = 0;
|
|
197
|
+
this.pAdjust = 0;
|
|
198
|
+
this.lengthScale = 0;
|
|
199
|
+
this.distance = getLineDistance(this._zincObject, this.currentIndex);
|
|
200
|
+
this.newDistance = this.distance;
|
|
201
|
+
if (this.edited) {
|
|
202
|
+
this.$emit("primitivesUpdated", this._zincObject);
|
|
203
|
+
this.edited = false;
|
|
204
|
+
}
|
|
111
205
|
},
|
|
112
206
|
setObject: function (object) {
|
|
113
|
-
|
|
207
|
+
this.currentIndex = -1;
|
|
208
|
+
this.distance = 0;
|
|
209
|
+
if (object.isLines2) {
|
|
114
210
|
this._zincObject = object;
|
|
115
211
|
this.width = this._zincObject.getMorph().material.linewidth;
|
|
212
|
+
if (object.isEditable) {
|
|
213
|
+
this.currentIndex = 0;
|
|
214
|
+
this.distance = getLineDistance(object, this.currentIndex);
|
|
215
|
+
}
|
|
116
216
|
} else {
|
|
117
217
|
this._zincObject = undefined;
|
|
118
218
|
this.linewidth = 10;
|
|
@@ -49,13 +49,86 @@
|
|
|
49
49
|
</el-select>
|
|
50
50
|
</el-col>
|
|
51
51
|
</el-row>
|
|
52
|
+
<template v-if="currentIndex > -1">
|
|
53
|
+
<el-row>
|
|
54
|
+
<el-col :offset="0" :span="4">
|
|
55
|
+
<el-button
|
|
56
|
+
size='small'
|
|
57
|
+
:disabled="currentIndex === 0"
|
|
58
|
+
:icon="ElIconArrowLeft"
|
|
59
|
+
@click="changeIndex(false)"
|
|
60
|
+
/>
|
|
61
|
+
</el-col>
|
|
62
|
+
<el-col :offset="4" :span="9">
|
|
63
|
+
Editing Point {{ currentIndex + 1}}
|
|
64
|
+
</el-col>
|
|
65
|
+
<el-col :offset="2" :span="2">
|
|
66
|
+
<el-button
|
|
67
|
+
size='small'
|
|
68
|
+
:icon="ElIconArrowRight"
|
|
69
|
+
@click="changeIndex(true)"
|
|
70
|
+
/>
|
|
71
|
+
</el-col>
|
|
72
|
+
</el-row>
|
|
73
|
+
<el-row>
|
|
74
|
+
<el-col :offset="0" :span="6">
|
|
75
|
+
x:
|
|
76
|
+
</el-col>
|
|
77
|
+
<el-col :offset="0" :span="16">
|
|
78
|
+
<el-slider
|
|
79
|
+
v-model="translation[0]"
|
|
80
|
+
:step="0.01"
|
|
81
|
+
:min="min[0]"
|
|
82
|
+
:max="max[0]"
|
|
83
|
+
:show-tooltip="false"
|
|
84
|
+
@input="onMoveSliding()"
|
|
85
|
+
@change="reset()"
|
|
86
|
+
/>
|
|
87
|
+
</el-col>
|
|
88
|
+
</el-row>
|
|
89
|
+
<el-row>
|
|
90
|
+
<el-col :offset="0" :span="6">
|
|
91
|
+
y:
|
|
92
|
+
</el-col>
|
|
93
|
+
<el-col :offset="0" :span="16">
|
|
94
|
+
<el-slider
|
|
95
|
+
v-model="translation[1]"
|
|
96
|
+
:step="0.01"
|
|
97
|
+
:min="min[1]"
|
|
98
|
+
:max="max[1]"
|
|
99
|
+
:show-tooltip="false"
|
|
100
|
+
@input="onMoveSliding()"
|
|
101
|
+
@change="reset()"
|
|
102
|
+
/>
|
|
103
|
+
</el-col>
|
|
104
|
+
</el-row>
|
|
105
|
+
<el-row>
|
|
106
|
+
<el-col :offset="0" :span="6">
|
|
107
|
+
z:
|
|
108
|
+
</el-col>
|
|
109
|
+
<el-col :offset="0" :span="16">
|
|
110
|
+
<el-slider
|
|
111
|
+
v-model="translation[2]"
|
|
112
|
+
:step="0.01"
|
|
113
|
+
:min="min[2]"
|
|
114
|
+
:max="max[2]"
|
|
115
|
+
:show-tooltip="false"
|
|
116
|
+
@input="onMoveSliding()"
|
|
117
|
+
@change="reset()"
|
|
118
|
+
/>
|
|
119
|
+
</el-col>
|
|
120
|
+
</el-row>
|
|
121
|
+
</template>
|
|
52
122
|
</el-main>
|
|
53
123
|
</el-container>
|
|
54
124
|
</template>
|
|
55
125
|
|
|
56
126
|
<script>
|
|
57
127
|
/* eslint-disable no-alert, no-console */
|
|
58
|
-
|
|
128
|
+
import { shallowRef } from 'vue';
|
|
129
|
+
import {
|
|
130
|
+
movePoint,
|
|
131
|
+
} from "../scripts/Utilities.js";
|
|
59
132
|
import {
|
|
60
133
|
ElCol as Col,
|
|
61
134
|
ElContainer as Container,
|
|
@@ -65,6 +138,10 @@ import {
|
|
|
65
138
|
ElSlider as Slider,
|
|
66
139
|
ElOption as Option,
|
|
67
140
|
} from "element-plus";
|
|
141
|
+
import{
|
|
142
|
+
ArrowLeft as ElIconArrowLeft,
|
|
143
|
+
ArrowRight as ElIconArrowRight,
|
|
144
|
+
} from '@element-plus/icons-vue';
|
|
68
145
|
|
|
69
146
|
/**
|
|
70
147
|
* A component to control the opacity of the target object.
|
|
@@ -79,7 +156,10 @@ export default {
|
|
|
79
156
|
Select,
|
|
80
157
|
Slider,
|
|
81
158
|
Option,
|
|
159
|
+
ElIconArrowLeft,
|
|
160
|
+
ElIconArrowRight,
|
|
82
161
|
},
|
|
162
|
+
inject: ['boundingDims'],
|
|
83
163
|
data: function () {
|
|
84
164
|
return {
|
|
85
165
|
attenuation: false,
|
|
@@ -94,17 +174,80 @@ export default {
|
|
|
94
174
|
label: "off",
|
|
95
175
|
},
|
|
96
176
|
],
|
|
177
|
+
min: [0, 0, 0],
|
|
178
|
+
max: [1, 1, 1],
|
|
179
|
+
translation: [0, 0, 0],
|
|
180
|
+
pTranslation: [0, 0, 0],
|
|
181
|
+
currentIndex: -1,
|
|
182
|
+
ElIconArrowLeft: shallowRef(ElIconArrowLeft),
|
|
183
|
+
ElIconArrowRight: shallowRef(ElIconArrowRight),
|
|
184
|
+
edited: false,
|
|
97
185
|
};
|
|
98
186
|
},
|
|
99
187
|
mounted: function () {
|
|
100
188
|
this._zincObject = undefined;
|
|
101
189
|
},
|
|
190
|
+
watch: {
|
|
191
|
+
boundingDims: {
|
|
192
|
+
handler: function (value) {
|
|
193
|
+
const size = value.size;
|
|
194
|
+
this.min = [
|
|
195
|
+
-size[0] / 2,
|
|
196
|
+
-size[1] / 2,
|
|
197
|
+
-size[2] / 2,
|
|
198
|
+
];
|
|
199
|
+
this.max = [
|
|
200
|
+
size[0] / 2,
|
|
201
|
+
size[1] / 2,
|
|
202
|
+
size[2] / 2,
|
|
203
|
+
];
|
|
204
|
+
},
|
|
205
|
+
immediate: true,
|
|
206
|
+
deep: true,
|
|
207
|
+
},
|
|
208
|
+
},
|
|
102
209
|
methods: {
|
|
210
|
+
changeIndex: function(increment) {
|
|
211
|
+
if (increment) {
|
|
212
|
+
if (this._zincObject.drawRange > this.currentIndex + 1) {
|
|
213
|
+
this.currentIndex++;
|
|
214
|
+
this.reset();
|
|
215
|
+
}
|
|
216
|
+
} else {
|
|
217
|
+
this.currentIndex--;
|
|
218
|
+
this.reset();
|
|
219
|
+
}
|
|
220
|
+
},
|
|
221
|
+
onMoveSliding: function() {
|
|
222
|
+
const diff = [
|
|
223
|
+
this.translation[0] - this.pTranslation[0],
|
|
224
|
+
this.translation[1] - this.pTranslation[1],
|
|
225
|
+
this.translation[2] - this.pTranslation[2],
|
|
226
|
+
];
|
|
227
|
+
this.edited = movePoint(this._zincObject, this.currentIndex, diff) || this.edited;
|
|
228
|
+
for (let i = 0; i < 3; i++) {
|
|
229
|
+
this.pTranslation[i] = this.translation[i];
|
|
230
|
+
}
|
|
231
|
+
},
|
|
232
|
+
reset: function() {
|
|
233
|
+
this.translation = [0, 0, 0];
|
|
234
|
+
this.pTranslation = [0, 0, 0];
|
|
235
|
+
if (this.edited) {
|
|
236
|
+
this.$emit("primitivesUpdated", this._zincObject);
|
|
237
|
+
this.edited = false;
|
|
238
|
+
}
|
|
239
|
+
},
|
|
103
240
|
setObject: function (object) {
|
|
241
|
+
this.currentIndex = -1;
|
|
104
242
|
if (object.isPointset) {
|
|
105
243
|
this._zincObject = object;
|
|
106
244
|
this.size = this._zincObject.morph.material.size;
|
|
107
|
-
this.attenuation = this._zincObject.morph.material.sizeAttenuation
|
|
245
|
+
this.attenuation = this._zincObject.morph.material.sizeAttenuation;
|
|
246
|
+
if (object.isEditable) {
|
|
247
|
+
if (this._zincObject.drawRange > 0) {
|
|
248
|
+
this.currentIndex = 0;
|
|
249
|
+
}
|
|
250
|
+
}
|
|
108
251
|
} else {
|
|
109
252
|
this._zincObject = undefined;
|
|
110
253
|
this.size = 10;
|