@abi-software/scaffoldvuer 0.1.52-beta.1 → 0.1.52-beta.4
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 +636 -283
- package/dist/scaffoldvuer.common.js.map +1 -1
- package/dist/scaffoldvuer.css +1 -1
- package/dist/scaffoldvuer.umd.js +636 -283
- 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 +1398 -2472
- package/package.json +4 -3
- package/src/App.vue +78 -49
- package/src/components/DropZone.vue +91 -0
- package/src/components/ScaffoldTooltip.vue +126 -0
- package/src/components/ScaffoldVuer.vue +79 -49
- 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 +36 -30
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.4",
|
|
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,23 +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
|
-
|
|
23
|
-
|
|
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>
|
|
24
30
|
<el-popover
|
|
25
31
|
placement="bottom"
|
|
26
32
|
trigger="click"
|
|
@@ -88,7 +94,7 @@
|
|
|
88
94
|
Capture
|
|
89
95
|
</el-button>
|
|
90
96
|
</el-row>
|
|
91
|
-
<el-row :gutter="
|
|
97
|
+
<el-row :gutter="10">
|
|
92
98
|
<el-button
|
|
93
99
|
size="mini"
|
|
94
100
|
@click="saveSettings()"
|
|
@@ -104,6 +110,12 @@
|
|
|
104
110
|
<el-button
|
|
105
111
|
size="mini"
|
|
106
112
|
@click="exportGLB()"
|
|
113
|
+
>
|
|
114
|
+
Export GLB
|
|
115
|
+
</el-button>
|
|
116
|
+
<el-button
|
|
117
|
+
size="mini"
|
|
118
|
+
@click="exportGLTF()"
|
|
107
119
|
>
|
|
108
120
|
Export GLTF
|
|
109
121
|
</el-button>
|
|
@@ -111,13 +123,37 @@
|
|
|
111
123
|
<el-row :gutter="30">
|
|
112
124
|
<el-col
|
|
113
125
|
:span="7"
|
|
114
|
-
:offset="
|
|
126
|
+
:offset="2"
|
|
115
127
|
>
|
|
116
128
|
<el-switch
|
|
117
129
|
v-model="syncMode"
|
|
118
130
|
active-text="Sync Mode"
|
|
119
131
|
active-color="#8300bf"
|
|
120
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>
|
|
121
157
|
</el-col>
|
|
122
158
|
</el-row>
|
|
123
159
|
<el-row :gutter="30">
|
|
@@ -201,9 +237,10 @@
|
|
|
201
237
|
<script>
|
|
202
238
|
/* eslint-disable no-alert, no-console */
|
|
203
239
|
import { ScaffoldVuer } from "./components/index.js";
|
|
240
|
+
import DropZone from "./components/DropZone.vue";
|
|
204
241
|
import ModelsTable from "./components/ModelsTable.vue";
|
|
205
242
|
import Vue from "vue";
|
|
206
|
-
import { Button, Col, Icon, Input, Popover, Row, Switch } from "element-ui";
|
|
243
|
+
import { Button, Col, Icon, Input, InputNumber, Popover, Row, Switch } from "element-ui";
|
|
207
244
|
import lang from "element-ui/lib/locale/lang/en";
|
|
208
245
|
import locale from "element-ui/lib/locale";
|
|
209
246
|
|
|
@@ -212,36 +249,15 @@ Vue.use(Button);
|
|
|
212
249
|
Vue.use(Col);
|
|
213
250
|
Vue.use(Icon);
|
|
214
251
|
Vue.use(Input);
|
|
252
|
+
Vue.use(InputNumber);
|
|
215
253
|
Vue.use(Popover);
|
|
216
254
|
Vue.use(Row);
|
|
217
255
|
Vue.use(Switch);
|
|
218
256
|
|
|
219
|
-
/*
|
|
220
|
-
const alignToObject = function(cameracontrol, scene) {
|
|
221
|
-
var object = scene.findGeometriesWithGroupName("Endocardium of left atrium")[0];
|
|
222
|
-
const boundingBox = object.getBoundingBox();
|
|
223
|
-
if (boundingBox) {
|
|
224
|
-
const radius = boundingBox.min.distanceTo(boundingBox.max)/2.0;
|
|
225
|
-
const centreX = (boundingBox.min.x + boundingBox.max.x) / 2.0;
|
|
226
|
-
const centreY = (boundingBox.min.y + boundingBox.max.y) / 2.0;
|
|
227
|
-
const centreZ = (boundingBox.min.z + boundingBox.max.z) / 2.0;
|
|
228
|
-
const clip_factor = 8.0;
|
|
229
|
-
const endingViewport = cameracontrol.getViewportFromCentreAndRadius(centreX, centreY, centreZ, radius, 40, radius * clip_factor );
|
|
230
|
-
const startingViewport = cameracontrol.getCurrentViewport();
|
|
231
|
-
cameracontrol.cameraTransition(startingViewport, endingViewport, 1500);
|
|
232
|
-
cameracontrol.enableCameraTransition();
|
|
233
|
-
}
|
|
234
|
-
setTimeout(function(){ tumble(cameracontrol) }, 2000);
|
|
235
|
-
}
|
|
236
|
-
|
|
237
|
-
const tumble = function(cameracontrol) {
|
|
238
|
-
cameracontrol.enableAutoTumble();
|
|
239
|
-
cameracontrol.autoTumble([1.0, 0.0], Math.PI / 2, true);
|
|
240
|
-
}
|
|
241
|
-
*/
|
|
242
257
|
export default {
|
|
243
258
|
name: "App",
|
|
244
259
|
components: {
|
|
260
|
+
DropZone,
|
|
245
261
|
ScaffoldVuer,
|
|
246
262
|
ModelsTable
|
|
247
263
|
},
|
|
@@ -252,10 +268,10 @@ export default {
|
|
|
252
268
|
displayUI: true,
|
|
253
269
|
selectedCoordinates: undefined,
|
|
254
270
|
helpMode: false,
|
|
255
|
-
displayMarkers:
|
|
271
|
+
displayMarkers: false,
|
|
256
272
|
syncMode: false,
|
|
257
273
|
currentTime: 0,
|
|
258
|
-
displayMinimap:
|
|
274
|
+
displayMinimap: false,
|
|
259
275
|
tumbleOn: false,
|
|
260
276
|
showColourPicker: true,
|
|
261
277
|
minimapSettings: {
|
|
@@ -269,7 +285,9 @@ export default {
|
|
|
269
285
|
region: "",
|
|
270
286
|
viewURL: "",
|
|
271
287
|
renderInfoOn: false,
|
|
272
|
-
rendererInfo: undefined
|
|
288
|
+
rendererInfo: undefined,
|
|
289
|
+
zoom: 1,
|
|
290
|
+
pos: [0, 0],
|
|
273
291
|
};
|
|
274
292
|
},
|
|
275
293
|
watch: {
|
|
@@ -288,7 +306,6 @@ export default {
|
|
|
288
306
|
this.$refs.scaffold.toggleSyncControl(val);
|
|
289
307
|
}
|
|
290
308
|
},
|
|
291
|
-
|
|
292
309
|
mounted: function() {
|
|
293
310
|
this._sceneSettings = [];
|
|
294
311
|
this.selectedCoordinates = this.$refs.scaffold.getDynamicSelectedCoordinates();
|
|
@@ -344,6 +361,9 @@ export default {
|
|
|
344
361
|
cameracontrol.stopAutoTumble();
|
|
345
362
|
}
|
|
346
363
|
},
|
|
364
|
+
onReady: function() {
|
|
365
|
+
this.$refs.dropzone.revokeURLs();
|
|
366
|
+
},
|
|
347
367
|
onSelected: function(data) {
|
|
348
368
|
if (data && data[0].data.group) {
|
|
349
369
|
delete this.$route.query["viewURL"];
|
|
@@ -353,13 +373,22 @@ export default {
|
|
|
353
373
|
}
|
|
354
374
|
},
|
|
355
375
|
onNavigated: function(data) {
|
|
356
|
-
|
|
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;
|
|
357
382
|
},
|
|
358
383
|
parseInput: function() {
|
|
359
|
-
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;
|
|
360
388
|
this.$router.replace({
|
|
361
389
|
query: { ...this.$route.query, url: this.input }
|
|
362
390
|
});
|
|
391
|
+
}
|
|
363
392
|
},
|
|
364
393
|
updateCurrentTime: function(val) {
|
|
365
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,126 @@
|
|
|
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
|
+
&.el-popper[x-placement^="bottom"] {
|
|
107
|
+
.popper__arrow {
|
|
108
|
+
border-bottom-color: $app-primary-color !important;
|
|
109
|
+
&:after {
|
|
110
|
+
border-bottom-color: #fff !important;
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
.tooltipContainer {
|
|
117
|
+
position: absolute;
|
|
118
|
+
height: 50px;
|
|
119
|
+
z-index: 2;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
::v-deep .non-selectable {
|
|
123
|
+
user-select: none;
|
|
124
|
+
pointer-events: none;
|
|
125
|
+
}
|
|
126
|
+
</style>
|