@abi-software/scaffoldvuer 0.1.4 → 0.1.5-1.beta.0

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.
@@ -1,94 +1,1469 @@
1
1
  <template>
2
- <div class="scaffold-container">
3
- <div style="height:100%;width:100%;position:relative">
4
- <div id="organsDisplayArea" style="height:100%;width:100%;" ref="display">
2
+ <div
3
+ ref="scaffoldContainer"
4
+ v-loading="loading"
5
+ class="scaffold-container"
6
+ element-loading-text="Loading..."
7
+ element-loading-spinner="el-icon-loading"
8
+ element-loading-background="rgba(0, 0, 0, 0.3)"
9
+ >
10
+ <SvgSpriteColor />
11
+ <div
12
+ id="organsDisplayArea"
13
+ ref="display"
14
+ tabindex="-1"
15
+ style="height:100%;width:100%;"
16
+ @keydown.66="backgroundChangeCallback"
17
+ />
18
+ <div v-show="displayUI && !isTransitioning">
19
+ <el-popover
20
+ v-if="displayWarning"
21
+ ref="warningPopover"
22
+ v-model="hoverVisabilities[6].value"
23
+ :content="warningMessage"
24
+ placement="right"
25
+ :append-to-body="false"
26
+ trigger="manual"
27
+ popper-class="warning-popper right-popper non-selectable"
28
+ />
29
+ <i
30
+ v-if="displayWarning"
31
+ v-popover:warningPopover
32
+ class="el-icon-warning warning-icon"
33
+ @mouseover="showToolitip(6)"
34
+ @mouseout="hideToolitip(6)"
35
+ >
36
+ <span class="warning-text">Beta</span>
37
+ </i>
38
+ <el-popover
39
+ ref="checkBoxPopover"
40
+ v-model="hoverVisabilities[5].value"
41
+ content="Change region visibility"
42
+ placement="right"
43
+ :append-to-body="false"
44
+ trigger="manual"
45
+ popper-class="scaffold-popper right-popper non-selectable"
46
+ />
47
+ <TraditionalControls
48
+ ref="traditionalControl"
49
+ v-popover:checkBoxPopover
50
+ :help-mode="helpMode"
51
+ :module="$module"
52
+ :show-colour-picker="showColourPicker"
53
+ @object-selected="objectSelected"
54
+ @object-hovered="objectHovered"
55
+ @drawer-toggled="drawerToggled"
56
+ />
57
+ <div class="opacity-box">
58
+ <OpacityControls ref="opacityControl" />
5
59
  </div>
6
- <div id="check-list">
7
- <button @click="viewAll">View all</button>
8
- <div v-for="item in sceneData.groups" v-bind:key="item">
9
- <input type="checkbox" :id="item" :value="item" @change="visibilityToggle(item, $event)" checked>
10
- <label :for="item">{{item}}</label>
11
- </div>
12
- <button v-if="isPlaying" @click="play(false)">Stop</button>
13
- <button v-else @click="play(true)">Play</button>
60
+ <el-popover
61
+ v-if="sceneData.timeVarying"
62
+ ref="sliderPopover"
63
+ v-model="hoverVisabilities[4].value"
64
+ content="Move the slider to animate the region"
65
+ placement="top"
66
+ :append-to-body="false"
67
+ trigger="manual"
68
+ popper-class="scaffold-popper top-popper non-selectable"
69
+ />
70
+ <div
71
+ v-if="sceneData.timeVarying"
72
+ v-popover:sliderPopover
73
+ class="time-slider-container"
74
+ :class="[ minimisedSlider ? 'minimised' : '', sliderPosition]"
75
+ >
76
+ <el-tabs type="card">
77
+ <el-tab-pane label="Animate scaffold">
78
+ <el-row class="tab-content">
79
+ <SvgIcon
80
+ v-if="isPlaying"
81
+ icon="pause"
82
+ class="icon-button video-button"
83
+ @click.native="play(false)"
84
+ />
85
+ <SvgIcon
86
+ v-else
87
+ icon="play"
88
+ class="video-button icon-button"
89
+ @click.native="play(true)"
90
+ />
91
+ <el-slider
92
+ :min="0"
93
+ :max="timeMax"
94
+ :value="sceneData.currentTime / 100 * timeMax"
95
+ :step="0.1"
96
+ tooltip-class="time-slider-tooltip"
97
+ class="slider"
98
+ :format-tooltip="formatTooltip"
99
+ :marks="timeStamps"
100
+ @input="timeChange($event)"
101
+ />
102
+ </el-row>
103
+ </el-tab-pane>
104
+ <el-tab-pane label="Animation data">
105
+ <el-row class="tab-content">
106
+ <div class="animation-data">
107
+ Original duration:
108
+ <div class="purple">
109
+ {{ orginalDuration }}
110
+ </div>
111
+ </div>
112
+ <div class="animation-data">
113
+ Animation duration:
114
+ <div class="purple">
115
+ {{ animateDuration }}
116
+ </div>
117
+ </div>
118
+ <div class="animation-data">
119
+ Playback speed
120
+ <el-select
121
+ :popper-append-to-body="true"
122
+ :value="currentSpeed"
123
+ placeholder="Select"
124
+ class="select-box"
125
+ popper-class="scaffold_viewer_dropdown"
126
+ @change="speedChanged($event)"
127
+ >
128
+ <el-option
129
+ v-for="item in playSpeed"
130
+ :key="item.value"
131
+ :label="item.label"
132
+ :value="item.value"
133
+ />
134
+ </el-select>
135
+ </div>
136
+ </el-row>
137
+ </el-tab-pane>
138
+ </el-tabs>
14
139
  </div>
