@3cr/viewer-browser 0.0.55 → 0.0.57

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 (38) hide show
  1. package/components.d.ts +1 -0
  2. package/coverage/3cr-viewer-browser/index.html +1 -1
  3. package/coverage/3cr-viewer-browser/index.ts.html +1 -1
  4. package/coverage/3cr-viewer-browser/src/App.vue.html +1 -1
  5. package/coverage/3cr-viewer-browser/src/components/WebGL3DR.vue.html +1 -1
  6. package/coverage/3cr-viewer-browser/src/components/icons/index.html +1 -1
  7. package/coverage/3cr-viewer-browser/src/components/icons/liver.vue.html +1 -1
  8. package/coverage/3cr-viewer-browser/src/components/index.html +1 -1
  9. package/coverage/3cr-viewer-browser/src/components/loading/LoadingSpinner.vue.html +1 -1
  10. package/coverage/3cr-viewer-browser/src/components/loading/index.html +1 -1
  11. package/coverage/3cr-viewer-browser/src/components/modal/MftpWebGL3DRModal.vue.html +205 -10
  12. package/coverage/3cr-viewer-browser/src/components/modal/index.html +19 -19
  13. package/coverage/3cr-viewer-browser/src/components/selectors/ValueSelector.vue.html +1 -1
  14. package/coverage/3cr-viewer-browser/src/components/selectors/index.html +1 -1
  15. package/coverage/3cr-viewer-browser/src/components/sliders/DoubleSliderSelector.vue.html +1 -1
  16. package/coverage/3cr-viewer-browser/src/components/sliders/VerticalSliderSelector.vue.html +1 -1
  17. package/coverage/3cr-viewer-browser/src/components/sliders/index.html +1 -1
  18. package/coverage/3cr-viewer-browser/src/helpers/index.html +1 -1
  19. package/coverage/3cr-viewer-browser/src/helpers/layoutOverlayStyle.ts.html +1 -1
  20. package/coverage/3cr-viewer-browser/src/helpers/modelHelper.ts.html +1 -1
  21. package/coverage/3cr-viewer-browser/src/helpers/utils.ts.html +1 -1
  22. package/coverage/3cr-viewer-browser/src/index.html +1 -1
  23. package/coverage/3cr-viewer-browser/src/main.ts.html +1 -1
  24. package/coverage/3cr-viewer-browser/src/plugins/index.html +1 -1
  25. package/coverage/3cr-viewer-browser/src/plugins/index.ts.html +1 -1
  26. package/coverage/3cr-viewer-browser/src/plugins/vuetify.ts.html +1 -1
  27. package/coverage/index.html +19 -19
  28. package/dist/Viewer3CR.js +12 -12
  29. package/dist/Viewer3CR.mjs +11467 -10882
  30. package/dist/Viewer3CR.umd.js +12 -12
  31. package/index.ts +33 -2
  32. package/package.json +2 -1
  33. package/src/App.vue +33 -36
  34. package/src/__tests__/app.spec.ts +1 -1
  35. package/src/components/loading/LoadingSpinner.vue +34 -12
  36. package/src/components/modal/DemoModal.vue +44 -0
  37. package/src/components/modal/MftpWebGL3DRModal.vue +134 -49
  38. package/src/plugins/index.ts +6 -4
package/index.ts CHANGED
@@ -3,6 +3,23 @@ import { ComponentPublicInstance, createApp } from "vue";
3
3
  import { registerPlugins } from "./src/plugins";
4
4
  import { App as BrowserViewer } from "./src/main";
5
5
 
