@abi-software/scaffoldvuer 0.1.3 → 0.1.5-1.beta.2

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