15
- <input v-if="sceneData.timeVarying" id="timeSlider" type="range" min="0" max="100" :value="sceneData.currentTime" step="0.1" @input="timeChange($event)"/>
140
+ <div class="bottom-right-control">
141
+ <el-popover
142
+ v-model="hoverVisabilities[0].value"
143
+ content="Zoom in"
144
+ placement="left"
145
+ :append-to-body="false"
146
+ trigger="manual"
147
+ popper-class="scaffold-popper left-popper non-selectable"
148
+ >
149
+ <SvgIcon
150
+ slot="reference"
151
+ icon="zoomIn"
152
+ class="icon-button zoomIn"
153
+ @click.native="zoomIn()"
154
+ @mouseover.native="showToolitip(0)"
155
+ @mouseout.native="hideToolitip(0)"
156
+ />
157
+ </el-popover>
158
+ <el-popover
159
+ v-model="hoverVisabilities[1].value"
160
+ content="Zoom out"
161
+ placement="top-end"
162
+ :append-to-body="false"
163
+ trigger="manual"
164
+ popper-class="scaffold-popper popper-zoomout non-selectable"
165
+ >
166
+ <SvgIcon
167
+ slot="reference"
168
+ icon="zoomOut"
169
+ class="icon-button zoomOut"
170
+ @click.native="zoomOut()"
171
+ @mouseover.native="showToolitip(1)"
172
+ @mouseout.native="hideToolitip(1)"
173
+ />
174
+ </el-popover>
175
+ <el-popover
176
+ v-model="hoverVisabilities[2].value"
177
+ placement="top"
178
+ :append-to-body="false"
179
+ trigger="manual"
180
+ popper-class="scaffold-popper non-selectable"
181
+ >
182
+ <div>
183
+ Fit to
184
+ <br>
185
+ window
186
+ </div>
187
+ <SvgIcon
188
+ slot="reference"
189
+ icon="fitWindow"
190
+ class="icon-button fitWindow"
191
+ @click.native="fitWindow()"
192
+ @mouseover.native="showToolitip(2)"
193
+ @mouseout.native="hideToolitip(2)"
194
+ />
195
+ </el-popover>
196
+ </div>
197
+ <el-popover
198
+ ref="backgroundPopover"
199
+ placement="top-start"
200
+ width="128"
201
+ :append-to-body="false"
202
+ trigger="click"
203
+ popper-class="background-popper non-selectable"
204
+ >
205
+ <el-row class="backgroundText">
206
+ Change background
207
+ </el-row>
208
+ <el-row class="backgroundChooser">
209
+ <div
210
+ v-for="item in availableBackground"
211
+ :key="item"
212
+ :class="['backgroundChoice', item, item == currentBackground ? 'active' :'']"
213
+ @click="backgroundChangeCallback(item)"
214
+ />
215
+ </el-row>
216
+ </el-popover>
217
+ <el-popover
218
+ v-model="hoverVisabilities[3].value"
219
+ content="Change background color"
220
+ placement="right"
221
+ :append-to-body="false"
222
+ trigger="manual"
223
+ popper-class="scaffold-popper right-popper non-selectable"
224
+ >
225
+ <SvgIcon
226
+ slot="reference"
227
+ v-popover:backgroundPopover
228
+ icon="changeBckgd"
229
+ class="icon-button background-colour"
230
+ :class="{ open: drawerOpen, close: !drawerOpen }"
231
+ @mouseover.native="showToolitip(3)"
232
+ @mouseout.native="hideToolitip(3)"
233
+ />
234
+ </el-popover>
16
235
  </div>
17
236
  </div>
18
237
  </template>
19
238
 
20
239
  <script>
21
240
  /* eslint-disable no-alert, no-console */
22
- const OrgansViewer = require('physiomeportal/src/modules/organsRenderer').OrgansViewer;
23
- const EventNotifier = require("physiomeportal/src/utilities/eventNotifier").EventNotifier;
241
+ import Vue from "vue";
242
+ import OpacityControls from "./OpacityControls";
243
+ import TraditionalControls from "./TraditionalControls";
244
+ import { SvgIcon, SvgSpriteColor } from "@abi-software/svg-sprite";
24
245
 
25
- const eventNotifierCallback = function(component) {
26
- return function(event) {
27
- if (event.eventType == 1)
28
- component.$emit('scaffold-selected', event.identifiers);
29
- else if (event.eventType == 2)
30
- component.$emit('scaffold-highlighted', event.identifiers);
31
- }
32
- }
246
+ import {
247
+ Col,
248
+ Loading,
249
+ Option,
250
+ Popover,
251
+ Row,
252
+ Select,
253
+ Slider,
254
+ TabPane,
255
+ Tabs
256
+ } from "element-ui";
257
+ import lang from "element-ui/lib/locale/lang/en";
258
+ import locale from "element-ui/lib/locale";
259
+
260
+ locale.use(lang);
261
+ Vue.use(Col);
262
+ Vue.use(Loading.directive);
263
+ Vue.use(Option);
264
+ Vue.use(Popover);
265
+ Vue.use(Row);
266
+ Vue.use(Select);
267
+ Vue.use(Slider);
268
+ Vue.use(TabPane);
269
+ Vue.use(Tabs);
33
270
 
