@3cr/viewer-browser 0.0.52 → 0.0.55
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/README.md +108 -81
- package/__tests__/index.spec.ts +31 -0
- package/components.d.ts +2 -2
- package/coverage/3cr-viewer-browser/index.html +116 -0
- package/coverage/3cr-viewer-browser/index.ts.html +211 -0
- package/coverage/3cr-viewer-browser/src/App.vue.html +313 -0
- package/coverage/3cr-viewer-browser/src/components/WebGL3DR.vue.html +442 -0
- package/coverage/3cr-viewer-browser/src/components/icons/index.html +116 -0
- package/coverage/3cr-viewer-browser/src/components/icons/liver.vue.html +148 -0
- package/coverage/3cr-viewer-browser/src/components/index.html +116 -0
- package/coverage/3cr-viewer-browser/src/components/loading/LoadingSpinner.vue.html +556 -0
- package/coverage/3cr-viewer-browser/src/components/loading/index.html +116 -0
- package/coverage/3cr-viewer-browser/src/components/modal/MftpWebGL3DRModal.vue.html +3931 -0
- package/coverage/3cr-viewer-browser/src/components/modal/index.html +116 -0
- package/coverage/3cr-viewer-browser/src/components/selectors/ValueSelector.vue.html +331 -0
- package/coverage/3cr-viewer-browser/src/components/selectors/index.html +116 -0
- package/coverage/3cr-viewer-browser/src/components/sliders/DoubleSliderSelector.vue.html +445 -0
- package/coverage/3cr-viewer-browser/src/components/sliders/VerticalSliderSelector.vue.html +349 -0
- package/coverage/3cr-viewer-browser/src/components/sliders/index.html +131 -0
- package/coverage/3cr-viewer-browser/src/helpers/index.html +146 -0
- package/coverage/3cr-viewer-browser/src/helpers/layoutOverlayStyle.ts.html +406 -0
- package/coverage/3cr-viewer-browser/src/helpers/modelHelper.ts.html +412 -0
- package/coverage/3cr-viewer-browser/src/helpers/utils.ts.html +133 -0
- package/coverage/3cr-viewer-browser/src/index.html +131 -0
- package/coverage/3cr-viewer-browser/src/main.ts.html +124 -0
- package/coverage/3cr-viewer-browser/src/plugins/index.html +131 -0
- package/coverage/3cr-viewer-browser/src/plugins/index.ts.html +130 -0
- package/coverage/3cr-viewer-browser/src/plugins/vuetify.ts.html +220 -0
- package/coverage/base.css +224 -0
- package/coverage/block-navigation.js +87 -0
- package/coverage/favicon.png +0 -0
- package/coverage/index.html +251 -0
- package/coverage/prettify.css +1 -0
- package/coverage/prettify.js +2 -0
- package/coverage/sort-arrow-sprite.png +0 -0
- package/coverage/sorter.js +196 -0
- package/dist/Viewer3CR.js +17 -11
- package/dist/Viewer3CR.mjs +5352 -5183
- package/dist/Viewer3CR.umd.js +17 -11
- package/index.html +4 -1
- package/index.ts +16 -12
- package/package.json +8 -3
- package/src/App.vue +1 -9
- package/src/__tests__/app.spec.ts +27 -0
- package/src/components/WebGL3DR.vue +49 -37
- package/src/components/__tests__/webgl3dr.spec.ts +56 -0
- package/src/components/icons/liver.vue +21 -0
- package/src/components/loading/__tests__/loading-spinner.spec.ts +11 -0
- package/src/components/modal/MftpWebGL3DRModal.vue +662 -394
- package/src/components/modal/__tests__/mftp-webgl-3dr-modal.spec.ts +690 -0
- package/src/components/selectors/__tests__/value-selector.spec.ts +35 -0
- package/src/components/sliders/DoubleSliderSelector.vue +30 -24
- package/src/components/sliders/VerticalSliderSelector.vue +25 -21
- package/src/components/sliders/__tests__/double-slider-selector.spec.ts +72 -0
- package/src/components/sliders/__tests__/vertical-slider-selector.spec.ts +61 -0
- package/src/helpers/__tests__/layout-overlay-style.spec.ts +288 -0
- package/src/helpers/__tests__/model-helper.spec.ts +118 -0
- package/src/helpers/__tests__/utils.spec.ts +70 -0
- package/src/helpers/layoutOverlayStyle.ts +50 -30
- package/src/plugins/__tests__/index.spec.ts +19 -0
- package/src/plugins/__tests__/vuetify.spec.ts +8 -0
- package/src/plugins/vuetify.ts +25 -8
- package/test/helper.ts +35 -0
- package/test/setup.ts +1 -0
- package/tsconfig.json +5 -2
- package/vite.config.mts +1 -0
- package/vitest.config.mts +44 -0
- package/README2.md +0 -201
- package/src/components/expansion-panels/ExpansionHeaderMiniMenu.vue +0 -19
- package/src/helpers/models.ts +0 -69
- /package/src/components/{sliders/SliderSelector.vue → selectors/ValueSelector.vue} +0 -0
|
@@ -1,22 +1,33 @@
|
|
|
1
|
+
<!-- /* c8 ignore start */ -->
|
|
1
2
|
<template>
|
|
2
3
|
<v-dialog
|
|
4
|
+
id="cr-viewer"
|
|
3
5
|
class="pa-0 ma-0 overflow-y-auto overflow-x-hidden"
|
|
4
6
|
:modelValue="value"
|
|
5
7
|
style="max-height: unset"
|
|
6
8
|
:scrollable="false"
|
|
7
9
|
fullscreen
|
|
8
10
|
persistent
|
|
9
|
-
@click:outside.prevent.stop="alterValue(false)"
|
|
10
11
|
@input="alterValue"
|
|
11
12
|
>
|
|
12
|
-
<v-dialog
|
|
13
|
+
<v-dialog
|
|
14
|
+
v-model="m_closeDialog"
|
|
15
|
+
id="close-dialog-prompt"
|
|
16
|
+
data-test="closemodal"
|
|
17
|
+
>
|
|
13
18
|
<v-card class="pa-1 ma-auto position-relative" max-width="450">
|
|
14
19
|
<v-card-title>Close Viewer?</v-card-title>
|
|
15
|
-
<v-card-text
|
|
20
|
+
<v-card-text
|
|
21
|
+
>Are you sure you want to close the Online Viewer?</v-card-text
|
|
22
|
+
>
|
|
16
23
|
<v-card-actions>
|
|
17
|
-
<v-btn variant="text" color="red" @click="m_closeDialog = false">
|
|
24
|
+
<v-btn variant="text" color="red" @click="m_closeDialog = false">
|
|
25
|
+
Cancel
|
|
26
|
+
</v-btn>
|
|
18
27
|
<v-spacer />
|
|
19
|
-
<v-btn color="primary" @click="closeModal">
|
|
28
|
+
<v-btn color="primary" @click="closeModal">
|
|
29
|
+
Close without saving
|
|
30
|
+
</v-btn>
|
|
20
31
|
<v-btn color="primary" @click="closeModal"> Save Session </v-btn>
|
|
21
32
|
</v-card-actions>
|
|
22
33
|
</v-card>
|
|
@@ -27,7 +38,12 @@
|
|
|
27
38
|
height="100vh"
|
|
28
39
|
>
|
|
29
40
|
<v-toolbar dense height="48">
|
|
30
|
-
<v-menu
|
|
41
|
+
<v-menu
|
|
42
|
+
:close-on-content-click="false"
|
|
43
|
+
:close-on-click="true"
|
|
44
|
+
open-on-hover
|
|
45
|
+
offset-y
|
|
46
|
+
>
|
|
31
47
|
<template #activator="{ props, isActive }">
|
|
32
48
|
<v-btn
|
|
33
49
|
v-bind="props"
|
|
@@ -38,61 +54,85 @@
|
|
|
38
54
|
<template #prepend>
|
|
39
55
|
<v-icon>description</v-icon>
|
|
40
56
|
</template>
|
|
41
|
-
|
|
57
|
+
File
|
|
42
58
|
</v-btn>
|
|
43
59
|
</template>
|
|
44
60
|
<v-card class="">
|
|
45
61
|
<v-list>
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
<!--
|
|
57
|
-
<!--
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
<v-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
62
|
+
<v-list-item disabled>
|
|
63
|
+
<template v-slot:prepend>
|
|
64
|
+
<v-icon> upload </v-icon>
|
|
65
|
+
</template>
|
|
66
|
+
<v-list-item-title
|
|
67
|
+
>Load New DICOM Series <v-chip x-small color="success"
|
|
68
|
+
>Coming Soon</v-chip
|
|
69
|
+
></v-list-item-title
|
|
70
|
+
>
|
|
71
|
+
</v-list-item>
|
|
72
|
+
<!-- <v-list-item @click="downloadDcm">-->
|
|
73
|
+
<!-- <v-list-item-icon><v-icon> download </v-icon></v-list-item-icon>-->
|
|
74
|
+
<!-- <v-list-item-title>Download DICOM Series</v-list-item-title>-->
|
|
75
|
+
<!-- </v-list-item>-->
|
|
76
|
+
<v-list-item disabled>
|
|
77
|
+
<template v-slot:prepend>
|
|
78
|
+
<v-icon> sync </v-icon>
|
|
79
|
+
</template>
|
|
80
|
+
<v-list-item-title
|
|
81
|
+
>Load Saved Session <v-chip x-small color="success"
|
|
82
|
+
>Coming Soon</v-chip
|
|
83
|
+
></v-list-item-title
|
|
84
|
+
>
|
|
85
|
+
</v-list-item>
|
|
86
|
+
<v-list-item disabled>
|
|
87
|
+
<template v-slot:prepend>
|
|
88
|
+
<v-icon> share </v-icon>
|
|
89
|
+
</template>
|
|
90
|
+
<v-list-item-title
|
|
91
|
+
>Share <v-chip x-small color="success"
|
|
92
|
+
>Coming Soon</v-chip
|
|
93
|
+
></v-list-item-title
|
|
94
|
+
>
|
|
95
|
+
</v-list-item>
|
|
96
|
+
<v-list-item @click="alterValue(false)">
|
|
97
|
+
<template v-slot:prepend>
|
|
98
|
+
<v-icon> close </v-icon>
|
|
99
|
+
</template>
|
|
100
|
+
<v-list-item-title>Close Viewer</v-list-item-title>
|
|
101
|
+
</v-list-item>
|
|
78
102
|
</v-list>
|
|
79
103
|
</v-card>
|
|
80
104
|
</v-menu>
|
|
81
|
-
<v-menu
|
|
105
|
+
<v-menu
|
|
106
|
+
:close-on-content-click="false"
|
|
107
|
+
:close-on-click="true"
|
|
108
|
+
open-on-hover
|
|
109
|
+
offset-y
|
|
110
|
+
>
|
|
82
111
|
<template #activator="{ props, isActive }">
|
|
83
112
|
<v-btn
|
|
84
113
|
variant="flat"
|
|
85
|
-
v-bind="props"
|
|
114
|
+
v-bind="props"
|
|
115
|
+
:color="isActive ? 'secondary' : 'primary'"
|
|
116
|
+
>
|
|
86
117
|
<template #prepend>
|
|
87
118
|
<v-icon>settings</v-icon>
|
|
88
119
|
</template>
|
|
89
|
-
|
|
120
|
+
Settings
|
|
90
121
|
</v-btn>
|
|
91
122
|
</template>
|
|
92
|
-
<v-card min-width="400" class="
|
|
93
|
-
<SliderSelector
|
|
94
|
-
|
|
95
|
-
|
|
123
|
+
<v-card min-width="400" class="pa-4">
|
|
124
|
+
<SliderSelector
|
|
125
|
+
v-model:value="scanState.Display.Brightness"
|
|
126
|
+
label="Adjust Brightness"
|
|
127
|
+
/>
|
|
128
|
+
<SliderSelector
|
|
129
|
+
v-model:value="scanState.Display.Contrast"
|
|
130
|
+
label="Adjust Contrast"
|
|
131
|
+
/>
|
|
132
|
+
<SliderSelector
|
|
133
|
+
v-model:value="scanState.Display.Opacity"
|
|
134
|
+
label="Adjust Opacity"
|
|
135
|
+
/>
|
|
96
136
|
<v-divider class="my-4" />
|
|
97
137
|
<SliderSelector
|
|
98
138
|
v-model:value="scanState.InteractionSettings.PanSensivitity"
|
|
@@ -113,7 +153,9 @@
|
|
|
113
153
|
label="Rotate Sensitivity"
|
|
114
154
|
/>
|
|
115
155
|
<SliderSelector
|
|
116
|
-
v-model:value="
|
|
156
|
+
v-model:value="
|
|
157
|
+
scanState.InteractionSettings.CameraRotateSensitivity
|
|
158
|
+
"
|
|
117
159
|
:min="0"
|
|
118
160
|
:max="100"
|
|
119
161
|
label="Camera Rotate Sensitivity"
|
|
@@ -140,7 +182,9 @@
|
|
|
140
182
|
@click="layouts('lo_03')"
|
|
141
183
|
><v-icon style="rotate: -90deg">view_comfy</v-icon></v-btn
|
|
142
184
|
>
|
|
143
|
-
<v-btn class="" variant="flat" color="red" @click="alterValue(false)"
|
|
185
|
+
<v-btn class="" variant="flat" color="red" @click="alterValue(false)"
|
|
186
|
+
>Close Viewer</v-btn
|
|
187
|
+
>
|
|
144
188
|
</v-toolbar>
|
|
145
189
|
<v-navigation-drawer
|
|
146
190
|
v-model="drawer"
|
|
@@ -154,7 +198,11 @@
|
|
|
154
198
|
width="300"
|
|
155
199
|
>
|
|
156
200
|
<template v-slot:prepend>
|
|
157
|
-
<div
|
|
201
|
+
<div
|
|
202
|
+
class="d-flex align-center pb-1"
|
|
203
|
+
:class="drawerCollapsed ? 'py-2' : 'pa-2'"
|
|
204
|
+
@click="snap"
|
|
205
|
+
>
|
|
158
206
|
<img
|
|
159
207
|
v-if="!drawerCollapsed"
|
|
160
208
|
src="../../assets/images/dark/3dicom-logo.svg"
|
|
@@ -197,14 +245,24 @@
|
|
|
197
245
|
<div
|
|
198
246
|
:class="[drawerCollapsed && 'mx-auto']"
|
|
199
247
|
class="mx-2"
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
248
|
+
:style="
|
|
249
|
+
drawerCollapsed &&
|
|
250
|
+
'margin-left: 10px !important; margin-right: 10px !important;'
|
|
251
|
+
"
|
|
252
|
+
>
|
|
253
|
+
<v-icon
|
|
254
|
+
:large="drawerCollapsed"
|
|
255
|
+
:size="drawerCollapsed ? 32 : 24"
|
|
256
|
+
:color="item.color"
|
|
257
|
+
>
|
|
258
|
+
{{ item.icon || "radio_button_checked" }}
|
|
204
259
|
</v-icon>
|
|
205
260
|
</div>
|
|
206
261
|
</template>
|
|
207
|
-
<v-list-item-title
|
|
262
|
+
<v-list-item-title
|
|
263
|
+
v-if="!drawerCollapsed"
|
|
264
|
+
class="text-white font-weight-medium ml-3"
|
|
265
|
+
>
|
|
208
266
|
{{ item.text }}
|
|
209
267
|
</v-list-item-title>
|
|
210
268
|
</v-list-item>
|
|
@@ -225,9 +283,16 @@
|
|
|
225
283
|
drawerCollapsed = false;
|
|
226
284
|
"
|
|
227
285
|
>
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
286
|
+
<v-icon
|
|
287
|
+
size="36"
|
|
288
|
+
color="white"
|
|
289
|
+
style="
|
|
290
|
+
margin-left: 8px !important;
|
|
291
|
+
margin-right: 10px !important;
|
|
292
|
+
"
|
|
293
|
+
>
|
|
294
|
+
{{ item.icon || "radio_button_checked" }}
|
|
295
|
+
</v-icon>
|
|
231
296
|
</v-list-item>
|
|
232
297
|
</template>
|
|
233
298
|
{{ item.tooltip }}
|
|
@@ -239,24 +304,35 @@
|
|
|
239
304
|
style="max-height: 95vh"
|
|
240
305
|
theme="dark"
|
|
241
306
|
accordion
|
|
242
|
-
class="mt-1
|
|
307
|
+
class="mt-1 transparent pr-0 mr-0"
|
|
243
308
|
>
|
|
244
309
|
<v-expansion-panel class="transparent px-0">
|
|
245
|
-
<
|
|
246
|
-
|
|
310
|
+
<v-expansion-panel-title class="font-weight-bold transparent">
|
|
311
|
+
<span
|
|
312
|
+
><v-icon small>{{ miniMenu[0].icon }}</v-icon
|
|
313
|
+
> {{ miniMenu[0].text }}</span
|
|
314
|
+
>
|
|
315
|
+
<v-spacer />
|
|
316
|
+
</v-expansion-panel-title>
|
|
317
|
+
<v-expansion-panel-text class="px-0">
|
|
247
318
|
<DoubleSliderSelector
|
|
248
319
|
v-model:value="windowSlider"
|
|
249
320
|
label="Skin to Bone"
|
|
250
321
|
:min="huMinMax.min"
|
|
251
322
|
:max="huMinMax.max"
|
|
252
323
|
/>
|
|
253
|
-
<DoubleSliderSelector
|
|
324
|
+
<DoubleSliderSelector
|
|
325
|
+
v-model:value="thresholdSlider"
|
|
326
|
+
label="Fine Adjustment"
|
|
327
|
+
v-bind="huMinMax"
|
|
328
|
+
/>
|
|
254
329
|
<v-card-actions class="py-3">
|
|
255
330
|
<v-select
|
|
256
331
|
:value="getCurrentGreyscalePreset()"
|
|
257
332
|
:items="initialScanState.GreyscalePresets"
|
|
258
333
|
label="Greyscale Preset"
|
|
259
334
|
item-text="Name"
|
|
335
|
+
theme="light"
|
|
260
336
|
density="compact"
|
|
261
337
|
variant="outlined"
|
|
262
338
|
persistent-placeholder
|
|
@@ -266,7 +342,7 @@
|
|
|
266
342
|
closeOnContentClick: true,
|
|
267
343
|
}"
|
|
268
344
|
placeholder="Select a Density Preset"
|
|
269
|
-
@change="setPreset(
|
|
345
|
+
@change="setPreset(PresetsActions.pr01, $event)"
|
|
270
346
|
>
|
|
271
347
|
<template #item="{ props, item }">
|
|
272
348
|
<v-list-item
|
|
@@ -274,22 +350,27 @@
|
|
|
274
350
|
ripple
|
|
275
351
|
:title="item.raw.Name"
|
|
276
352
|
lines="three"
|
|
277
|
-
|
|
278
353
|
@mousedown.prevent
|
|
279
|
-
@click="setPreset(
|
|
354
|
+
@click="setPreset(PresetsActions.pr01, item.raw)"
|
|
280
355
|
>
|
|
281
356
|
<template v-slot:prepend>
|
|
282
|
-
<v-icon
|
|
357
|
+
<v-icon
|
|
358
|
+
:icon="getIconForPreset(item.raw.Name)"
|
|
359
|
+
></v-icon>
|
|
283
360
|
</template>
|
|
284
361
|
<template v-slot:subtitle>
|
|
285
|
-
Skin Density:
|
|
362
|
+
Skin Density:
|
|
363
|
+
<span class="text-mono">{{ item.raw.Lower }}</span>
|
|
286
364
|
<v-spacer />
|
|
287
|
-
Bone Density:
|
|
365
|
+
Bone Density:
|
|
366
|
+
<span class="text-mono">{{ item.raw.Upper }}</span>
|
|
288
367
|
</template>
|
|
289
368
|
</v-list-item>
|
|
290
369
|
</template>
|
|
291
370
|
<template v-slot:selection="{ item }">
|
|
292
|
-
<span v-if="item.raw === undefined || !item.raw.Name"
|
|
371
|
+
<span v-if="item.raw === undefined || !item.raw.Name"
|
|
372
|
+
>None</span
|
|
373
|
+
>
|
|
293
374
|
<span v-else>{{ item.raw.Name }}</span>
|
|
294
375
|
</template>
|
|
295
376
|
</v-select>
|
|
@@ -308,12 +389,11 @@
|
|
|
308
389
|
}"
|
|
309
390
|
placeholder="Select a Colour Preset"
|
|
310
391
|
return-object
|
|
311
|
-
@update:modelValue="setPreset(
|
|
392
|
+
@update:modelValue="setPreset(PresetsActions.pr02, $event)"
|
|
312
393
|
></v-select>
|
|
313
394
|
</v-card-actions>
|
|
314
395
|
</v-expansion-panel-text>
|
|
315
396
|
</v-expansion-panel>
|
|
316
|
-
|
|
317
397
|
</v-expansion-panels>
|
|
318
398
|
</v-navigation-drawer>
|
|
319
399
|
|
|
@@ -333,10 +413,15 @@
|
|
|
333
413
|
:style="drawerCollapsed ? 'left: 68px' : 'left: 300px'"
|
|
334
414
|
@click="drawerCollapsed = !drawerCollapsed"
|
|
335
415
|
>
|
|
336
|
-
<v-icon>{{
|
|
416
|
+
<v-icon>{{
|
|
417
|
+
drawerCollapsed ? "chevron_right" : "chevron_left"
|
|
418
|
+
}}</v-icon>
|
|
337
419
|
</v-btn>
|
|
338
420
|
|
|
339
|
-
<div
|
|
421
|
+
<div
|
|
422
|
+
class="position-relative pa-0"
|
|
423
|
+
:style="drawerCollapsed ? 'margin-left: 68px' : 'margin-left: 300px'"
|
|
424
|
+
>
|
|
340
425
|
<WebGL3DR
|
|
341
426
|
v-show="instanceLoaded && !scanLoading"
|
|
342
427
|
:class="!(instanceLoaded && !scanLoading) && 'no-pointer-events'"
|
|
@@ -352,140 +437,194 @@
|
|
|
352
437
|
:key="layout.Anchor"
|
|
353
438
|
:style="{
|
|
354
439
|
...generateDivStyleForLayout(layout),
|
|
355
|
-
cursor:
|
|
440
|
+
cursor:
|
|
441
|
+
getCurrentActiveView(layout) === ScanView.Volume
|
|
442
|
+
? 'grab !important'
|
|
443
|
+
: 'default',
|
|
356
444
|
}"
|
|
357
445
|
>
|
|
358
446
|
<v-hover>
|
|
359
447
|
<template v-slot:default="{ isHovering, props }">
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
448
|
+
<div style="width: 100%; height: 100%" v-bind="props">
|
|
449
|
+
<div class="buttons-in-view" v-show="isHovering">
|
|
450
|
+
<div v-if="scanState.Layout.PositionData.length !== 1">
|
|
451
|
+
<v-btn
|
|
452
|
+
color="transparent"
|
|
453
|
+
@click="fullscreenLayout(layout.DefaultView)"
|
|
454
|
+
:icon="true"
|
|
455
|
+
>
|
|
456
|
+
<v-icon color="white">fullscreen</v-icon>
|
|
457
|
+
</v-btn>
|
|
458
|
+
<v-tooltip
|
|
459
|
+
target="cursor"
|
|
460
|
+
location="top"
|
|
461
|
+
activator="parent"
|
|
462
|
+
>
|
|
463
|
+
Make
|
|
464
|
+
{{ getViewName(getCurrentActiveView(layout)) }}
|
|
465
|
+
fullscreen
|
|
466
|
+
</v-tooltip>
|
|
467
|
+
</div>
|
|
468
|
+
<div v-if="scanState.Layout.PositionData.length === 1">
|
|
469
|
+
<v-btn
|
|
470
|
+
color="transparent"
|
|
471
|
+
@click="layouts(previousLayout)"
|
|
472
|
+
:icon="true"
|
|
473
|
+
>
|
|
474
|
+
<v-icon color="white">fullscreen_exit</v-icon>
|
|
475
|
+
</v-btn>
|
|
476
|
+
<v-tooltip
|
|
477
|
+
target="cursor"
|
|
478
|
+
location="top"
|
|
479
|
+
activator="parent"
|
|
480
|
+
>
|
|
481
|
+
Exit Fullscreen View
|
|
482
|
+
</v-tooltip>
|
|
483
|
+
</div>
|
|
484
|
+
<div
|
|
485
|
+
v-if="getCurrentActiveView(layout) === ScanView.Volume"
|
|
368
486
|
>
|
|
369
|
-
<v-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
487
|
+
<v-btn
|
|
488
|
+
color="transparent"
|
|
489
|
+
:icon="true"
|
|
490
|
+
@click="
|
|
491
|
+
viewSelection('vs_05');
|
|
492
|
+
viewSelection('vs_06');
|
|
493
|
+
"
|
|
494
|
+
><v-icon color="white">home</v-icon></v-btn
|
|
495
|
+
>
|
|
496
|
+
<v-tooltip
|
|
497
|
+
target="cursor"
|
|
498
|
+
location="top"
|
|
499
|
+
activator="parent"
|
|
500
|
+
>
|
|
501
|
+
Reset volume to default view
|
|
502
|
+
</v-tooltip>
|
|
503
|
+
</div>
|
|
504
|
+
<div
|
|
505
|
+
v-if="getCurrentActiveView(layout) === ScanView.Volume"
|
|
381
506
|
>
|
|
382
|
-
<v-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
507
|
+
<v-menu
|
|
508
|
+
:close-on-content-click="false"
|
|
509
|
+
:close-on-click="true"
|
|
510
|
+
>
|
|
511
|
+
<template v-slot:activator="{ props }">
|
|
512
|
+
<div v-bind="{ ...props }">
|
|
513
|
+
<v-btn color="transparent" :icon="true">
|
|
514
|
+
<v-icon color="white">cut</v-icon>
|
|
515
|
+
</v-btn>
|
|
516
|
+
<v-tooltip
|
|
517
|
+
target="cursor"
|
|
518
|
+
location="top"
|
|
519
|
+
activator="parent"
|
|
520
|
+
>
|
|
521
|
+
Slice the 3D Volume
|
|
522
|
+
</v-tooltip>
|
|
523
|
+
</div>
|
|
524
|
+
</template>
|
|
525
|
+
<v-card min-width="400" class="pb-2">
|
|
526
|
+
<v-card-title>Slice into the 3D Volume</v-card-title>
|
|
527
|
+
<DoubleSliderSelector
|
|
528
|
+
v-model="tSlider"
|
|
529
|
+
label="Transverse"
|
|
530
|
+
v-bind="tMinMax"
|
|
531
|
+
/>
|
|
532
|
+
<DoubleSliderSelector
|
|
533
|
+
v-model="sSlider"
|
|
534
|
+
label="Sagittal"
|
|
535
|
+
v-bind="sMinMax"
|
|
536
|
+
/>
|
|
537
|
+
<DoubleSliderSelector
|
|
538
|
+
v-model="cSlider"
|
|
539
|
+
label="Coronal"
|
|
540
|
+
v-bind="cMinMax"
|
|
541
|
+
/>
|
|
542
|
+
</v-card>
|
|
543
|
+
</v-menu>
|
|
544
|
+
</div>
|
|
545
|
+
<div
|
|
546
|
+
v-if="getCurrentActiveView(layout) !== ScanView.Volume"
|
|
397
547
|
>
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
548
|
+
<v-menu
|
|
549
|
+
:close-on-content-click="false"
|
|
550
|
+
:close-on-click="true"
|
|
551
|
+
offset-overflow
|
|
552
|
+
top
|
|
553
|
+
>
|
|
554
|
+
<template v-slot:activator="{ props }">
|
|
555
|
+
<v-tooltip top>
|
|
556
|
+
<template #activator="{ props: ttprops }">
|
|
557
|
+
<v-btn
|
|
558
|
+
v-bind="{ ...props, ...ttprops }"
|
|
559
|
+
icon
|
|
560
|
+
class="icon transparent"
|
|
561
|
+
>
|
|
562
|
+
<v-icon color="white">360</v-icon>
|
|
563
|
+
</v-btn>
|
|
564
|
+
</template>
|
|
565
|
+
Rotate
|
|
566
|
+
{{ getViewName(getCurrentActiveView(layout)) }} by
|
|
567
|
+
an angle
|
|
415
568
|
</v-tooltip>
|
|
416
|
-
</
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
569
|
+
</template>
|
|
570
|
+
<v-card min-width="200" width="200" class="pb-2">
|
|
571
|
+
<v-card-subtitle
|
|
572
|
+
>Rotate
|
|
573
|
+
{{ getViewName(getCurrentActiveView(layout)) }} by
|
|
574
|
+
an angle</v-card-subtitle
|
|
575
|
+
>
|
|
576
|
+
<v-card-text class="py-0">
|
|
577
|
+
<v-text-field
|
|
578
|
+
hide-details
|
|
579
|
+
outlined
|
|
580
|
+
v-model="rotationDeg"
|
|
581
|
+
type="number"
|
|
582
|
+
suffix="deg"
|
|
583
|
+
></v-text-field>
|
|
584
|
+
</v-card-text>
|
|
585
|
+
<v-card-actions>
|
|
586
|
+
<v-spacer />
|
|
431
587
|
<v-btn
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
588
|
+
color="primary"
|
|
589
|
+
@click="
|
|
590
|
+
rotateByDeg(
|
|
591
|
+
getCurrentActiveView(layout),
|
|
592
|
+
rotationDeg
|
|
593
|
+
)
|
|
594
|
+
"
|
|
595
|
+
>Rotate</v-btn
|
|
435
596
|
>
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
>
|
|
460
|
-
</v-card-actions>
|
|
461
|
-
</v-card>
|
|
462
|
-
</v-menu>
|
|
597
|
+
</v-card-actions>
|
|
598
|
+
</v-card>
|
|
599
|
+
</v-menu>
|
|
600
|
+
</div>
|
|
601
|
+
</div>
|
|
602
|
+
<div class="slider-in-view" v-if="isHovering">
|
|
603
|
+
<VerticalSliderSelector
|
|
604
|
+
v-if="
|
|
605
|
+
getCurrentActiveView(layout) === ScanView.Transverse
|
|
606
|
+
"
|
|
607
|
+
v-model:value="scanState.Orientations.Transverse.Slice"
|
|
608
|
+
v-bind="tMinMax"
|
|
609
|
+
/>
|
|
610
|
+
<VerticalSliderSelector
|
|
611
|
+
v-if="getCurrentActiveView(layout) === ScanView.Coronal"
|
|
612
|
+
v-model:value="scanState.Orientations.Coronal.Slice"
|
|
613
|
+
v-bind="cMinMax"
|
|
614
|
+
/>
|
|
615
|
+
<VerticalSliderSelector
|
|
616
|
+
v-if="getCurrentActiveView(layout) === ScanView.Sagittal"
|
|
617
|
+
v-model:value="scanState.Orientations.Sagittal.Slice"
|
|
618
|
+
v-bind="sMinMax"
|
|
619
|
+
/>
|
|
463
620
|
</div>
|
|
464
|
-
</div>
|
|
465
|
-
<div class="slider-in-view" v-if="isHovering">
|
|
466
|
-
<VerticalSliderSelector
|
|
467
|
-
v-if="getCurrentActiveView(layout) === ScanView.Transverse"
|
|
468
|
-
v-model:value="scanState.Orientations.Transverse.Slice"
|
|
469
|
-
v-bind="tMinMax"
|
|
470
|
-
/>
|
|
471
|
-
<VerticalSliderSelector
|
|
472
|
-
v-if="getCurrentActiveView(layout) === ScanView.Coronal"
|
|
473
|
-
v-model:value="scanState.Orientations.Coronal.Slice"
|
|
474
|
-
v-bind="cMinMax"
|
|
475
|
-
/>
|
|
476
|
-
<VerticalSliderSelector
|
|
477
|
-
v-if="getCurrentActiveView(layout) === ScanView.Sagittal"
|
|
478
|
-
v-model:value="scanState.Orientations.Sagittal.Slice"
|
|
479
|
-
v-bind="sMinMax"
|
|
480
|
-
/>
|
|
481
|
-
</div>
|
|
482
621
|
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
622
|
+
<div class="top-lhc" v-if="isHovering">
|
|
623
|
+
<div class="white--text">
|
|
624
|
+
{{ getViewName(getCurrentActiveView(layout)) }}
|
|
625
|
+
</div>
|
|
486
626
|
</div>
|
|
487
627
|
</div>
|
|
488
|
-
</div>
|
|
489
628
|
</template>
|
|
490
629
|
</v-hover>
|
|
491
630
|
</div>
|
|
@@ -493,10 +632,19 @@
|
|
|
493
632
|
</div>
|
|
494
633
|
|
|
495
634
|
<LoadingSpinner v-if="!instanceLoaded" />
|
|
496
|
-
<LoadingSpinner
|
|
635
|
+
<LoadingSpinner
|
|
636
|
+
v-if="scanLoading"
|
|
637
|
+
text="Rendering your scan in <span class='sub-type'>3DICOM</span>"
|
|
638
|
+
/>
|
|
497
639
|
<v-textarea
|
|
498
640
|
v-if="stateOverlay"
|
|
499
|
-
style="
|
|
641
|
+
style="
|
|
642
|
+
position: absolute;
|
|
643
|
+
top: 0px;
|
|
644
|
+
right: -0px;
|
|
645
|
+
width: 240px;
|
|
646
|
+
z-index: 10000;
|
|
647
|
+
"
|
|
500
648
|
class="text--white"
|
|
501
649
|
color="white"
|
|
502
650
|
dark
|
|
@@ -508,66 +656,59 @@
|
|
|
508
656
|
</v-card>
|
|
509
657
|
</v-dialog>
|
|
510
658
|
</template>
|
|
511
|
-
|
|
659
|
+
<!-- /* c8 ignore stop */ -->
|
|
660
|
+
<script setup lang="ts">
|
|
661
|
+
import LoadingSpinner from "@/components/loading/LoadingSpinner.vue";
|
|
662
|
+
import WebGL3DR from "@/components/WebGL3DR.vue";
|
|
663
|
+
import DoubleSliderSelector from "@/components/sliders/DoubleSliderSelector.vue";
|
|
664
|
+
import SliderSelector from "@/components/selectors/ValueSelector.vue";
|
|
665
|
+
import VerticalSliderSelector from "@/components/sliders/VerticalSliderSelector.vue";
|
|
512
666
|
|
|
513
|
-
import
|
|
514
|
-
import LoadingSpinner from '@/components/loading/LoadingSpinner.vue';
|
|
515
|
-
import WebGL3DR from '@/components/WebGL3DR.vue';
|
|
516
|
-
import DoubleSliderSelector from '@/components/sliders/DoubleSliderSelector.vue';
|
|
517
|
-
import SliderSelector from '@/components/sliders/SliderSelector.vue';
|
|
518
|
-
import VerticalSliderSelector from '@/components/sliders/VerticalSliderSelector.vue';
|
|
667
|
+
import { generateDivStyleForLayout } from "@/helpers/layoutOverlayStyle";
|
|
519
668
|
|
|
520
|
-
import { generateDivStyleForLayout } from '@/helpers/layoutOverlayStyle';
|
|
521
669
|
import {
|
|
522
|
-
|
|
523
|
-
|
|
670
|
+
inflateInitialScanState,
|
|
671
|
+
inflateScanState,
|
|
672
|
+
} from "@/helpers/modelHelper";
|
|
673
|
+
import {
|
|
674
|
+
SlidersActions,
|
|
675
|
+
PresetsActions,
|
|
524
676
|
ScanMovementActions,
|
|
525
677
|
ScanOrientationActions,
|
|
526
678
|
FileManagementActions,
|
|
527
679
|
FrontEndInterfaces,
|
|
528
|
-
} from '@/helpers/models';
|
|
529
|
-
import {
|
|
530
|
-
inflateInitialScanState,
|
|
531
|
-
inflateScanState,
|
|
532
|
-
} from '../../helpers/modelHelper';
|
|
533
|
-
import {
|
|
534
680
|
AnchorPoint,
|
|
535
681
|
ColourPresetData,
|
|
536
682
|
CurrentScanState,
|
|
537
683
|
InitialScanState,
|
|
538
684
|
PositionData,
|
|
539
685
|
ScanView,
|
|
540
|
-
} from
|
|
686
|
+
} from "@3cr/types-ts";
|
|
541
687
|
|
|
542
|
-
import { toNumber } from
|
|
543
|
-
import {computed, ref, unref, watch, defineEmits, nextTick} from "vue";
|
|
544
|
-
import {LoadViewerPayload} from "../../../index";
|
|
688
|
+
import { toNumber } from "@/helpers/utils";
|
|
689
|
+
import { computed, ref, unref, watch, defineEmits, nextTick } from "vue";
|
|
690
|
+
import { LoadViewerPayload } from "../../../index";
|
|
545
691
|
|
|
546
692
|
const emit = defineEmits<{
|
|
547
693
|
instanceLoaded: [void];
|
|
694
|
+
snap: [void];
|
|
548
695
|
}>();
|
|
549
696
|
|
|
550
|
-
defineExpose({
|
|
551
|
-
alterValue,
|
|
552
|
-
load
|
|
553
|
-
});
|
|
554
|
-
|
|
555
697
|
export interface Props {
|
|
556
|
-
payload
|
|
698
|
+
payload?: LoadViewerPayload;
|
|
557
699
|
}
|
|
558
|
-
const componentKey = ref(0);
|
|
559
700
|
|
|
560
701
|
const props = withDefaults(defineProps<Props>(), {
|
|
561
702
|
payload: () => ({
|
|
562
|
-
Url:"https://webgl-3dr.singular.health/test_scans/8bdddee1-e581-485d-827d-6aa12eef2fc8/Head+Axial+Axial.3vxl",
|
|
563
|
-
DecryptionKey:{
|
|
564
|
-
Iv:"x856FgjpYDsRhIa3BFj5cg==",
|
|
565
|
-
Key:"OWjSMiL/ewUV1V6fGybhKcTyiysTPsIMp2DjdVoOUGI="
|
|
566
|
-
}
|
|
567
|
-
})
|
|
703
|
+
Url: "https://webgl-3dr.singular.health/test_scans/8bdddee1-e581-485d-827d-6aa12eef2fc8/Head+Axial+Axial.3vxl",
|
|
704
|
+
DecryptionKey: {
|
|
705
|
+
Iv: "x856FgjpYDsRhIa3BFj5cg==",
|
|
706
|
+
Key: "OWjSMiL/ewUV1V6fGybhKcTyiysTPsIMp2DjdVoOUGI=",
|
|
707
|
+
},
|
|
708
|
+
}),
|
|
568
709
|
});
|
|
569
710
|
|
|
570
|
-
const emptyPayload = { Version:
|
|
711
|
+
const emptyPayload = { Version: "1.1.0" };
|
|
571
712
|
|
|
572
713
|
const value = ref<boolean>(false);
|
|
573
714
|
const drawer = ref<boolean>(true);
|
|
@@ -578,222 +719,297 @@ const scanState = ref<CurrentScanState>(inflateScanState());
|
|
|
578
719
|
const initialScanState = ref<InitialScanState>(inflateInitialScanState());
|
|
579
720
|
const currentColourPreset = ref<ColourPresetData | undefined>(undefined);
|
|
580
721
|
const openPanels = ref<number>(0);
|
|
581
|
-
const previousLayout = ref<string>(
|
|
722
|
+
const previousLayout = ref<string>("lo_02");
|
|
582
723
|
const footerItems = ref([
|
|
583
724
|
{
|
|
584
|
-
text:
|
|
585
|
-
icon:
|
|
586
|
-
color:
|
|
725
|
+
text: "Reset Scan",
|
|
726
|
+
icon: "refresh",
|
|
727
|
+
color: "red",
|
|
587
728
|
click: async () => {
|
|
588
|
-
console.log(
|
|
589
|
-
await viewSelection(
|
|
590
|
-
await viewSelection(
|
|
729
|
+
console.log("Reset Scan");
|
|
730
|
+
await viewSelection("vs_05");
|
|
731
|
+
await viewSelection("vs_06");
|
|
591
732
|
},
|
|
592
733
|
},
|
|
593
734
|
{
|
|
594
|
-
text:
|
|
595
|
-
icon:
|
|
596
|
-
color:
|
|
597
|
-
click: () => alterValue(false),
|
|
735
|
+
text: "Send to 3rd Party",
|
|
736
|
+
icon: "send",
|
|
737
|
+
color: "blue",
|
|
738
|
+
click: async () => alterValue(false),
|
|
598
739
|
},
|
|
599
740
|
{
|
|
600
|
-
text:
|
|
601
|
-
icon:
|
|
602
|
-
color:
|
|
603
|
-
click: () => alterValue(false),
|
|
741
|
+
text: "Share to Mobile / VR",
|
|
742
|
+
icon: "share",
|
|
743
|
+
color: "yellow",
|
|
744
|
+
click: async () => alterValue(false),
|
|
604
745
|
},
|
|
605
746
|
{
|
|
606
|
-
text:
|
|
607
|
-
icon:
|
|
608
|
-
color:
|
|
609
|
-
click: () => {
|
|
610
|
-
snap();
|
|
747
|
+
text: "Screenshot View",
|
|
748
|
+
icon: "screenshot_region",
|
|
749
|
+
color: "green",
|
|
750
|
+
click: async () => {
|
|
751
|
+
await snap();
|
|
611
752
|
},
|
|
612
753
|
},
|
|
613
754
|
]);
|
|
614
755
|
|
|
615
756
|
const miniMenu = ref([
|
|
616
757
|
{
|
|
617
|
-
icon:
|
|
618
|
-
text:
|
|
758
|
+
icon: "display_settings",
|
|
759
|
+
text: "Tissue Density",
|
|
619
760
|
tooltip:
|
|
620
|
-
|
|
761
|
+
"Tissue Density - Change the view of density within the scan, allowing you to see through a certain density of particles",
|
|
621
762
|
},
|
|
622
763
|
// { icon: 'display_settings', text: 'Display', tooltip: 'Display - Alter the view of the current scan' },
|
|
623
|
-
])
|
|
764
|
+
]);
|
|
624
765
|
|
|
625
766
|
const huMinMax = ref({
|
|
626
767
|
min: -999999,
|
|
627
768
|
max: 999999,
|
|
628
|
-
})
|
|
769
|
+
});
|
|
629
770
|
|
|
630
771
|
const tMinMax = ref({
|
|
631
772
|
min: 0,
|
|
632
773
|
max: 999999,
|
|
633
|
-
})
|
|
774
|
+
});
|
|
634
775
|
const sMinMax = ref({
|
|
635
776
|
min: 0,
|
|
636
777
|
max: 999999,
|
|
637
|
-
})
|
|
778
|
+
});
|
|
638
779
|
const cMinMax = ref({
|
|
639
780
|
min: 0,
|
|
640
781
|
max: 999999,
|
|
641
|
-
})
|
|
642
|
-
const rotationDeg = ref<number>(0)
|
|
643
|
-
const scanStateIncoming = ref<string>(
|
|
644
|
-
const transactionStarted = ref<boolean>(false)
|
|
645
|
-
const stateOverlay = ref<boolean>(false)
|
|
646
|
-
const m_closeDialog = ref<boolean>(false)
|
|
647
|
-
|
|
648
|
-
watch(currentColourPreset, (val) => {console.log(val)})
|
|
782
|
+
});
|
|
783
|
+
const rotationDeg = ref<number>(0);
|
|
784
|
+
const scanStateIncoming = ref<string>("");
|
|
785
|
+
const transactionStarted = ref<boolean>(false);
|
|
786
|
+
const stateOverlay = ref<boolean>(false);
|
|
787
|
+
const m_closeDialog = ref<boolean>(false);
|
|
788
|
+
|
|
649
789
|
const windowSlider = computed({
|
|
650
790
|
get() {
|
|
651
|
-
return [
|
|
791
|
+
return [
|
|
792
|
+
unref(scanState).Display.WindowLower,
|
|
793
|
+
unref(scanState).Display.WindowUpper,
|
|
794
|
+
];
|
|
652
795
|
},
|
|
653
796
|
set(value: Array<number>) {
|
|
654
797
|
scanState.value.Display.WindowLower = value[0];
|
|
655
798
|
scanState.value.Display.WindowUpper = value[1];
|
|
656
|
-
}
|
|
657
|
-
})
|
|
799
|
+
},
|
|
800
|
+
});
|
|
658
801
|
const thresholdSlider = computed({
|
|
659
802
|
get() {
|
|
660
|
-
return [
|
|
803
|
+
return [
|
|
804
|
+
Math.trunc(unref(scanState).Display.ThresholdLower),
|
|
805
|
+
Math.trunc(unref(scanState).Display.ThresholdUpper),
|
|
806
|
+
];
|
|
661
807
|
},
|
|
662
808
|
set(value: Array<number>) {
|
|
663
809
|
scanState.value.Display.ThresholdLower = value[0];
|
|
664
810
|
scanState.value.Display.ThresholdUpper = value[1];
|
|
665
|
-
}
|
|
666
|
-
})
|
|
811
|
+
},
|
|
812
|
+
});
|
|
667
813
|
const tSlider = computed({
|
|
668
814
|
get() {
|
|
669
|
-
return [
|
|
815
|
+
return [
|
|
816
|
+
Math.trunc(unref(scanState).Slice.TransverseLower),
|
|
817
|
+
Math.trunc(unref(scanState).Slice.TransverseUpper),
|
|
818
|
+
];
|
|
670
819
|
},
|
|
671
820
|
set(value: Array<number>) {
|
|
672
821
|
scanState.value.Slice.TransverseLower = value[0];
|
|
673
822
|
scanState.value.Slice.TransverseLower = value[1];
|
|
674
|
-
}
|
|
675
|
-
})
|
|
823
|
+
},
|
|
824
|
+
});
|
|
676
825
|
const sSlider = computed({
|
|
677
826
|
get() {
|
|
678
|
-
return [
|
|
827
|
+
return [
|
|
828
|
+
Math.trunc(unref(scanState).Slice.SagittalLower),
|
|
829
|
+
Math.trunc(unref(scanState).Slice.SagittalUpper),
|
|
830
|
+
];
|
|
679
831
|
},
|
|
680
832
|
set(value: Array<number>) {
|
|
681
833
|
scanState.value.Slice.SagittalLower = value[0];
|
|
682
834
|
scanState.value.Slice.SagittalUpper = value[1];
|
|
683
|
-
}
|
|
684
|
-
})
|
|
835
|
+
},
|
|
836
|
+
});
|
|
685
837
|
|
|
686
838
|
const cSlider = computed({
|
|
687
839
|
get() {
|
|
688
|
-
return [
|
|
840
|
+
return [
|
|
841
|
+
Math.trunc(unref(scanState).Slice.CoronalLower),
|
|
842
|
+
Math.trunc(unref(scanState).Slice.CoronalUpper),
|
|
843
|
+
];
|
|
689
844
|
},
|
|
690
845
|
set(value: Array<number>) {
|
|
691
846
|
scanState.value.Slice.CoronalLower = value[0];
|
|
692
847
|
scanState.value.Slice.CoronalUpper = value[1];
|
|
693
|
-
}
|
|
694
|
-
})
|
|
848
|
+
},
|
|
849
|
+
});
|
|
695
850
|
const web_gl = ref<typeof WebGL3DR | null>(null);
|
|
696
851
|
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
852
|
+
watch(
|
|
853
|
+
() => scanState.value.Display.Brightness,
|
|
854
|
+
async (value: number) => {
|
|
855
|
+
await sliderHandler(SlidersActions.sl01, value);
|
|
856
|
+
}
|
|
857
|
+
);
|
|
858
|
+
watch(
|
|
859
|
+
() => scanState.value.Display.Contrast,
|
|
860
|
+
async (value: number) => {
|
|
861
|
+
await sliderHandler(SlidersActions.sl02, value);
|
|
862
|
+
}
|
|
863
|
+
);
|
|
864
|
+
watch(
|
|
865
|
+
() => scanState.value.Display.Opacity,
|
|
866
|
+
async (value: number) => {
|
|
867
|
+
await sliderHandler(SlidersActions.sl03, value);
|
|
868
|
+
}
|
|
869
|
+
);
|
|
870
|
+
watch(
|
|
871
|
+
() => scanState.value.Display.WindowLower,
|
|
872
|
+
async (value: number) => {
|
|
873
|
+
await sliderHandler(SlidersActions.sl04, value);
|
|
874
|
+
}
|
|
875
|
+
);
|
|
876
|
+
watch(
|
|
877
|
+
() => scanState.value.Display.WindowUpper,
|
|
878
|
+
async (value: number) => {
|
|
879
|
+
await sliderHandler(SlidersActions.sl05, value);
|
|
880
|
+
}
|
|
881
|
+
);
|
|
882
|
+
watch(
|
|
883
|
+
() => scanState.value.Display.ThresholdLower,
|
|
884
|
+
async (value: number) => {
|
|
885
|
+
await sliderHandler(SlidersActions.sl06, value);
|
|
886
|
+
}
|
|
887
|
+
);
|
|
888
|
+
watch(
|
|
889
|
+
() => scanState.value.Display.ThresholdUpper,
|
|
890
|
+
async (value: number) => {
|
|
891
|
+
await sliderHandler(SlidersActions.sl07, value);
|
|
892
|
+
}
|
|
893
|
+
);
|
|
894
|
+
watch(
|
|
895
|
+
() => scanState.value.Slice.TransverseLower,
|
|
896
|
+
async (value: number) => {
|
|
897
|
+
await sliderHandler(SlidersActions.sl08, value);
|
|
898
|
+
}
|
|
899
|
+
);
|
|
900
|
+
watch(
|
|
901
|
+
() => scanState.value.Orientations.Transverse.Slice,
|
|
902
|
+
async (value: number) => {
|
|
903
|
+
await sliderHandler(SlidersActions.sl09, value);
|
|
904
|
+
}
|
|
905
|
+
);
|
|
906
|
+
watch(
|
|
907
|
+
() => scanState.value.Slice.TransverseUpper,
|
|
908
|
+
async (value: number) => {
|
|
909
|
+
await sliderHandler(SlidersActions.sl10, value);
|
|
910
|
+
}
|
|
911
|
+
);
|
|
912
|
+
watch(
|
|
913
|
+
() => scanState.value.Slice.SagittalLower,
|
|
914
|
+
async (value: number) => {
|
|
915
|
+
await sliderHandler(SlidersActions.sl11, value);
|
|
916
|
+
}
|
|
917
|
+
);
|
|
918
|
+
watch(
|
|
919
|
+
() => scanState.value.Orientations.Sagittal.Slice,
|
|
920
|
+
async (value: number) => {
|
|
921
|
+
await sliderHandler(SlidersActions.sl12, value);
|
|
922
|
+
}
|
|
923
|
+
);
|
|
924
|
+
watch(
|
|
925
|
+
() => scanState.value.Slice.SagittalUpper,
|
|
926
|
+
async (value: number) => {
|
|
927
|
+
await sliderHandler(SlidersActions.sl13, value);
|
|
928
|
+
}
|
|
929
|
+
);
|
|
930
|
+
watch(
|
|
931
|
+
() => scanState.value.Slice.CoronalLower,
|
|
932
|
+
async (value: number) => {
|
|
933
|
+
await sliderHandler(SlidersActions.sl14, value);
|
|
934
|
+
}
|
|
935
|
+
);
|
|
936
|
+
watch(
|
|
937
|
+
() => scanState.value.Orientations.Coronal.Slice,
|
|
938
|
+
async (value: number) => {
|
|
939
|
+
await sliderHandler(SlidersActions.sl15, value);
|
|
940
|
+
}
|
|
941
|
+
);
|
|
942
|
+
watch(
|
|
943
|
+
() => scanState.value.Slice.CoronalUpper,
|
|
944
|
+
async (value: number) => {
|
|
945
|
+
await sliderHandler(SlidersActions.sl16, value);
|
|
946
|
+
}
|
|
947
|
+
);
|
|
948
|
+
watch(
|
|
949
|
+
() => scanState.value.InteractionSettings.PanSensivitity,
|
|
950
|
+
async (value: number) => {
|
|
951
|
+
await scanMovementHandler(ScanMovementActions.sm05, value);
|
|
952
|
+
}
|
|
953
|
+
);
|
|
954
|
+
watch(
|
|
955
|
+
() => scanState.value.InteractionSettings.ZoomSensitivity,
|
|
956
|
+
async (value: number) => {
|
|
957
|
+
await scanMovementHandler(ScanMovementActions.sm08, value);
|
|
958
|
+
}
|
|
959
|
+
);
|
|
960
|
+
watch(
|
|
961
|
+
() => scanState.value.InteractionSettings.RotateSensitivity,
|
|
962
|
+
async (value: number) => {
|
|
963
|
+
await scanMovementHandler(ScanMovementActions.sm10, value);
|
|
964
|
+
}
|
|
965
|
+
);
|
|
966
|
+
watch(
|
|
967
|
+
() => scanState.value.InteractionSettings.CameraRotateSensitivity,
|
|
968
|
+
async (value: number) => {
|
|
969
|
+
await scanMovementHandler(ScanMovementActions.sm12, value);
|
|
970
|
+
}
|
|
971
|
+
);
|
|
761
972
|
|
|
762
973
|
function getIconForPreset(presetName: string): string | undefined {
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
return undefined
|
|
974
|
+
if (presetName === "Bone") return "fa:fas fa-bone";
|
|
975
|
+
if (presetName === "Brain") return "fa:fas fa-brain";
|
|
976
|
+
if (presetName === "Liver") return "custom:liver_icon";
|
|
977
|
+
if (presetName === "Lungs") return "fa:fas fa-lungs";
|
|
978
|
+
if (presetName === "Muscle") return "custom:muscle_icon";
|
|
979
|
+
if (presetName === "Temporal Bones") return "custom:temporal_bones_icon";
|
|
980
|
+
if (presetName === "Soft Tissue") return "custom:torso_icon";
|
|
981
|
+
if (presetName === "Skin") return "custom:skin_icon";
|
|
982
|
+
return undefined;
|
|
772
983
|
}
|
|
773
984
|
async function rotateByDeg(view: ScanView, deg: number) {
|
|
774
|
-
await (
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
985
|
+
await sendPayload(
|
|
986
|
+
FrontEndInterfaces.scan_orientation,
|
|
987
|
+
ScanOrientationActions.so01,
|
|
988
|
+
{
|
|
989
|
+
Version: "0.0.1",
|
|
990
|
+
View: view,
|
|
991
|
+
Angle: deg,
|
|
992
|
+
}
|
|
993
|
+
);
|
|
779
994
|
}
|
|
780
995
|
function getCurrentActiveView(position: PositionData): ScanView {
|
|
781
|
-
return unref(scanState).Layout.PositionData.length !== 1
|
|
996
|
+
return unref(scanState).Layout.PositionData.length !== 1
|
|
997
|
+
? position.DefaultView
|
|
998
|
+
: unref(scanState).CurrentView;
|
|
782
999
|
}
|
|
783
1000
|
function getViewName(index: number) {
|
|
784
1001
|
return Object.values(ScanView)
|
|
785
|
-
.filter((value) => typeof value ===
|
|
1002
|
+
.filter((value) => typeof value === "string")
|
|
786
1003
|
.map((x) => {
|
|
787
|
-
if (x ===
|
|
1004
|
+
if (x === "Volume") return "3D Volume";
|
|
788
1005
|
return x;
|
|
789
1006
|
})[index];
|
|
790
1007
|
}
|
|
791
1008
|
async function fullscreenLayout(view: ScanView) {
|
|
792
|
-
await layouts(
|
|
1009
|
+
await layouts("lo_01");
|
|
793
1010
|
await viewSelection(`vs_0${view + 1}`);
|
|
794
1011
|
}
|
|
795
|
-
|
|
796
|
-
async function scanMovementHandler(action: string, value: number) {
|
|
1012
|
+
async function scanMovementHandler(action: string, value: number) {
|
|
797
1013
|
if (unref(transactionStarted)) return;
|
|
798
1014
|
await scanMovement(action, value);
|
|
799
1015
|
}
|
|
@@ -809,51 +1025,68 @@ function closeModal() {
|
|
|
809
1025
|
function alterValue(val: boolean) {
|
|
810
1026
|
if (!val) {
|
|
811
1027
|
m_closeDialog.value = true;
|
|
812
|
-
return
|
|
1028
|
+
return;
|
|
813
1029
|
}
|
|
814
1030
|
|
|
815
1031
|
value.value = val;
|
|
816
1032
|
}
|
|
817
|
-
async function sendPayload(
|
|
1033
|
+
async function sendPayload(
|
|
1034
|
+
interfaceType: string,
|
|
1035
|
+
actionType: string,
|
|
1036
|
+
message: any
|
|
1037
|
+
) {
|
|
818
1038
|
await unref(web_gl)?.sendPayload(
|
|
819
1039
|
JSON.stringify({
|
|
820
|
-
Version:
|
|
1040
|
+
Version: "0.0.1",
|
|
821
1041
|
Interface: interfaceType,
|
|
822
1042
|
Action: actionType,
|
|
823
1043
|
Message: JSON.stringify(message),
|
|
824
|
-
})
|
|
1044
|
+
})
|
|
825
1045
|
);
|
|
826
1046
|
}
|
|
827
1047
|
async function load() {
|
|
828
1048
|
instanceLoaded.value = true;
|
|
829
1049
|
scanLoading.value = true;
|
|
830
|
-
await sendPayload(
|
|
1050
|
+
await sendPayload("file_management", "fm_01", props.payload);
|
|
831
1051
|
}
|
|
832
1052
|
async function viewSelection(action: string) {
|
|
833
|
-
await sendPayload(FrontEndInterfaces.view_selection, action, emptyPayload)
|
|
1053
|
+
await sendPayload(FrontEndInterfaces.view_selection, action, emptyPayload);
|
|
834
1054
|
}
|
|
835
1055
|
async function layouts(action: string) {
|
|
836
|
-
if (action !==
|
|
837
|
-
await sendPayload(FrontEndInterfaces.layout, action, emptyPayload)
|
|
1056
|
+
if (action !== "lo_01") previousLayout.value = action;
|
|
1057
|
+
await sendPayload(FrontEndInterfaces.layout, action, emptyPayload);
|
|
838
1058
|
}
|
|
839
1059
|
async function snap() {
|
|
840
|
-
|
|
1060
|
+
emit("snap");
|
|
841
1061
|
}
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
1062
|
+
|
|
1063
|
+
async function setPreset(action: PresetsActions, preset: any) {
|
|
1064
|
+
await sendPayload("presets", action, preset);
|
|
1065
|
+
if (action === PresetsActions.pr02) {
|
|
845
1066
|
currentColourPreset.value = preset;
|
|
846
1067
|
}
|
|
847
1068
|
}
|
|
848
1069
|
async function slider(action: string, value: number) {
|
|
849
|
-
await sendPayload(
|
|
1070
|
+
await sendPayload("sliders", action, {
|
|
1071
|
+
Version: "0.0.1",
|
|
1072
|
+
Value: toNumber(value),
|
|
1073
|
+
});
|
|
850
1074
|
}
|
|
851
1075
|
async function scanMovement(action: string, value: number) {
|
|
852
|
-
await sendPayload(
|
|
1076
|
+
await sendPayload(FrontEndInterfaces.scan_movement, action, {
|
|
1077
|
+
Version: "0.0.1",
|
|
1078
|
+
Value: toNumber(value),
|
|
1079
|
+
});
|
|
853
1080
|
}
|
|
854
1081
|
async function hoverOverCanvas(isHovering: boolean) {
|
|
855
|
-
await sendPayload(
|
|
856
|
-
|
|
1082
|
+
await sendPayload("interactivity", "in_01", {
|
|
1083
|
+
Version: "0.0.1",
|
|
1084
|
+
Value: isHovering,
|
|
1085
|
+
});
|
|
1086
|
+
await sendPayload("interactivity", "in_02", {
|
|
1087
|
+
Version: "0.0.1",
|
|
1088
|
+
Value: isHovering,
|
|
1089
|
+
});
|
|
857
1090
|
}
|
|
858
1091
|
async function i_scanState(_: string, message: string) {
|
|
859
1092
|
transactionStarted.value = true;
|
|
@@ -889,7 +1122,6 @@ async function i_notifications(action: string, message: string) {
|
|
|
889
1122
|
// const obj = JSON.parse(message);
|
|
890
1123
|
// console.log(obj);
|
|
891
1124
|
//{\"Version\":\"1.0.0\",\"Interface\":\"interactivity\",\"Action\":\"in_01\",\"Code\":\"0000\",\"Description\":\"\"}"
|
|
892
|
-
|
|
893
1125
|
// if (obj.Description) {
|
|
894
1126
|
// if (action === NotificationActions.no01) {
|
|
895
1127
|
// await NotificationService.Instantiate().notificationSuccess(obj.Description);
|
|
@@ -907,10 +1139,11 @@ const isLayout2x2 = computed(() => {
|
|
|
907
1139
|
unref(scanState).Layout.PositionData.length > 1 &&
|
|
908
1140
|
unref(scanState).Layout.PositionData[0].Anchor === AnchorPoint.TOP_LEFT &&
|
|
909
1141
|
unref(scanState).Layout.PositionData[1].Anchor === AnchorPoint.TOP_RIGHT &&
|
|
910
|
-
unref(scanState).Layout.PositionData[2].Anchor ===
|
|
1142
|
+
unref(scanState).Layout.PositionData[2].Anchor ===
|
|
1143
|
+
AnchorPoint.BOTTOM_LEFT &&
|
|
911
1144
|
unref(scanState).Layout.PositionData[3].Anchor === AnchorPoint.BOTTOM_RIGHT
|
|
912
|
-
)
|
|
913
|
-
})
|
|
1145
|
+
);
|
|
1146
|
+
});
|
|
914
1147
|
const isLayout1x3 = computed(() => {
|
|
915
1148
|
return (
|
|
916
1149
|
unref(scanState).Layout.PositionData.length > 1 &&
|
|
@@ -918,19 +1151,20 @@ const isLayout1x3 = computed(() => {
|
|
|
918
1151
|
unref(scanState).Layout.PositionData[1].Anchor === AnchorPoint.TOP_RIGHT &&
|
|
919
1152
|
unref(scanState).Layout.PositionData[2].Anchor === AnchorPoint.RIGHT &&
|
|
920
1153
|
unref(scanState).Layout.PositionData[3].Anchor === AnchorPoint.BOTTOM_RIGHT
|
|
921
|
-
)
|
|
922
|
-
})
|
|
923
|
-
|
|
1154
|
+
);
|
|
1155
|
+
});
|
|
924
1156
|
|
|
925
1157
|
function getCurrentGreyscalePreset() {
|
|
926
1158
|
for (const preset of unref(initialScanState).GreyscalePresets) {
|
|
927
1159
|
if (
|
|
928
1160
|
(unref(scanState).Display.WindowLower === preset.Lower ||
|
|
929
|
-
(preset.Lower
|
|
930
|
-
unref(scanState).Display.WindowLower ===
|
|
1161
|
+
(preset.Lower < unref(initialScanState).HuLower &&
|
|
1162
|
+
unref(scanState).Display.WindowLower ===
|
|
1163
|
+
unref(initialScanState).HuLower)) &&
|
|
931
1164
|
(unref(scanState).Display.WindowUpper === preset.Upper ||
|
|
932
1165
|
(preset.Upper > unref(initialScanState).HuUpper &&
|
|
933
|
-
unref(scanState).Display.WindowUpper ===
|
|
1166
|
+
unref(scanState).Display.WindowUpper ===
|
|
1167
|
+
unref(initialScanState).HuUpper))
|
|
934
1168
|
) {
|
|
935
1169
|
return preset.Name;
|
|
936
1170
|
}
|
|
@@ -941,18 +1175,52 @@ function setScanState(message: string) {
|
|
|
941
1175
|
scanState.value = JSON.parse(message) as CurrentScanState;
|
|
942
1176
|
}
|
|
943
1177
|
|
|
944
|
-
function handleOnPayload(
|
|
945
|
-
|
|
946
|
-
|
|
1178
|
+
function handleOnPayload(
|
|
1179
|
+
interfaceSet: string | FrontEndInterfaces,
|
|
1180
|
+
actionSet: string,
|
|
1181
|
+
message: string
|
|
1182
|
+
) {
|
|
1183
|
+
if (interfaceSet === FrontEndInterfaces.scan_state) {
|
|
1184
|
+
i_scanState(actionSet, message);
|
|
947
1185
|
}
|
|
948
1186
|
if (interfaceSet === FrontEndInterfaces.file_management) {
|
|
949
|
-
i_fileManagement(actionSet, message)
|
|
1187
|
+
i_fileManagement(actionSet, message);
|
|
950
1188
|
}
|
|
951
|
-
if (interfaceSet ===
|
|
952
|
-
i_notifications(actionSet, message)
|
|
1189
|
+
if (interfaceSet === FrontEndInterfaces.notifications) {
|
|
1190
|
+
i_notifications(actionSet, message);
|
|
953
1191
|
}
|
|
954
1192
|
}
|
|
955
1193
|
|
|
1194
|
+
defineExpose({
|
|
1195
|
+
alterValue,
|
|
1196
|
+
load,
|
|
1197
|
+
handleOnPayload,
|
|
1198
|
+
setScanState,
|
|
1199
|
+
sendPayload,
|
|
1200
|
+
getIconForPreset,
|
|
1201
|
+
cSlider,
|
|
1202
|
+
sSlider,
|
|
1203
|
+
tSlider,
|
|
1204
|
+
thresholdSlider,
|
|
1205
|
+
windowSlider,
|
|
1206
|
+
isLayout2x2,
|
|
1207
|
+
isLayout1x3,
|
|
1208
|
+
m_closeDialog,
|
|
1209
|
+
getCurrentGreyscalePreset,
|
|
1210
|
+
closeModal,
|
|
1211
|
+
snap,
|
|
1212
|
+
scanState,
|
|
1213
|
+
initialScanState,
|
|
1214
|
+
footerItems,
|
|
1215
|
+
rotateByDeg,
|
|
1216
|
+
getCurrentActiveView,
|
|
1217
|
+
getViewName,
|
|
1218
|
+
fullscreenLayout,
|
|
1219
|
+
layouts,
|
|
1220
|
+
setPreset,
|
|
1221
|
+
value,
|
|
1222
|
+
transactionStarted,
|
|
1223
|
+
});
|
|
956
1224
|
</script>
|
|
957
1225
|
<style>
|
|
958
1226
|
.v-dialog:not(.v-dialog--fullscreen) {
|