@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.
Files changed (71) hide show
  1. package/README.md +108 -81
  2. package/__tests__/index.spec.ts +31 -0
  3. package/components.d.ts +2 -2
  4. package/coverage/3cr-viewer-browser/index.html +116 -0
  5. package/coverage/3cr-viewer-browser/index.ts.html +211 -0
  6. package/coverage/3cr-viewer-browser/src/App.vue.html +313 -0
  7. package/coverage/3cr-viewer-browser/src/components/WebGL3DR.vue.html +442 -0
  8. package/coverage/3cr-viewer-browser/src/components/icons/index.html +116 -0
  9. package/coverage/3cr-viewer-browser/src/components/icons/liver.vue.html +148 -0
  10. package/coverage/3cr-viewer-browser/src/components/index.html +116 -0
  11. package/coverage/3cr-viewer-browser/src/components/loading/LoadingSpinner.vue.html +556 -0
  12. package/coverage/3cr-viewer-browser/src/components/loading/index.html +116 -0
  13. package/coverage/3cr-viewer-browser/src/components/modal/MftpWebGL3DRModal.vue.html +3931 -0
  14. package/coverage/3cr-viewer-browser/src/components/modal/index.html +116 -0
  15. package/coverage/3cr-viewer-browser/src/components/selectors/ValueSelector.vue.html +331 -0
  16. package/coverage/3cr-viewer-browser/src/components/selectors/index.html +116 -0
  17. package/coverage/3cr-viewer-browser/src/components/sliders/DoubleSliderSelector.vue.html +445 -0
  18. package/coverage/3cr-viewer-browser/src/components/sliders/VerticalSliderSelector.vue.html +349 -0
  19. package/coverage/3cr-viewer-browser/src/components/sliders/index.html +131 -0
  20. package/coverage/3cr-viewer-browser/src/helpers/index.html +146 -0
  21. package/coverage/3cr-viewer-browser/src/helpers/layoutOverlayStyle.ts.html +406 -0
  22. package/coverage/3cr-viewer-browser/src/helpers/modelHelper.ts.html +412 -0
  23. package/coverage/3cr-viewer-browser/src/helpers/utils.ts.html +133 -0
  24. package/coverage/3cr-viewer-browser/src/index.html +131 -0
  25. package/coverage/3cr-viewer-browser/src/main.ts.html +124 -0
  26. package/coverage/3cr-viewer-browser/src/plugins/index.html +131 -0
  27. package/coverage/3cr-viewer-browser/src/plugins/index.ts.html +130 -0
  28. package/coverage/3cr-viewer-browser/src/plugins/vuetify.ts.html +220 -0
  29. package/coverage/base.css +224 -0
  30. package/coverage/block-navigation.js +87 -0
  31. package/coverage/favicon.png +0 -0
  32. package/coverage/index.html +251 -0
  33. package/coverage/prettify.css +1 -0
  34. package/coverage/prettify.js +2 -0
  35. package/coverage/sort-arrow-sprite.png +0 -0
  36. package/coverage/sorter.js +196 -0
  37. package/dist/Viewer3CR.js +17 -11
  38. package/dist/Viewer3CR.mjs +5352 -5183
  39. package/dist/Viewer3CR.umd.js +17 -11
  40. package/index.html +4 -1
  41. package/index.ts +16 -12
  42. package/package.json +8 -3
  43. package/src/App.vue +1 -9
  44. package/src/__tests__/app.spec.ts +27 -0
  45. package/src/components/WebGL3DR.vue +49 -37
  46. package/src/components/__tests__/webgl3dr.spec.ts +56 -0
  47. package/src/components/icons/liver.vue +21 -0
  48. package/src/components/loading/__tests__/loading-spinner.spec.ts +11 -0
  49. package/src/components/modal/MftpWebGL3DRModal.vue +662 -394
  50. package/src/components/modal/__tests__/mftp-webgl-3dr-modal.spec.ts +690 -0
  51. package/src/components/selectors/__tests__/value-selector.spec.ts +35 -0
  52. package/src/components/sliders/DoubleSliderSelector.vue +30 -24
  53. package/src/components/sliders/VerticalSliderSelector.vue +25 -21
  54. package/src/components/sliders/__tests__/double-slider-selector.spec.ts +72 -0
  55. package/src/components/sliders/__tests__/vertical-slider-selector.spec.ts +61 -0
  56. package/src/helpers/__tests__/layout-overlay-style.spec.ts +288 -0
  57. package/src/helpers/__tests__/model-helper.spec.ts +118 -0
  58. package/src/helpers/__tests__/utils.spec.ts +70 -0
  59. package/src/helpers/layoutOverlayStyle.ts +50 -30
  60. package/src/plugins/__tests__/index.spec.ts +19 -0
  61. package/src/plugins/__tests__/vuetify.spec.ts +8 -0
  62. package/src/plugins/vuetify.ts +25 -8
  63. package/test/helper.ts +35 -0
  64. package/test/setup.ts +1 -0
  65. package/tsconfig.json +5 -2
  66. package/vite.config.mts +1 -0
  67. package/vitest.config.mts +44 -0
  68. package/README2.md +0 -201
  69. package/src/components/expansion-panels/ExpansionHeaderMiniMenu.vue +0 -19
  70. package/src/helpers/models.ts +0 -69
  71. /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 v-model="m_closeDialog">
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>Are you sure you want to close the Online Viewer?</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"> Cancel </v-btn>
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"> Close without saving </v-btn>
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 :close-on-content-click="false" :close-on-click="true" open-on-hover offset-y>
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
- File
57
+ File
42
58
  </v-btn>