271
+ const OrgansViewer = require("physiomeportal/src/modules/organsRenderer")
272
+ .OrgansViewer;
273
+ const EventNotifier = require("physiomeportal/src/utilities/eventNotifier")
274
+ .EventNotifier;
275
+
276
+ /**
277
+ * A vue component of the scaffold viewer.
278
+ *
279
+ * @requires ./OpacityControls.vue
280
+ * @requires ./TraditionalControls.vue
281
+ */
34
282
  export default {
35
- name: 'ScaffoldVuer',
283
+ name: "ScaffoldVuer",
284
+ components: {
285
+ OpacityControls,
286
+ SvgIcon,
287
+ SvgSpriteColor,
288
+ TraditionalControls
289
+ },
290
+ props: {
291
+ /**
292
+ * URL of the zincjs metadata. This value will be ignored if a valid
293
+ * state prop is also provided.
294
+ * If the url needs to be updated with state present, please use
295
+ * the setURL method.
296
+ */
297
+ url: {
298
+ type: String,
299
+ default: ""
300
+ },
301
+ /**
302
+ * Show the colour control of set to true.
303
+ */
304
+ showColourPicker: {
305
+ type: Boolean,
306
+ default: false
307
+ },
308
+ /**
309
+ * Flag to show/hide the UI.
310
+ */
311
+ displayUI: {
312
+ type: Boolean,
313
+ default: true
314
+ },
315
+ /**
316
+ * Display all graphics at start.
317
+ *
318
+ * This setting only works when traditional is set to false.
319
+ */
320
+ displayAtStartUp: {
321
+ type: Boolean,
322
+ default: true
323
+ },
324
+ /**
325
+ * Use for toggling the help tooltips.
326
+ */
327
+ helpMode: {
328
+ type: Boolean,
329
+ default: false
330
+ },
331
+ /**
332
+ * Use for show/display beta warning icon.
333
+ */
334
+ displayWarning: {
335
+ type: Boolean,
336
+ default: true
337
+ },
338
+ /**
339
+ * Warning message for the hovered over text
340
+ * on the warning icon.
341
+ */
342
+ warningMessage: {
343
+ type: String,
344
+ default: "Beta feature - under active development"
345
+ },
346
+ /**
347
+ * Show/hide pickable markers for regions.
348
+ */
349
+ displayMarkers: {
350
+ type: Boolean,
351
+ default: true
352
+ },
353
+ /**
354
+ * Show/hide minimap.
355
+ */
356
+ displayMinimap: {
357
+ type: Boolean,
358
+ default: false
359
+ },
360
+ /**
361
+ * Settings for minimap position, size and alignment.
362
+ */
363
+ minimapSettings: {
364
+ type: Object,
365
+ default: function() {
366
+ return {
367
+ x_offset: 16,
368
+ y_offset: 16,
369
+ width: 128,
370
+ height: 128,
371
+ align: "top-right"
372
+ };
373
+ }
374
+ },
375
+ /**
376
+ * State containing state of the scaffold.
377
+ */
378
+ state: {
379
+ type: Object,
380
+ default: undefined
381
+ },
382
+ /**
383
+ * Optional prop for the name of the region to focus on,
384
+ * this option is ignored if state or viewURL is also provided.
385
+ */
386
+ region: {
387
+ type: String,
388
+ default: ""
389
+ },
390
+ /**
391
+ * Optional prop for an URL of containing information of a viewport.
392
+ * This option is ignored if state is also provided.
393
+ * It will use the provided URL as base if a relative parth is provided.
394
+ */
395
+ viewURL: {
396
+ type: String,
397
+ default: ""
398
+ },
399
+ /**
400
+ * Settings for turning on/off rendering
401
+ */
402
+ render: {
403
+ type: Boolean,
404
+ default: true
405
+ }
406
+ },
407
+ data: function() {
408
+ return {
409
+ sceneData: this.$module.sceneData,
410
+ isPlaying: false,
411
+ /**
412
+ * This is set when scene is transitioning.
413
+ */
414
+ isTransitioning: false,
415
+ tooltipAppendToBody: false,
416
+ hoverVisabilities: [
417
+ { value: false },
418
+ { value: false },
419
+ { value: false },
420
+ { value: false },
421
+ { value: false },
422
+ { value: false },
423
+ { value: false }
424
+ ],
425
+ inHelp: false,
426
+ loading: false,
427
+ duration: 3000,
428
+ drawerOpen: true,
429
+ currentBackground: "white",
430
+ availableBackground: ["white", "lightskyblue", "black"],
431
+ minimisedSlider: false,
432
+ sliderPosition: "",
433
+ timeMax: 100,
434
+ orginalDuration: "",
435
+ animateDuration: "6secs",
436
+ playSpeed: [
437
+ {
438
+ value: 0.1,
439
+ label: "0.1x"
440
+ },
441
+ {
442
+ value: 0.5,
443
+ label: "0.5x"
444
+ },
445
+ {
446
+ value: 1,
447
+ label: "1x"
448
+ },
449
+ {
450
+ value: 2,
451
+ label: "2x"
452
+ },
453
+ {
454
+ value: 5,
455
+ label: "5x"
456
+ },
457
+ {
458
+ value: 10,
459
+ label: "10x"
460
+ }
461
+ ],
462
+ currentSpeed: 1,
463
+ timeStamps: {}
464
+ };
465
+ },
466
+ watch: {
467
+ url: {
468
+ handler: function(newValue) {
469
+ if (this.state === undefined || this.state.url === undefined)
470
+ this.setURL(newValue);
471
+ },
472
+ immediate: true
473
+ },
474
+ region: {
475
+ handler: function(region) {
476
+ if (!(this.state || this.viewURL)) this.setFocusedRegion(region);
477
+ },
478
+ immediate: true
479
+ },
480
+ state: {
481
+ handler: function(state) {
482
+ this.setState(state);
483
+ },
484
+ immediate: true,
485
+ deep: true
486
+ },
487
+ viewURL: {
488
+ handler: function(viewURL) {
489
+ this.updateViewURL(viewURL);
490
+ },
491
+ immediate: true
492
+ },
493
+ helpMode: function(val) {
494
+ this.setHelpMode(val);
495
+ },
496
+ displayMarkers: function(val) {
497
+ this.$module.scene.displayMarkers = val;
498
+ },
499
+ displayMinimap: function(val) {
500
+ this.$module.scene.displayMinimap = val;
501
+ },
502
+ "sceneData.currentTime": function() {
503
+ /**
504
+ * Triggers when scene time changes.
505
+ *
506
+ * @property {number} time Current build-in time of scene.
507
+ * of selected object.
508
+ */
509
+ this.$emit("timeChanged", this.sceneData.currentTime);
510
+ },
511
+ duration: function() {
512
+ this.$module.scene.setDuration(this.duration);
513
+ },
514
+ minimapSettings: {
515
+ deep: true,
516
+ handler: "updateMinimapScissor"
517
+ },
518
+ render: function(val) {
519
+ this.toggleRendering(val);
520
+ }
521
+ },
36
522
  beforeCreate: function() {
37
- let eventNotifier = new EventNotifier();
38
- eventNotifier.subscribe(this, eventNotifierCallback(this));
39
523
  this.$module = new OrgansViewer();
524
+ this.isReady = false;
525
+ this.selectedObject = undefined;
526
+ this.hoveredObject = undefined;
527
+ this.currentBackground = "white";
528
+ this._currentURL = undefined;
529
+ this.availableBackground = ["white", "black", "lightskyblue"];
530
+ },
531
+ mounted: function() {
532
+ let eventNotifier = new EventNotifier();
533
+ eventNotifier.subscribe(this, this.eventNotifierCallback);
40
534
  this.$module.addNotifier(eventNotifier);
535
+ this.$module.addOrganPartAddedCallback(this.organsAdded);
536
+ this.$module.initialiseRenderer(this.$refs.display);
537
+ this.toggleRendering(this.render);
538
+ this.$module.toolTip = undefined;
539
+ this.ro = new ResizeObserver(this.adjustLayout).observe(
540
+ this.$refs.scaffoldContainer
541
+ );
542
+ this.defaultRate = this.$module.getPlayRate();
543
+ },
544
+ beforeDestroy: function() {
545
+ if (this.ro) this.ro.disconnect();
546
+ this.$module.destroy();
547
+ this.$module = undefined;
41
548
  },
42
549
  methods: {
43
- viewAll: function() {
44
- this.$module.viewAll();
550
+ /**
551
+ * This is called when a new organ is read into the scene.
552
+ */
553
+ organsAdded: function() {
554
+ this.loading = false;
555
+ },
556
+ /**
557
+ * This is called when Change backgspeedround colour button
558
+ * is pressed an causes the backgrouColornd colour to be changed
559
+ * to one of the three preset colour: white, black and
560
+ * lightskyblue.
561
+ */
562
+ backgroundChangeCallback: function(colour) {
563
+ this.currentBackground = colour;
564
+ this.$module.zincRenderer
565
+ .getThreeJSRenderer()
566
+ .setClearColor(this.currentBackground, 1);
567
+ },
568
+ /**
569
+ * This is called by captueeScreenshot and after the last render
570
+ * loop, it download a screenshot of the current scene with no UI.
571
+ */
572
+ captureScreenshotCallback: function() {
573
+ //Remove the callback, only needs to happen once
574
+ this.$module.zincRenderer.removePostRenderCallbackFunction(
575
+ this.captureID
576
+ );
577
+ let screenshot = this.$module.zincRenderer
578
+ .getThreeJSRenderer()
579
+ .domElement.toDataURL("image/png");
580
+ let hrefElement = document.createElement("a");
581
+ document.body.append(hrefElement);
582
+ if (!this.captureFilename) hrefElement.download = `screenshot.png`;
583
+ else hrefElement.download = this.captureFilename;
584
+ hrefElement.href = screenshot;
585
+ hrefElement.click();
586
+ hrefElement.remove();
587
+ },
588
+ /**
589
+ * Function for capturing a screenshot of the current rendering.
590
+ *
591
+ * @param {String} filename filename given to the screenshot.
592
+ *
593
+ * @public
594
+ */
595
+ captureScreenshot: function(filename) {
596
+ this.captureFilename = filename;
597
+ this.captureID = this.$module.zincRenderer.addPostRenderCallbackFunction(
598
+ this.captureScreenshotCallback
599
+ );
600
+ },
601
+ formatTooltip(val) {
602
+ if (this.timeMax >= 1000) {
603
+ if (val) {
604
+ let sec = ((val % 60000) / 1000).toFixed(2) + "s";
605
+ let min = val > 60000 ? (val / 60000).toFixed(0) + "m " : "";
606
+ return min + sec;
607
+ }
608
+ }
609
+ return val ? val.toFixed(2) + " ms" : "0 ms";
610
+ },
611
+ /**
612
+ * Function to reset the view to default.
613
+ * Also called when the associated button is pressed.
614
+ *
615
+ * @public
616
+ */
617
+ fitWindow: function() {
618
+ if (this.$module.scene) {
619
+ this.$module.scene.viewAll();
620
+ }
621
+ },
622
+ /**
623
+ * Function to zoom in.
624
+ * Also called when the associated button is pressed.
625
+ *
626
+ * @public
627
+ */
628
+ zoomIn: function() {
629
+ if (this.$module.scene) {
630
+ this.$module.scene.changeZoomByScrollRateUnit(-1);
631
+ }
632
+ },
633
+ /**
634
+ * Function to zoom out.
635
+ * Also called when the associated button is pressed.
636
+ *
637
+ * @public
638
+ */
639
+ zoomOut: function() {
640
+ if (this.$module.scene) {
641
+ this.$module.scene.changeZoomByScrollRateUnit(1);
642
+ }
643
+ },
644
+ /**
645
+ * Function to change the current play speed.
646
+ *
647
+ * @public
648
+ */
649
+ speedChanged: function(speed) {
650
+ this.currentSpeed = speed;
651
+ this.$module.setPlayRate(this.defaultRate * this.currentSpeed);
652
+ },
653
+ /**
654
+ * Function used to stop the free spin
655
+ *
656
+ * @public
657
+ */
658
+ stopFreeSpin: function() {
659
+ let cameracontrol = this.$module.scene.getZincCameraControls();
660
+ cameracontrol.stopAutoTumble();
661
+ this.isTransitioning = false;
662
+ },
663
+ /**
664
+ * Focus on named region
665
+ */
666
+ viewRegion: function(name) {
667
+ if (name && name != "" && this.$module.scene) {
668
+ let objects = this.$module.scene.findObjectsWithGroupName(name);
669
+ let box = this.$module.scene.getBoundingBoxOfZincObjects(objects);
670
+ if (box) {
671
+ this.$module.scene.viewAllWithBoundingBox(box);
672
+ }
673
+ }
674
+ },
675
+ setFocusedRegion: function(name) {
676
+ if (name) {
677
+ if (this.isReady) {
678
+ this.viewRegion(name);
679
+ } else {
680
+ this.$module.setFinishDownloadCallback(
681
+ this.setURLFinishCallback({ region: name })
682
+ );
683
+ }
684
+ }
45
685
  },
46
- visibilityToggle: function(item, event) {
47
- this.$module.changeOrganPartsVisibility(item, event.srcElement.checked);
686
+ updateViewURL: function(viewURL) {
687
+ if (viewURL) {
688
+ if (this.isReady) {
689
+ const url = new URL(viewURL, this.url);
690
+ this.$module.scene.loadViewURL(url);
691
+ } else {
692
+ this.$module.setFinishDownloadCallback(
693
+ this.setURLFinishCallback({ viewURL: viewURL })
694
+ );
695
+ }
696
+ }
48
697
  },
698
+ /**
699
+ * Function used to rotate the scene.
700
+ * Also called when the associated button is pressed.
701
+ *
702
+ * @public
703
+ */
704
+ freeSpin: function() {
705
+ if (this.$module.scene) {
706
+ let cameracontrol = this.$module.scene.getZincCameraControls();
707
+ this.isTransitioning = true;
708
+ cameracontrol.enableAutoTumble();
709
+ cameracontrol.autoTumble([1.0, 0.0], Math.PI, true);
710
+ setTimeout(this.stopFreeSpin, 4000);
711
+ }
712
+ },
713
+ /**
714
+ * Callback when a region is selected/highlighted.
715
+ * It will also update other controls.
716
+ */
717
+ eventNotifierCallback: function(event) {
718
+ if (event.eventType == 1) {
719
+ if (this.$refs.traditionalControl) {
720
+ if (event.identifiers[0]) {
721
+ let id = event.identifiers[0].data.id
722
+ ? event.identifiers[0].data.id
723
+ : event.identifiers[0].data.group;
724
+ this.$refs.traditionalControl.changeActiveByName(id);
725
+ } else {
726
+ this.$refs.traditionalControl.removeActive();
727
+ }
728
+ }
729
+ /**
730
+ * Triggers when an object has been selected
731
+ *
732
+ * @property {array} identifiers array of identifiers
733
+ * of selected object.
734
+ */
735
+ this.$emit("scaffold-selected", event.identifiers);
736
+ } else if (event.eventType == 2) {
737
+ if (this.$refs.traditionalControl) {
738
+ if (event.identifiers[0]) {
739
+ let id = event.identifiers[0].data.id
740
+ ? event.identifiers[0].data.id
741
+ : event.identifiers[0].data.group;
742
+ this.$refs.traditionalControl.changeHoverByName(id);
743
+ } else this.$refs.traditionalControl.removeHover();
744
+ }
745
+ /**
746
+ * Triggers when an object has been highlighted
747
+ *
748
+ * @property {array} identifiers array of identifiers
749
+ * of highlighted object.
750
+ */
751
+ this.$emit("scaffold-highlighted", event.identifiers);
752
+ }
753
+ },
754
+ /**
755
+ * Get the coordinates of the current selected region.
756
+ *
757
+ * @public
758
+ */
759
+ getCoordinatesOfSelected: function() {
760
+ if (this.selectedObject) {
761
+ return this.$module.scene.getObjectsScreenXY([this.selectedObject]);
762
+ }
763
+ return undefined;
764
+ },
765
+ /**
766
+ * Return an object containing the window coordinates of the
767
+ * current selected region which will be updated after each render
768
+ * loop.
769
+ *
770
+ * @public
771
+ */
772
+ getDynamicSelectedCoordinates: function() {
773
+ return this.$module.selectedScreenCoordinates;
774
+ },
775
+ /**
776
+ * Callback when time is changed through the UI.
777
+ */
49
778
  timeChange: function(event) {
50
- this.$module.updateTime(event.srcElement.value);
779
+ let normalizedTime = (event / this.timeMax) * 100;
780
+ if (normalizedTime != this.sceneData.currentTime)
781
+ this.$module.updateTime(normalizedTime);
782
+ },
783
+ /**
784
+ * A callback used by children components. Set the selected zinc object
785
+ *
786
+ * @param {object} object Zinc object
787
+ */
788
+ objectSelected: function(object) {
789
+ if (object !== this.selectedObject) {
790
+ this.selectedObject = object;
791
+ this.$refs.opacityControl.setObject(this.selectedObject);
792
+ if (object) this.$module.setSelectedByZincObject(object, true);
793
+ else this.$module.setSelectedByObjects([], true);
794
+ }
795
+ },
796
+ /**
797
+ * A callback used by children components. Set the highlighted zinc object
798
+ *
799
+ * @param {object} object Zinc object
800
+ */
801
+ objectHovered: function(object) {
802
+ if (object !== this.hoveredObject) {
803
+ this.hoveredObject = object;
804
+ if (object) this.$module.setHighlightedByZincObject(object, true);
805
+ else this.$module.setHighlightedByObjects([], true);
806
+ }
807
+ },
808
+ /**
809
+ * Set the selected by name.
810
+ *
811
+ * @param {name} name Name of the region
812
+ */
813
+ changeActiveByName: function(name) {
814
+ this.$refs.traditionalControl.changeActiveByName(name);
815
+ if (name === undefined)
816
+ this.$refs.traditionalControl.removeActive();
51
817
  },
818
+ /**
819
+ * Set the highlighted by name.
820
+ *
821
+ * @param {name} name Name of the region
822
+ */
823
+ changeHighlightedByName: function(name) {
824
+ this.$refs.traditionalControl.changeHoverByName(name);
825
+ if (name === undefined)
826
+ this.$refs.traditionalControl.removeHover();
827
+ },
828
+ /**
829
+ * Start the animation.
830
+ *
831
+ * @param {object} object Zinc object
832
+ */
52
833
  play: function(flag) {
53
834
  this.$module.playAnimation(flag);
54
835
  this.isPlaying = flag;
836
+ },
837
+ /**
838
+ * Function to toggle on/off overlay help.
839
+ */
840
+ setHelpMode: function(helpMode) {
841
+ if (helpMode) {
842
+ this.inHelp = true;
843
+ this.hoverVisabilities.forEach(item => {
844
+ item.value = true;
845
+ });
846
+ } else {
847
+ this.inHelp = false;
848
+ this.hoverVisabilities.forEach(item => {
849
+ item.value = false;
850
+ });
851
+ }
852
+ },
853
+ /**
854
+ * This is called when mouse cursor enters supported elements
855
+ * with help tootltips.
856
+ */
857
+ showToolitip: function(tooltipNumber) {
858
+ if (!this.inHelp) {
859
+ this.tooltipWait = setTimeout(() => {
860
+ this.hoverVisabilities[tooltipNumber].value = true;
861
+ }, 500);
862
+ }
863
+ },
864
+ /**
865
+ * This is called when mouse cursor exits supported element..
866
+ */
867
+ hideToolitip: function(tooltipNumber) {
868
+ if (!this.inHelp) {
869
+ this.hoverVisabilities[tooltipNumber].value = false;
870
+ clearTimeout(this.tooltipWait);
871
+ }
872
+ },
873
+ /**
874
+ * Called when minimap settings has changed. Pass the
875
+ * parameters to ZincJS and marked it for update.
876
+ */
877
+ updateMinimapScissor: function() {
878
+ Object.keys(this.minimapSettings).forEach(key => {
879
+ this.$module.scene.minimapScissor[key] = this.minimapSettings[key];
880
+ });
881
+ this.$module.scene.minimapScissor.updateRequired = true;
882
+ },
883
+ updateSettingsfromScene: function() {
884
+ this.currentSpeed = 1;
885
+ this.$module.setPlayRate(this.defaultRate);
886
+ this.orginalDuration = this.$module.scene.getMetadataTag(
887
+ "OriginalDuration"
888
+ );
889
+ this.animateDuration = this.$module.scene.getMetadataTag("Duration");
890
+ let timeStamps = this.$module.scene.getMetadataTag("TimeStamps");
891
+ this.timeStamps = {};
892
+ for (const key in timeStamps) {
893
+ this.timeStamps[timeStamps[key]] = key;
894
+ }
895
+ this.timeMax = this.$module.scene.getDuration();
896
+ },
897
+ setURLFinishCallback: function(options) {
898
+ return () => {
899
+ if (options) {
900
+ if (options.viewport) {
901
+ this.$module.scene
902
+ .getZincCameraControls()
903
+ .setCurrentCameraSettings(options.viewport);
904
+ } else if (options.viewURL && options.viewURL !== "") {
905
+ const url = new URL(options.viewURL, this.url);
906
+ this.$module.scene.loadViewURL(url);
907
+ } else if (options.region && options.region !== "") {
908
+ this.viewRegion(options.region);
909
+ }
910
+ if (options.visibility) {
911
+ // Some UIs may not be ready at this time.
912
+ this.$nextTick(() => {
913
+ this.$refs.traditionalControl.setState(options.visibility);
914
+ });
915
+ }
916
+ }
917
+ this.updateSettingsfromScene();
918
+ this.$module.updateTime(0.01);
919
+ this.$module.updateTime(0);
920
+ this.$module.unsetFinishDownloadCallback();
921
+ this.isReady = true;
922
+ };
923
+ },
924
+ /**
925
+ * Function used for getting the current states of the scene. This exported states
926
+ * can be imported using the importStates method.
927
+ *
928
+ * @public
929
+ */
930
+ getState: function() {
931
+ let state = {
932
+ url: this._currentURL,
933
+ viewport: undefined,
934
+ visibility: undefined
935
+ };
936
+ if (this.$refs.traditionalControl)
937
+ state.visibility = this.$refs.traditionalControl.getState();
938
+ if (this.$module.scene) {
939
+ let zincCameraControls = this.$module.scene.getZincCameraControls();
940
+ state.viewport = zincCameraControls.getCurrentViewport();
941
+ }
942
+ return state;
943
+ },
944
+ /**
945
+ * Function used for importing the states of the scene. This exported states
946
+ * can be imported using the read states method.
947
+ *
948
+ * @public
949
+ */
950
+ setState: function(state) {
951
+ if (state) {
952
+ if (state.url && state.url !== this._currentURL) {
953
+ this.setURLAndState(state.url, {
954
+ viewport: state.viewport,
955
+ visibility: state.visibility
956
+ });
957
+ } else {
958
+ if (state.viewport || state.visibility) {
959
+ if (this.isReady && this.$module.scene) {
960
+ if (state.viewport)
961
+ this.$module.scene
962
+ .getZincCameraControls()
963
+ .setCurrentCameraSettings(state.viewport);
964
+ if (state.visibility)
965
+ this.$refs.traditionalControl.setState(state.visibility);
966
+ } else {
967
+ this.$module.setFinishDownloadCallback(
968
+ this.setURLFinishCallback({
969
+ viewport: state.viewport,
970
+ visibility: state.visibility
971
+ })
972
+ );
973
+ }
974
+ }
975
+ }
976
+ }
977
+ },
978
+ exportGLTF: function(binary) {
979
+ return this.$module.scene.exportGLTF(binary);
980
+ },
981
+ /**
982
+ * Function used for reading in new scaffold metadata and a custom
983
+ * viewport. This function will ignore the state prop and
984
+ * read in the new url.
985
+ *
986
+ * @public
987
+ */
988
+ setURLAndState: function(newValue, state) {
989
+ if (newValue != this._currentURL) {
990
+ let viewport = state && state.viewport ? state.viewport : undefined;
991
+ let visibility =
992
+ state && state.visibility ? state.visibility : undefined;
993
+ this._currentURL = newValue;
994
+ if (this.$refs.traditionalControl)
995
+ this.$refs.traditionalControl.clear();
996
+ this.loading = true;
997
+ this.isReady = false;
998
+ this.$module.setFinishDownloadCallback(
999
+ this.setURLFinishCallback({
1000
+ viewport: viewport,
1001
+ region: this.region,
1002
+ viewURL: this.viewURL,
1003
+ visibility: visibility
1004
+ })
1005
+ );
1006
+ this.$module.loadOrgansFromURL(
1007
+ newValue,
1008
+ undefined,
1009
+ undefined,
1010
+ "scene",
1011
+ undefined
1012
+ );
1013
+ this.$module.scene.displayMarkers = this.displayMarkers;
1014
+ this.$module.scene.displayMinimap = this.displayMinimap;
1015
+ this.updateMinimapScissor();
1016
+ }
1017
+ },
1018
+ /**
1019
+ * Function used for reading in new scaffold metadata. This function will ignore
1020
+ * the state prop and read in the new url.
1021
+ *
1022
+ * @public
1023
+ */
1024
+ setURL: function(newValue) {
1025
+ this.setURLAndState(newValue, undefined);
1026
+ },
1027
+ /**
1028
+ * Callback when drawer is toggled.
1029
+ *
1030
+ */
1031
+ drawerToggled: function(flag) {
1032
+ this.drawerOpen = flag;
1033
+ this.adjustLayout();
1034
+ },
1035
+ /**
1036
+ * Callback using ResizeObserver.
1037
+
1038
+ */
1039
+ adjustLayout: function() {
1040
+ let width = this.$refs.scaffoldContainer.clientWidth;
1041
+ this.minimisedSlider = width < 812;
1042
+ if (this.minimisedSlider) {
1043
+ this.sliderPosition = this.drawerOpen ? "right" : "left";
1044
+ } else {
1045
+ this.sliderPosition = "";
1046
+ }
1047
+ },
1048
+ toggleRendering: function(flag) {
1049
+ if (this.$module.zincRenderer) {
1050
+ if (flag) {
1051
+ this.$module.zincRenderer.animate();
1052
+ } else {
1053
+ this.$module.zincRenderer.stopAnimate();
1054
+ }
1055
+ }
1056
+ },
1057
+ forceResize: function() {
1058
+ if (this.$module.zincRenderer) {
1059
+ this.$module.zincRenderer.onWindowResize();
1060
+ }
55
1061
  }
56
- },
57
- props: ['url'],
58
- data: function() {
59
- return {
60
- sceneData: this.$module.sceneData,
61
- isPlaying: false
62
- }
63
- },
64
- mounted: function () {
65
- this.$module.loadOrgansFromURL(this.url, undefined, undefined, "Overlay", undefined);
66
- this.$module.initialiseRenderer(this.$refs.display);
67
1062
  }
68
- }
1063
+ };
69
1064
  </script>
70
1065
 
71
1066
  <!-- Add "scoped" attribute to limit CSS to this component only -->
72
- <style scoped>
1067
+ <style scoped lang="scss">
1068
+ @import "~element-ui/packages/theme-chalk/src/col";
1069
+ @import "~element-ui/packages/theme-chalk/src/loading";
1070
+ @import "~element-ui/packages/theme-chalk/src/option";
1071
+ @import "~element-ui/packages/theme-chalk/src/popover";
1072
+ @import "~element-ui/packages/theme-chalk/src/row";
1073
+ @import "~element-ui/packages/theme-chalk/src/select";
1074
+ @import "~element-ui/packages/theme-chalk/src/slider";
1075
+ @import "~element-ui/packages/theme-chalk/src/tabs";
1076
+ @import "~element-ui/packages/theme-chalk/src/tab-pane";
1077
+
1078
+ .warning-icon {
1079
+ position: absolute;
1080
+ top: 15px;
1081
+ left: 37px;
1082
+ text-align: left;
1083
+ font-size: 25px;
1084
+ color: $warning;
1085
+
1086
+ &:hover {
1087
+ cursor: pointer;
1088
+ }
1089
+ }
1090
+
1091
+ .warning-text {
1092
+ font-size: 15px;
1093
+ vertical-align: 5px;
1094
+ }
1095
+
1096
+ ::v-deep .warning-popper {
1097
+ padding: 9px 10px;
1098
+ min-width: 150px;
1099
+ font-size: 12px;
1100
+ color: #fff;
1101
+ background-color: $warning;
1102
+
1103
+ &.right-popper {
1104
+ .popper__arrow {
1105
+ &::after {
1106
+ border-right-color: $warning !important;
1107
+ }
1108
+ }
1109
+ }
1110
+ }
1111
+
1112
+ #organsDisplayArea {
1113
+ &:focus {
1114
+ outline: none !important;
1115
+ border: 0px;
1116
+ }
1117
+ }
73
1118
 
