@abi-software/scaffoldvuer 1.3.3-beta.1 → 1.4.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 +15378 -14664
- package/dist/scaffoldvuer.umd.cjs +184 -179
- package/dist/style.css +1 -1
- package/package.json +4 -4
- package/src/App.vue +13 -3
- package/src/components/ScaffoldTooltip.vue +36 -12
- package/src/components/ScaffoldVuer.vue +157 -14
- package/src/components.d.ts +2 -0
- package/src/main.js +1 -1
- package/src/mixins/imageMixin.js +89 -0
- package/src/services/scicrunchQueries.js +280 -0
- package/src/stores/settings.js +46 -0
- /package/src/{store → stores}/index.js +0 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@abi-software/scaffoldvuer",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.4.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/map-utilities": "^1.0.
|
|
44
|
+
"@abi-software/map-utilities": "^1.1.0-beta.2",
|
|
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,12 +55,12 @@
|
|
|
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.11.
|
|
58
|
+
"zincjs": "^1.11.3"
|
|
59
59
|
},
|
|
60
60
|
"devDependencies": {
|
|
61
61
|
"@vitejs/plugin-vue": "^4.6.2",
|
|
62
62
|
"@vuese/markdown-render": "^2.11.3",
|
|
63
|
-
"@vuese/parser": "^2.
|
|
63
|
+
"@vuese/parser": "^2.9.1",
|
|
64
64
|
"auto-changelog": "^2.4.0",
|
|
65
65
|
"babel-eslint": "^10.1.0",
|
|
66
66
|
"babel-plugin-component": "^1.1.1",
|
package/src/App.vue
CHANGED
|
@@ -28,6 +28,7 @@
|
|
|
28
28
|
:format="format"
|
|
29
29
|
:marker-labels="markerLabels"
|
|
30
30
|
:enableLocalAnnotations="false"
|
|
31
|
+
:sparcAPI="sparcAPI"
|
|
31
32
|
@open-map="openMap"
|
|
32
33
|
@on-ready="onReady"
|
|
33
34
|
@scaffold-selected="onSelected"
|
|
@@ -321,6 +322,9 @@ import {
|
|
|
321
322
|
import { useRoute, useRouter } from 'vue-router'
|
|
322
323
|
import { HelpModeDialog } from '@abi-software/map-utilities'
|
|
323
324
|
import '@abi-software/map-utilities/dist/style.css'
|
|
325
|
+
import { mapStores } from 'pinia';
|
|
326
|
+
import { useSettingsStore } from '@/stores/settings';
|
|
327
|
+
import { getOrganCuries } from '@/services/scicrunchQueries'
|
|
324
328
|
|
|
325
329
|
let texture_prefix = undefined;
|
|
326
330
|
|
|
@@ -358,7 +362,7 @@ export default {
|
|
|
358
362
|
},
|
|
359
363
|
data: function () {
|
|
360
364
|
return {
|
|
361
|
-
consoleOn:
|
|
365
|
+
consoleOn: false,
|
|
362
366
|
createLinesWithNormal: false,
|
|
363
367
|
url: undefined,
|
|
364
368
|
input: undefined,
|
|
@@ -406,9 +410,14 @@ export default {
|
|
|
406
410
|
router: useRouter(),
|
|
407
411
|
ElIconSetting: shallowRef(ElIconSetting),
|
|
408
412
|
ElIconFolderOpened: shallowRef(ElIconFolderOpened),
|
|
409
|
-
auto: NaN
|
|
413
|
+
auto: NaN,
|
|
414
|
+
sparcAPI: import.meta.env.VITE_SPARC_API,
|
|
415
|
+
// sparcAPI: "http://localhost:8000/",
|
|
410
416
|
};
|
|
411
417
|
},
|
|
418
|
+
computed: {
|
|
419
|
+
...mapStores(useSettingsStore),
|
|
420
|
+
},
|
|
412
421
|
watch: {
|
|
413
422
|
input: function () {
|
|
414
423
|
this.parseInput();
|
|
@@ -422,7 +431,7 @@ export default {
|
|
|
422
431
|
"body proper": 9,
|
|
423
432
|
"Spinal cord": 8,
|
|
424
433
|
"lung": 11,
|
|
425
|
-
"stomach":
|
|
434
|
+
"stomach": 12,
|
|
426
435
|
"urinary bladder": 11,
|
|
427
436
|
"Brainstem": 11,
|
|
428
437
|
"heart": 9,
|
|
@@ -454,6 +463,7 @@ export default {
|
|
|
454
463
|
},
|
|
455
464
|
mounted: function () {
|
|
456
465
|
this._objects = [];
|
|
466
|
+
getOrganCuries(this.sparcAPI).then((organCuries) => this.settingsStore.updateOrganCuries(organCuries))
|
|
457
467
|
},
|
|
458
468
|
created: function () {
|
|
459
469
|
texture_prefix = import.meta.env.VITE_TEXTURE_FOOT_PREFIX;
|
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
<template #default>
|
|
15
15
|
<div class="tooltip-text">{{ label }}</div>
|
|
16
16
|
<div class="tooltip-text" v-if="region">Region: {{ region }}</div>
|
|
17
|
-
<
|
|
17
|
+
<CreateTooltipContent
|
|
18
18
|
v-show="createData.toBeConfirmed"
|
|
19
19
|
:createData="createData"
|
|
20
20
|
@confirm-create="$emit('confirm-create', $event)"
|
|
@@ -22,10 +22,14 @@
|
|
|
22
22
|
/>
|
|
23
23
|
<Tooltip
|
|
24
24
|
class="p-tooltip"
|
|
25
|
-
v-show="
|
|
26
|
-
|
|
27
|
-
|
|
25
|
+
v-show="
|
|
26
|
+
(annotationDisplay && !createData.toBeConfirmed) ||
|
|
27
|
+
imageEntry.length
|
|
28
|
+
"
|
|
29
|
+
ref="tooltip"
|
|
30
|
+
:tooltipType="annotationDisplay ? 'annotation' : 'image'"
|
|
28
31
|
:annotationEntry="annotationEntry"
|
|
32
|
+
:imageEntry="imageEntry"
|
|
29
33
|
/>
|
|
30
34
|
<div v-if="createData.toBeDeleted" class="delete-container">
|
|
31
35
|
<el-row>
|
|
@@ -66,9 +70,9 @@ import {
|
|
|
66
70
|
import {
|
|
67
71
|
Delete as ElIconDelete,
|
|
68
72
|
} from '@element-plus/icons-vue'
|
|
69
|
-
import CreateTooltiipContent from "./CreateTooltipContent.vue";
|
|
70
73
|
import { mapState } from 'pinia';
|
|
71
|
-
import { useMainStore } from "@/
|
|
74
|
+
import { useMainStore } from "@/stores/index";
|
|
75
|
+
import CreateTooltipContent from "./CreateTooltipContent.vue";
|
|
72
76
|
import { Tooltip } from '@abi-software/map-utilities'
|
|
73
77
|
import '@abi-software/map-utilities/dist/style.css'
|
|
74
78
|
|
|
@@ -79,7 +83,7 @@ export default {
|
|
|
79
83
|
name: "ScaffoldTooltip",
|
|
80
84
|
components: {
|
|
81
85
|
Col,
|
|
82
|
-
|
|
86
|
+
CreateTooltipContent,
|
|
83
87
|
ElIconDelete,
|
|
84
88
|
Icon,
|
|
85
89
|
Popover,
|
|
@@ -121,6 +125,14 @@ export default {
|
|
|
121
125
|
type: Number,
|
|
122
126
|
default: 200,
|
|
123
127
|
},
|
|
128
|
+
imageThumbnails: {
|
|
129
|
+
type: Object,
|
|
130
|
+
default: {},
|
|
131
|
+
},
|
|
132
|
+
imageThumbnailSidebar: {
|
|
133
|
+
type: Boolean,
|
|
134
|
+
default: false,
|
|
135
|
+
},
|
|
124
136
|
},
|
|
125
137
|
inject: ['scaffoldUrl'],
|
|
126
138
|
provide() {
|
|
@@ -130,7 +142,6 @@ export default {
|
|
|
130
142
|
},
|
|
131
143
|
data: function () {
|
|
132
144
|
return {
|
|
133
|
-
display: false,
|
|
134
145
|
annotationEntry: { },
|
|
135
146
|
ElIconDelete: shallowRef(ElIconDelete),
|
|
136
147
|
};
|
|
@@ -145,11 +156,26 @@ export default {
|
|
|
145
156
|
const x = this.x - 40;
|
|
146
157
|
return { left: x + "px", top: this.y - yOffset + "px" };
|
|
147
158
|
},
|
|
159
|
+
imageEntry: function () {
|
|
160
|
+
let imageEntries = []
|
|
161
|
+
const imageThumbnailsEntries = Object.assign({},
|
|
162
|
+
Object.fromEntries(
|
|
163
|
+
Object.entries(this.imageThumbnails)
|
|
164
|
+
.filter(([key, value]) => value.length > 0)
|
|
165
|
+
.map(([key, value]) => [key.toLowerCase(), value])))
|
|
166
|
+
if (this.label in imageThumbnailsEntries) {
|
|
167
|
+
imageEntries = imageThumbnailsEntries[this.label];
|
|
168
|
+
}
|
|
169
|
+
if (this.imageThumbnailSidebar) {
|
|
170
|
+
this.$emit('image-thumbnail-open', imageEntries)
|
|
171
|
+
return [];
|
|
172
|
+
}
|
|
173
|
+
return imageEntries;
|
|
174
|
+
},
|
|
148
175
|
},
|
|
149
176
|
methods: {
|
|
150
177
|
checkForDisplay: function () {
|
|
151
178
|
if (this.visible && this.label && this.label !== "") {
|
|
152
|
-
this.display = true;
|
|
153
179
|
if (this.annotationDisplay) {
|
|
154
180
|
const region = this.region ? this.region +"/" : "";
|
|
155
181
|
this.annotationEntry = {
|
|
@@ -158,9 +184,7 @@ export default {
|
|
|
158
184
|
"resource": encodeURIComponent(this.scaffoldUrl),
|
|
159
185
|
};
|
|
160
186
|
}
|
|
161
|
-
}
|
|
162
|
-
else {
|
|
163
|
-
this.display = false;
|
|
187
|
+
} else {
|
|
164
188
|
this.annotationEntry = { };
|
|
165
189
|
}
|
|
166
190
|
},
|
|
@@ -15,9 +15,12 @@
|
|
|
15
15
|
:x="tData.x"
|
|
16
16
|
:y="tData.y"
|
|
17
17
|
:annotationDisplay="annotationDisplay"
|
|
18
|
+
:imageThumbnailSidebar="imageThumbnailSidebar"
|
|
19
|
+
:imageThumbnails="imageThumbnailsEntry"
|
|
18
20
|
@confirm-create="confirmCreate($event)"
|
|
19
21
|
@cancel-create="cancelCreate()"
|
|
20
22
|
@confirm-delete="confirmDelete($event)"
|
|
23
|
+
@image-thumbnail-open="onImageThumbnailOpen"
|
|
21
24
|
/>
|
|
22
25
|
<div
|
|
23
26
|
id="organsDisplayArea"
|
|
@@ -284,7 +287,7 @@
|
|
|
284
287
|
ref="backgroundPopover"
|
|
285
288
|
:virtual-ref="backgroundIconRef"
|
|
286
289
|
placement="top-start"
|
|
287
|
-
width="
|
|
290
|
+
width="330"
|
|
288
291
|
:teleported="false"
|
|
289
292
|
trigger="click"
|
|
290
293
|
popper-class="background-popper non-selectable h-auto"
|
|
@@ -292,7 +295,7 @@
|
|
|
292
295
|
>
|
|
293
296
|
<div>
|
|
294
297
|
<el-row class="backgroundText">Viewing Mode</el-row>
|
|
295
|
-
<el-row class="
|
|
298
|
+
<el-row class="backgroundChooser">
|
|
296
299
|
<div style="margin-bottom: 2px;">
|
|
297
300
|
<template
|
|
298
301
|
v-for="(value, key, index) in viewingModes"
|
|
@@ -310,6 +313,41 @@
|
|
|
310
313
|
{{ viewingModes[viewingMode] }}
|
|
311
314
|
</el-row>
|
|
312
315
|
</el-row>
|
|
316
|
+
<el-row class="backgroundSpacer" v-if="viewingMode === 'Exploration'"></el-row>
|
|
317
|
+
<el-row class="backgroundText" v-if="viewingMode === 'Exploration'">Markers display</el-row>
|
|
318
|
+
<el-row class="backgroundChooser" v-if="viewingMode === 'Exploration'">
|
|
319
|
+
<el-col :span="14">
|
|
320
|
+
<el-radio-group
|
|
321
|
+
v-model="imageRadio"
|
|
322
|
+
class="flatmap-radio"
|
|
323
|
+
@change="setImage"
|
|
324
|
+
>
|
|
325
|
+
<el-radio :value="false">Standard</el-radio>
|
|
326
|
+
<el-radio :value="true">Image</el-radio>
|
|
327
|
+
</el-radio-group>
|
|
328
|
+
</el-col>
|
|
329
|
+
<el-col :span="10" v-if="imageRadio">
|
|
330
|
+
<el-select
|
|
331
|
+
:teleported="false"
|
|
332
|
+
v-model="imageType"
|
|
333
|
+
placeholder="Select"
|
|
334
|
+
class="scaffold-select-box imageSelector"
|
|
335
|
+
popper-class="scaffold_viewer_dropdown"
|
|
336
|
+
@change="setImageType"
|
|
337
|
+
>
|
|
338
|
+
<el-option
|
|
339
|
+
v-for="item in imageTypes"
|
|
340
|
+
:key="item"
|
|
341
|
+
:label="item"
|
|
342
|
+
:value="item"
|
|
343
|
+
>
|
|
344
|
+
<el-row>
|
|
345
|
+
<el-col :span="12">{{ item }}</el-col>
|
|
346
|
+
</el-row>
|
|
347
|
+
</el-option>
|
|
348
|
+
</el-select>
|
|
349
|
+
</el-col>
|
|
350
|
+
</el-row>
|
|
313
351
|
<el-row class="backgroundSpacer"></el-row>
|
|
314
352
|
<el-row class="backgroundText"> Change background </el-row>
|
|
315
353
|
<el-row class="backgroundChooser">
|
|
@@ -382,7 +420,7 @@
|
|
|
382
420
|
|
|
383
421
|
<script>
|
|
384
422
|
/* eslint-disable no-alert, no-console */
|
|
385
|
-
import { markRaw, shallowRef } from 'vue';
|
|
423
|
+
import { markRaw, toRaw, shallowRef } from 'vue';
|
|
386
424
|
import {
|
|
387
425
|
WarningFilled as ElIconWarningFilled,
|
|
388
426
|
ArrowDown as ElIconArrowDown,
|
|
@@ -421,8 +459,16 @@ import { AnnotationService } from '@abi-software/sparc-annotation';
|
|
|
421
459
|
import { EventNotifier } from "../scripts/EventNotifier.js";
|
|
422
460
|
import { OrgansViewer } from "../scripts/OrgansRenderer.js";
|
|
423
461
|
import { SearchIndex } from "../scripts/Search.js";
|
|
424
|
-
import { mapState } from 'pinia';
|
|
425
|
-
import { useMainStore } from "@/
|
|
462
|
+
import { mapState, mapStores } from 'pinia';
|
|
463
|
+
import { useMainStore } from "@/stores/index";
|
|
464
|
+
import { useSettingsStore } from '@/stores/settings'
|
|
465
|
+
import {
|
|
466
|
+
getBiolucidaThumbnails,
|
|
467
|
+
getSegmentationThumbnails,
|
|
468
|
+
getScaffoldThumbnails,
|
|
469
|
+
getPlotThumbnails
|
|
470
|
+
} from '../services/scicrunchQueries'
|
|
471
|
+
import imageMixin from '../mixins/imageMixin.js'
|
|
426
472
|
|
|
427
473
|
/**
|
|
428
474
|
* A vue component of the scaffold viewer.
|
|
@@ -432,6 +478,7 @@ import { useMainStore } from "@/store/index";
|
|
|
432
478
|
*/
|
|
433
479
|
export default {
|
|
434
480
|
name: "ScaffoldVuer",
|
|
481
|
+
mixins: [imageMixin],
|
|
435
482
|
components: {
|
|
436
483
|
Button,
|
|
437
484
|
Col,
|
|
@@ -689,10 +736,24 @@ export default {
|
|
|
689
736
|
/**
|
|
690
737
|
* Enable local annotations
|
|
691
738
|
*/
|
|
692
|
-
|
|
739
|
+
enableLocalAnnotations: {
|
|
693
740
|
type: Boolean,
|
|
694
741
|
default: false
|
|
695
742
|
},
|
|
743
|
+
/**
|
|
744
|
+
* Specify the endpoint of the SPARC API.
|
|
745
|
+
*/
|
|
746
|
+
sparcAPI: {
|
|
747
|
+
type: String,
|
|
748
|
+
default: 'https://api.sparc.science/',
|
|
749
|
+
},
|
|
750
|
+
/**
|
|
751
|
+
* The option to show image thumbnail in sidebar
|
|
752
|
+
*/
|
|
753
|
+
imageThumbnailSidebar: {
|
|
754
|
+
type: Boolean,
|
|
755
|
+
default: false,
|
|
756
|
+
},
|
|
696
757
|
},
|
|
697
758
|
provide() {
|
|
698
759
|
return {
|
|
@@ -700,6 +761,7 @@ export default {
|
|
|
700
761
|
scaffoldUrl: this.url,
|
|
701
762
|
$annotator: this.annotator,
|
|
702
763
|
boundingDims: this.boundingDims,
|
|
764
|
+
getFeaturesAlert: () => undefined,
|
|
703
765
|
};
|
|
704
766
|
},
|
|
705
767
|
data: function () {
|
|
@@ -790,7 +852,8 @@ export default {
|
|
|
790
852
|
active: false,
|
|
791
853
|
},
|
|
792
854
|
fileFormat: "metadata",
|
|
793
|
-
|
|
855
|
+
markerLabelEntry: markRaw({}),
|
|
856
|
+
previousMarkerLabelEntry: markRaw({}),
|
|
794
857
|
viewingMode: "Exploration",
|
|
795
858
|
viewingModes: {
|
|
796
859
|
"Exploration": "View and explore detailed visualization of 3D scaffolds",
|
|
@@ -812,6 +875,10 @@ export default {
|
|
|
812
875
|
centre: [0, 0, 0],
|
|
813
876
|
size:[1, 1, 1],
|
|
814
877
|
},
|
|
878
|
+
imageRadio: false,
|
|
879
|
+
imageType: 'Image',
|
|
880
|
+
imageTypes: ['Image', 'Segmentation', 'Scaffold', 'Plot'],
|
|
881
|
+
imageClicked: '',
|
|
815
882
|
};
|
|
816
883
|
},
|
|
817
884
|
watch: {
|
|
@@ -891,14 +958,17 @@ export default {
|
|
|
891
958
|
},
|
|
892
959
|
immediate: true,
|
|
893
960
|
},
|
|
894
|
-
markerLabels: function(labels) {
|
|
895
|
-
|
|
961
|
+
markerLabels: function (labels) {
|
|
962
|
+
this.markerLabelEntry = markRaw({...labels})
|
|
963
|
+
},
|
|
964
|
+
markerLabelEntry: function (entry) {
|
|
965
|
+
for (const [key, value] of Object.entries(this.previousMarkerLabelEntry)) {
|
|
896
966
|
this.setMarkerModeForObjectsWithName(key, value, "off");
|
|
897
967
|
}
|
|
898
|
-
for (const [key, value] of Object.entries(
|
|
968
|
+
for (const [key, value] of Object.entries(entry)) {
|
|
899
969
|
this.setMarkerModeForObjectsWithName(key, value, "on");
|
|
900
970
|
}
|
|
901
|
-
this.
|
|
971
|
+
this.previousMarkerLabelEntry = markRaw({...entry});
|
|
902
972
|
},
|
|
903
973
|
},
|
|
904
974
|
beforeCreate: function () {
|
|
@@ -938,9 +1008,13 @@ export default {
|
|
|
938
1008
|
},
|
|
939
1009
|
computed: {
|
|
940
1010
|
...mapState(useMainStore, ['userToken']),
|
|
1011
|
+
...mapStores(useSettingsStore),
|
|
941
1012
|
annotationDisplay: function() {
|
|
942
1013
|
return this.viewingMode === 'Annotation' && this.tData.active === true &&
|
|
943
1014
|
(this.activeDrawMode === 'Edit' || this.activeDrawMode === 'Delete');
|
|
1015
|
+
},
|
|
1016
|
+
imageThumbnailsEntry: function() {
|
|
1017
|
+
return this.imageClicked ? this.convertUberonToName() : {};
|
|
944
1018
|
}
|
|
945
1019
|
},
|
|
946
1020
|
methods: {
|
|
@@ -1503,6 +1577,13 @@ export default {
|
|
|
1503
1577
|
this.$refs.scaffoldTreeControls.removeActive(false);
|
|
1504
1578
|
}
|
|
1505
1579
|
}
|
|
1580
|
+
if (this.imageRadio && event.identifiers.length && event.identifiers[0]) {
|
|
1581
|
+
this.imageClicked = event.identifiers[0].data.id
|
|
1582
|
+
? event.identifiers[0].data.id
|
|
1583
|
+
: event.identifiers[0].data.group;
|
|
1584
|
+
} else {
|
|
1585
|
+
this.imageClicked = ''
|
|
1586
|
+
}
|
|
1506
1587
|
//Emit when an object is selected
|
|
1507
1588
|
//@arg Identifier of selected objects
|
|
1508
1589
|
this.$emit("scaffold-selected", event.identifiers);
|
|
@@ -1553,6 +1634,12 @@ export default {
|
|
|
1553
1634
|
this.createEditTemporaryLines(event.identifiers[0].extraData.worldCoords);
|
|
1554
1635
|
}
|
|
1555
1636
|
this.createEditTemporaryLines(event.identifiers[0].extraData.worldCoords);
|
|
1637
|
+
const id = event.identifiers[0].data.id
|
|
1638
|
+
? event.identifiers[0].data.id
|
|
1639
|
+
: event.identifiers[0].data.group;
|
|
1640
|
+
if (this.imageClicked !== id) {
|
|
1641
|
+
this.imageClicked = ''
|
|
1642
|
+
}
|
|
1556
1643
|
}
|
|
1557
1644
|
}
|
|
1558
1645
|
}
|
|
@@ -2327,15 +2414,67 @@ export default {
|
|
|
2327
2414
|
this.$module.toggleSyncControl(flag, rotateMode);
|
|
2328
2415
|
this.$module.setSyncControlCallback(this.syncControlCallback);
|
|
2329
2416
|
},
|
|
2330
|
-
|
|
2331
2417
|
/**
|
|
2332
2418
|
* Set the markers for the scene.
|
|
2333
2419
|
*/
|
|
2334
2420
|
setMarkers: function () {
|
|
2335
|
-
for (const [key, value] of Object.entries(this.
|
|
2421
|
+
for (const [key, value] of Object.entries(this.markerLabelEntry)) {
|
|
2336
2422
|
this.setMarkerModeForObjectsWithName(key, value, "on");
|
|
2337
2423
|
}
|
|
2338
2424
|
},
|
|
2425
|
+
removeImageThumbnails: function () {
|
|
2426
|
+
this.imageThumbnails = {}
|
|
2427
|
+
this.markerLabelEntry = markRaw(this.markerLabels)
|
|
2428
|
+
},
|
|
2429
|
+
setImage: function (flag) {
|
|
2430
|
+
if (flag) {
|
|
2431
|
+
this.setImageType(this.imageType)
|
|
2432
|
+
} else {
|
|
2433
|
+
this.removeImageThumbnails()
|
|
2434
|
+
}
|
|
2435
|
+
},
|
|
2436
|
+
setImageType: async function (type) {
|
|
2437
|
+
this.imageType = type
|
|
2438
|
+
if (!this.settingsStore.imageTypeCached(type)) {
|
|
2439
|
+
this.loading = true
|
|
2440
|
+
await this.fetchImageThumbnails(type)
|
|
2441
|
+
this.loading = false
|
|
2442
|
+
}
|
|
2443
|
+
this.populateImageThumbnails(type)
|
|
2444
|
+
},
|
|
2445
|
+
fetchImageThumbnails: async function (type) {
|
|
2446
|
+
let thumbnails = {}
|
|
2447
|
+
const organCuries = this.settingsStore.organCuries
|
|
2448
|
+
if (type === 'Image') {
|
|
2449
|
+
thumbnails = await getBiolucidaThumbnails(this.sparcAPI, organCuries, type)
|
|
2450
|
+
} else if (type === 'Segmentation') {
|
|
2451
|
+
thumbnails = await getSegmentationThumbnails(this.sparcAPI, organCuries, type)
|
|
2452
|
+
} else if (type === 'Scaffold') {
|
|
2453
|
+
thumbnails = await getScaffoldThumbnails(this.sparcAPI, organCuries, type)
|
|
2454
|
+
} else if (type === 'Plot') {
|
|
2455
|
+
thumbnails = await getPlotThumbnails(this.sparcAPI, organCuries, type)
|
|
2456
|
+
}
|
|
2457
|
+
this.settingsStore.updateImageThumbnails(type, thumbnails)
|
|
2458
|
+
},
|
|
2459
|
+
convertUberonToName: function () {
|
|
2460
|
+
const organCuries = this.settingsStore.organCuries
|
|
2461
|
+
const identifiers = organCuries.filter((curie) => curie.name in this.markerLabels).map((curie) => curie.id)
|
|
2462
|
+
const imageThumbnails = this.settingsStore.getImageThumbnails(this.imageType, identifiers)
|
|
2463
|
+
return Object.assign({},
|
|
2464
|
+
Object.fromEntries(
|
|
2465
|
+
Object.entries(imageThumbnails)
|
|
2466
|
+
.map(([key, value]) => [organCuries.filter((curie) => curie.id === key)[0].name, value])))
|
|
2467
|
+
},
|
|
2468
|
+
populateImageThumbnails: async function (type) {
|
|
2469
|
+
this.removeImageThumbnails()
|
|
2470
|
+
const thumbnails = this.convertUberonToName()
|
|
2471
|
+
this.loading = true
|
|
2472
|
+
this.markerLabelEntry = markRaw(await this.populateMapWithImages(thumbnails, type))
|
|
2473
|
+
this.loading = false
|
|
2474
|
+
},
|
|
2475
|
+
onImageThumbnailOpen: function (payload) {
|
|
2476
|
+
this.$emit('image-thumbnail-open', payload);
|
|
2477
|
+
},
|
|
2339
2478
|
},
|
|
2340
2479
|
};
|
|
2341
2480
|
</script>
|
|
@@ -2495,7 +2634,7 @@ export default {
|
|
|
2495
2634
|
background-color: #ffffff;
|
|
2496
2635
|
border: 1px solid $app-primary-color;
|
|
2497
2636
|
box-shadow: 0px 2px 12px 0px rgba(0, 0, 0, 0.06);
|
|
2498
|
-
height:
|
|
2637
|
+
height: fit-content;
|
|
2499
2638
|
min-width: 200px;
|
|
2500
2639
|
.el-popper__arrow {
|
|
2501
2640
|
&:before {
|
|
@@ -2752,6 +2891,10 @@ export default {
|
|
|
2752
2891
|
min-height: 24px
|
|
2753
2892
|
}
|
|
2754
2893
|
}
|
|
2894
|
+
|
|
2895
|
+
&.imageSelector {
|
|
2896
|
+
width: 125px!important;
|
|
2897
|
+
}
|
|
2755
2898
|
}
|
|
2756
2899
|
|
|
2757
2900
|
:deep(.scaffold_viewer_dropdown) {
|
package/src/components.d.ts
CHANGED
|
@@ -26,6 +26,8 @@ declare module 'vue' {
|
|
|
26
26
|
ElMain: typeof import('element-plus/es')['ElMain']
|
|
27
27
|
ElOption: typeof import('element-plus/es')['ElOption']
|
|
28
28
|
ElPopover: typeof import('element-plus/es')['ElPopover']
|
|
29
|
+
ElRadio: typeof import('element-plus/es')['ElRadio']
|
|
30
|
+
ElRadioGroup: typeof import('element-plus/es')['ElRadioGroup']
|
|
29
31
|
ElRow: typeof import('element-plus/es')['ElRow']
|
|
30
32
|
ElSelect: typeof import('element-plus/es')['ElSelect']
|
|
31
33
|
ElSlider: typeof import('element-plus/es')['ElSlider']
|
package/src/main.js
CHANGED
|
@@ -2,7 +2,7 @@ import { createApp } from 'vue'
|
|
|
2
2
|
import { createPinia } from 'pinia'
|
|
3
3
|
import * as VueRouter from 'vue-router'
|
|
4
4
|
import App from './App.vue'
|
|
5
|
-
import { useMainStore } from '@/
|
|
5
|
+
import { useMainStore } from '@/stores/index'
|
|
6
6
|
|
|
7
7
|
const routes = [
|
|
8
8
|
{ path: '/'},
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
export default {
|
|
2
|
+
methods: {
|
|
3
|
+
populateMapWithImages: async function (images, type) {
|
|
4
|
+
let imageMarkerLabels = {};
|
|
5
|
+
for (const [key, list] of Object.entries(images)) {
|
|
6
|
+
const response = await this.downloadImageThumbnail(key, list, type);
|
|
7
|
+
if (response) {
|
|
8
|
+
imageMarkerLabels[key] = response;
|
|
9
|
+
} else {
|
|
10
|
+
imageMarkerLabels[key] = this.markerLabels[key];
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
return imageMarkerLabels;
|
|
14
|
+
},
|
|
15
|
+
downloadImageThumbnail: async function (key, list, type) {
|
|
16
|
+
const count = list.length;
|
|
17
|
+
if (count > 0) {
|
|
18
|
+
//Pick a random image
|
|
19
|
+
const index = Math.floor(Math.random() * count);
|
|
20
|
+
const thumbnail = list[index].thumbnail;
|
|
21
|
+
try {
|
|
22
|
+
const response = await this.getImageThumbnail(thumbnail, type);
|
|
23
|
+
const markerObject = await this.addImageThumbnailMarker(key, response);
|
|
24
|
+
return markerObject;
|
|
25
|
+
} catch (error) {
|
|
26
|
+
// Failed to download, pick another one
|
|
27
|
+
list.splice(index);
|
|
28
|
+
this.downloadImageThumbnail(key, list, type);
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
},
|
|
32
|
+
getImageThumbnail: async function (url, type) {
|
|
33
|
+
return new Promise((resolve, reject) => {
|
|
34
|
+
if (type === "Image" || type === "Segmentation") {
|
|
35
|
+
this.getBinaryThumbnail(url)
|
|
36
|
+
.then((response) => resolve(response))
|
|
37
|
+
.catch((response) => reject(response));
|
|
38
|
+
} else {
|
|
39
|
+
this.getGenericThumbnail(url)
|
|
40
|
+
.then((response) => resolve(response))
|
|
41
|
+
.catch((response) => reject(response));
|
|
42
|
+
}
|
|
43
|
+
});
|
|
44
|
+
},
|
|
45
|
+
getBinaryThumbnail: async function (url) {
|
|
46
|
+
return new Promise((resolve, reject) => {
|
|
47
|
+
fetch(url)
|
|
48
|
+
.then((response) => {
|
|
49
|
+
if (response.status >= 200 && response.status < 300) {
|
|
50
|
+
return response.text();
|
|
51
|
+
} else {
|
|
52
|
+
reject();
|
|
53
|
+
}
|
|
54
|
+
})
|
|
55
|
+
.then((data) => {
|
|
56
|
+
if (data) {
|
|
57
|
+
let img = new Image();
|
|
58
|
+
img.onload = function () {
|
|
59
|
+
resolve(`data:'image/png';base64,${data}`);
|
|
60
|
+
};
|
|
61
|
+
img.onerror = function () {
|
|
62
|
+
reject(new Error("Failed to load image at " + url));
|
|
63
|
+
};
|
|
64
|
+
img.src = `data:'image/png';base64,${data}`;
|
|
65
|
+
} else {
|
|
66
|
+
reject(new Error("Failed to load image at " + url));
|
|
67
|
+
}
|
|
68
|
+
});
|
|
69
|
+
});
|
|
70
|
+
},
|
|
71
|
+
getGenericThumbnail: async function (url) {
|
|
72
|
+
return new Promise((resolve, reject) => {
|
|
73
|
+
let img = new Image();
|
|
74
|
+
img.onload = function () {
|
|
75
|
+
resolve(url);
|
|
76
|
+
};
|
|
77
|
+
img.onerror = function () {
|
|
78
|
+
reject(new Error("Failed to load image at " + url));
|
|
79
|
+
};
|
|
80
|
+
img.src = url;
|
|
81
|
+
});
|
|
82
|
+
},
|
|
83
|
+
addImageThumbnailMarker: async function (id, source) {
|
|
84
|
+
const blob = await (await fetch(source)).blob();
|
|
85
|
+
const blobUrl = URL.createObjectURL(blob);
|
|
86
|
+
return { number: this.markerLabels[id], imgURL: blobUrl };
|
|
87
|
+
},
|
|
88
|
+
},
|
|
89
|
+
};
|