6
+ export type ViewerCallback = () => void;
7
+ export type ViewerAsyncCallback = () => Promise<void>;
8
+
9
+ // Note: not defining the option will not display the item
10
+ export interface LoadViewerOptions {
11
+ OnShare?: ViewerCallback | ViewerAsyncCallback | undefined;
12
+ OnScreenshot?: ViewerCallback | ViewerAsyncCallback | undefined;
13
+ OnLoadNewDicomSeries?: ViewerCallback | ViewerAsyncCallback | undefined;
14
+ OnDownloadDicomSeries?: ViewerCallback | ViewerAsyncCallback | undefined;
15
+ OnLoadSavedSession?: ViewerCallback | ViewerAsyncCallback | undefined;
16
+ OnShareToMobile?: ViewerCallback | ViewerAsyncCallback | undefined;
17
+ OnSendTo3rdParty?: ViewerCallback | ViewerAsyncCallback | undefined;
18
+ OnSaveSession?: ViewerCallback | ViewerAsyncCallback | undefined;
19
+ OnClosePopup?: ViewerCallback | ViewerAsyncCallback | undefined;
20
+ OnExitViewer?: ViewerCallback | ViewerAsyncCallback | undefined;
21
+ }
22
+
6
23
  export interface LoadViewerPayload {
7
24
  Url: string;
8
25
  DecryptionKey: MftpDecryptionKey;
@@ -12,6 +29,19 @@ export interface MftpDecryptionKey {
12
29
  Iv: string;
13
30
  }
14
31
 
32
+ export const defaultOptions: LoadViewerOptions = {
33
+ OnClosePopup: () => Promise.resolve(),
34
+ OnExitViewer: () => Promise.resolve(),
35
+ OnLoadNewDicomSeries: () => Promise.resolve(),
36
+ OnDownloadDicomSeries: () => Promise.resolve(),
37
+ OnLoadSavedSession: () => Promise.resolve(),
38
+ OnSaveSession: () => Promise.resolve(),
39
+ OnSendTo3rdParty: () => Promise.resolve(),
40
+ OnShareToMobile: () => Promise.resolve(),
41
+ OnShare: () => Promise.resolve(),
42
+ OnScreenshot: () => Promise.resolve(),
43
+ };
44
+
15
45
  let mountedApp: ComponentPublicInstance | undefined = undefined;
16
46
 
17
47
  export async function registerViewer(version: string) {
@@ -31,12 +61,13 @@ export async function registerViewer(version: string) {
31
61
 
32
62
  // TODO: accept callbacks for each function we want the parent to handle
33
63
  export async function loadViewer(
34
- payload: LoadViewerPayload | undefined = undefined
64
+ payload: LoadViewerPayload | undefined = undefined,
65
+ options: LoadViewerOptions = defaultOptions
35
66
  ): Promise<void> {
36
67
  if (!mountedApp) {
37
68
  throw new Error(
38
69
  "Please call `registerViewer(version: string, idSelector: string)` first"
39
70
  );
40
71
  }
41
- await (mountedApp as any).loadInstance(payload);
72
+ await (mountedApp as any).loadInstance(payload, options);
42
73
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@3cr/viewer-browser",
3
- "version": "0.0.55",
3
+ "version": "0.0.57",
4
4
  "main": "./dist/Viewer3CR.umd.js",
5
5
  "module": "dist/Viewer3CR.umd.js",
6
6
  "homepage": "https://docs.3cr.singular.health",
@@ -21,6 +21,7 @@
21
21
  "dependencies": {
22
22
  "@3cr/sdk-browser": "^1.0.13",
23
23
  "@3cr/types-ts": "^1.0.9",
24
+ "@kyvg/vue3-notification": "^3.2.1",
24
25
  "@mdi/font": "6.2.95",
25
26
  "@mdi/js": "^7.4.47",
26
27
  "roboto-fontface": "*",
package/src/App.vue CHANGED
@@ -1,62 +1,59 @@
1
1
  <template>
2
- <v-app style="height: 0; width: 0;">
2
+ <v-app style="height: 0; width: 0">
3
3
  <MftpWebGL3DRModal ref="mftpWebGL3DRModal" :payload="payload" />
4
4
  </v-app>
5
+ <Notifications />
5
6
  </template>
6
7
 
7
8
  <script setup lang="ts">
8
-
9
9
  import MftpWebGL3DRModal from "@/components/modal/MftpWebGL3DRModal.vue";
10
- import {ref, unref} from "vue";
11
- import {LoadViewerPayload} from "../index";
10
+ import { ref, unref } from "vue";
11
+ import { defaultOptions, LoadViewerOptions, LoadViewerPayload } from "../index";
12
+ import { Notifications } from "@kyvg/vue3-notification";
12
13
 
13
14
  const payload = ref<LoadViewerPayload>({
14
- Url:"https://webgl-3dr.singular.health/test_scans/01440d4e-8b04-4b90-bb2c-698535ce16d6/CHEST.3vxl",
15
- DecryptionKey:{
16
- Iv:"XEloSh+OcO7TG77au6HjPw==",
17
- Key:"KUc722X1y4w42M+jCf9a3+6EGz66z7UMWK3m2aMqGxM="
18
- }
15
+ Url: "https://webgl-3dr.singular.health/test_scans/01440d4e-8b04-4b90-bb2c-698535ce16d6/CHEST.3vxl",
16
+ DecryptionKey: {
17
+ Iv: "XEloSh+OcO7TG77au6HjPw==",
18
+ Key: "KUc722X1y4w42M+jCf9a3+6EGz66z7UMWK3m2aMqGxM=",
19
+ },
19
20
  });
21
+ const options = ref<LoadViewerOptions>(defaultOptions);
20
22
 
21
- const mftpWebGL3DRModal = ref<typeof MftpWebGL3DRModal | null>(null)
23
+ const mftpWebGL3DRModal = ref<typeof MftpWebGL3DRModal | null>(null);
22
24
  defineExpose({
23
- loadInstance
24
- })
25
+ loadInstance,
26
+ });
25
27
 
26
- async function loadInstance(payloadIncoming: LoadViewerPayload | undefined = undefined) {
28
+ async function loadInstance(
29
+ payloadIncoming: LoadViewerPayload | undefined,
30
+ optionsIncoming: LoadViewerOptions
31
+ ) {
27
32
  payload.value = payloadIncoming || payload.value;
33
+ options.value = optionsIncoming;
28
34
 
29
- unref(mftpWebGL3DRModal)?.alterValue(true)
35
+ unref(mftpWebGL3DRModal)?.alterValue(true);
30
36
  }
31
37
  </script>
32
38
  <style>
33
-
34
- .material-icons-outlined, .material-symbols-outlined {
35
- font-variation-settings:
36
- 'FILL' 0,
37
- 'wght' 300,
38
- 'GRAD' 0,
39
- 'opsz' 24;
39
+ .material-icons-outlined,
40
+ .material-symbols-outlined {
41
+ font-variation-settings: "FILL" 0, "wght" 300, "GRAD" 0, "opsz" 24;
40
42
  }
41
- .material-icons, .material-symbols {
42
- font-variation-settings:
43
- 'FILL' 0,
44
- 'wght' 300,
45
- 'GRAD' 0,
46
- 'opsz' 24;
43
+ .material-icons,
44
+ .material-symbols {
45
+ font-variation-settings: "FILL" 0, "wght" 300, "GRAD" 0, "opsz" 24;
47
46
  }
48
- .material-icons-filled, .material-symbols-filled {
49
- font-variation-settings:
50
- 'FILL' 1,
51
- 'wght' 300,
52
- 'GRAD' 0,
53
- 'opsz' 24 !important;
47
+ .material-icons-filled,
48
+ .material-symbols-filled {
49
+ font-variation-settings: "FILL" 1, "wght" 300, "GRAD" 0, "opsz" 24 !important;
54
50
  }
55
51
  .overflow-y-scroll {
56
52
  overflow-y: scroll;
57
53
  }
58
- .material-icons-outlined, .material-icons {
59
- font-family: 'Material Symbols Outlined' !important;
54
+ .material-icons-outlined,
55
+ .material-icons {
56
+ font-family: "Material Symbols Outlined" !important;
60
57
  font-weight: normal;
61
58
  font-style: normal;
62
59
  font-size: 24px;
@@ -67,7 +64,7 @@ async function loadInstance(payloadIncoming: LoadViewerPayload | undefined = und
67
64
  white-space: nowrap;
68
65
  word-wrap: normal;
69
66
  direction: ltr;
70
- -webkit-font-feature-settings: 'liga';
67
+ -webkit-font-feature-settings: "liga";
71
68
  -webkit-font-smoothing: antialiased;
72
69
  }
73
70
  .transparent {
@@ -21,7 +21,7 @@ describe("App.vue", () => {
21
21
  expect(wrapper).toBeTruthy();
22
22
  });
23
23
  it("should loadScan", async () => {
24
- await wrapper.vm.loadInstance();
24
+ await wrapper.vm.loadInstance(undefined, {});
25
25
  expect(wrapper).toBeTruthy();
26
26
  });
27
27
  });
@@ -1,8 +1,11 @@
1
1
  <script setup lang="ts">
2
- import {ref} from "vue";
3
-
4
- const text = ref<string>('Loading Online Viewer')
2
+ export interface Props {
3
+ text: string;
4
+ }
5
5
 
6
+ const props = withDefaults(defineProps<Props>(), {
7
+ text: "Loading Online Viewer",
8
+ });
6
9
  </script>
7
10
 
8
11
  <template>
@@ -15,7 +18,10 @@ const text = ref<string>('Loading Online Viewer')
15
18
  <div class="circle"></div>
16
19
  </div>
17
20
  </div>
18
- <div class="mx-auto text-center white--text text-h3" v-html="text"></div>
21
+ <div
22
+ class="mx-auto text-center text-white text-h3"
23
+ v-html="props.text"
24
+ ></div>
19
25
  </div>
20
26
  </template>
21
27
 
@@ -50,9 +56,20 @@ const text = ref<string>('Loading Online Viewer')
50
56
  --in: 80%;
51
57
  --ar: #8799a4;
52
58
  --dt: #ffffff;
53
- --shadow: drop-shadow(0vmin 0vmin 0.5vmin rgba(0, 0, 0, 0.35)) drop-shadow(0vmin 1vmin 0.5vmin rgba(0, 0, 0, 0.09));
54
- --cross: linear-gradient(0deg, #fff0 calc(50% - 2px), #000 calc(50% - 1px) calc(50% + 1px), #fff0 calc(50% + 2px)),
55
- linear-gradient(90deg, #fff0 calc(50% - 2px), #000 calc(50% - 1px) calc(50% + 1px), #fff0 calc(50% + 2px));
59
+ --shadow: drop-shadow(0vmin 0vmin 0.5vmin rgba(0, 0, 0, 0.35))
60
+ drop-shadow(0vmin 1vmin 0.5vmin rgba(0, 0, 0, 0.09));
61
+ --cross: linear-gradient(
62
+ 0deg,
63
+ #fff0 calc(50% - 2px),
64
+ #000 calc(50% - 1px) calc(50% + 1px),
65
+ #fff0 calc(50% + 2px)
66
+ ),
67
+ linear-gradient(
68
+ 90deg,
69
+ #fff0 calc(50% - 2px),
70
+ #000 calc(50% - 1px) calc(50% + 1px),
71
+ #fff0 calc(50% + 2px)
72
+ );
56
73
  border: 6vmin solid var(--ar);
57
74
  width: var(--in);
58
75
  height: var(--in);
@@ -64,7 +81,8 @@ const text = ref<string>('Loading Online Viewer')
64
81
  top: 15vmin;
65
82
  right: -10vmin;
66
83
  animation: spin-bot var(--sp) ease 0s infinite;
67
- background-image: var(--cross), radial-gradient(var(--dt) 5.5vmin, #fff0 calc(5.5vmin + 1px));
84
+ background-image: var(--cross),
85
+ radial-gradient(var(--dt) 5.5vmin, #fff0 calc(5.5vmin + 1px));
68
86
  background-repeat: no-repeat;
69
87
  background-size: 3vmin 1vmin, 1vmin 3vmin, 100% 100%;
70
88
  background-position: center center;
@@ -76,7 +94,8 @@ const text = ref<string>('Loading Online Viewer')
76
94
  top: -2vmin;
77
95
  animation: spin-top var(--sp) ease 0s infinite;
78
96
  transform: rotate(-45deg);
79
- background-image: var(--cross), radial-gradient(var(--dt) 1.25vmin, #fff0 calc(1.25vmin + 1px));
97
+ background-image: var(--cross),
98
+ radial-gradient(var(--dt) 1.25vmin, #fff0 calc(1.25vmin + 1px));
80
99
  right: -4vmin;
81
100
  filter: hue-rotate(10deg) var(--shadow);
82
101
  background-size: 1.4vmin 1vmin, 1vmin 1.4vmin, 100% 100%;
@@ -88,7 +107,8 @@ const text = ref<string>('Loading Online Viewer')
88
107
  left: -13vmin;
89
108
  transform: rotate(175deg);
90
109
  animation: spin-left var(--sp) ease calc(var(--sp) / 4) infinite;
91
- background-image: var(--cross), radial-gradient(var(--dt) 9vmin, #fff0 calc(9vmin + 1px));
110
+ background-image: var(--cross),
111
+ radial-gradient(var(--dt) 9vmin, #fff0 calc(9vmin + 1px));
92
112
  filter: hue-rotate(20deg) var(--shadow);
93
113
  background-size: 5vmin 1vmin, 1vmin 5vmin, 100% 100%;
94
114
  }
@@ -98,8 +118,10 @@ const text = ref<string>('Loading Online Viewer')
98
118
  top: 35vmin;
99
119
  left: -6vmin;
100
120
  transform: rotate(-280deg);
101
- animation: spin-last var(--sp) ease calc(calc(calc(var(--sp) / 4) + var(--sp)) * -1) infinite;
102
- background-image: var(--cross), radial-gradient(var(--dt) 2.5vmin, #fff0 calc(2.5vmin + 1px));
121
+ animation: spin-last var(--sp) ease
122
+ calc(calc(calc(var(--sp) / 4) + var(--sp)) * -1) infinite;
123
+ background-image: var(--cross),
124
+ radial-gradient(var(--dt) 2.5vmin, #fff0 calc(2.5vmin + 1px));
103
125
  filter: hue-rotate(30deg) var(--shadow);
104
126
  background-size: 2vmin 1vmin, 1vmin 2vmin, 100% 100%;
105
127
  }
@@ -0,0 +1,44 @@
1
+ <script setup lang="ts">
2
+ import { computed } from "vue";
3
+
4
+ export interface Props {
5
+ modal: boolean;
6
+ }
7
+
8
+ const emit = defineEmits<{
9
+ "update:modal": [value: boolean];
10
+ }>();
11
+
12
+ const props = withDefaults(defineProps<Props>(), {
13
+ modal: false,
14
+ });
15
+
16
+ const modalState = computed({
17
+ get() {
18
+ return props.modal;
19
+ },
20
+ set(value) {
21
+ emit("update:modal", value);
22
+ },
23
+ });
24
+ </script>
25
+
26
+ <template>
27
+ <v-dialog v-model:model-value="modalState">
28
+ <v-card class="pa-1 ma-auto position-relative" max-width="450">
29
+ <v-card-title>Demo Instance</v-card-title>
30
+ <v-card-text>
31
+ This instance of 3Dicom Online Viewer is a Demo instance.
32
+ </v-card-text>
33
+ <v-card-text>
34
+ Please contact us if you would like to integrate this viewer into your
35
+ platform
36
+ </v-card-text>
37
+ <v-card-text> support@singular.health </v-card-text>
38
+ <v-card-actions>
39
+ <v-spacer />
40
+ <v-btn color="primary" @click="modalState = false"> Thanks! </v-btn>
41
+ </v-card-actions>
42
+ </v-card>
43
+ </v-dialog>
44
+ </template>
@@ -1,5 +1,6 @@
1
1
  <!-- /* c8 ignore start */ -->
2
2
  <template>
3
+ <DemoModal v-model:modal="m_demo" />
3
4
  <v-dialog
4
5
  id="cr-viewer"
5
6
  class="pa-0 ma-0 overflow-y-auto overflow-x-hidden"
@@ -11,7 +12,7 @@
11
12
  @input="alterValue"
12
13
  >
13
14
  <v-dialog
14
- v-model="m_closeDialog"
15
+ v-model:model-value="m_closeDialog"
15
16
  id="close-dialog-prompt"
16
17
  data-test="closemodal"
17
18
  >
@@ -59,41 +60,36 @@
59
60
  </template>
60
61
  <v-card class="">
61
62
  <v-list>
62
- <v-list-item disabled>
63
+ <v-list-item @click="executeOption('OnLoadNewDicomSeries')">
63
64
  <template v-slot:prepend>
64
65
  <v-icon> upload </v-icon>
65
66
  </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
- >
67
+ <v-list-item-title>Load New DICOM Series</v-list-item-title>
68
+ </v-list-item>
69
+ <v-list-item @click="executeOption('OnDownloadDicomSeries')">
70
+ <template v-slot:prepend>
71
+ <v-icon> download </v-icon>
72
+ </template>
73
+ <v-list-item-title>Download DICOM Series</v-list-item-title>
71
74
  </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>
75
+ <v-list-item @click="executeOption('OnLoadSavedSession')">
77
76
  <template v-slot:prepend>
78
77
  <v-icon> sync </v-icon>
79
78
  </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
- >
79
+ <v-list-item-title> Load Saved Session </v-list-item-title>
85
80
  </v-list-item>
86
- <v-list-item disabled>
81
+ <v-list-item @click="executeOption('OnShare')">
87
82
  <template v-slot:prepend>
88
83
  <v-icon> share </v-icon>
89
84
  </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
- >
85
+ <v-list-item-title>Share</v-list-item-title>
95
86
  </v-list-item>
96
- <v-list-item @click="alterValue(false)">
87
+ <v-list-item
88
+ @click="
89
+ executeOption('OnClosePopup');
90
+ alterValue(false);
91
+ "
92
+ >
97
93
  <template v-slot:prepend>
98
94
  <v-icon> close </v-icon>
99
95
  </template>
@@ -164,7 +160,9 @@
164
160
  </v-menu>
165
161
 
166
162
  <v-spacer />
167
- <div class="font-weight-bold">Not for Diagnostic Use</div>
163
+ <div class="font-weight-bold">
164
+ <span v-if="isDemo">[DEMO]&nbsp;</span>Not for Diagnostic Use
165
+ </div>
168
166
  <v-spacer />
169
167
  <v-btn
170
168
  class="ma-1 mr-0 pa-1"
@@ -427,6 +425,7 @@
427
425
  :class="!(instanceLoaded && !scanLoading) && 'no-pointer-events'"
428
426
  v-if="value"
429
427
  ref="web_gl"
428
+ id="webgl-container"
430
429
  @on_payload="handleOnPayload"
431
430
  @instance_loaded="load"
432
431
  @hover="hoverOverCanvas"
@@ -442,6 +441,7 @@
442
441
  ? 'grab !important'
443
442
  : 'default',
444
443
  }"
444
+ :data-box-internal="layout.DefaultView"
445
445
  >
446
446
  <v-hover>
447
447
  <template v-slot:default="{ isHovering, props }">
@@ -632,10 +632,7 @@
632
632
  </div>
633
633
 
634
634
  <LoadingSpinner v-if="!instanceLoaded" />
635
- <LoadingSpinner
636
- v-if="scanLoading"
637
- text="Rendering your scan in <span class='sub-type'>3DICOM</span>"
638
- />
635
+ <LoadingSpinner v-if="scanLoading" text="Rendering your scan in 3D" />
639
636
  <v-textarea
640
637
  v-if="stateOverlay"
641
638
  style="
@@ -683,11 +680,18 @@ import {
683
680
  InitialScanState,
684
681
  PositionData,
685
682
  ScanView,
683
+ InteractivityActions,
684
+ NotificationsActions,
685
+ NotificationPayload,
686
686
  } from "@3cr/types-ts";
687
687
 
688
688
  import { toNumber } from "@/helpers/utils";
689
689
  import { computed, ref, unref, watch, defineEmits, nextTick } from "vue";
690
- import { LoadViewerPayload } from "../../../index";
690
+ import {
691
+ defaultOptions,
692
+ LoadViewerOptions,
693
+ LoadViewerPayload,
694
+ } from "../../../index";
691
695
 
692
696
  const emit = defineEmits<{
693
697
  instanceLoaded: [void];
@@ -696,6 +700,7 @@ const emit = defineEmits<{
696
700
 
697
701
  export interface Props {
698
702
  payload?: LoadViewerPayload;
703
+ options?: LoadViewerOptions;
699
704
  }
700
705
 
701
706
  const props = withDefaults(defineProps<Props>(), {
@@ -706,7 +711,55 @@ const props = withDefaults(defineProps<Props>(), {
706
711
  Key: "OWjSMiL/ewUV1V6fGybhKcTyiysTPsIMp2DjdVoOUGI=",
707
712
  },
708
713
  }),
714
+ options: () => defaultOptions,
709
715
  });
716
+ const isDemo = ref<boolean>(false);
717
+ let m_demo = ref<boolean>(false);
718
+
719
+ const demoOptions: LoadViewerOptions = {
720
+ OnClosePopup: () => Promise.resolve(),
721
+ OnExitViewer: () => {
722
+ m_demo.value = true;
723
+ },
724
+ OnLoadNewDicomSeries: () => {
725
+ m_demo.value = true;
726
+ },
727
+ OnDownloadDicomSeries: () => {
728
+ m_demo.value = true;
729
+ },
730
+ OnLoadSavedSession: () => {
731
+ m_demo.value = true;
732
+ },
733
+ OnSaveSession: () => {
734
+ m_demo.value = true;
735
+ },
736
+ OnSendTo3rdParty: () => {
737
+ m_demo.value = true;
738
+ },
739
+ OnShareToMobile: () => {
740
+ m_demo.value = true;
741
+ },
742
+ OnShare: () => {
743
+ m_demo.value = true;
744
+ },
745
+ OnScreenshot: () => {
746
+ m_demo.value = true;
747
+ },
748
+ };
749
+
750
+ function executeOption(key: keyof LoadViewerOptions) {
751
+ if (unref(isDemo)) {
752
+ const functionToExecute = demoOptions[key];
753
+ if (functionToExecute !== undefined) {
754
+ functionToExecute();
755
+ }
756
+ } else {
757
+ const functionToExecute = unref(props.options)[key];
758
+ if (functionToExecute !== undefined) {
759
+ functionToExecute();
760
+ }
761
+ }
762
+ }
710
763
 
711
764
  const emptyPayload = { Version: "1.1.0" };
712
765
 
@@ -735,21 +788,19 @@ const footerItems = ref([
735
788
  text: "Send to 3rd Party",
736
789
  icon: "send",
737
790
  color: "blue",
738
- click: async () => alterValue(false),
791
+ click: async () => executeOption("OnSendTo3rdParty"),
739
792
  },
740
793
  {
741
794
  text: "Share to Mobile / VR",
742
795
  icon: "share",
743
796
  color: "yellow",
744
- click: async () => alterValue(false),
797
+ click: async () => executeOption("OnShareToMobile"),
745
798
  },
746
799
  {
747
800
  text: "Screenshot View",
748
801
  icon: "screenshot_region",
749
802
  color: "green",
750
- click: async () => {
751
- await snap();
752
- },
803
+ click: async () => executeOption("OnScreenshot"),
753
804
  },
754
805
  ]);
755
806
 
@@ -1021,11 +1072,16 @@ async function sliderHandler(action: string, value: number) {
1021
1072
  function closeModal() {
1022
1073
  m_closeDialog.value = false;
1023
1074
  value.value = false;
1075
+ executeOption("OnExitViewer");
1024
1076
  }
1025
1077
  function alterValue(val: boolean) {
1026
1078
  if (!val) {
1027
1079
  m_closeDialog.value = true;
1028
1080
  return;
1081
+ } else {
1082
+ isDemo.value =
1083
+ props.payload.Url ===
1084
+ "https://webgl-3dr.singular.health/test_scans/01440d4e-8b04-4b90-bb2c-698535ce16d6/CHEST.3vxl";
1029
1085
  }
1030
1086
 
1031
1087
  value.value = val;
@@ -1118,21 +1174,50 @@ async function i_fileManagement(action: string, message: string) {
1118
1174
  drawerCollapsed.value = false;
1119
1175
  await hoverOverCanvas(false);
1120
1176
  }
1177
+
1178
+ import { useNotification } from "@kyvg/vue3-notification";
1179
+
1180
+ const { notify } = useNotification();
1181
+
1121
1182
  async function i_notifications(action: string, message: string) {
1122
- // const obj = JSON.parse(message);
1123
- // console.log(obj);
1124
- //{\"Version\":\"1.0.0\",\"Interface\":\"interactivity\",\"Action\":\"in_01\",\"Code\":\"0000\",\"Description\":\"\"}"
1125
- // if (obj.Description) {
1126
- // if (action === NotificationActions.no01) {
1127
- // await NotificationService.Instantiate().notificationSuccess(obj.Description);
1128
- // }
1129
- // if (action === NotificationActions.no02) {
1130
- // await NotificationService.Instantiate().notificationError(obj.Description);
1131
- // }
1132
- // if (action === NotificationActions.no03) {
1133
- // await NotificationService.Instantiate().notificationWarning(obj.Description);
1134
- // }
1135
- // }
1183
+ const notification = JSON.parse(message) as NotificationPayload;
1184
+
1185
+ switch (notification.Action) {
1186
+ case InteractivityActions.in01:
1187
+ case InteractivityActions.in02:
1188
+ case InteractivityActions.in03:
1189
+ case InteractivityActions.in04:
1190
+ return;
1191
+ default:
1192
+ }
1193
+ if (notification.Action.startsWith("sl")) return;
1194
+
1195
+ let type = "success";
1196
+ switch (action) {
1197
+ // Muting no01
1198
+ case NotificationsActions.no01:
1199
+ type = "success";
1200
+ return;
1201
+
1202
+ case NotificationsActions.no02:
1203
+ type = "warn";
1204
+ break;
1205
+
1206
+ case NotificationsActions.no03:
1207
+ type = "error";
1208
+ break;
1209
+
1210
+ // Muting no04
1211
+ case NotificationsActions.no04:
1212
+ type = "info";
1213
+ return;
1214
+ }
1215
+
1216
+ notify({
1217
+ title: notification.Code,
1218
+ text: notification.Action,
1219
+ type,
1220
+ });
1136
1221
  }
1137
1222
  const isLayout2x2 = computed(() => {
1138
1223
  return (
@@ -5,11 +5,13 @@
5
5
  */
6
6
 
7
7
  // Plugins
8
- import vuetify from './vuetify'
8
+ import vuetify from "./vuetify";
9
9
 
10
10
  // Types
11
- import type { App } from 'vue'
11
+ import type { App } from "vue";
12
+ import Notifications from "@kyvg/vue3-notification";
12
13
 
13
- export function registerPlugins (app: App) {
14
- app.use(vuetify)
14
+ export function registerPlugins(app: App) {
15
+ app.use(vuetify);
16
+ app.use(Notifications);
15
17
  }