@abi-software/scaffoldvuer 0.1.52-beta.0 → 0.1.52-beta.3
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.common.js +668 -285
- package/dist/scaffoldvuer.common.js.map +1 -1
- package/dist/scaffoldvuer.css +1 -1
- package/dist/scaffoldvuer.umd.js +668 -285
- package/dist/scaffoldvuer.umd.js.map +1 -1
- package/dist/scaffoldvuer.umd.min.js +1 -1
- package/dist/scaffoldvuer.umd.min.js.map +1 -1
- package/package-lock.json +1404 -2475
- package/package.json +4 -3
- package/src/App.vue +95 -46
- package/src/components/DropZone.vue +91 -0
- package/src/components/ScaffoldTooltip.vue +117 -0
- package/src/components/ScaffoldVuer.vue +85 -50
- package/src/components/TreeControls.vue +633 -0
- package/src/scripts/RendererModule.js +21 -14
- package/src/scripts/eventNotifier.js +1 -1
- package/src/scripts/organsRenderer.js +58 -29
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@abi-software/scaffoldvuer",
|
|
3
|
-
"version": "0.1.52-beta.
|
|
3
|
+
"version": "0.1.52-beta.3",
|
|
4
4
|
"license": "Apache-2.0",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -33,7 +33,7 @@
|
|
|
33
33
|
"vue": "^2.6.10",
|
|
34
34
|
"vue-drag-resize": "^1.3.2",
|
|
35
35
|
"vue-router": "^3.5.1",
|
|
36
|
-
"zincjs": "^0.
|
|
36
|
+
"zincjs": "^1.0.0-alpha-3"
|
|
37
37
|
},
|
|
38
38
|
"devDependencies": {
|
|
39
39
|
"@vue/cli-plugin-babel": "^4.0.0",
|
|
@@ -47,8 +47,9 @@
|
|
|
47
47
|
"node-sass": "^4.14.1",
|
|
48
48
|
"raw-loader": "^0.5.1",
|
|
49
49
|
"sass-loader": "^8.0.2",
|
|
50
|
+
"simple-dropzone": "^0.8.1",
|
|
50
51
|
"vue-cli-plugin-styleguidist": "^4.32.2",
|
|
51
|
-
"vue-styleguidist": "^4.
|
|
52
|
+
"vue-styleguidist": "^4.44.22",
|
|
52
53
|
"vue-template-compiler": "^2.6.10",
|
|
53
54
|
"webpack-node-externals": "^2.5.2"
|
|
54
55
|
},
|
package/src/App.vue
CHANGED
|
@@ -4,22 +4,29 @@
|
|
|
4
4
|
rel="stylesheet"
|
|
5
5
|
href="https://fonts.googleapis.com/css?family=Asap:400,400i,500,600,700&display=swap"
|
|
6
6
|
>
|
|
7
|
-
<
|
|
8
|
-
ref="
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
7
|
+
<drop-zone
|
|
8
|
+
ref="dropzone"
|
|
9
|
+
@files-drop="onFilesDrop"
|
|
10
|
+
>
|
|
11
|
+
<ScaffoldVuer
|
|
12
|
+
ref="scaffold"
|
|
13
|
+
class="vuer"
|
|
14
|
+
:display-u-i="displayUI"
|
|
15
|
+
:url="url"
|
|
16
|
+
:help-mode="helpMode"
|
|
17
|
+
:display-minimap="displayMinimap"
|
|
18
|
+
:display-markers="displayMarkers"
|
|
19
|
+
:minimap-settings="minimapSettings"
|
|
20
|
+
:show-colour-picker="showColourPicker"
|
|
21
|
+
:render="render"
|
|
22
|
+
:region="region"
|
|
23
|
+
:view-u-r-l="viewURL"
|
|
24
|
+
@on-ready="onReady"
|
|
25
|
+
@scaffold-selected="onSelected"
|
|
26
|
+
@scaffold-navigated="onNavigated"
|
|
27
|
+
@timeChanged="updateCurrentTime"
|
|
28
|
+
/>
|
|
29
|
+
</drop-zone>
|
|
23
30
|
<el-popover
|
|
24
31
|
placement="bottom"
|
|
25
32
|
trigger="click"
|
|
@@ -87,7 +94,7 @@
|
|
|
87
94
|
Capture
|
|
88
95
|
</el-button>
|
|
89
96
|
</el-row>
|
|
90
|
-
<el-row :gutter="
|
|
97
|
+
<el-row :gutter="10">
|
|
91
98
|
<el-button
|
|
92
99
|
size="mini"
|
|
93
100
|
@click="saveSettings()"
|
|
@@ -103,10 +110,52 @@
|
|
|
103
110
|
<el-button
|
|
104
111
|
size="mini"
|
|
105
112
|
@click="exportGLB()"
|
|
113
|
+
>
|
|
114
|
+
Export GLB
|
|
115
|
+
</el-button>
|
|
116
|
+
<el-button
|
|
117
|
+
size="mini"
|
|
118
|
+
@click="exportGLTF()"
|
|
106
119
|
>
|
|
107
120
|
Export GLTF
|
|
108
121
|
</el-button>
|
|
109
122
|
</el-row>
|
|
123
|
+
<el-row :gutter="30">
|
|
124
|
+
<el-col
|
|
125
|
+
:span="7"
|
|
126
|
+
:offset="2"
|
|
127
|
+
>
|
|
128
|
+
<el-switch
|
|
129
|
+
v-model="syncMode"
|
|
130
|
+
active-text="Sync Mode"
|
|
131
|
+
active-color="#8300bf"
|
|
132
|
+
/>
|
|
133
|
+
<el-row v-if="syncMode">
|
|
134
|
+
<el-input-number
|
|
135
|
+
v-model="zoom"
|
|
136
|
+
:min="1.0"
|
|
137
|
+
:controls="false"
|
|
138
|
+
placeholder="Please input"
|
|
139
|
+
label="zoom"
|
|
140
|
+
/>
|
|
141
|
+
<el-input-number
|
|
142
|
+
v-model="pos[0]"
|
|
143
|
+
:min="-1.0"
|
|
144
|
+
:max="1.0"
|
|
145
|
+
:controls="false"
|
|
146
|
+
placeholder="Please input"
|
|
147
|
+
label="x"
|
|
148
|
+
/>
|
|
149
|
+
<el-input-number
|
|
150
|
+
v-model="pos[1]"
|
|
151
|
+
:min="-1.0"
|
|
152
|
+
:max="1.0"
|
|
153
|
+
:controls="false"
|
|
154
|
+
label="y"
|
|
155
|
+
/>
|
|
156
|
+
</el-row>
|
|
157
|
+
</el-col>
|
|
158
|
+
</el-row>
|
|
110
159
|
<el-row :gutter="30">
|
|
111
160
|
<el-col
|
|
112
161
|
:span="7"
|
|
@@ -188,9 +237,10 @@
|
|
|
188
237
|
<script>
|
|
189
238
|
/* eslint-disable no-alert, no-console */
|
|
190
239
|
import { ScaffoldVuer } from "./components/index.js";
|
|
240
|
+
import DropZone from "./components/DropZone.vue";
|
|
191
241
|
import ModelsTable from "./components/ModelsTable.vue";
|
|
192
242
|
import Vue from "vue";
|
|
193
|
-
import { Button, Col, Icon, Input, Popover, Row, Switch } from "element-ui";
|
|
243
|
+
import { Button, Col, Icon, Input, InputNumber, Popover, Row, Switch } from "element-ui";
|
|
194
244
|
import lang from "element-ui/lib/locale/lang/en";
|
|
195
245
|
import locale from "element-ui/lib/locale";
|
|
196
246
|
|
|
@@ -199,36 +249,15 @@ Vue.use(Button);
|
|
|
199
249
|
Vue.use(Col);
|
|
200
250
|
Vue.use(Icon);
|
|
201
251
|
Vue.use(Input);
|
|
252
|
+
Vue.use(InputNumber);
|
|
202
253
|
Vue.use(Popover);
|
|
203
254
|
Vue.use(Row);
|
|
204
255
|
Vue.use(Switch);
|
|
205
256
|
|
|
206
|
-
/*
|
|
207
|
-
const alignToObject = function(cameracontrol, scene) {
|
|
208
|
-
var object = scene.findGeometriesWithGroupName("Endocardium of left atrium")[0];
|
|
209
|
-
const boundingBox = object.getBoundingBox();
|
|
210
|
-
if (boundingBox) {
|
|
211
|
-
const radius = boundingBox.min.distanceTo(boundingBox.max)/2.0;
|
|
212
|
-
const centreX = (boundingBox.min.x + boundingBox.max.x) / 2.0;
|
|
213
|
-
const centreY = (boundingBox.min.y + boundingBox.max.y) / 2.0;
|
|
214
|
-
const centreZ = (boundingBox.min.z + boundingBox.max.z) / 2.0;
|
|
215
|
-
const clip_factor = 8.0;
|
|
216
|
-
const endingViewport = cameracontrol.getViewportFromCentreAndRadius(centreX, centreY, centreZ, radius, 40, radius * clip_factor );
|
|
217
|
-
const startingViewport = cameracontrol.getCurrentViewport();
|
|
218
|
-
cameracontrol.cameraTransition(startingViewport, endingViewport, 1500);
|
|
219
|
-
cameracontrol.enableCameraTransition();
|
|
220
|
-
}
|
|
221
|
-
setTimeout(function(){ tumble(cameracontrol) }, 2000);
|
|
222
|
-
}
|
|
223
|
-
|
|
224
|
-
const tumble = function(cameracontrol) {
|
|
225
|
-
cameracontrol.enableAutoTumble();
|
|
226
|
-
cameracontrol.autoTumble([1.0, 0.0], Math.PI / 2, true);
|
|
227
|
-
}
|
|
228
|
-
*/
|
|
229
257
|
export default {
|
|
230
258
|
name: "App",
|
|
231
259
|
components: {
|
|
260
|
+
DropZone,
|
|
232
261
|
ScaffoldVuer,
|
|
233
262
|
ModelsTable
|
|
234
263
|
},
|
|
@@ -239,9 +268,10 @@ export default {
|
|
|
239
268
|
displayUI: true,
|
|
240
269
|
selectedCoordinates: undefined,
|
|
241
270
|
helpMode: false,
|
|
242
|
-
displayMarkers:
|
|
271
|
+
displayMarkers: false,
|
|
272
|
+
syncMode: false,
|
|
243
273
|
currentTime: 0,
|
|
244
|
-
displayMinimap:
|
|
274
|
+
displayMinimap: false,
|
|
245
275
|
tumbleOn: false,
|
|
246
276
|
showColourPicker: true,
|
|
247
277
|
minimapSettings: {
|
|
@@ -255,7 +285,9 @@ export default {
|
|
|
255
285
|
region: "",
|
|
256
286
|
viewURL: "",
|
|
257
287
|
renderInfoOn: false,
|
|
258
|
-
rendererInfo: undefined
|
|
288
|
+
rendererInfo: undefined,
|
|
289
|
+
zoom: 1,
|
|
290
|
+
pos: [0, 0],
|
|
259
291
|
};
|
|
260
292
|
},
|
|
261
293
|
watch: {
|
|
@@ -269,9 +301,11 @@ export default {
|
|
|
269
301
|
handler: "parseQuery",
|
|
270
302
|
deep: true,
|
|
271
303
|
immediate: true
|
|
304
|
+
},
|
|
305
|
+
syncMode: function(val) {
|
|
306
|
+
this.$refs.scaffold.toggleSyncControl(val);
|
|
272
307
|
}
|
|
273
308
|
},
|
|
274
|
-
|
|
275
309
|
mounted: function() {
|
|
276
310
|
this._sceneSettings = [];
|
|
277
311
|
this.selectedCoordinates = this.$refs.scaffold.getDynamicSelectedCoordinates();
|
|
@@ -327,6 +361,9 @@ export default {
|
|
|
327
361
|
cameracontrol.stopAutoTumble();
|
|
328
362
|
}
|
|
329
363
|
},
|
|
364
|
+
onReady: function() {
|
|
365
|
+
this.$refs.dropzone.revokeURLs();
|
|
366
|
+
},
|
|
330
367
|
onSelected: function(data) {
|
|
331
368
|
if (data && data[0].data.group) {
|
|
332
369
|
delete this.$route.query["viewURL"];
|
|
@@ -335,11 +372,23 @@ export default {
|
|
|
335
372
|
});
|
|
336
373
|
}
|
|
337
374
|
},
|
|
375
|
+
onNavigated: function(data) {
|
|
376
|
+
this.zoom = data.zoom;
|
|
377
|
+
this.pos[0] = data.target[0];
|
|
378
|
+
this.pos[1] = data.target[1];
|
|
379
|
+
},
|
|
380
|
+
onFilesDrop: function(metaURL) {
|
|
381
|
+
this.input = metaURL;
|
|
382
|
+
},
|
|
338
383
|
parseInput: function() {
|
|
339
|
-
if (this.$route.query.url !== this.input)
|
|
384
|
+
if (this.$route.query.url !== this.input) {
|
|
385
|
+
const queries = {...this.$route.query};
|
|
386
|
+
if (this.input && this.input !== "")
|
|
387
|
+
queries.url = this.input;
|
|
340
388
|
this.$router.replace({
|
|
341
389
|
query: { ...this.$route.query, url: this.input }
|
|
342
390
|
});
|
|
391
|
+
}
|
|
343
392
|
},
|
|
344
393
|
updateCurrentTime: function(val) {
|
|
345
394
|
this.currentTime = val;
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div
|
|
3
|
+
ref="dropEl"
|
|
4
|
+
class="dropzone"
|
|
5
|
+
>
|
|
6
|
+
<slot />
|
|
7
|
+
<input
|
|
8
|
+
ref="fileInput"
|
|
9
|
+
type="file"
|
|
10
|
+
>
|
|
11
|
+
</div>
|
|
12
|
+
</template>
|
|
13
|
+
|
|
14
|
+
<script>
|
|
15
|
+
/* eslint-disable no-alert, no-console */
|
|
16
|
+
import { SimpleDropzone } from "simple-dropzone";
|
|
17
|
+
import path from "path";
|
|
18
|
+
|
|
19
|
+
export default {
|
|
20
|
+
name: "DropZone",
|
|
21
|
+
data: function () {
|
|
22
|
+
return {
|
|
23
|
+
objectURLs: [],
|
|
24
|
+
};
|
|
25
|
+
},
|
|
26
|
+
mounted: function () {
|
|
27
|
+
const dropCtrl = new SimpleDropzone(
|
|
28
|
+
this.$refs.dropEl,
|
|
29
|
+
this.$refs.fileInput
|
|
30
|
+
);
|
|
31
|
+
dropCtrl.on("drop", ({ files }) => {
|
|
32
|
+
this.localDrop(files);
|
|
33
|
+
});
|
|
34
|
+
},
|
|
35
|
+
methods: {
|
|
36
|
+
createObjectURLs: function (text, list) {
|
|
37
|
+
let content = text;
|
|
38
|
+
for (const [key, file] of Object.entries(list)) {
|
|
39
|
+
if (content.includes(key)) {
|
|
40
|
+
const objectURL = URL.createObjectURL(file);
|
|
41
|
+
content = content.replace(key, objectURL);
|
|
42
|
+
this.objectURLs.push(objectURL);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
let blob = new Blob([content], { type: "application/json" });
|
|
46
|
+
const metaURL = URL.createObjectURL(blob);
|
|
47
|
+
this.objectURLs.push(metaURL);
|
|
48
|
+
this.$emit("files-drop", metaURL);
|
|
49
|
+
},
|
|
50
|
+
revokeURLs: function () {
|
|
51
|
+
this.objectURLs.forEach(objectURL => URL.revokeObjectURL(objectURL));
|
|
52
|
+
this.objectURLs = [];
|
|
53
|
+
},
|
|
54
|
+
localDrop: function (fileMap) {
|
|
55
|
+
const dataMaps = {};
|
|
56
|
+
let list = {};
|
|
57
|
+
let metadata = undefined;
|
|
58
|
+
const flatarray = Array.from(fileMap);
|
|
59
|
+
let rootPath = "";
|
|
60
|
+
for (let i = 0; i < flatarray.length; i++) {
|
|
61
|
+
if (flatarray[i][1].name.includes("metadata.json")) {
|
|
62
|
+
rootPath = flatarray[i][0].replace(flatarray[i][1].name, "");
|
|
63
|
+
metadata = { rootPath, file: flatarray[i][1] };
|
|
64
|
+
break;
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
if (metadata) {
|
|
68
|
+
flatarray.forEach(([filePath, file]) => {
|
|
69
|
+
if (file.name.match(/\.(json)$/)) {
|
|
70
|
+
const relativePath = path.relative(rootPath, filePath);
|
|
71
|
+
list[relativePath] = file;
|
|
72
|
+
}
|
|
73
|
+
});
|
|
74
|
+
const metaFileURL = URL.createObjectURL(metadata.file);
|
|
75
|
+
fetch(metaFileURL)
|
|
76
|
+
.then((response) => response.text())
|
|
77
|
+
.then((text) => this.createObjectURLs(text, list));
|
|
78
|
+
URL.revokeObjectURL(metaFileURL);
|
|
79
|
+
}
|
|
80
|
+
},
|
|
81
|
+
},
|
|
82
|
+
};
|
|
83
|
+
</script>
|
|
84
|
+
|
|
85
|
+
<style scoped lang="scss">
|
|
86
|
+
.dropzone {
|
|
87
|
+
position: absolute;
|
|
88
|
+
width: 100%;
|
|
89
|
+
height: 100%;
|
|
90
|
+
}
|
|
91
|
+
</style>
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div :style="position" class="tooltipContainer">
|
|
3
|
+
<el-popover
|
|
4
|
+
ref="tooltip"
|
|
5
|
+
v-model="display"
|
|
6
|
+
placement="top"
|
|
7
|
+
:append-to-body="false"
|
|
8
|
+
trigger="manual"
|
|
9
|
+
popper-class="tooltip-popper non-selectable"
|
|
10
|
+
>
|
|
11
|
+
<div>{{ label }}</div>
|
|
12
|
+
<i v-popover:tooltip />
|
|
13
|
+
</el-popover>
|
|
14
|
+
</div>
|
|
15
|
+
</template>
|
|
16
|
+
|
|
17
|
+
<script>
|
|
18
|
+
/* eslint-disable no-alert, no-console */
|
|
19
|
+
import Vue from "vue";
|
|
20
|
+
import { Popover } from "element-ui";
|
|
21
|
+
import lang from "element-ui/lib/locale/lang/en";
|
|
22
|
+
import locale from "element-ui/lib/locale";
|
|
23
|
+
|
|
24
|
+
locale.use(lang);
|
|
25
|
+
Vue.use(Popover);
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* A component to control the opacity of the target object.
|
|
29
|
+
*/
|
|
30
|
+
export default {
|
|
31
|
+
name: "ScaffoldTooltip",
|
|
32
|
+
props: {
|
|
33
|
+
label: {
|
|
34
|
+
type: String,
|
|
35
|
+
default: "",
|
|
36
|
+
},
|
|
37
|
+
visible: {
|
|
38
|
+
type: Boolean,
|
|
39
|
+
default: false,
|
|
40
|
+
},
|
|
41
|
+
x: {
|
|
42
|
+
type: Number,
|
|
43
|
+
default: 200,
|
|
44
|
+
},
|
|
45
|
+
y: {
|
|
46
|
+
type: Number,
|
|
47
|
+
default: 200,
|
|
48
|
+
},
|
|
49
|
+
},
|
|
50
|
+
data: function () {
|
|
51
|
+
return {
|
|
52
|
+
display: false,
|
|
53
|
+
};
|
|
54
|
+
},
|
|
55
|
+
computed: {
|
|
56
|
+
position: function () {
|
|
57
|
+
return { left: this.x + "px", top: this.y - 30 + "px" };
|
|
58
|
+
},
|
|
59
|
+
},
|
|
60
|
+
watch: {
|
|
61
|
+
label: {
|
|
62
|
+
handler: function () {
|
|
63
|
+
if (this.visible && this.label && this.label !== "")
|
|
64
|
+
this.display = true;
|
|
65
|
+
else this.display = false;
|
|
66
|
+
},
|
|
67
|
+
immediate: true,
|
|
68
|
+
},
|
|
69
|
+
visible: {
|
|
70
|
+
handler: function () {
|
|
71
|
+
if (this.visible && this.label && this.label !== "")
|
|
72
|
+
this.display = true;
|
|
73
|
+
else this.display = false;
|
|
74
|
+
},
|
|
75
|
+
immediate: true,
|
|
76
|
+
},
|
|
77
|
+
},
|
|
78
|
+
};
|
|
79
|
+
</script>
|
|
80
|
+
|
|
81
|
+
<!-- Add "scoped" attribute to limit CSS to this component only -->
|
|
82
|
+
<style scoped lang="scss">
|
|
83
|
+
@import "~element-ui/packages/theme-chalk/src/popover";
|
|
84
|
+
|
|
85
|
+
::v-deep .tooltip-popper {
|
|
86
|
+
padding: 2px 6px;
|
|
87
|
+
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.1);
|
|
88
|
+
font-size: 16px;
|
|
89
|
+
color: $app-primary-color;
|
|
90
|
+
background-color: #fff;
|
|
91
|
+
border: 1px solid $app-primary-color;
|
|
92
|
+
border-radius: 4px;
|
|
93
|
+
white-space: nowrap;
|
|
94
|
+
min-width: unset;
|
|
95
|
+
pointer-events: none;
|
|
96
|
+
|
|
97
|
+
&.el-popper[x-placement^="top"] {
|
|
98
|
+
.popper__arrow {
|
|
99
|
+
border-top-color: $app-primary-color !important;
|
|
100
|
+
&:after {
|
|
101
|
+
border-top-color: #fff !important;
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
.tooltipContainer {
|
|
108
|
+
position: absolute;
|
|
109
|
+
height: 50px;
|
|
110
|
+
z-index: 2;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
::v-deep .non-selectable {
|
|
114
|
+
user-select: none;
|
|
115
|
+
pointer-events: none;
|
|
116
|
+
}
|
|
117
|
+
</style>
|