@3cr/viewer-browser 0.0.112 → 0.0.114
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/Viewer3CR.js +12 -12
- package/dist/Viewer3CR.mjs +4410 -4357
- package/dist/Viewer3CR.umd.js +12 -12
- package/package.json +1 -1
- package/src/components/modal/MftpWebGL3DRModal.vue +111 -44
- package/src/components/selectors/ValueSelector.vue +6 -2
- package/src/demo/options.ts +12 -6
package/package.json
CHANGED
|
@@ -22,20 +22,30 @@
|
|
|
22
22
|
id="close-dialog-prompt"
|
|
23
23
|
data-test="closemodal"
|
|
24
24
|
>
|
|
25
|
-
<v-card
|
|
25
|
+
<v-card
|
|
26
|
+
class="pa-1 ma-auto position-relative motif-background"
|
|
27
|
+
width="600"
|
|
28
|
+
theme="dark"
|
|
29
|
+
>
|
|
26
30
|
<v-card-title>Close Viewer?</v-card-title>
|
|
27
31
|
<v-card-text
|
|
28
32
|
>Are you sure you want to close the Online Viewer?</v-card-text
|
|
29
33
|
>
|
|
30
34
|
<v-card-actions>
|
|
31
|
-
<v-btn
|
|
35
|
+
<v-btn
|
|
36
|
+
variant="tonal"
|
|
37
|
+
color="secondary"
|
|
38
|
+
@click="m_closeDialog = false"
|
|
39
|
+
>
|
|
32
40
|
Cancel
|
|
33
41
|
</v-btn>
|
|
34
42
|
<v-spacer />
|
|
35
|
-
<v-btn color="
|
|
43
|
+
<v-btn color="red" variant="tonal" @click="closeModal">
|
|
36
44
|
Close without saving
|
|
37
45
|
</v-btn>
|
|
38
|
-
<v-btn color="primary" @click="closeModal">
|
|
46
|
+
<v-btn color="primary" variant="tonal" @click="closeModal">
|
|
47
|
+
Save Session
|
|
48
|
+
</v-btn>
|
|
39
49
|
</v-card-actions>
|
|
40
50
|
</v-card>
|
|
41
51
|
</v-dialog>
|
|
@@ -84,12 +94,19 @@
|
|
|
84
94
|
</template>
|
|
85
95
|
<v-list-item-title> Load Saved Session </v-list-item-title>
|
|
86
96
|
</v-list-item>
|
|
97
|
+
<v-list-item @click="executeOption('OnSendTo3rdParty')">
|
|
98
|
+
<template v-slot:prepend>
|
|
99
|
+
<v-icon> send </v-icon>
|
|
100
|
+
</template>
|
|
101
|
+
<v-list-item-title>Send to 3rd Party</v-list-item-title>
|
|
102
|
+
</v-list-item>
|
|
87
103
|
<v-list-item @click="executeOption('OnShare')">
|
|
88
104
|
<template v-slot:prepend>
|
|
89
105
|
<v-icon> share </v-icon>
|
|
90
106
|
</template>
|
|
91
|
-
<v-list-item-title>Share</v-list-item-title>
|
|
107
|
+
<v-list-item-title>Share to Mobile / VR</v-list-item-title>
|
|
92
108
|
</v-list-item>
|
|
109
|
+
|
|
93
110
|
<v-list-item
|
|
94
111
|
@click="
|
|
95
112
|
executeOption('OnClosePopup');
|
|
@@ -122,18 +139,21 @@
|
|
|
122
139
|
Settings
|
|
123
140
|
</v-btn>
|
|
124
141
|
</template>
|
|
125
|
-
<v-card
|
|
142
|
+
<v-card width="350" class="pa-4">
|
|
126
143
|
<SliderSelector
|
|
127
144
|
v-model:value="scanState.Display.Brightness"
|
|
128
145
|
label="Adjust Brightness"
|
|
146
|
+
prepend="percent"
|
|
129
147
|
/>
|
|
130
148
|
<SliderSelector
|
|
131
149
|
v-model:value="scanState.Display.Contrast"
|
|
132
150
|
label="Adjust Contrast"
|
|
151
|
+
prepend="percent"
|
|
133
152
|
/>
|
|
134
153
|
<SliderSelector
|
|
135
154
|
v-model:value="scanState.Display.Opacity"
|
|
136
155
|
label="Adjust Opacity"
|
|
156
|
+
prepend="percent"
|
|
137
157
|
/>
|
|
138
158
|
<v-divider class="my-4" />
|
|
139
159
|
<SliderSelector
|
|
@@ -141,18 +161,21 @@
|
|
|
141
161
|
:min="0"
|
|
142
162
|
:max="100"
|
|
143
163
|
label="Pan Sensitivity"
|
|
164
|
+
prepend="percent"
|
|
144
165
|
/>
|
|
145
166
|
<SliderSelector
|
|
146
167
|
v-model:value="scanState.InteractionSettings.ZoomSensitivity"
|
|
147
168
|
:min="0"
|
|
148
169
|
:max="100"
|
|
149
170
|
label="Zoom Sensitivity"
|
|
171
|
+
prepend="percent"
|
|
150
172
|
/>
|
|
151
173
|
<SliderSelector
|
|
152
174
|
v-model:value="scanState.InteractionSettings.RotateSensitivity"
|
|
153
175
|
:min="0"
|
|
154
176
|
:max="100"
|
|
155
177
|
label="Rotate Sensitivity"
|
|
178
|
+
prepend="percent"
|
|
156
179
|
/>
|
|
157
180
|
<SliderSelector
|
|
158
181
|
v-model:value="
|
|
@@ -161,6 +184,7 @@
|
|
|
161
184
|
:min="0"
|
|
162
185
|
:max="100"
|
|
163
186
|
label="Camera Rotate Sensitivity"
|
|
187
|
+
prepend="percent"
|
|
164
188
|
/>
|
|
165
189
|
</v-card>
|
|
166
190
|
</v-menu>
|
|
@@ -178,19 +202,25 @@
|
|
|
178
202
|
style="min-width: 36px !important"
|
|
179
203
|
:color="isLayout2x2 ? 'secondary' : 'primary'"
|
|
180
204
|
@click="payloadHandler.layouts(LayoutActions.lo02)"
|
|
181
|
-
><v-icon>grid_view</v-icon
|
|
182
|
-
|
|
205
|
+
><v-icon>grid_view</v-icon>
|
|
206
|
+
<v-tooltip location="bottom" activator="parent">
|
|
207
|
+
Change Layout to 2:2
|
|
208
|
+
</v-tooltip>
|
|
209
|
+
</v-btn>
|
|
183
210
|
<v-btn
|
|
184
|
-
class="ma-1 mr-
|
|
211
|
+
class="ma-1 mr-1 pa-1"
|
|
185
212
|
height="36"
|
|
186
213
|
style="min-width: 36px !important"
|
|
187
214
|
:color="isLayout1x3 ? 'secondary' : 'primary'"
|
|
188
215
|
@click="payloadHandler.layouts(LayoutActions.lo03)"
|
|
189
|
-
><v-icon style="rotate: -90deg">view_comfy</v-icon
|
|
216
|
+
><v-icon style="rotate: -90deg">view_comfy</v-icon>
|
|
217
|
+
<v-tooltip location="bottom" activator="parent">
|
|
218
|
+
Change Layout to 1:3
|
|
219
|
+
</v-tooltip></v-btn
|
|
190
220
|
>
|
|
191
221
|
<v-btn class="" variant="flat" color="red" @click="alterValue(false)"
|
|
192
|
-
>Close Viewer
|
|
193
|
-
>
|
|
222
|
+
>Close Viewer
|
|
223
|
+
</v-btn>
|
|
194
224
|
</v-toolbar>
|
|
195
225
|
<v-navigation-drawer
|
|
196
226
|
v-model="drawer"
|
|
@@ -235,7 +265,13 @@
|
|
|
235
265
|
<template v-slot:append>
|
|
236
266
|
<v-divider></v-divider>
|
|
237
267
|
<v-list>
|
|
238
|
-
<v-tooltip
|
|
268
|
+
<v-tooltip
|
|
269
|
+
right
|
|
270
|
+
v-for="(item, index) in footerItems.filter((x) =>
|
|
271
|
+
x.conditional()
|
|
272
|
+
)"
|
|
273
|
+
:key="index"
|
|
274
|
+
>
|
|
239
275
|
<template #activator="{ props }">
|
|
240
276
|
<v-list-item
|
|
241
277
|
class="px-2"
|
|
@@ -271,7 +307,7 @@
|
|
|
271
307
|
</v-list-item-title>
|
|
272
308
|
</v-list-item>
|
|
273
309
|
</template>
|
|
274
|
-
{{ item.
|
|
310
|
+
{{ item.tooltip }}
|
|
275
311
|
</v-tooltip>
|
|
276
312
|
</v-list>
|
|
277
313
|
</template>
|
|
@@ -317,6 +353,9 @@
|
|
|
317
353
|
> {{ miniMenu[0].text }}</span
|
|
318
354
|
>
|
|
319
355
|
<v-spacer />
|
|
356
|
+
<v-tooltip location="right" activator="parent">
|
|
357
|
+
{{ miniMenu[0].tooltip }}
|
|
358
|
+
</v-tooltip>
|
|
320
359
|
</v-expansion-panel-title>
|
|
321
360
|
<v-expansion-panel-text class="px-0">
|
|
322
361
|
<DoubleSliderSelector
|
|
@@ -444,7 +483,7 @@
|
|
|
444
483
|
>
|
|
445
484
|
<div
|
|
446
485
|
class="bordered-event-window"
|
|
447
|
-
v-for="layout in scanState.Layout.PositionData"
|
|
486
|
+
v-for="(layout, index) in scanState.Layout.PositionData"
|
|
448
487
|
:key="layout.Anchor"
|
|
449
488
|
:style="{
|
|
450
489
|
...generateDivStyleForLayout(layout),
|
|
@@ -458,7 +497,12 @@
|
|
|
458
497
|
<v-hover>
|
|
459
498
|
<template v-slot:default="{ isHovering, props }">
|
|
460
499
|
<div style="width: 100%; height: 100%" v-bind="props">
|
|
461
|
-
<div
|
|
500
|
+
<div
|
|
501
|
+
class="buttons-in-view"
|
|
502
|
+
v-show="
|
|
503
|
+
isHovering || menu || menus.filter((x) => x).length > 0
|
|
504
|
+
"
|
|
505
|
+
>
|
|
462
506
|
<div v-if="scanState.Layout.PositionData.length !== 1">
|
|
463
507
|
<v-btn
|
|
464
508
|
color="transparent"
|
|
@@ -493,9 +537,7 @@
|
|
|
493
537
|
Exit Fullscreen View
|
|
494
538
|
</v-tooltip>
|
|
495
539
|
</div>
|
|
496
|
-
<div
|
|
497
|
-
v-if="getCurrentActiveView(layout) === ScanView.Volume"
|
|
498
|
-
>
|
|
540
|
+
<div>
|
|
499
541
|
<v-btn
|
|
500
542
|
color="transparent"
|
|
501
543
|
:icon="true"
|
|
@@ -521,22 +563,23 @@
|
|
|
521
563
|
v-if="getCurrentActiveView(layout) === ScanView.Volume"
|
|
522
564
|
>
|
|
523
565
|
<v-menu
|
|
566
|
+
v-model="menu"
|
|
524
567
|
:close-on-content-click="false"
|
|
525
|
-
|
|
568
|
+
location="end"
|
|
526
569
|
>
|
|
527
570
|
<template v-slot:activator="{ props }">
|
|
528
|
-
<
|
|
529
|
-
<v-
|
|
530
|
-
<v-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
</
|
|
571
|
+
<v-tooltip location="top">
|
|
572
|
+
<template v-slot:activator="{ props: tooltip }">
|
|
573
|
+
<v-btn
|
|
574
|
+
v-bind="mergeProps(props, tooltip)"
|
|
575
|
+
color="transparent"
|
|
576
|
+
:icon="true"
|
|
577
|
+
>
|
|
578
|
+
<v-icon color="white">cut</v-icon>
|
|
579
|
+
</v-btn>
|
|
580
|
+
</template>
|
|
581
|
+
Slice the 3D Volume
|
|
582
|
+
</v-tooltip>
|
|
540
583
|
</template>
|
|
541
584
|
<v-card min-width="400" class="pb-2">
|
|
542
585
|
<v-card-title>Slice into the 3D Volume</v-card-title>
|
|
@@ -562,6 +605,7 @@
|
|
|
562
605
|
v-if="getCurrentActiveView(layout) !== ScanView.Volume"
|
|
563
606
|
>
|
|
564
607
|
<v-menu
|
|
608
|
+
v-model="menus[index]"
|
|
565
609
|
:close-on-content-click="false"
|
|
566
610
|
:close-on-click="true"
|
|
567
611
|
offset-overflow
|
|
@@ -572,8 +616,7 @@
|
|
|
572
616
|
<template #activator="{ props: ttprops }">
|
|
573
617
|
<v-btn
|
|
574
618
|
v-bind="{ ...props, ...ttprops }"
|
|
575
|
-
icon
|
|
576
|
-
class="icon transparent"
|
|
619
|
+
:icon="true"
|
|
577
620
|
>
|
|
578
621
|
<v-icon color="white">360</v-icon>
|
|
579
622
|
</v-btn>
|
|
@@ -691,12 +734,20 @@ import {
|
|
|
691
734
|
SlidersActions,
|
|
692
735
|
ViewSelectionActions,
|
|
693
736
|
} from "@3cr/types-ts";
|
|
694
|
-
import {
|
|
737
|
+
import {
|
|
738
|
+
defineEmits,
|
|
739
|
+
mergeProps,
|
|
740
|
+
nextTick,
|
|
741
|
+
ref,
|
|
742
|
+
unref,
|
|
743
|
+
watch,
|
|
744
|
+
WatchSource,
|
|
745
|
+
} from "vue";
|
|
695
746
|
|
|
696
747
|
import {
|
|
697
748
|
checkIsDemo,
|
|
698
749
|
demoType,
|
|
699
|
-
|
|
750
|
+
getDemoOption,
|
|
700
751
|
isDemo,
|
|
701
752
|
m_demo,
|
|
702
753
|
m_demoPatient,
|
|
@@ -732,6 +783,7 @@ import {
|
|
|
732
783
|
windowSlider,
|
|
733
784
|
} from "@/dataLayer/scanState";
|
|
734
785
|
import { getIconForPreset } from "@/dataLayer/iconData";
|
|
786
|
+
import { ViewerAsyncCallback, ViewerCallback } from "@/models/Callbacks";
|
|
735
787
|
|
|
736
788
|
export interface Props {
|
|
737
789
|
payload?: LoadViewerPayload;
|
|
@@ -755,6 +807,8 @@ const props = withDefaults(defineProps<Props>(), {
|
|
|
755
807
|
const web_gl = ref<typeof WebGL3DR | null>(null);
|
|
756
808
|
const payloadHandler = new PayloadHandler(web_gl);
|
|
757
809
|
const value = ref<boolean>(false);
|
|
810
|
+
const menu = ref<boolean>(false);
|
|
811
|
+
const menus = ref<Array<boolean>>([false, false, false, false]);
|
|
758
812
|
const drawer = ref<boolean>(true);
|
|
759
813
|
const drawerCollapsed = ref<boolean>(true);
|
|
760
814
|
const scanLoading = ref<boolean>(true);
|
|
@@ -763,30 +817,39 @@ const openPanels = ref<number>(0);
|
|
|
763
817
|
const footerItems = ref([
|
|
764
818
|
{
|
|
765
819
|
text: "Reset Scan",
|
|
820
|
+
tooltip: "Resets your scan to original position and settings in all views",
|
|
766
821
|
icon: "refresh",
|
|
767
822
|
color: "red",
|
|
768
823
|
click: async () => {
|
|
769
824
|
await payloadHandler.viewSelection(ViewSelectionActions.vs05);
|
|
770
825
|
await payloadHandler.viewSelection(ViewSelectionActions.vs06);
|
|
771
826
|
},
|
|
827
|
+
conditional: () => true,
|
|
772
828
|
},
|
|
773
829
|
{
|
|
774
830
|
text: "Send to 3rd Party",
|
|
831
|
+
tooltip:
|
|
832
|
+
"Securely share your loaded scan with 3rd parties via email with option to anonymise",
|
|
775
833
|
icon: "send",
|
|
776
834
|
color: "blue",
|
|
777
835
|
click: async () => executeOption("OnSendTo3rdParty"),
|
|
836
|
+
conditional: () => getOption("OnSendTo3rdParty") !== undefined,
|
|
778
837
|
},
|
|
779
838
|
{
|
|
780
839
|
text: "Share to Mobile / VR",
|
|
840
|
+
tooltip:
|
|
841
|
+
"Share your loaded scan with the 3Dicom Mobile and VR applications to download within 7 days",
|
|
781
842
|
icon: "share",
|
|
782
843
|
color: "yellow",
|
|
783
844
|
click: async () => executeOption("OnShareToMobile"),
|
|
845
|
+
conditional: () => getOption("OnShareToMobile") !== undefined,
|
|
784
846
|
},
|
|
785
847
|
{
|
|
786
848
|
text: "Screenshot View",
|
|
787
849
|
icon: "screenshot_region",
|
|
788
850
|
color: "green",
|
|
789
851
|
click: async () => executeOption("OnScreenshot"),
|
|
852
|
+
conditional: () => getOption("OnScreenshot") !== undefined,
|
|
790
853
|
},
|
|
791
854
|
]);
|
|
792
855
|
const miniMenu = ref([
|
|
@@ -794,22 +857,26 @@ const miniMenu = ref([
|
|
|
794
857
|
icon: "display_settings",
|
|
795
858
|
text: "Tissue Density",
|
|
796
859
|
tooltip:
|
|
797
|
-
"
|
|
860
|
+
"Change the range of visible anatomy in the scan by only showing areas with certain density of tissue",
|
|
798
861
|
},
|
|
799
862
|
]);
|
|
800
863
|
const rotationDeg = ref<number>(0);
|
|
801
864
|
const stateOverlay = ref<boolean>(false);
|
|
802
865
|
const m_closeDialog = ref<boolean>(false);
|
|
803
866
|
|
|
804
|
-
function
|
|
867
|
+
function getOption(
|
|
868
|
+
key: keyof LoadViewerOptions
|
|
869
|
+
): ViewerCallback | ViewerAsyncCallback | undefined {
|
|
805
870
|
if (unref(isDemo)) {
|
|
806
|
-
|
|
871
|
+
return getDemoOption(key);
|
|
807
872
|
} else {
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
873
|
+
return unref(props.options)[key];
|
|
874
|
+
}
|
|
875
|
+
}
|
|
876
|
+
function executeOption(key: keyof LoadViewerOptions) {
|
|
877
|
+
const functionToExecute = getOption(key);
|
|
878
|
+
if (functionToExecute !== undefined) {
|
|
879
|
+
functionToExecute();
|
|
813
880
|
}
|
|
814
881
|
}
|
|
815
882
|
|
|
@@ -49,7 +49,7 @@ defineExpose({
|
|
|
49
49
|
{{ label }}
|
|
50
50
|
</span>
|
|
51
51
|
</v-col>
|
|
52
|
-
<v-col cols="
|
|
52
|
+
<v-col cols="4">
|
|
53
53
|
<v-text-field
|
|
54
54
|
:model-value="sliderValue"
|
|
55
55
|
@update:modelValue="sliderValue = toNumber($event)"
|
|
@@ -60,7 +60,7 @@ defineExpose({
|
|
|
60
60
|
variant="outlined"
|
|
61
61
|
density="compact"
|
|
62
62
|
type="number"
|
|
63
|
-
:append-icon="prepend"
|
|
63
|
+
:append-inner-icon="prepend"
|
|
64
64
|
></v-text-field>
|
|
65
65
|
</v-col>
|
|
66
66
|
</v-row>
|
|
@@ -88,4 +88,8 @@ defineExpose({
|
|
|
88
88
|
.single-slider-selector .v-slider__thumb-label {
|
|
89
89
|
color: black;
|
|
90
90
|
}
|
|
91
|
+
.single-slider-selector {
|
|
92
|
+
margin-top: 4px;
|
|
93
|
+
margin-bottom: 4px;
|
|
94
|
+
}
|
|
91
95
|
</style>
|
package/src/demo/options.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { computed, ref, unref } from "vue";
|
|
2
2
|
import { LoadViewerOptions } from "@/models/LoadViewerOptions";
|
|
3
3
|
import { LoadViewerPayload } from "@/models/LoadViewerPayload";
|
|
4
|
+
import { ViewerAsyncCallback, ViewerCallback } from "@/models/Callbacks";
|
|
4
5
|
|
|
5
6
|
export function checkIsDemo(payload: LoadViewerPayload) {
|
|
6
7
|
isDemo.value =
|
|
@@ -37,9 +38,7 @@ export const demoLicenceOptions: LoadViewerOptions = {
|
|
|
37
38
|
OnShare: () => {
|
|
38
39
|
m_demo.value = true;
|
|
39
40
|
},
|
|
40
|
-
OnScreenshot:
|
|
41
|
-
m_demo.value = true;
|
|
42
|
-
},
|
|
41
|
+
OnScreenshot: undefined,
|
|
43
42
|
};
|
|
44
43
|
|
|
45
44
|
export const demoPatientOptions: LoadViewerOptions = {
|
|
@@ -68,9 +67,7 @@ export const demoPatientOptions: LoadViewerOptions = {
|
|
|
68
67
|
OnShare: () => {
|
|
69
68
|
m_demoPatient.value = true;
|
|
70
69
|
},
|
|
71
|
-
OnScreenshot:
|
|
72
|
-
m_demoPatient.value = true;
|
|
73
|
-
},
|
|
70
|
+
OnScreenshot: undefined,
|
|
74
71
|
};
|
|
75
72
|
|
|
76
73
|
export const demoType = computed(() => {
|
|
@@ -91,3 +88,12 @@ export function executeDemoOption(key: keyof LoadViewerOptions) {
|
|
|
91
88
|
}
|
|
92
89
|
}
|
|
93
90
|
}
|
|
91
|
+
export function getDemoOption(
|
|
92
|
+
key: keyof LoadViewerOptions
|
|
93
|
+
): ViewerCallback | ViewerAsyncCallback | undefined {
|
|
94
|
+
if (unref(demoType) === "licence") {
|
|
95
|
+
return demoLicenceOptions[key];
|
|
96
|
+
} else if (unref(demoType) === "patient") {
|
|
97
|
+
return demoPatientOptions[key];
|
|
98
|
+
}
|
|
99
|
+
}
|