43
59
  </template>
44
60
  <v-card class="">
45
61
  <v-list>
46
- <v-list-item disabled>
47
- <template v-slot:prepend>
48
- <v-icon> upload </v-icon>
49
- </template>
50
- <v-list-item-title
51
- >Load New DICOM Series&nbsp;<v-chip x-small color="success">Coming Soon</v-chip></v-list-item-title
52
- >
53
- </v-list-item>
54
- <!-- <v-list-item @click="downloadDcm">-->
55
- <!-- <v-list-item-icon><v-icon> download </v-icon></v-list-item-icon>-->
56
- <!-- <v-list-item-title>Download DICOM Series</v-list-item-title>-->
57
- <!-- </v-list-item>-->
58
- <v-list-item disabled>
59
- <template v-slot:prepend>
60
- <v-icon> sync </v-icon>
61
- </template>
62
- <v-list-item-title
63
- >Load Saved Session&nbsp;<v-chip x-small color="success">Coming Soon</v-chip></v-list-item-title
64
- >
65
- </v-list-item>
66
- <v-list-item disabled>
67
- <template v-slot:prepend>
68
- <v-icon> share </v-icon>
69
- </template>
70
- <v-list-item-title>Share&nbsp;<v-chip x-small color="success">Coming Soon</v-chip></v-list-item-title>
71
- </v-list-item>
72
- <v-list-item @click="alterValue(false)">
73
- <template v-slot:prepend>
74
- <v-icon> close </v-icon>
75
- </template>
76
- <v-list-item-title>Close Viewer</v-list-item-title>
77
- </v-list-item>
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&nbsp;<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&nbsp;<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&nbsp;<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 :close-on-content-click="false" :close-on-click="true" open-on-hover offset-y>
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" :color="isActive ? 'secondary' : 'primary'">
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
- Settings
120
+ Settings
90
121
  </v-btn>
91
122
  </template>