74
1119
  .scaffold-container {
75
- height:100%;
76
- width:100%;
1120
+ height: 100%;
1121
+ width: 100%;
1122
+ position: relative;
77
1123
  }
78
1124
 
79
- #check-list {
1125
+ .time-slider-container {
1126
+ text-align: left;
80
1127
  position: absolute;
81
- top:10px;
82
- left: 10px;
83
- text-align:left;
1128
+ right: 155px;
1129
+ width: calc(100% - 530px);
1130
+ bottom: 16px;
1131
+ transition: all 1s ease;
1132
+ outline: none;
1133
+
1134
+ &.minimised {
1135
+ width: calc(40%);
1136
+ }
1137
+
1138
+ &.left {
1139
+ right: 155px;
1140
+ width: calc(100% - 250px);
1141
+ }
1142
+
1143
+ &.right {
1144
+ right: 8px;
1145
+ bottom: 54px;
1146
+ }
84
1147
  }
85
1148
 
86
- #timeSlider {
1149
+ .slider-display-text {
1150
+ height: 20px;
1151
+ color: rgb(48, 49, 51);
1152
+ font-size: 14px;
1153
+ font-weight: normal;
1154
+ line-height: 20px;
1155
+ padding-left: 8px;
1156
+ text-shadow: -1px -1px #fff, 1px -1px #fff, -1px 1px #fff, 1px -1px #fff;
1157
+ }
1158
+
1159
+ .tab-content {
1160
+ display: flex;
1161
+ height: 34px;
1162
+ padding-top: 8px;
1163
+ font-size: 14px;
1164
+ }
1165
+
1166
+ .tab-content ::v-deep .el-slider__marks-text {
1167
+ margin-top: 12px;
1168
+ margin-left: 8px;
1169
+ font-size: 10px;
1170
+ }
1171
+
1172
+ .tab-content ::v-deep .el-slider__stop {
1173
+ width: 10px;
1174
+ height: 10px;
1175
+ top: -1px;
1176
+ border: solid 1px $app-primary-color;
1177
+ }
1178
+
1179
+ .animation-data {
1180
+ margin-left: 8px;
1181
+ line-height: 26px;
1182
+ display: flex;
1183
+
1184
+ :not(:first-child) {
1185
+ margin-left: 8px;
1186
+ }
1187
+ .purple {
1188
+ padding-left: 2px;
1189
+ color: $app-primary-color;
1190
+ }
1191
+ }
1192
+ .slider {
1193
+ margin-left: 30px;
1194
+ width: calc(100% - 88px);
1195
+ margin-top: -7px;
1196
+
1197
+ ::v-deep .el-slider__runway {
1198
+ height: 10px;
1199
+ margin: 14px 0;
1200
+ }
1201
+
1202
+ ::v-deep .el-slider__button-wrapper {
1203
+ top: -13px;
1204
+ }
1205
+ }
1206
+
1207
+ .zoomOut {
1208
+ padding-left: 8px;
1209
+ }
1210
+
1211
+ .fitWindow {
1212
+ padding-left: 8px;
1213
+ }
1214
+
1215
+ ::v-deep .non-selectable {
1216
+ user-select: none;
1217
+ }
1218
+
1219
+ ::v-deep .background-popper {
1220
+ padding: 5px 12px;
1221
+ background-color: #ffffff;
1222
+ border: 1px solid $app-primary-color;
1223
+ box-shadow: 0px 2px 12px 0px rgba(0, 0, 0, 0.06);
1224
+ height: 72px;
1225
+ width: 128px;
1226
+ min-width: 128px;
1227
+
1228
+ &.el-popper[x-placement^="top"] {
1229
+ .popper__arrow {
1230
+ border-top-color: $app-primary-color !important;
1231
+ &:after {
1232
+ border-top-color: #fff !important;
1233
+ }
1234
+ }
1235
+ }
1236
+ }
1237
+
1238
+ .background-colour {
1239
+ bottom: 16px;
1240
+ position: absolute;
1241
+ transition: all 1s ease;
1242
+
1243
+ &.open {
1244
+ left: 322px;
1245
+ }
1246
+
1247
+ &.close {
1248
+ left: 24px;
1249
+ }
1250
+ }
1251
+
1252
+ .backgroundText {
1253
+ color: rgb(48, 49, 51);
1254
+ font-size: 14px;
1255
+ font-weight: normal;
1256
+ line-height: 20px;
1257
+ }
1258
+
1259
+ .backgroundChooser {
1260
+ display: flex;
1261
+ margin-top: 16px;
1262
+ }
1263
+
1264
+ .backgroundChoice {
1265
+ width: 20px;
1266
+ height: 20px;
1267
+ border: 1px solid rgb(144, 147, 153);
1268
+ margin-left: 20px;
1269
+
1270
+ &.active {
1271
+ border: 2px solid $app-primary-color;
1272
+ }
1273
+
1274
+ &:hover {
1275
+ cursor: pointer;
1276
+ }
1277
+
1278
+ &.white {
1279
+ background-color: white;
1280
+ margin-left: 10px;
1281
+ }
1282
+
1283
+ &.black {
1284
+ background-color: black;
1285
+ }
1286
+
1287
+ &.lightskyblue {
1288
+ background-color: lightskyblue;
1289
+ }
1290
+ }
1291
+
1292
+ .icon-button {
1293
+ height: 24px !important;
1294
+ width: 24px !important;
1295
+
1296
+ &:hover {
1297
+ cursor: pointer;
1298
+ }
1299
+ }
1300
+
1301
+ .bottom-right-control {
87
1302
  position: absolute;
88
- left: 2.5%;
89
- height: 48px;
90
- width:95%;
91
- bottom: 10px;
1303
+ right: 16px;
1304
+ bottom: 16px;
1305
+ }
1306
+
1307
+ .video-button {
1308
+ margin-left: 8px;
1309
+ }
1310
+
1311
+ .time-slider-container {
1312
+ ::v-deep .el-tabs__header {
1313
+ margin: 0px;
1314
+ border-bottom: 1px solid rgb(144, 147, 153);
1315
+ }
1316
+
1317
+ .el-row {
1318
+ margin-bottom: 5px;
1319
+ }
1320
+
1321
+ ::v-deep .el-tabs__content {
1322
+ border-left: 1px solid rgb(144, 147, 153);
1323
+ border-bottom: 1px solid rgb(144, 147, 153);
1324
+ border-right: 1px solid rgb(144, 147, 153);
1325
+ border-radius: 0px 0px 4px 4px;
1326
+ background-color: white;
1327
+ }
1328
+
1329
+ ::v-deep .el-tabs--card {
1330
+ > .el-tabs__header {
1331
+ .el-tabs__nav {
1332
+ border: 1px solid rgb(144, 147, 153);
1333
+ border-bottom: none;
1334
+ border-radius: 4px 4px 0px 0px;
1335
+ background-color: white;
1336
+ }
1337
+
1338
+ .el-tabs__item {
1339
+ height: 24px;
1340
+ line-height: 24px;
1341
+ padding: 0 8px !important;
1342
+ border-bottom: 1px solid;
1343
+ border-left: 1px solid rgb(144, 147, 153);
1344
+ &:first-child {
1345
+ border-left: none;
1346
+ }
1347
+ &.is-active {
1348
+ border-bottom: 1px solid white;
1349
+ color: rgb(48, 49, 51);
1350
+ }
1351
+ &:hover {
1352
+ color: $app-primary-color;
1353
+ }
1354
+ }
1355
+ }
1356
+ }
92
1357
  }
