@abi-software/scaffoldvuer 1.2.1 → 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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@abi-software/scaffoldvuer",
3
- "version": "1.2.1",
3
+ "version": "1.3.0-beta.0",
4
4
  "license": "Apache-2.0",
5
5
  "repository": {
6
6
  "type": "git",
@@ -41,7 +41,7 @@
41
41
  "*.js"
42
42
  ],
43
43
  "dependencies": {
44
- "@abi-software/flatmapvuer": "^1.1.0",
44
+ "@abi-software/map-utilities": "^0.0.0-beta.4",
45
45
  "@abi-software/sparc-annotation": "^0.3.1",
46
46
  "@abi-software/svg-sprite": "^1.0.0",
47
47
  "@element-plus/icons-vue": "^2.3.1",
@@ -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.3"
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"
@@ -64,80 +65,96 @@
64
65
  </el-row>
65
66
 
66
67
  <el-row :gutter="20" justify="center" align="middle">
67
- <el-col span="auto">
68
+ <el-col :span="auto">
68
69
  <el-switch v-model="displayUI" active-text="UI" />
69
70
  </el-col>
70
- <el-col span="auto">
71
+ <el-col :span="auto">
71
72
  <el-switch v-model="displayMarkers" active-text="Markers" active-icon-class="el-icon-location"
72
73
  active-color="#8300bf" />
73
74
  </el-col>
74
- <el-col span="auto">
75
+ <el-col :span="auto">
75
76
  <el-switch v-model="markerCluster" active-text="Marker Cluster" active-icon-class="el-icon-location"
76
77
  active-color="#8300bf" />
77
78
  </el-col>
78
- <el-col span="auto">
79
+ <el-col :span="auto">
79
80
  <el-switch v-model="displayMinimap" active-text="Minimap" active-icon-class="el-icon-discover"
80
81
  active-color="#8300bf" />
81
82
  </el-col>
82
83
  </el-row>
83
84
 
84
85
  <el-row :gutter="20" justify="center" align="middle">
85
- <el-col span="auto">
86
+ <el-col :span="auto">
86
87
  <el-switch v-model="tumbleOn" active-text="Tumble" active-color="#8300bf" />
87
88
  </el-col>
88
- <el-col span="auto">
89
+ <el-col :span="auto">
89
90
  <el-row>
90
91
  <el-col :span="8"> x: </el-col>
91
92
  <el-col :span="16">
92
93
  <el-input-number class="tumble-direction" controls-position="right" v-model="tumbleDirection[0]" :min="-1.0"
93
- :max="1.0" :controls="false" placeholder="Please input" label="x" @change="autoTumble" />
94
+ :max="1.0" :controls="false" placeholder="Please input" aria-label="x" @change="autoTumble" />
94
95
  </el-col>
95
96
  </el-row>
96
97
  </el-col>
97
- <el-col span="auto">
98
+ <el-col :span="auto">
98
99
  <el-row>
99
100
  <el-col :span="8"> y: </el-col>
100
101
  <el-col :span="16">
101
102
  <el-input-number class="tumble-direction" controls-position="right" v-model="tumbleDirection[1]" :min="-1.0"
102
- :max="1.0" :controls="false" placeholder="Please input" label="y" @change="autoTumble" />
103
+ :max="1.0" :controls="false" placeholder="Please input" aria-label="y" @change="autoTumble" />
103
104
  </el-col>
104
105
  </el-row>
105
106
  </el-col>
106
107
  </el-row>
107
108
 
108
109
  <el-row :gutter="20" justify="center" align="middle">
109
- <el-col span="auto">
110
+ <el-col :span="auto">
110
111
  <el-button size="small" @click="helpMode = !helpMode">
111
112
  Help Mode
112
113
  </el-button>
113
114
  </el-col>
114
- <el-col span="auto">
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">
123
- <el-col span="auto">
121
+ <el-col :span="auto">
124
122
  <el-button size="small" @click="saveSettings()">
125
123
  Save Settings
126
124
  </el-button>
127
125
  </el-col>
128
- <el-col span="auto">
126
+ <el-col :span="auto">
129
127
  <el-button size="small" @click="restoreSettings()">
130
128
  Restore Settings
131
129
  </el-button>
132
130
  </el-col>
133
- <el-col span="auto">
131
+ <el-col :span="auto">
134
132
  <el-button size="small" @click="exportGLB()"> Export GLB </el-button>
135
133
  </el-col>
136
- <el-col span="auto">
134
+ <el-col :span="auto">
137
135
  <el-button size="small" @click="exportGLTF()"> Export GLTF </el-button>
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">
@@ -147,35 +164,35 @@
147
164
  </el-row>
148
165
  <el-row :gutter="20" justify="center" align="middle" v-if="syncMode">
149
166
  <el-col :span="8">
150
- <el-input-number v-model="zoom" :min="1.0" :controls="false" placeholder="Please input" label="zoom" />
167
+ <el-input-number v-model="zoom" :min="1.0" :controls="false" placeholder="Please input" aria-label="zoom" />
151
168
  </el-col>
152
169
  <el-col :span="8">
153
- <el-input-number v-model="pos[0]" :min="-1.0" :max="1.0" :controls="false" placeholder="Please input" label="x" />
170
+ <el-input-number v-model="pos[0]" :min="-1.0" :max="1.0" :controls="false" placeholder="Please input" aria-label="x" />
154
171
  </el-col>
155
172
  <el-col :span="8">
156
- <el-input-number v-model="pos[1]" :min="-1.0" :max="1.0" :controls="false" label="y" />
173
+ <el-input-number v-model="pos[1]" :min="-1.0" :max="1.0" :controls="false" aria-label="y" />
157
174
  </el-col>
158
175
  </el-row>
159
176
  </el-col>
160
177
  </el-row>
161
178
 
162
179
  <el-row :gutter="20" justify="center" align="middle">
163
- <el-col span="auto">
180
+ <el-col :span="auto">
164
181
  <el-switch v-model="render" active-text="Rendering" active-color="#8300bf" />
165
182
  </el-col>
166
- <el-col span="auto">
183
+ <el-col :span="auto">
167
184
  <el-switch v-model="renderInfoOn" active-text="Renderer Info" active-color="#8300bf" />
168
185
  </el-col>
169
186
  </el-row>
170
187
 
171
188
  <template v-if="renderInfoOn && rendererInfo">
172
189
  <el-row :gutter="20" justify="center" align="middle">
173
- <el-col v-for="(value, name) in rendererInfo.memory" :key="name" span="auto">
190
+ <el-col v-for="(value, name) in rendererInfo.memory" :key="name" :span="auto">
174
191
  {{ name }} : {{ value }}
175
192
  </el-col>
176
193
  </el-row>
177
194
  <el-row :gutter="20" justify="center" align="middle">
178
- <el-col v-for="(value, name) in rendererInfo.render" :key="name" span="auto">
195
+ <el-col v-for="(value, name) in rendererInfo.render" :key="name" :span="auto">
179
196
  {{ name }} : {{ value }}
180
197
  </el-col>
181
198
  </el-row>
@@ -189,41 +206,41 @@
189
206
  </el-col>
190
207
  </el-row>
191
208
  <el-row :gutter="20" justify="center" align="middle">
192
- <el-col span="auto">
209
+ <el-col :span="auto">
193
210
  <el-button size="small" @click="featureTextureVolume(false)">
194
211
  Texture volume
195
212
  </el-button>
196
213
  </el-col>
197
- <el-col span="auto">
214
+ <el-col :span="auto">
198
215
  <el-button size="small" @click="featureTextureSlides(false)">
199
216
  Texture slides
200
217
  </el-button>
201
218
  </el-col>
202
- <el-col span="auto">
219
+ <el-col :span="auto">
203
220
  <el-button size="small" @click="featureTextureVolume(true)">
204
221
  Body volume
205
222
  </el-button>
206
223
  </el-col>
207
- <el-col span="auto">
224
+ <el-col :span="auto">
208
225
  <el-button size="small" @click="featureTextureSlides(true)">
209
226
  Body slides
210
227
  </el-button>
211
228
  </el-col>
212
- <el-col span="auto">
229
+ <el-col :span="auto">
213
230
  <el-button size="small" @click="featureArmSlides(true)">
214
231
  Arm slides
215
232
  </el-button>
216
233
  </el-col>
217
234
  </el-row>
218
235
  <el-row :gutter="20" justify="center" align="middle">
219
- <el-col span="auto">
236
+ <el-col :span="auto">
220
237
  <el-switch
221
238
  v-model="onClickMarkers"
222
239
  active-text="Markers On Selection"
223
240
  active-color="#8300bf"
224
241
  />
225
242
  </el-col>
226
- <el-col span="auto">
243
+ <el-col :span="auto">
227
244
  <el-switch
228
245
  v-model="wireframe"
229
246
  active-text="Wireframe"
@@ -297,13 +314,27 @@ 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'
303
- import HelpModeDialog from './components/HelpModeDialog.vue';
321
+ import { HelpModeDialog } from '@abi-software/map-utilities'
322
+ import '@abi-software/map-utilities/dist/style.css'
304
323
 
305
324
  let texture_prefix = undefined;
306
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
+
307
338
  export default {
308
339
  name: "app",
309
340
  components: {
@@ -316,6 +347,7 @@ export default {
316
347
  Popover,
317
348
  Row,
318
349
  Switch,
350
+ Upload,
319
351
  ElIconFolderOpened,
320
352
  ElIconSetting,
321
353
  DropZone,
@@ -326,7 +358,7 @@ export default {
326
358
  data: function () {
327
359
  return {
328
360
  consoleOn: true,
329
- createPoints: false,
361
+ createLinesWithNormal: true,
330
362
  url: undefined,
331
363
  input: undefined,
332
364
  displayUI: true,
@@ -341,7 +373,7 @@ export default {
341
373
  tumbleOn: false,
342
374
  tumbleDirection: [1.0, 0.0],
343
375
  showColourPicker: true,
344
- markerCluster: true,
376
+ markerCluster: false,
345
377
  minimapSettings: {
346
378
  x_offset: 16,
347
379
  y_offset: 50,
@@ -349,22 +381,7 @@ export default {
349
381
  height: 128,
350
382
  align: "top-right",
351
383
  },
352
- markerLabels: {
353
- "body proper": 9,
354
- "Spinal cord": 8,
355
- "lung": 11,
356
- "stomach": 12,
357
- "urinary bladder": 11,
358
- "Brainstem": 11,
359
- "heart": 9,
360
- "skin epidermis": 5,
361
- "Diaphragm": 7,
362
- "colon": 9,
363
- "vagus nerve": 3,
364
- "myenteric nerve plexus": 2,
365
- "esophagus": 1,
366
- "urethra": 3
367
- },
384
+ markerLabels: { },
368
385
  render: true,
369
386
  region: "",
370
387
  viewURL: "",
@@ -388,7 +405,7 @@ export default {
388
405
  router: useRouter(),
389
406
  ElIconSetting: shallowRef(ElIconSetting),
390
407
  ElIconFolderOpened: shallowRef(ElIconFolderOpened),
391
- coordinatesClicked: [],
408
+ auto: NaN
392
409
  };
393
410
  },
394
411
  watch: {
@@ -398,6 +415,28 @@ export default {
398
415
  tumbleOn: function () {
399
416
  this.autoTumble();
400
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
+ },
401
440
  "route.query": {
402
441
  handler: "parseQuery",
403
442
  deep: true,
@@ -424,15 +463,8 @@ export default {
424
463
  methods: {
425
464
  exportGLTF: function () {
426
465
  this.$refs.scaffold.exportGLTF(false).then((data) => {
427
- let dataStr =
428
- "data:text/json;charset=utf-8," +
429
- encodeURIComponent(JSON.stringify(data));
430
- let hrefElement = document.createElement("a");
431
- document.body.append(hrefElement);
432
- hrefElement.download = `export.gltf`;
433
- hrefElement.href = dataStr;
434
- hrefElement.click();
435
- hrefElement.remove();
466
+ const filename = 'export' + JSON.stringify(new Date()) + '.gltf';
467
+ writeTextFile(filename, data);
436
468
  });
437
469
  },
438
470
  exportGLB: function () {
@@ -447,14 +479,26 @@ export default {
447
479
  hrefElement.remove();
448
480
  });
449
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
+ },
450
497
  objectAdded: function (zincObject) {
451
498
  if (this.consoleOn) {
452
499
  console.log(zincObject)
453
500
  console.log(this.$refs.scaffold.$module.scene.getBoundingBox())
454
501
  }
455
- if (this._objects.length === 0) {
456
- zincObject.setMarkerMode("on");
457
- }
458
502
  if (zincObject.isGeometry) {
459
503
  zincObject._lod._material.wireframe = this.wireframe;
460
504
  }
@@ -599,40 +643,36 @@ export default {
599
643
  }
600
644
  this.scaffoldRef = this.$refs.scaffold;
601
645
  },
602
- addLines: function (coord) {
603
- if (this.coordinatesClicked.length === 1) {
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
+ ];
604
653
  const returned = this.$refs.scaffold.$module.scene.createLines(
605
- "test",
606
- "lines",
607
- [this.coordinatesClicked[0], coord],
608
- 0x00ee22,
609
- );
610
- this.coordinatesClicked.length = 0;
611
- if (this.consoleOn) console.log(returned);
612
- } else {
613
- 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);
614
661
  }
615
662
  },
616
663
  onSelected: function (data) {
617
664
  if (data && data.length > 0 && data[0].data.group) {
618
- if (this.consoleOn) console.log(data[0]);
619
- if (this.createPoints && data[0].extraData.worldCoords) {
620
- const returned = this.$refs.scaffold.$module.scene.createPoints(
621
- "test",
622
- "points",
623
- [data[0].extraData.worldCoords],
624
- undefined,
625
- 0x0022ee,
626
- );
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)
627
669
  }
628
670
  delete this.route.query["viewURL"];
629
- this.$refs.scaffold.showRegionTooltipWithAnnotations(data, false, true);
671
+ //this.$refs.scaffold.showRegionTooltipWithAnnotations(data, false, true);
630
672
  if (this.onClickMarkers) this.$refs.scaffold.setMarkerModeForObjectsWithName(data[0].data.group, "on");
631
673
  }
632
674
  },
633
- changeMarkers: function () {
634
- this.markerLabels = {"left atrium": 3, "epicardium": 4 , "stomach": 5};
635
- },
675
+
636
676
  onNavigated: function (data) {
637
677
  this.zoom = data.zoom;
638
678
  this.pos[0] = data.target[0];
@@ -826,4 +866,9 @@ body {
826
866
  svg.map-icon {
827
867
  color: $app-primary-color;
828
868
  }
869
+
870
+ input[type="file"] {
871
+ display: none;
872
+ }
873
+
829
874
  </style>