92
- <v-card min-width="400" class=" pa-4">
93
- <SliderSelector v-model:value="scanState.Display.Brightness" label="Adjust Brightness" />
94
- <SliderSelector v-model:value="scanState.Display.Contrast" label="Adjust Contrast" />
95
- <SliderSelector v-model:value="scanState.Display.Opacity" label="Adjust Opacity" />
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="scanState.InteractionSettings.CameraRotateSensitivity"
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)">Close Viewer</v-btn>
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 class="d-flex align-center pb-1" :class="drawerCollapsed ? 'py-2' : 'pa-2'" @click="snap">
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
- :style="drawerCollapsed && 'margin-left: 10px !important; margin-right: 10px !important;'">
202
- <v-icon :large="drawerCollapsed" :size="drawerCollapsed ? 32 : 24" :color="item.color">
203
- {{ item.icon || 'radio_button_checked' }}
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 v-if="!drawerCollapsed" class="text-white font-weight-medium ml-3">
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
- <v-icon size="36" color="white" style="margin-left: 8px !important; margin-right: 10px !important;">
229
- {{ item.icon || 'radio_button_checked' }}
230
- </v-icon>
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 transparent pr-0 mr-0"
307
+ class="mt-1 transparent pr-0 mr-0"
243
308
  >
244
309
  <v-expansion-panel class="transparent px-0">
