@3cr/viewer-browser 0.0.15 → 0.0.18

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/index.html CHANGED
@@ -3,7 +3,7 @@
3
3
 
4
4
  <head>
5
5
  <meta charset="UTF-8" />
6
- <link rel="icon" href="/favicon.ico" />
6
+ <link rel="icon" href="/playground/favicon.ico" />
7
7
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
8
8
  <title>Welcome to Vuetify 3</title>
9
9
  </head>
@@ -13,7 +13,7 @@
13
13
  <script type="module">
14
14
  import {registerViewer, loadViewer} from './index.ts';
15
15
 
16
- registerViewer('1.0.0_234', '#app').then(() => {
16
+ registerViewer('1.0.0', '#app').then(() => {
17
17
  loadViewer().then()
18
18
  })
19
19
  </script>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@3cr/viewer-browser",
3
- "version": "0.0.15",
3
+ "version": "0.0.18",
4
4
  "main": "./dist/Viewer3CR.umd.js",
5
5
  "module": "dist/Viewer3CR.umd.js",
6
6
  "homepage": "https://docs.3cr.singular.health",
@@ -14,6 +14,8 @@
14
14
  "deploy": "npm version --no-git-tag-version patch && npm run build && npm publish",
15
15
  "preview": "vite preview",
16
16
  "test": "vitest",
17
+ "compile:scripts": "tsc --project tsconfig.build-scripts.json",
18
+ "deploy:playground": "npm run compile:scripts && node scripts/postPublish.js",
17
19
  "coverage": "vitest run --coverage"
18
20
  },
19
21
  "dependencies": {
@@ -29,7 +31,10 @@
29
31
  "@types/node": "^20.11.25",
30
32
  "@vitejs/plugin-vue": "^5.0.4",
31
33
  "@vue/test-utils": "^2.4.1",
34
+ "aws-sdk": "^2.1594.0",
32
35
  "material-design-icons-iconfont": "^6.7.0",
36
+ "mime-types": "^2.1.35",
37
+ "randomstring": "^1.3.0",
33
38
  "sass": "^1.71.1",
34
39
  "typescript": "^5.4.2",
35
40
  "unplugin-fonts": "^1.1.1",
Binary file
@@ -0,0 +1,21 @@
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+
4
+ <head>
5
+ <meta charset="UTF-8" />
6
+ <link rel="icon" href="/favicon.ico" />
7
+ <script src="https://cdn.jsdelivr.net/npm/@3cr/viewer-browser"> </script>
8
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
9
+ <title>3CR Viewer Playground</title>
10
+ </head>
11
+
12
+ <body>
13
+ <div id="app"></div>
14
+ <script type="module">
15
+ window.registerViewer('1.0.0', '#app').then(() => {
16
+ window.loadViewer().then()
17
+ })
18
+ </script>
19
+ </body>
20
+
21
+ </html>
@@ -0,0 +1,2 @@
1
+ declare module 'randomstring';
2
+ declare module 'mime-types';
@@ -0,0 +1,92 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ // import { CloudFront, S3 } from 'aws-sdk';
7
+ const randomstring_1 = require("randomstring");
8
+ const path_1 = require("path");
9
+ const mime_types_1 = require("mime-types");
10
+ const fs_1 = require("fs");
11
+ const aws_sdk_1 = __importDefault(require("aws-sdk"));
12
+ const { CloudFront, S3 } = aws_sdk_1.default;
13
+ //Note: Config is injected in CI now. (leaving this for in case we need to do a local)
14
+ // import dotenv from 'dotenv';
15
+ // dotenv.config();
16
+ const { DIST_NAME, AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, BUCKET_NAME } = process.env;
17
+ if (!AWS_ACCESS_KEY_ID || !AWS_SECRET_ACCESS_KEY)
18
+ throw Error('Please define environment variables for AWS');
19
+ if (!DIST_NAME)
20
+ throw Error('Please define environment variables for DIST_NAME');
21
+ const DistributionName = DIST_NAME;
22
+ const BucketName = BUCKET_NAME;
23
+ const s3 = new S3({
24
+ region: 'ap-southeast-2',
25
+ });
26
+ const cloudfront = new CloudFront();
27
+ async function uploadDir(s3Path) {
28
+ for (const name of (0, fs_1.readdirSync)(s3Path)) {
29
+ const filePath = (0, path_1.join)(s3Path, name);
30
+ const stat = (0, fs_1.statSync)(filePath);
31
+ if (stat.isFile()) {
32
+ if (!filePath.endsWith('.map'))
33
+ await executeUpload(s3Path, filePath);
34
+ }
35
+ else if (stat.isDirectory()) {
36
+ await uploadDir(filePath);
37
+ }
38
+ }
39
+ }
40
+ async function executeUpload(s3Path, filePath) {
41
+ const parentDir = s3Path.includes('/')
42
+ ? s3Path.substring(0, s3Path.indexOf('/'))
43
+ : s3Path;
44
+ const bucketPath = filePath.substring(parentDir.length + 1);
45
+ const options = {
46
+ Bucket: BucketName,
47
+ Key: `${bucketPath}`,
48
+ Body: (0, fs_1.readFileSync)(filePath),
49
+ };
50
+ if (typeof (0, mime_types_1.lookup)(bucketPath) === 'string') {
51
+ options.ContentType = (0, mime_types_1.lookup)(bucketPath);
52
+ }
53
+ await s3.putObject(options).promise();
54
+ }
55
+ async function deployToAws() {
56
+ const listObjectsParams = {
57
+ Bucket: BucketName,
58
+ Prefix: ``
59
+ };
60
+ const listObjectsResponse = await s3
61
+ .listObjectsV2(listObjectsParams)
62
+ .promise();
63
+ if (listObjectsResponse.Contents && listObjectsResponse.Contents.length > 0) {
64
+ const deleteParams = {
65
+ Bucket: BucketName,
66
+ Delete: {
67
+ Objects: listObjectsResponse.Contents?.map((x) => ({
68
+ Key: x.Key || '',
69
+ })).filter((x) => x.Key !== '') || [],
70
+ },
71
+ };
72
+ await s3.deleteObjects(deleteParams).promise();
73
+ }
74
+ await uploadDir('playground');
75
+ const reference = (0, randomstring_1.generate)(16);
76
+ const params = {
77
+ DistributionId: DistributionName,
78
+ InvalidationBatch: {
79
+ CallerReference: reference,
80
+ Paths: {
81
+ Quantity: 1,
82
+ Items: ['/*'],
83
+ },
84
+ },
85
+ };
86
+ console.log(`Creating Invalidation for (${DistributionName}): ${reference}`);
87
+ const invalidation = await cloudfront.createInvalidation(params).promise();
88
+ console.log(invalidation);
89
+ }
90
+ deployToAws()
91
+ .then((data) => console.log(data))
92
+ .catch((err) => console.error(err));
@@ -0,0 +1,104 @@
1
+ // import { CloudFront, S3 } from 'aws-sdk';
2
+ import { generate } from 'randomstring';
3
+ import { join } from 'path';
4
+ import { lookup } from 'mime-types';
5
+ import { readdirSync, statSync, readFileSync } from 'fs';
6
+ import pkg from 'aws-sdk';
7
+ const { CloudFront, S3 } = pkg;
8
+
9
+ import { CreateInvalidationRequest } from 'aws-sdk/clients/cloudfront';
10
+ import {DeleteObjectsRequest, ListObjectsV2Request, PutObjectRequest } from 'aws-sdk/clients/s3';
11
+
12
+ //Note: Config is injected in CI now. (leaving this for in case we need to do a local)
13
+ // import dotenv from 'dotenv';
14
+ // dotenv.config();
15
+
16
+ const { DIST_NAME, AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, BUCKET_NAME } = process.env;
17
+
18
+ if (!AWS_ACCESS_KEY_ID || !AWS_SECRET_ACCESS_KEY) throw Error('Please define environment variables for AWS');
19
+ if (!DIST_NAME) throw Error('Please define environment variables for DIST_NAME');
20
+
21
+
22
+ const DistributionName = DIST_NAME as string;
23
+ const BucketName = BUCKET_NAME as string;
24
+ const s3 = new S3({
25
+ region: 'ap-southeast-2',
26
+ });
27
+ const cloudfront = new CloudFront();
28
+
29
+ async function uploadDir(s3Path: string) {
30
+ for (const name of readdirSync(s3Path)) {
31
+ const filePath = join(s3Path, name);
32
+ const stat = statSync(filePath);
33
+
34
+ if (stat.isFile()) {
35
+ if (!filePath.endsWith('.map')) await executeUpload(s3Path, filePath);
36
+ } else if (stat.isDirectory()) {
37
+ await uploadDir(filePath);
38
+ }
39
+ }
40
+ }
41
+ async function executeUpload(s3Path: string, filePath: string) {
42
+ const parentDir = s3Path.includes('/')
43
+ ? s3Path.substring(0, s3Path.indexOf('/'))
44
+ : s3Path;
45
+ const bucketPath = filePath.substring(parentDir.length + 1);
46
+ const options: PutObjectRequest = {
47
+ Bucket: BucketName,
48
+ Key: `${bucketPath}`,
49
+ Body: readFileSync(filePath),
50
+ };
51
+ if (typeof lookup(bucketPath) === 'string') {
52
+ options.ContentType = lookup(bucketPath) as string;
53
+ }
54
+
55
+ await s3.putObject(options).promise();
56
+ }
57
+
58
+ async function deployToAws() {
59
+ const listObjectsParams: ListObjectsV2Request = {
60
+ Bucket: BucketName,
61
+ Prefix: ``
62
+ };
63
+
64
+ const listObjectsResponse = await s3
65
+ .listObjectsV2(listObjectsParams)
66
+ .promise();
67
+
68
+ if (listObjectsResponse.Contents && listObjectsResponse.Contents.length > 0) {
69
+ const deleteParams: DeleteObjectsRequest = {
70
+ Bucket: BucketName,
71
+ Delete: {
72
+ Objects:
73
+ listObjectsResponse.Contents?.map((x) => ({
74
+ Key: x.Key || '',
75
+ })).filter((x) => x.Key !== '') || [],
76
+ },
77
+ };
78
+ await s3.deleteObjects(deleteParams).promise();
79
+ }
80
+
81
+ await uploadDir('playground');
82
+
83
+ const reference = generate(16);
84
+ const params: CreateInvalidationRequest = {
85
+ DistributionId: DistributionName,
86
+ InvalidationBatch: {
87
+ CallerReference: reference,
88
+ Paths: {
89
+ Quantity: 1,
90
+ Items: ['/*'],
91
+ },
92
+ },
93
+ };
94
+ console.log(`Creating Invalidation for (${DistributionName}): ${reference}`);
95
+
96
+ const invalidation = await cloudfront.createInvalidation(params).promise();
97
+ console.log(invalidation);
98
+ }
99
+
100
+ deployToAws()
101
+ .then((data) => console.log(data))
102
+ .catch((err) => console.error(err));
103
+
104
+
package/src/App.vue CHANGED
@@ -11,10 +11,10 @@ import {ref, unref} from "vue";
11
11
  import {LoadViewerPayload} from "../index";
12
12
 
13
13
  const payload = ref<LoadViewerPayload>({
14
- Url:"https://webgl-3dr.singular.health/test_scans/8bdddee1-e581-485d-827d-6aa12eef2fc8/Head+Axial+Axial.3vxl",
14
+ Url:"https://webgl-3dr.singular.health/test_scans/01440d4e-8b04-4b90-bb2c-698535ce16d6/CHEST.3vxl",
15
15
  DecryptionKey:{
16
- Iv:"x856FgjpYDsRhIa3BFj5cg==",
17
- Key:"OWjSMiL/ewUV1V6fGybhKcTyiysTPsIMp2DjdVoOUGI="
16
+ Iv:"XEloSh+OcO7TG77au6HjPw==",
17
+ Key:"KUc722X1y4w42M+jCf9a3+6EGz66z7UMWK3m2aMqGxM="
18
18
  }
19
19
  });
20
20
  const mftpWebGL3DRModal = ref<typeof MftpWebGL3DRModal | null>(null)
@@ -3,12 +3,12 @@ import {computed, defineEmits, ref, unref, watch} from 'vue';
3
3
 
4
4
  export interface Props {
5
5
  value: Array<number>;
6
- loading: boolean;
7
- label: string;
8
- lower: number;
9
- upper: number;
10
- min: number;
11
- max: number;
6
+ loading?: boolean;
7
+ label?: string;
8
+ lower?: number;
9
+ upper?: number;
10
+ min?: number;
11
+ max?: number;
12
12
  }
13
13
 
14
14
  const props = withDefaults(defineProps<Props>(), {
@@ -22,8 +22,9 @@ const props = withDefaults(defineProps<Props>(), {
22
22
  });
23
23
 
24
24
  const emit = defineEmits<{
25
- input: [Array<number>];
25
+ 'update:value': [Array<number>];
26
26
  }>();
27
+
27
28
  const prevValue = ref<Array<number>>([])
28
29
  const showThumb = ref<"always" | boolean>(false)
29
30
  const showThumbTimeout = ref<number>(0)
@@ -32,7 +33,7 @@ const sliderValue = computed({
32
33
  return props.value
33
34
  },
34
35
  set(value: Array<number>) {
35
- emit('input', value);
36
+ emit('update:value', value);
36
37
  }
37
38
  })
38
39
 
@@ -26,22 +26,27 @@
26
26
  class="pa-0 ma-0 position-relative motif-background overflow-y-hidden rounded-0"
27
27
  height="100vh"
28
28
  >
29
- <v-toolbar dense>
29
+ <v-toolbar dense height="48">
30
30
  <v-menu :close-on-content-click="false" :close-on-click="true" open-on-hover offset-y>
31
31
  <template #activator="{ props, isActive }">
32
32
  <v-btn
33
33
  v-bind="props"
34
+ variant="flat"
34
35
  :color="isActive ? 'secondary' : 'primary'"
35
- class="ma-1 ml-n1 pa-1"
36
+ class="mr-2"
36
37
  >
37
- <v-icon>description</v-icon> File
38
+ <template #prepend>
39
+ <v-icon>description</v-icon>
40
+ </template>
41
+ File
38
42
  </v-btn>
39
43
  </template>
40
44
  <v-card class="">
41
45
  <v-list>
42
- <v-list-item-group>
43
46
  <v-list-item disabled>
44
- <v-list-item-icon><v-icon> upload </v-icon></v-list-item-icon>
47
+ <template v-slot:prepend>
48
+ <v-icon> upload </v-icon>
49
+ </template>
45
50
  <v-list-item-title
46
51
  >Load New DICOM Series&nbsp;<v-chip x-small color="success">Coming Soon</v-chip></v-list-item-title
47
52
  >
@@ -51,51 +56,60 @@
51
56
  <!-- <v-list-item-title>Download DICOM Series</v-list-item-title>-->
52
57
  <!-- </v-list-item>-->
53
58
  <v-list-item disabled>
54
- <v-list-item-icon><v-icon> sync </v-icon></v-list-item-icon>
59
+ <template v-slot:prepend>
60
+ <v-icon> sync </v-icon>
61
+ </template>
55
62
  <v-list-item-title
56
63
  >Load Saved Session&nbsp;<v-chip x-small color="success">Coming Soon</v-chip></v-list-item-title
57
64
  >
58
65
  </v-list-item>
59
66
  <v-list-item disabled>
60
- <v-list-item-icon><v-icon> share </v-icon></v-list-item-icon>
67
+ <template v-slot:prepend>
68
+ <v-icon> share </v-icon>
69
+ </template>
61
70
  <v-list-item-title>Share&nbsp;<v-chip x-small color="success">Coming Soon</v-chip></v-list-item-title>
62
71
  </v-list-item>
63
72
  <v-list-item @click="alterValue(false)">
64
- <v-list-item-icon><v-icon> close </v-icon></v-list-item-icon>
73
+ <template v-slot:prepend>
74
+ <v-icon> close </v-icon>
75
+ </template>
65
76
  <v-list-item-title>Close Viewer</v-list-item-title>
66
77
  </v-list-item>
67
- </v-list-item-group>
68
78
  </v-list>
69
79
  </v-card>
70
80
  </v-menu>
71
81
  <v-menu :close-on-content-click="false" :close-on-click="true" open-on-hover offset-y>
72
82
  <template #activator="{ props, isActive }">
73
- <v-btn v-bind="props" :color="isActive ? 'secondary' : 'primary'" class="">
74
- <v-icon>settings</v-icon> Settings
83
+ <v-btn
84
+ variant="flat"
85
+ v-bind="props" :color="isActive ? 'secondary' : 'primary'">
86
+ <template #prepend>
87
+ <v-icon>settings</v-icon>
88
+ </template>
89
+ Settings
75
90
  </v-btn>
76
91
  </template>
77
92
  <v-card min-width="400" class="pb-2">
78
- <v-card-subtitle>Viewer Settings</v-card-subtitle>
79
93
  <SliderSelector
80
- v-model="scanState.InteractionSettings.PanSensivitity"
94
+ v-model:value="scanState.InteractionSettings.PanSensivitity"
81
95
  :min="0"
82
96
  :max="100"
83
97
  label="Pan Sensitivity"
84
98
  />
85
99
  <SliderSelector
86
- v-model="scanState.InteractionSettings.ZoomSensitivity"
100
+ v-model:value="scanState.InteractionSettings.ZoomSensitivity"
87
101
  :min="0"
88
102
  :max="100"
89
103
  label="Zoom Sensitivity"
90
104
  />
91
105
  <SliderSelector
92
- v-model="scanState.InteractionSettings.RotateSensitivity"
106
+ v-model:value="scanState.InteractionSettings.RotateSensitivity"
93
107
  :min="0"
94
108
  :max="100"
95
109
  label="Rotate Sensitivity"
96
110
  />
97
111
  <SliderSelector
98
- v-model="scanState.InteractionSettings.CameraRotateSensitivity"
112
+ v-model:value="scanState.InteractionSettings.CameraRotateSensitivity"
99
113
  :min="0"
100
114
  :max="100"
101
115
  label="Camera Rotate Sensitivity"
@@ -130,18 +144,18 @@
130
144
  @click="layouts('lo_03')"
131
145
  ><v-icon style="rotate: -90deg">view_comfy</v-icon></v-btn
132
146
  >
133
- <v-btn class="ma-1 ml-1 pa-1 white--text mr-n1" color="red" @click="alterValue(false)">Close Viewer</v-btn>
147
+ <v-btn class="" variant="flat" color="red" @click="alterValue(false)">Close Viewer</v-btn>
134
148
  </v-toolbar>
135
149
  <v-navigation-drawer
136
150
  v-model="drawer"
137
151
  permanent
138
- :mini-variant="drawerCollapsed"
139
- mini-variant-width="68"
152
+ :rail="drawerCollapsed"
153
+ rail-width="68"
140
154
  style="opacity: 0.95; margin-top: 48px; height: calc(100vh - 40px)"
141
155
  absolute
142
156
  dark
143
157
  class="rounded-0 motif-background"
144
- width="300px"
158
+ width="300"
145
159
  >
146
160
  <template v-slot:prepend>
147
161
  <div class="d-flex align-center pb-1" :class="drawerCollapsed ? 'py-2' : 'pa-2'" @click="snap">
@@ -183,19 +197,18 @@
183
197
  :disabled="!(instanceLoaded && !scanLoading)"
184
198
  @click="item.click()"
185
199
  >
186
- <v-list-item-icon
187
- :class="[drawerCollapsed && 'mx-auto']"
188
- :style="drawerCollapsed && 'margin-left: 7px !important; margin-right: 7px !important;'"
189
- >
190
- <v-icon :large="drawerCollapsed" :color="item.color">
191
- {{ item.icon || 'radio_button_checked' }}
192
- </v-icon>
193
- </v-list-item-icon>
194
- <v-list-item-content v-if="!drawerCollapsed">
195
- <v-list-item-title>
196
- {{ item.text }}
197
- </v-list-item-title>
198
- </v-list-item-content>
200
+ <template v-slot:prepend>
201
+ <div
202
+ :class="[drawerCollapsed && 'mx-auto']"
203
+ :style="drawerCollapsed && 'margin-left: 7px !important; margin-right: 7px !important;'">
204
+ <v-icon :large="drawerCollapsed" :color="item.color">
205
+ {{ item.icon || 'radio_button_checked' }}
206
+ </v-icon>
207
+ </div>
208
+ </template>
209
+ <v-list-item-title v-if="!drawerCollapsed">
210
+ {{ item.text }}
211
+ </v-list-item-title>
199
212
  </v-list-item>
200
213
  </template>
201
214
  {{ item.text }}
@@ -236,12 +249,12 @@
236
249
  <ExpansionHeaderMiniMenu :mini-menu="miniMenu[0]" />
237
250
  <v-expansion-panel-text>
238
251
  <DoubleSliderSelector
239
- v-model="windowSlider"
252
+ v-model:value="windowSlider"
240
253
  label="Skin to Bone"
241
254
  :min="huMinMax.min"
242
255
  :max="huMinMax.max"
243
256
  />
244
- <DoubleSliderSelector v-model="thresholdSlider" label="Fine Adjustment" v-bind="huMinMax" />
257
+ <DoubleSliderSelector v-model:value="thresholdSlider" label="Fine Adjustment" v-bind="huMinMax" />
245
258
  <v-card-actions class="py-1">
246
259
  <v-select
247
260
  :value="getCurrentGreyscalePreset()"
@@ -307,9 +320,9 @@
307
320
  <v-expansion-panel class="transparent">
308
321
  <ExpansionHeaderMiniMenu :mini-menu="miniMenu[1]" />
309
322
  <v-expansion-panel-text>
310
- <SliderSelector v-model="scanState.Display.Brightness" label="Adjust Brightness" />
311
- <SliderSelector v-model="scanState.Display.Contrast" label="Adjust Contrast" />
312
- <SliderSelector v-model="scanState.Display.Opacity" label="Adjust Opacity" />
323
+ <SliderSelector v-model:value="scanState.Display.Brightness" label="Adjust Brightness" />
324
+ <SliderSelector v-model:value="scanState.Display.Contrast" label="Adjust Contrast" />
325
+ <SliderSelector v-model:value="scanState.Display.Opacity" label="Adjust Opacity" />
313
326
  </v-expansion-panel-text>
314
327
  </v-expansion-panel>
315
328
  </v-expansion-panels>
@@ -468,17 +481,17 @@
468
481
  <div class="slider-in-view" v-if="isHovering">
469
482
  <VerticalSliderSelector
470
483
  v-if="getCurrentActiveView(layout) === ScanView.Transverse"
471
- v-model="scanState.Orientations.Transverse.Slice"
484
+ v-model:value="scanState.Orientations.Transverse.Slice"
472
485
  v-bind="tMinMax"
473
486
  />
474
487
  <VerticalSliderSelector
475
488
  v-if="getCurrentActiveView(layout) === ScanView.Coronal"
476
- v-model="scanState.Orientations.Coronal.Slice"
489
+ v-model:value="scanState.Orientations.Coronal.Slice"
477
490
  v-bind="cMinMax"
478
491
  />
479
492
  <VerticalSliderSelector
480
493
  v-if="getCurrentActiveView(layout) === ScanView.Sagittal"
481
- v-model="scanState.Orientations.Sagittal.Slice"
494
+ v-model:value="scanState.Orientations.Sagittal.Slice"
482
495
  v-bind="sMinMax"
483
496
  />
484
497
  </div>
@@ -586,25 +599,22 @@ const footerItems = ref([
586
599
  text: 'Reset Scan',
587
600
  icon: 'refresh',
588
601
  color: 'red',
589
- click: () => {
590
- //@ts-ignore
591
- viewSelection('vs_05');
592
- //@ts-ignore
593
- viewSelection('vs_06');
602
+ click: async () => {
603
+ console.log('Reset Scan');
604
+ await viewSelection('vs_05');
605
+ await viewSelection('vs_06');
594
606
  },
595
607
  },
596
608
  {
597
609
  text: 'Send to 3rd Party',
598
610
  icon: 'send',
599
611
  color: 'blue',
600
- //@ts-ignore
601
612
  click: () => alterValue(false),
602
613
  },
603
614
  {
604
615
  text: 'Share to Mobile / VR',
605
616
  icon: 'share',
606
617
  color: 'yellow',
607
- //@ts-ignore
608
618
  click: () => alterValue(false),
609
619
  },
610
620
  {
@@ -612,7 +622,6 @@ const footerItems = ref([
612
622
  icon: 'screenshot_region',
613
623
  color: 'green',
614
624
  click: () => {
615
- //@ts-ignore
616
625
  snap();
617
626
  },
618
627
  },
@@ -762,18 +771,18 @@ watch(() => scanState.value.InteractionSettings.CameraRotateSensitivity, async (
762
771
  })
763
772
 
764
773
  function getIconForPreset(presetName: string): string | undefined {
765
- if (presetName === 'Bone') return 'fa-solid fa-bone';
766
- if (presetName === 'Brain') return 'fa-solid fa-brain';
767
- if (presetName === 'Liver') return '$liver_icon';
768
- if (presetName === 'Lungs') return 'fa-solid fa-lungs';
769
- if (presetName === 'Muscle') return '$muscle_icon';
770
- if (presetName === 'Temporal Bones') return '$temporal_bones_icon';
771
- if (presetName === 'Soft Tissue') return '$torso_icon';
772
- if (presetName === 'Skin') return '$skin_icon';
774
+ // if (presetName === 'Bone') return 'fa-solid fa-bone';
775
+ // if (presetName === 'Brain') return 'fa-solid fa-brain';
776
+ // if (presetName === 'Liver') return '$liver_icon';
777
+ // if (presetName === 'Lungs') return 'fa-solid fa-lungs';
778
+ // if (presetName === 'Muscle') return '$muscle_icon';
779
+ // if (presetName === 'Temporal Bones') return '$temporal_bones_icon';
780
+ // if (presetName === 'Soft Tissue') return '$torso_icon';
781
+ // if (presetName === 'Skin') return '$skin_icon';
773
782
  return undefined
774
783
  }
775
784
  async function rotateByDeg(view: ScanView, deg: number) {
776
- await sendPayload(FrontEndInterfaces.scan_orientation, ScanOrientationActions.so01, {
785
+ await (FrontEndInterfaces.scan_orientation, ScanOrientationActions.so01, {
777
786
  Version: '0.0.1',
778
787
  View: view,
779
788
  Angle: deg,
@@ -832,11 +841,11 @@ async function load() {
832
841
  await sendPayload('file_management', 'fm_01', props.payload);
833
842
  }
834
843
  async function viewSelection(action: string) {
835
- await sendPayload('view_selection', action, emptyPayload)
844
+ await sendPayload(FrontEndInterfaces.view_selection, action, emptyPayload)
836
845
  }
837
846
  async function layouts(action: string) {
838
847
  if (action !== 'lo_01') previousLayout.value = action;
839
- await sendPayload('layout', action, emptyPayload)
848
+ await sendPayload(FrontEndInterfaces.layout, action, emptyPayload)
840
849
  }
841
850
  async function snap() {
842
851
  // await unref(web_gl).snap();
@@ -1005,4 +1014,8 @@ function handleOnPayload(interfaceSet: string | FrontEndInterfaces, actionSet: s
1005
1014
  .buttons-in-view > div {
1006
1015
  display: inline-block;
1007
1016
  }
1017
+ .motif-background {
1018
+ background: url("data:image/svg+xml,%3Csvg width='992' height='560' viewBox='15 7 992 560' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Crect x='15' y='1' width='992' height='567' fill='url(%23paint0_linear_504_579)'/%3E%3Cg filter='url(%23filter0_i_504_579)'%3E%3Cpath d='M567.029 291.5C574.21 421.339 748.15 561 825.931 561H12L12.0001 0C153.713 0 580.363 0 580.363 0C684.258 142 560.918 181 567.029 291.5Z' fill='%231B2E43' fill-opacity='0.9'/%3E%3C/g%3E%3Cg filter='url(%23filter1_i_504_579)'%3E%3Cpath d='M435.911 260.5C462.579 433.5 652.034 561 729.815 561H12L12.0001 0C233.678 0 409.954 92.1126 435.911 260.5Z' fill='%231B2E43' fill-opacity='0.9'/%3E%3C/g%3E%3Cg filter='url(%23filter2_i_504_579)'%3E%3Ccircle cx='46' cy='521' r='93' fill='%231B2E43' fill-opacity='0.3'/%3E%3C/g%3E%3Cdefs%3E%3Cfilter id='filter0_i_504_579' x='12' y='0' width='858.931' height='606' filterUnits='userSpaceOnUse' color-interpolation-filters='sRGB'%3E%3CfeFlood flood-opacity='0' result='BackgroundImageFix'/%3E%3CfeBlend mode='normal' in='SourceGraphic' in2='BackgroundImageFix' result='shape'/%3E%3CfeColorMatrix in='SourceAlpha' type='matrix' values='0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0' result='hardAlpha'/%3E%3CfeOffset dx='45' dy='45'/%3E%3CfeGaussianBlur stdDeviation='50'/%3E%3CfeComposite in2='hardAlpha' operator='arithmetic' k2='-1' k3='1'/%3E%3CfeColorMatrix type='matrix' values='0 0 0 0 0.653125 0 0 0 0 0.761642 0 0 0 0 0.916667 0 0 0 0.15 0'/%3E%3CfeBlend mode='normal' in2='shape' result='effect1_innerShadow_504_579'/%3E%3C/filter%3E%3Cfilter id='filter1_i_504_579' x='12' y='0' width='762.815' height='606' filterUnits='userSpaceOnUse' color-interpolation-filters='sRGB'%3E%3CfeFlood flood-opacity='0' result='BackgroundImageFix'/%3E%3CfeBlend mode='normal' in='SourceGraphic' in2='BackgroundImageFix' result='shape'/%3E%3CfeColorMatrix in='SourceAlpha' type='matrix' values='0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0' result='hardAlpha'/%3E%3CfeOffset dx='45' dy='45'/%3E%3CfeGaussianBlur stdDeviation='50'/%3E%3CfeComposite in2='hardAlpha' operator='arithmetic' k2='-1' k3='1'/%3E%3CfeColorMatrix type='matrix' values='0 0 0 0 0.653125 0 0 0 0 0.761642 0 0 0 0 0.916667 0 0 0 0.25 0'/%3E%3CfeBlend mode='normal' in2='shape' result='effect1_innerShadow_504_579'/%3E%3C/filter%3E%3Cfilter id='filter2_i_504_579' x='-47' y='428' width='231' height='231' filterUnits='userSpaceOnUse' color-interpolation-filters='sRGB'%3E%3CfeFlood flood-opacity='0' result='BackgroundImageFix'/%3E%3CfeBlend mode='normal' in='SourceGraphic' in2='BackgroundImageFix' result='shape'/%3E%3CfeColorMatrix in='SourceAlpha' type='matrix' values='0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0' result='hardAlpha'/%3E%3CfeOffset dx='45' dy='45'/%3E%3CfeGaussianBlur stdDeviation='50'/%3E%3CfeComposite in2='hardAlpha' operator='arithmetic' k2='-1' k3='1'/%3E%3CfeColorMatrix type='matrix' values='0 0 0 0 0.653125 0 0 0 0 0.761642 0 0 0 0 0.916667 0 0 0 0.15 0'/%3E%3CfeBlend mode='normal' in2='shape' result='effect1_innerShadow_504_579'/%3E%3C/filter%3E%3ClinearGradient id='paint0_linear_504_579' x1='1251.04' y1='696.83' x2='21.486' y2='-10.2783' gradientUnits='userSpaceOnUse'%3E%3Cstop stop-color='%230E141D'/%3E%3Cstop offset='1' stop-color='%2323405E'/%3E%3C/linearGradient%3E%3C/defs%3E%3C/svg%3E%0A") !important;
1019
+ background-size: cover !important;
1020
+ }
1008
1021
  </style>