93
1358
 
1359
+ ::v-deep .scaffold-popper {
1360
+ padding: 6px 4px;
1361
+ font-size: 12px;
1362
+ color: rgb(48, 49, 51);
1363
+ background-color: #f3ecf6;
1364
+ border: 1px solid $app-primary-color;
1365
+ white-space: nowrap;
1366
+ min-width: unset;
1367
+ pointer-events: none;
1368
+
1369
+ &.left-popper {
1370
+ .popper__arrow {
1371
+ border-left-color: $app-primary-color !important;
1372
+ &:after {
1373
+ border-left-color: #f3ecf6 !important;
1374
+ }
1375
+ }
1376
+ }
1377
+
1378
+ &.right-popper {
1379
+ .popper__arrow {
1380
+ border-right-color: $app-primary-color !important;
1381
+ &:after {
1382
+ border-right-color: #f3ecf6 !important;
1383
+ }
1384
+ }
1385
+ }
1386
+
1387
+ &.el-popper[x-placement^="top"] {
1388
+ .popper__arrow {
1389
+ border-top-color: $app-primary-color !important;
1390
+ &:after {
1391
+ border-top-color: #f3ecf6 !important;
1392
+ }
1393
+ }
1394
+ }
1395
+ }
1396
+
1397
+ ::v-deep .el-slider__button {
1398
+ border: 2px solid $app-primary-color;
1399
+ }
1400
+
1401
+ ::v-deep .el-slider__bar {
1402
+ background-color: $app-primary-color;
1403
+ height: 10px;
1404
+ }
1405
+
1406
+ ::v-deep .el-loading-spinner {
1407
+ i, .el-loading-text {
1408
+ color: $app-primary-color;
1409
+ }
1410
+ }
1411
+
1412
+ ::v-deep .popper-zoomout {
1413
+ padding-right: 11px;
1414
+ left: -21px !important;
1415
+ .popper__arrow {
1416
+ left: 53px !important;
1417
+ }
1418
+ }
1419
+
1420
+ .select-box {
1421
+ width: 57px;
1422
+ border-radius: 4px;
1423
+ border: 1px solid rgb(144, 147, 153);
1424
+ background-color: var(--white);
1425
+ font-weight: 500;
1426
+ color: rgb(48, 49, 51);
1427
+ margin-left: 8px;
1428
+
1429
+ ::v-deep .el-input__inner {
1430
+ color: $app-primary-color;
1431
+ height: 22px;
1432
+ padding-left: 8px;
1433
+ padding-right: 8px;
1434
+ border: none;
1435
+ font-family: "Asap", sans-serif;
1436
+ line-height: 22px;
1437
+ }
1438
+
1439
+ ::v-deep .el-input,
1440
+ ::v-deep .el-input__icon {
1441
+ line-height: 22px;
1442
+ }
1443
+ }
1444
+ </style>
1445
+
1446
+ <style lang="scss">
1447
+ .time-slider-tooltip {
1448
+ padding: 6px 4px !important;
1449
+ font-family: "Asap", sans-serif;
1450
+ font-size: 12px !important;
1451
+ color: rgb(48, 49, 51) !important;
1452
+ background-color: #f3ecf6 !important;
1453
+ border: 1px solid $app-primary-color !important;
1454
+ white-space: nowrap !important;
1455
+ min-width: unset !important;
1456
+ }
1457
+
1458
+ .scaffold_viewer_dropdown .el-select-dropdown__item {
1459
+ white-space: nowrap;
1460
+ text-align: left;
1461
+ font-family: "Asap", sans-serif;
1462
+ }
1463
+
1464
+ .opacity-box {
1465
+ right: 0px;
1466
+ bottom:200px;
1467
+ position:absolute;
1468
+ }
94
1469
  </style>