245
- <ExpansionHeaderMiniMenu :mini-menu="miniMenu[0]" />
246
- <v-expansion-panel-text class="px-0" >
310
+ <v-expansion-panel-title class="font-weight-bold transparent">
311
+ <span
312
+ ><v-icon small>{{ miniMenu[0].icon }}</v-icon
313
+ >&nbsp;&nbsp;{{ 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 v-model:value="thresholdSlider" label="Fine Adjustment" v-bind="huMinMax" />
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(PresetActions.pr01, $event)"
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(PresetActions.pr01, item.raw)"
354
+ @click="setPreset(PresetsActions.pr01, item.raw)"
280
355
  >
281
356
  <template v-slot:prepend>
282
- <v-icon :icon="getIconForPreset(item.raw.Name)"></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: <span class="text-mono">{{ item.raw.Lower }}</span>
362
+ Skin Density:
363
+ <span class="text-mono">{{ item.raw.Lower }}</span>
286
364
  <v-spacer />
287
- Bone Density: <span class="text-mono">{{ item.raw.Upper }}</span>
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">None</span>
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(PresetActions.pr02, $event)"
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>{{ drawerCollapsed ? 'chevron_right' : 'chevron_left' }}</v-icon>
416
+ <v-icon>{{
417
+ drawerCollapsed ? "chevron_right" : "chevron_left"
418
+ }}</v-icon>
337
419
  </v-btn>
338
420
 
339
- <div class="position-relative pa-0" :style="drawerCollapsed ? 'margin-left: 68px' : 'margin-left: 300px'">
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: getCurrentActiveView(layout) === ScanView.Volume ? 'grab !important' : 'default',
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
- <div style="width: 100%; height: 100%" v-bind="props">
361
- <div class="buttons-in-view" v-show="isHovering" >
362
-
363
- <div v-if="scanState.Layout.PositionData.length !== 1">
364
- <v-btn
365
- color="transparent"
366
- @click="fullscreenLayout(layout.DefaultView)"
367
- :icon="true"
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-icon color="white">fullscreen</v-icon>
370
-
371
- </v-btn>
372
- <v-tooltip target="cursor" location="top" activator="parent">
373
- Make {{ getViewName(getCurrentActiveView(layout)) }} fullscreen
374
- </v-tooltip>
375
- </div>
376
- <div v-if="scanState.Layout.PositionData.length === 1">
377
- <v-btn
378
- color="transparent"
379
- @click="layouts(previousLayout)"
380
- :icon="true"
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-icon color="white">fullscreen_exit</v-icon>
383
- </v-btn>
384
- <v-tooltip target="cursor" location="top" activator="parent">
385
- Exit Fullscreen View
386
- </v-tooltip>
387
- </div>
388
- <div v-if="getCurrentActiveView(layout) === ScanView.Volume">
389
- <v-btn
390
- color="transparent"
391
- :icon="true"
392
- @click="
393
- viewSelection('vs_05');
394
- viewSelection('vs_06');
395
- "
396
- ><v-icon color="white">home</v-icon></v-btn
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
- <v-tooltip target="cursor" location="top" activator="parent">
399
- Reset volume to default view
400
- </v-tooltip>
401
- </div>
402
- <div v-if="getCurrentActiveView(layout) === ScanView.Volume">
403
- <v-menu :close-on-content-click="false" :close-on-click="true">
404
- <template v-slot:activator="{ props }">
405
- <div v-bind="{ ...props }"
406
- >
407
- <v-btn
408
- color="transparent"
409
- :icon="true"
410
- >
411
- <v-icon color="white">cut</v-icon>
412
- </v-btn>
413
- <v-tooltip target="cursor" location="top" activator="parent">
414
- Slice the 3D Volume
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
- </div>
417
- </template>
418
- <v-card min-width="400" class="pb-2">
419
- <v-card-title>Slice into the 3D Volume</v-card-title>
420
- <DoubleSliderSelector v-model="tSlider" label="Transverse" v-bind="tMinMax" />
421
- <DoubleSliderSelector v-model="sSlider" label="Sagittal" v-bind="sMinMax" />
422
- <DoubleSliderSelector v-model="cSlider" label="Coronal" v-bind="cMinMax" />
423
- </v-card>
424
- </v-menu>
425
- </div>
426
- <div v-if="getCurrentActiveView(layout) !== ScanView.Volume">
427
- <v-menu :close-on-content-click="false" :close-on-click="true" offset-overflow top>
428
- <template v-slot:activator="{ props }">
429
- <v-tooltip top>
430
- <template #activator="{ props: ttprops}">
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
- v-bind="{ ...props, ...ttprops }"
433
- icon
434
- class="icon transparent"
588
+ color="primary"
589
+ @click="
590
+ rotateByDeg(
591
+ getCurrentActiveView(layout),
592
+ rotationDeg
593
+ )
594
+ "
595
+ >Rotate</v-btn
435
596
  >
436
- <v-icon color="white">360</v-icon>
437
- </v-btn>
438
- </template>
439
- Rotate {{ getViewName(getCurrentActiveView(layout)) }} by an angle
440
- </v-tooltip>
441
- </template>
442
- <v-card min-width="200" width="200" class="pb-2">
443
- <v-card-subtitle
444
- >Rotate {{ getViewName(getCurrentActiveView(layout)) }} by an angle</v-card-subtitle
445
- >
446
- <v-card-text class="py-0">
447
- <v-text-field
448
- hide-details
449
- outlined
450
- v-model="rotationDeg"
451
- type="number"
452
- suffix="deg"
453
- ></v-text-field>
454
- </v-card-text>
455
- <v-card-actions>
456
- <v-spacer />
457
- <v-btn color="primary" @click="rotateByDeg(getCurrentActiveView(layout), rotationDeg)"
458
- >Rotate</v-btn
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
- <div class="top-lhc" v-if="isHovering">
484
- <div class="white--text">
485
- {{ getViewName(getCurrentActiveView(layout)) }}
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 v-if="scanLoading" text="Rendering your scan in <span class='sub-type'>3DICOM</span>" />
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="position: absolute; top: 0px; right: -0px; width: 240px; z-index: 10000"
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
- <script setup lang="ts" >
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 ExpansionHeaderMiniMenu from '@/components/expansion-panels/ExpansionHeaderMiniMenu.vue';
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
- SliderActions,
523
- PresetActions,
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 '@3cr/types-ts';
686
+ } from "@3cr/types-ts";
541
687
 
542
- import { toNumber } from '@/helpers/utils';
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: LoadViewerPayload;
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: '1.1.0' };
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>('lo_02');
722
+ const previousLayout = ref<string>("lo_02");
582
723
  const footerItems = ref([
583
724
  {
584
- text: 'Reset Scan',
585
- icon: 'refresh',
586
- color: 'red',
725
+ text: "Reset Scan",
726
+ icon: "refresh",
727
+ color: "red",
587
728
  click: async () => {
588
- console.log('Reset Scan');
589
- await viewSelection('vs_05');
590
- await viewSelection('vs_06');
729
+ console.log("Reset Scan");
730
+ await viewSelection("vs_05");
731
+ await viewSelection("vs_06");
591
732
  },
592
733
  },
593
734
  {
594
- text: 'Send to 3rd Party',
595
- icon: 'send',
596
- color: 'blue',
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: 'Share to Mobile / VR',
601
- icon: 'share',
602
- color: 'yellow',
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: 'Screenshot View',
607
- icon: 'screenshot_region',
608
- color: 'green',
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: 'display_settings',
618
- text: 'Tissue Density',
758
+ icon: "display_settings",
759
+ text: "Tissue Density",
619
760
  tooltip:
620
- 'Tissue Density - Change the view of density within the scan, allowing you to see through a certain density of particles',
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 [unref(scanState).Display.WindowLower, unref(scanState).Display.WindowUpper];
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 [Math.trunc(unref(scanState).Display.ThresholdLower), Math.trunc(unref(scanState).Display.ThresholdUpper)];
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 [Math.trunc(unref(scanState).Slice.TransverseLower), Math.trunc(unref(scanState).Slice.TransverseUpper)];
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 [Math.trunc(unref(scanState).Slice.SagittalLower), Math.trunc(unref(scanState).Slice.SagittalUpper)];
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 [Math.trunc(unref(scanState).Slice.CoronalLower), Math.trunc(unref(scanState).Slice.CoronalUpper)];
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
- watch(() => scanState.value.Display.Brightness, async (value: number) => {
699
- await sliderHandler(SliderActions.sl01, value);
700
- })
701
- watch(() => scanState.value.Display.Contrast, async (value: number) => {
702
- await sliderHandler(SliderActions.sl02, value);
703
- })
704
- watch(() => scanState.value.Display.Opacity, async (value: number) => {
705
- await sliderHandler(SliderActions.sl03, value);
706
- })
707
- watch(() => scanState.value.Display.WindowLower, async (value: number) => {
708
- await sliderHandler(SliderActions.sl04, value);
709
- })
710
- watch(() => scanState.value.Display.WindowUpper, async (value: number) => {
711
- await sliderHandler(SliderActions.sl05, value);
712
- })
713
- watch(() => scanState.value.Display.ThresholdLower, async (value: number) => {
714
- await sliderHandler(SliderActions.sl06, value);
715
- })
716
- watch(() => scanState.value.Display.ThresholdUpper, async (value: number) => {
717
- await sliderHandler(SliderActions.sl07, value);
718
- })
719
- watch(() => scanState.value.Slice.TransverseLower, async (value: number) => {
720
- await sliderHandler(SliderActions.sl08, value);
721
- })
722
- watch(() => scanState.value.Orientations.Transverse.Slice, async (value: number) => {
723
- await sliderHandler(SliderActions.sl09, value);
724
- })
725
- watch(() => scanState.value.Slice.TransverseUpper, async (value: number) => {
726
- await sliderHandler(SliderActions.sl10, value);
727
- })
728
- watch(() => scanState.value.Slice.SagittalLower, async (value: number) => {
729
- await sliderHandler(SliderActions.sl11, value);
730
- })
731
- watch(() => scanState.value.Orientations.Sagittal.Slice, async (value: number) => {
732
- await sliderHandler(SliderActions.sl12, value);
733
- })
734
- watch(() => scanState.value.Slice.SagittalUpper, async (value: number) => {
735
- await sliderHandler(SliderActions.sl13, value);
736
- })
737
- watch(() => scanState.value.Slice.CoronalLower, async (value: number) => {
738
- await sliderHandler(SliderActions.sl14, value);
739
- })
740
- watch(() => scanState.value.Orientations.Coronal.Slice, async (value: number) => {
741
- await sliderHandler(SliderActions.sl15, value);
742
- })
743
- watch(() => scanState.value.Slice.CoronalUpper, async (value: number) => {
744
- await sliderHandler(SliderActions.sl16, value);
745
- })
746
- watch(() => scanState.value.InteractionSettings.PanSensivitity, async (value: number) => {
747
- await scanMovementHandler(ScanMovementActions.sm05, value);
748
- })
749
- watch(() => scanState.value.InteractionSettings.ZoomSensitivity, async (value: number) => {
750
- await scanMovementHandler(ScanMovementActions.sm08, value);
751
- })
752
- watch(() => scanState.value.InteractionSettings.RotateSensitivity, async (value: number) => {
753
- await scanMovementHandler(ScanMovementActions.sm10, value);
754
- })
755
- watch(() => scanState.value.InteractionSettings.CameraRotateSensitivity, async (value: number) => {
756
- await scanMovementHandler(ScanMovementActions.sm12, value);
757
- })
758
- watch( () => scanState.value.Layout.PositionData, () => {
759
- componentKey.value += 1
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
- // if (presetName === 'Bone') return 'fa-solid fa-bone';
764
- // if (presetName === 'Brain') return 'fa-solid fa-brain';
765
- // if (presetName === 'Liver') return '$liver_icon';
766
- // if (presetName === 'Lungs') return 'fa-solid fa-lungs';
767
- // if (presetName === 'Muscle') return '$muscle_icon';
768
- // if (presetName === 'Temporal Bones') return '$temporal_bones_icon';
769
- // if (presetName === 'Soft Tissue') return '$torso_icon';
770
- // if (presetName === 'Skin') return '$skin_icon';
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 (FrontEndInterfaces.scan_orientation, ScanOrientationActions.so01, {
775
- Version: '0.0.1',
776
- View: view,
777
- Angle: deg,
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 ? position.DefaultView : unref(scanState).CurrentView;
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 === 'string')
1002
+ .filter((value) => typeof value === "string")
786
1003
  .map((x) => {
787
- if (x === 'Volume') return '3D Volume';
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('lo_01');
1009
+ await layouts("lo_01");
793
1010
  await viewSelection(`vs_0${view + 1}`);
794
1011
  }
795
- // generateDivStyleForLayout,
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(interfaceType: string, actionType: string, message: any) {
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: '0.0.1',
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('file_management', 'fm_01', props.payload);
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 !== 'lo_01') previousLayout.value = 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
- // await unref(web_gl).snap();
1060
+ emit("snap");
841
1061
  }
842
- async function setPreset(action: PresetActions, preset: any) {
843
- await sendPayload('presets', action, preset)
844
- if (action === PresetActions.pr02) {
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('sliders', action, { Version: '0.0.1', Value: toNumber(value) })
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('scan_movement', action, { Version: '0.0.1', Value: toNumber(value) })
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('interactivity', 'in_01', { Version: '0.0.1', Value: isHovering })
856
- await sendPayload('interactivity', 'in_02', { Version: '0.0.1', Value: isHovering })
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 === AnchorPoint.BOTTOM_LEFT &&
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 > unref(initialScanState).HuLower &&
930
- unref(scanState).Display.WindowLower === unref(initialScanState).HuLower)) &&
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 === unref(initialScanState).HuUpper))
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(interfaceSet: string | FrontEndInterfaces, actionSet: string, message: string) {
945
- if (interfaceSet === FrontEndInterfaces.scan_loading || interfaceSet === 'scan_state') {
946
- i_scanState(actionSet, message)
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 === 'notifications') {
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) {