1268 lines
42 KiB
Vue
1268 lines
42 KiB
Vue
<template>
|
|
<div class="none-dicom-viewer">
|
|
<!-- viewports -->
|
|
<div class="viewports-wrapper" v-loading="loading" ref="viewports-wrapper">
|
|
<div ref="container" class="grid-container" :style="gridStyle">
|
|
<div v-for="(v, index) in viewportInfos" :ref="`grid-cell-${index}`" :key="index" :style="getCellStyle(index)"
|
|
:class="['grid-cell', index === activeCanvasIndex ? 'cell_active' : '', index === fullScreenIndex ? 'cell-full-screen' : '']"
|
|
@dblclick="toggleFullScreen($event, index)" @click="activeCanvas(index)"
|
|
@mouseup="sliderMouseup($event, index)" @mousemove="sliderMousemove($event, index)"
|
|
@mouseleave="sliderMouseleave($event, index)">
|
|
<div v-show="imageType.includes(v.fileType)" :ref="`canvas-${index}`" class="content">
|
|
<div class="left-top-text">
|
|
<div v-if="v.currentFileName">{{ v.currentFileName }}</div>
|
|
<div v-if="v.imageIds.length > 0">{{ `${ v.currentImageIdIndex + 1 } / ${ v.imageIds.length }` }}</div>
|
|
</div>
|
|
<div class="left-bottom-text">
|
|
<div v-if="v.zoomText">{{ `Zoom: ${v.zoomText}` }}</div>
|
|
</div>
|
|
<div :ref="`sliderBox-${index}`" class="right-slider-box" @click.stop="clickSlider($event, index)">
|
|
<div :style="{ top: v.height + '%' }" class="slider" @click.stop.prevent="() => { return }"
|
|
@mousedown.stop="sliderMousedown($event, index)" />
|
|
</div>
|
|
</div>
|
|
<div v-if="v.fileType === 'application/pdf' && fullScreenIndex === null" class="content flex_col">
|
|
<div class="content-top" style="height: 50px;">
|
|
<div class="left-top-text">
|
|
<div v-if="v.currentFileName">{{ v.currentFileName }}</div>
|
|
</div>
|
|
</div>
|
|
<div class="content-main" style="flex: 1;">
|
|
<iframe v-if="v.currentFilePath" :ref="`iframe-${index}`"
|
|
:src="`/static/pdfjs/web/viewer.html?file=${OSSclientConfig.basePath}${v.currentFilePath}?index=${index}`"
|
|
width="100%" height="100%" frameborder="0" crossorigin="anonymous" />
|
|
</div>
|
|
|
|
</div>
|
|
|
|
<div v-if="v.fileType.includes('mp4')" class="content flex_col">
|
|
<div class="content-top" style="height: 50px;">
|
|
<div class="left-top-text">
|
|
<div v-if="v.currentFileName">{{ v.currentFileName }}</div>
|
|
</div>
|
|
</div>
|
|
<div class="content-main" :ref="`video-content-main-${index}`" style="flex: 1;">
|
|
<video v-if="v.currentFilePath" :ref="`videovideo-${index}`"
|
|
:src="`${OSSclientConfig.basePath}${v.currentFilePath}`" crossorigin="anonymous" width="100%"
|
|
height="100%" autoplay controls controlsList="nodownload"></video>
|
|
</div>
|
|
|
|
</div>
|
|
|
|
</div>
|
|
</div>
|
|
<div class="Anonymous" v-if="isAnonymous">
|
|
<div
|
|
:class="{ btn: true, activeBtn: activeTool === 'Note_RectangleRoi' && !isComparison, isNoted: isComparison }"
|
|
@click="setToolActive('Note_RectangleRoi')">{{
|
|
$t('DicomViewer:anonymous:Note_RectangleRoi') }}</div>
|
|
<div :class="{ btn: true, activeBtn: activeTool === 'Eraser' && !isComparison, isNoted: isComparison }"
|
|
@click="setToolActive('Eraser')">{{
|
|
$t('DicomViewer:anonymous:Eraser') }}
|
|
</div>
|
|
<div :class="{ btn: true, isNoted: isComparison }" @click="anonymousImage(false)">{{
|
|
$t('DicomViewer:anonymous:Application') }}</div>
|
|
<!-- <div class="btn">刷新图像</div> -->
|
|
<div class="btn" v-if="!isComparison" @click="comparison(true)">{{
|
|
$t('DicomViewer:anonymous:Comparison') }}</div>
|
|
<div class="btn" v-else @click="comparison(false)">{{
|
|
$t('DicomViewer:anonymous:Exit') }}</div>
|
|
<div :class="{ btn: true }" @click="recovery(false)">{{
|
|
$t('DicomViewer:anonymous:Recovery') }}</div>
|
|
<!-- <div :class="{ btn: true }" @click="recovery(true)">{{
|
|
$t('DicomViewer:anonymous:RecoveryAll') }}</div> -->
|
|
</div>
|
|
</div>
|
|
<!-- tools -->
|
|
<div class="dicom-tools">
|
|
<div class="measureTool-wrapper" v-if="hasAnonymous && hasPermi(['role:iqc'])">
|
|
<div class="sideTool-title">{{ $t('DicomViewer:anonymous:PixelAnonymity') }}</div>
|
|
<div class="sideTool-wrapper">
|
|
<!-- <label>{{ $t('trials:reading:button:layout') }}:</label> -->
|
|
<!-- <select class="sidetool-select" style="width:90px" :value="layout.replace('*', 'x')"
|
|
@change="handleLayoutChange">
|
|
<option value="1x1">1x1</option>
|
|
<option value="1x2">1x2</option>
|
|
<option value="2x1">2x1</option>
|
|
<option value="2x2">2x2</option>
|
|
</select> -->
|
|
<div :class="{ btnBox: true, activeBtnBox: isAnonymous }" @click="openAnonymous">{{
|
|
$t('DicomViewer:anonymous:PixelAnonymity')
|
|
}}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<!-- 图像变换 -->
|
|
<div class="measureTool-wrapper">
|
|
<div class="sideTool-title">{{ $t('trials:dicom-show:transform') }}</div>
|
|
<div class="sideTool-wrapper">
|
|
<button :title="$t('trials:reading:button:zoom')"
|
|
:class="{ 'btn-link': true, activeTool: activeTool === 'Zoom' }" data-tool="Zoom"
|
|
@click="setToolActive('Zoom')">
|
|
<svg-icon icon-class="magnifier" style="font-size:20px;" />
|
|
</button>
|
|
<button :title="$t('trials:reading:button:move')"
|
|
:class="{ 'btn-link': true, activeTool: activeTool === 'Pan' }" data-tool="Pan"
|
|
@click="setToolActive('Pan')">
|
|
<svg-icon icon-class="move" style="font-size:20px;" />
|
|
</button>
|
|
<button :title="$t('trials:reading:button:rotate')"
|
|
:class="{ 'btn-link': true, activeTool: activeTool === 'PlanarRotate' }" data-tool="PlanarRotate"
|
|
@click="setToolActive('PlanarRotate')">
|
|
<svg-icon icon-class="rotate" style="font-size:20px;" />
|
|
</button>
|
|
<button
|
|
:title="isFitToWindowMode ? $t('trials:reading:button:fitImage') : $t('trials:reading:button:fitWindow')"
|
|
class="btn-link" @click="toggleFitMode">
|
|
<svg-icon v-if="isFitToWindowMode" icon-class="fitToImage" style="font-size:20px;" />
|
|
<svg-icon v-else icon-class="fitToWindow" style="font-size:20px;" />
|
|
</button>
|
|
<button :title="$t('trials:reading:button:reset')" class="btn-link" @click="resetViewport">
|
|
<svg-icon icon-class="refresh" style="font-size:20px;" />
|
|
</button>
|
|
</div>
|
|
</div>
|
|
<!-- 测量工具 -->
|
|
<!-- <div class="measureTool-wrapper">
|
|
<div class="sideTool-title">{{ $t('trials:dicom-show:measurementLabeling') }}</div>
|
|
<div class="sideTool-wrapper">
|
|
<button :title="$t('trials:reading:button:screenShot')" class="btn-link" @click="saveImage">
|
|
<svg-icon icon-class="image" style="font-size:20px;" />
|
|
</button>
|
|
<button :title="$t('trials:reading:button:reset')" class="btn-link" @click="resetViewport">
|
|
<svg-icon icon-class="refresh" style="font-size:20px;" />
|
|
</button>
|
|
</div>
|
|
</div> -->
|
|
</div>
|
|
</div>
|
|
</template>
|
|
<script>
|
|
|
|
import {
|
|
RenderingEngine,
|
|
Enums,
|
|
imageLoader,
|
|
metaData,
|
|
getRenderingEngine,
|
|
eventTarget,
|
|
utilities as csUtils
|
|
// getEnabledElementByIds
|
|
} from '@cornerstonejs/core'
|
|
|
|
import * as cornerstoneTools from '@cornerstonejs/tools'
|
|
import LengthscaleTool from "@/views/trials/trials-panel/reading/visit-review/tools/LengthscaleTool"
|
|
import initLibraries from '@/views/trials/trials-panel/reading/dicoms/components/Fusion/js/initLibraries'
|
|
import hardcodedMetaDataProvider from '@/views/trials/trials-panel/reading/visit-review/js/hardcodedMetaDataProvider'
|
|
import registerWebImageLoader from '@/views/trials/trials-panel/reading/visit-review/js/registerWebImageLoader'
|
|
import Note_RectangleRoiTool from '@/views/trials/trials-panel/reading/dicoms3D/components/tools/Note_RectangleRoiTool'
|
|
import { noneDicomStudyMaskImage, noneDicomStudyUndoMaskImage } from "@/api/reading"
|
|
const { ViewportType } = Enums
|
|
const renderingEngineId = 'myRenderingEngine'
|
|
const {
|
|
ToolGroupManager,
|
|
Enums: csToolsEnums,
|
|
StackScrollTool,
|
|
PanTool,
|
|
ZoomTool,
|
|
PlanarRotateTool,
|
|
ArrowAnnotateTool,
|
|
RectangleROITool,
|
|
PlanarFreehandROITool,
|
|
SplineROITool,
|
|
EraserTool,
|
|
LengthTool,
|
|
EllipticalROITool,
|
|
CircleROITool,
|
|
AngleTool,
|
|
BidirectionalTool,
|
|
// cursors
|
|
annotation
|
|
} = cornerstoneTools
|
|
const newStyles = {
|
|
global: {
|
|
color: 'rgb(255, 0, 0)',
|
|
colorHighlighted: 'rgb(0, 255, 0)',
|
|
colorSelected: 'rgb(255, 0, 0)',
|
|
colorLocked: 'rgb(255, 0, 0)',
|
|
lineWidth: '1',
|
|
lineDash: '',
|
|
shadow: true,
|
|
textBoxVisibility: true,
|
|
textBoxFontFamily: 'Helvetica Neue, Helvetica, Arial, sans-serif',
|
|
textBoxFontSize: '14px',
|
|
textBoxColor: 'rgb(255, 0, 0)',
|
|
textBoxColorHighlighted: 'rgb(0, 255, 0)',
|
|
textBoxColorSelected: 'rgb(255, 0, 0)',
|
|
textBoxColorLocked: 'rgb(255, 0, 0)',
|
|
textBoxBackground: '',
|
|
textBoxLinkLineWidth: '1',
|
|
textBoxLinkLineDash: '2,3',
|
|
textBoxShadow: true,
|
|
markerSize: '10'
|
|
}
|
|
}
|
|
cornerstoneTools.annotation.config.style.setDefaultToolStyles(newStyles)
|
|
const { MouseBindings, Events: toolsEvents } = csToolsEnums
|
|
export default {
|
|
name: 'ImageViewer',
|
|
data() {
|
|
return {
|
|
hasAnonymous: false,
|
|
isAnonymous: false,
|
|
isComparison: false,
|
|
rows: 1,
|
|
cols: 1,
|
|
fullScreenIndex: null,
|
|
imageIds: [],
|
|
layout: '1*1',
|
|
cellsMax: 4,
|
|
activeTool: '',
|
|
imageType: ['image/jpeg', 'image/jpg', 'image/bmp', 'image/png'],
|
|
loading: false,
|
|
isFitToWindowMode: false,
|
|
trialId: null,
|
|
activeName: '1',
|
|
tools: [],
|
|
viewportInfos: [],
|
|
activeCanvasIndex: 0,
|
|
serie: {}
|
|
}
|
|
},
|
|
computed: {
|
|
gridStyle() {
|
|
return {
|
|
display: 'grid',
|
|
gridTemplateRows: `repeat(${this.rows}, 1fr)`,
|
|
gridTemplateColumns: `repeat(${this.cols}, 1fr)`,
|
|
height: '100%',
|
|
width: '100%'
|
|
}
|
|
},
|
|
cellStyle() {
|
|
return {
|
|
border: '1px dashed #ccc',
|
|
display: 'flex',
|
|
alignItems: 'center',
|
|
justifyContent: 'center'
|
|
}
|
|
},
|
|
cells() {
|
|
return Array(this.rows * this.cols).fill(0)
|
|
}
|
|
},
|
|
mounted() {
|
|
// let type = this.$router.currentRoute.query.isQcCheck ? this.$router.currentRoute.query.type : ''
|
|
this.hasAnonymous = this.$router.currentRoute.query.isQcCheck
|
|
this.tools = config.customizeStandardsNoneDicom
|
|
this.trialId = this.$route.query.trialId
|
|
this.viewportInfos = Array.from({ length: this.cellsMax }, (_, index) => ({
|
|
index: index,
|
|
studyId: '',
|
|
currentImageIdIndex: 0,
|
|
viewportId: `canvas-${index}`,
|
|
fileType: '',
|
|
currentFileName: '',
|
|
currentFilePath: '',
|
|
imageIds: [],
|
|
oldB: null,
|
|
oldM: null,
|
|
isMove: false,
|
|
height: 0,
|
|
zoomText: ''
|
|
}))
|
|
this.initLoader()
|
|
this.$refs['viewports-wrapper'].addEventListener('wheel', (e) => {
|
|
this.setToolsPassive()
|
|
});
|
|
},
|
|
methods: {
|
|
// 对比
|
|
comparison(f) {
|
|
this.setToolsPassive()
|
|
if (f) {
|
|
if (!this.serie.fileInfo.IsBeMark) return this.$confirm(this.$t("DicomViewer:anonymous:notMasked"))
|
|
this.isComparison = f
|
|
this.$emit("update:isComparison", this.isComparison)
|
|
const toolGroup = ToolGroupManager.getToolGroup(`canvas-0`)
|
|
toolGroup.setToolEnabled(StackScrollTool.toolName)
|
|
this.handleLayoutChange({
|
|
target: {
|
|
value: `1x2`
|
|
}
|
|
})
|
|
let path = this.serie.fileInfo.Path.split(".MaskNoneDicom_")[0]
|
|
let imageIds = [`web:${this.OSSclientConfig.basePath}${path}`]
|
|
let file = Object.assign({}, this.serie.fileInfo)
|
|
file.Path = path
|
|
file.FullFilePath = path
|
|
this.viewportInfos[1] = Object.assign({}, this.viewportInfos[0])
|
|
this.viewportInfos[1].fileList = [file]
|
|
this.viewportInfos[1].imageIds = imageIds
|
|
console.log(imageIds, 'imageIds')
|
|
if (imageIds.length > 0) {
|
|
this.renderImage(imageIds, 1, 0)
|
|
}
|
|
} else {
|
|
this.isComparison = f
|
|
this.$emit("update:isComparison", this.isComparison)
|
|
const toolGroup = ToolGroupManager.getToolGroup(`canvas-0`)
|
|
toolGroup.setToolActive(StackScrollTool.toolName, {
|
|
bindings: [{ mouseButton: MouseBindings.Wheel }]
|
|
})
|
|
this.handleLayoutChange({
|
|
target: {
|
|
value: `1x1`
|
|
}
|
|
})
|
|
this.activeCanvasIndex = 0
|
|
this.$emit('toggleImage', {
|
|
studyId: this.serie.studyId,
|
|
path: this.serie.fileInfo.Path,
|
|
})
|
|
}
|
|
},
|
|
// 恢复
|
|
async recovery() {
|
|
// if (this.isComparison) return false
|
|
if (!this.serie.fileInfo.IsBeMark) return this.$confirm(this.$t("DicomViewer:anonymous:notMasked"))
|
|
if (this.isAnonymous) {
|
|
this.comparison(false)
|
|
}
|
|
this.setToolsPassive()
|
|
let data = {
|
|
// NodicomStudyId: this.serie.studyId,
|
|
NoneDicomStudyFileIdList: [
|
|
this.serie.fileInfo.Id
|
|
],
|
|
}
|
|
let res = await this.noneDicomStudyUndoMaskImage(data)
|
|
if (!res) return false
|
|
let file = res.find(item => item.Id === this.serie.fileInfo.Id)
|
|
this.$emit('replaceImage', {
|
|
studyId: this.serie.studyId,
|
|
path: this.serie.fileInfo.Path,
|
|
file,
|
|
IsBeMark: false
|
|
})
|
|
},
|
|
// 应用
|
|
async anonymousImage() {
|
|
if (this.isComparison) return false
|
|
this.setToolsPassive()
|
|
const renderingEngine = getRenderingEngine(renderingEngineId)
|
|
const viewport = renderingEngine.getViewport(`canvas-${this.activeCanvasIndex}`)
|
|
let imageId = viewport.getCurrentImageId()
|
|
console.log(imageId);
|
|
let annotations = annotation.state.getAllAnnotations().filter(item => item.metadata.toolName === "Note_RectangleRoi" && item.metadata.referencedImageId === imageId)
|
|
if (annotations.length <= 0) return false
|
|
console.log(annotations)
|
|
let data = {
|
|
// NodicomStudyId: this.serie.studyId,
|
|
NoneDicomStudyFileIdList: [
|
|
this.serie.fileInfo.Id
|
|
],
|
|
MaskRegionList: []
|
|
}
|
|
annotations.forEach(item => {
|
|
let points = item.data.handles.points
|
|
let currentStart = points[0]
|
|
let currentEnd = points[3]
|
|
let start = {
|
|
x: currentStart[0] > currentEnd[0] ? Math.round(currentEnd[0]) : Math.round(currentStart[0]),
|
|
y: currentStart[1] > currentEnd[1] ? Math.round(currentEnd[1]) : Math.round(currentStart[1]),
|
|
}
|
|
let end = {
|
|
x: currentStart[0] > currentEnd[0] ? Math.round(currentStart[0]) : Math.round(currentEnd[0]),
|
|
y: currentStart[1] > currentEnd[1] ? Math.round(currentStart[1]) : Math.round(currentEnd[1]),
|
|
}
|
|
let width = end.x - start.x
|
|
let height = end.y - start.y
|
|
data.MaskRegionList.push({
|
|
X: start.x,
|
|
Y: start.y,
|
|
Width: width,
|
|
Height: height
|
|
})
|
|
})
|
|
let res = await this.noneDicomStudyMaskImage(data)
|
|
if (!res || res.length <= 0) return this.$confirm(this.$t("DicomViewer:anonymous:studyMaskImageFail"))
|
|
annotations.forEach(item => {
|
|
annotation.state.removeAnnotation(item.annotationUID)
|
|
})
|
|
let file = res.find(item => item.Id === this.serie.fileInfo.Id)
|
|
this.$emit('replaceImage', {
|
|
studyId: this.serie.studyId,
|
|
path: this.serie.fileInfo.Path,
|
|
file,
|
|
IsBeMark: true
|
|
})
|
|
},
|
|
openAnonymous() {
|
|
if (this.loading || this.isComparison) return false
|
|
this.isAnonymous = !this.isAnonymous
|
|
// if (!this.isAnonymous) {
|
|
// const elements = document.querySelectorAll('.dicom-item')
|
|
// const scope = this
|
|
// Array.from(elements).forEach((element, index) => {
|
|
// if (element.style.display !== 'none') {
|
|
// scope.$refs[`dicomCanvas${index}`].setToolPassive(scope.activeTool)
|
|
// }
|
|
// })
|
|
// scope.activeTool = null
|
|
// } else {
|
|
// this.activateDicomCanvas(0)
|
|
// this.changeLayout('1x1')
|
|
// }
|
|
},
|
|
async noneDicomStudyMaskImage(data) {
|
|
try {
|
|
this.loading = true
|
|
let res = await noneDicomStudyMaskImage(data)
|
|
this.loading = false
|
|
if (res.IsSuccess) {
|
|
return res.Result.OkList
|
|
}
|
|
return false
|
|
} catch (err) {
|
|
console.log(err)
|
|
this.loading = false
|
|
return false
|
|
}
|
|
},
|
|
async noneDicomStudyUndoMaskImage(data) {
|
|
try {
|
|
this.loading = true
|
|
let res = await noneDicomStudyUndoMaskImage(data)
|
|
this.loading = false
|
|
if (res.IsSuccess) {
|
|
return res.Result.OkList
|
|
}
|
|
return false
|
|
} catch (err) {
|
|
console.log(err)
|
|
this.loading = false
|
|
return false
|
|
}
|
|
},
|
|
showPanel(e) {
|
|
e.currentTarget.firstChild.lastChild.style.display = 'block'
|
|
},
|
|
toolMouseout(e) {
|
|
e.currentTarget.firstChild.lastChild.style.display = 'none'
|
|
},
|
|
// 初始化加载器
|
|
async initLoader() {
|
|
registerWebImageLoader(imageLoader)
|
|
await initLibraries()
|
|
|
|
let renderingEngine = getRenderingEngine(renderingEngineId)
|
|
if (!renderingEngine) {
|
|
renderingEngine = new RenderingEngine(renderingEngineId)
|
|
}
|
|
const resizeObserver = new ResizeObserver(() => {
|
|
const renderingEngine = getRenderingEngine(renderingEngineId)
|
|
if (renderingEngine) {
|
|
renderingEngine.resize(true, false)
|
|
this.$nextTick(() => {
|
|
this.reapplyFitModeForVisibleViewports()
|
|
})
|
|
}
|
|
})
|
|
const element1 = this.$refs['canvas-0'][0]
|
|
const element2 = this.$refs['canvas-1'][0]
|
|
const element3 = this.$refs['canvas-2'][0]
|
|
const element4 = this.$refs['canvas-3'][0]
|
|
const elements = [
|
|
element1,
|
|
element2,
|
|
element3,
|
|
element4
|
|
]
|
|
elements.forEach((element, i) => {
|
|
element.oncontextmenu = (e) => e.preventDefault()
|
|
resizeObserver.observe(element)
|
|
element.addEventListener('CORNERSTONE_STACK_NEW_IMAGE', this.stackNewImage)
|
|
element.addEventListener('CORNERSTONE_IMAGE_RENDERED', this.handleImageRendered)
|
|
})
|
|
const viewportInputArray = [
|
|
{
|
|
viewportId: 'canvas-0',
|
|
type: ViewportType.STACK,
|
|
element: element1
|
|
},
|
|
{
|
|
viewportId: 'canvas-1',
|
|
type: ViewportType.STACK,
|
|
element: element2
|
|
},
|
|
{
|
|
viewportId: 'canvas-2',
|
|
type: ViewportType.STACK,
|
|
element: element3
|
|
},
|
|
{
|
|
viewportId: 'canvas-3',
|
|
type: ViewportType.STACK,
|
|
element: element4
|
|
}
|
|
]
|
|
const viewportIds = ['canvas-0', 'canvas-1', 'canvas-2', 'canvas-3']
|
|
renderingEngine.setViewports(viewportInputArray)
|
|
cornerstoneTools.addTool(StackScrollTool)
|
|
cornerstoneTools.addTool(PanTool)
|
|
cornerstoneTools.addTool(ZoomTool)
|
|
cornerstoneTools.addTool(PlanarRotateTool)
|
|
cornerstoneTools.addTool(ArrowAnnotateTool)
|
|
cornerstoneTools.addTool(RectangleROITool)
|
|
cornerstoneTools.addTool(EllipticalROITool)
|
|
cornerstoneTools.addTool(CircleROITool)
|
|
cornerstoneTools.addTool(AngleTool)
|
|
cornerstoneTools.addTool(PlanarFreehandROITool)
|
|
cornerstoneTools.addTool(SplineROITool)
|
|
cornerstoneTools.addTool(EraserTool)
|
|
cornerstoneTools.addTool(Note_RectangleRoiTool)
|
|
cornerstoneTools.addTool(LengthTool)
|
|
cornerstoneTools.addTool(LengthscaleTool)
|
|
cornerstoneTools.addTool(BidirectionalTool)
|
|
viewportIds.forEach((viewportId, i) => {
|
|
const toolGroupId = `canvas-${i}`
|
|
const toolGroup = ToolGroupManager.createToolGroup(toolGroupId)
|
|
toolGroup.addViewport(viewportId, renderingEngineId)
|
|
toolGroup.addTool(StackScrollTool.toolName)
|
|
toolGroup.addTool(PanTool.toolName)
|
|
toolGroup.addTool(ZoomTool.toolName)
|
|
toolGroup.addTool(PlanarRotateTool.toolName)
|
|
toolGroup.addTool(ArrowAnnotateTool.toolName)
|
|
toolGroup.addTool(RectangleROITool.toolName)
|
|
toolGroup.addTool(BidirectionalTool.toolName)
|
|
toolGroup.addTool(EllipticalROITool.toolName)
|
|
toolGroup.addTool(CircleROITool.toolName)
|
|
toolGroup.addTool(AngleTool.toolName)
|
|
toolGroup.addTool(PlanarFreehandROITool.toolName)
|
|
toolGroup.addTool(SplineROITool.toolName)
|
|
|
|
toolGroup.addTool(EraserTool.toolName)
|
|
toolGroup.addTool(Note_RectangleRoiTool.toolName)
|
|
toolGroup.addTool(LengthTool.toolName)
|
|
toolGroup.addTool(LengthscaleTool.toolName)
|
|
|
|
toolGroup.setToolActive(StackScrollTool.toolName, {
|
|
bindings: [{ mouseButton: MouseBindings.Wheel }]
|
|
})
|
|
toolGroup.setToolPassive(PanTool.toolName)
|
|
toolGroup.setToolPassive(ZoomTool.toolName)
|
|
toolGroup.setToolPassive(PlanarRotateTool.toolName)
|
|
toolGroup.setToolPassive(EraserTool.toolName)
|
|
toolGroup.setToolPassive(Note_RectangleRoiTool.toolName)
|
|
})
|
|
},
|
|
lengthscaleToolDisabled(saved) {
|
|
const viewportIds = ['canvas-0', 'canvas-1', 'canvas-2', 'canvas-3']
|
|
viewportIds.forEach(toolGroupId => {
|
|
const toolGroup = ToolGroupManager.getToolGroup(toolGroupId)
|
|
if (saved) {
|
|
toolGroup.setToolPassive(LengthscaleTool.toolName)
|
|
} else {
|
|
toolGroup.setToolEnabled(LengthscaleTool.toolName)
|
|
}
|
|
})
|
|
},
|
|
// 加载图片回调
|
|
stackNewImage(e) {
|
|
if (this.isComparison) return false
|
|
const { detail } = e
|
|
const i = this.viewportInfos.findIndex(i => i.viewportId === detail.viewportId)
|
|
if (i === -1) return
|
|
if (detail.imageIdIndex !== this.viewportInfos[i].currentImageIdIndex) {
|
|
this.viewportInfos[i].currentImageIdIndex = detail.imageIdIndex
|
|
const obj = this.viewportInfos[i].fileList[detail.imageIdIndex]
|
|
if (!obj) return
|
|
this.viewportInfos[i].currentFileName = obj.FileName
|
|
const total = this.viewportInfos[i].imageIds.length
|
|
this.viewportInfos[i].height = total > 1 ? (this.viewportInfos[i].currentImageIdIndex) * 100 / (total - 1) : 0
|
|
this.$emit('toggleImage', {
|
|
studyId: this.viewportInfos[i].studyId,
|
|
path: obj.Path
|
|
})
|
|
this.$nextTick(() => {
|
|
this.applyFitMode(i, this.isFitToWindowMode)
|
|
})
|
|
return
|
|
}
|
|
this.updateZoomDisplayByViewportId(detail.viewportId)
|
|
},
|
|
handleImageRendered(e) {
|
|
const viewportId = e?.detail?.viewportId || e?.currentTarget?.dataset?.viewportUid
|
|
if (!viewportId) return
|
|
this.updateZoomDisplayByViewportId(viewportId)
|
|
},
|
|
updateZoomDisplayByViewportId(viewportId) {
|
|
const index = this.viewportInfos.findIndex(item => item.viewportId === viewportId)
|
|
if (index === -1) return
|
|
this.updateZoomDisplay(index)
|
|
},
|
|
updateZoomDisplay(index) {
|
|
const viewportInfo = this.viewportInfos[index]
|
|
if (!viewportInfo || !this.imageType.includes(viewportInfo.fileType) || !viewportInfo.imageIds.length) {
|
|
if (viewportInfo) viewportInfo.zoomText = ''
|
|
return
|
|
}
|
|
const renderingEngine = getRenderingEngine(renderingEngineId)
|
|
const viewport = renderingEngine?.getViewport(viewportInfo.viewportId)
|
|
if (!viewport) return
|
|
const camera = viewport.getCamera?.()
|
|
const canvas = viewport.getCanvas?.() || this.$refs[`canvas-${index}`]?.[0]
|
|
const canvasHeight = canvas?.clientHeight
|
|
const parallelScale = Number(camera?.parallelScale)
|
|
if (!canvasHeight || !Number.isFinite(parallelScale) || parallelScale <= 0) {
|
|
viewportInfo.zoomText = ''
|
|
return
|
|
}
|
|
const magnification = canvasHeight / (parallelScale * 2)
|
|
if (!Number.isFinite(magnification) || magnification <= 0) {
|
|
viewportInfo.zoomText = ''
|
|
return
|
|
}
|
|
viewportInfo.zoomText = `${magnification.toFixed(1)}x`
|
|
},
|
|
// 渲染图片
|
|
async renderImage(imageIds, canvasIndex, sliceIndex) {
|
|
metaData.addProvider((type, imageId) => hardcodedMetaDataProvider(type, imageId, imageIds), 10000)
|
|
const renderingEngine = getRenderingEngine(renderingEngineId)
|
|
const viewport = renderingEngine.getViewport(`canvas-${canvasIndex}`)
|
|
await viewport.setStack(imageIds)
|
|
this.setToolsPassive()
|
|
viewport.setImageIdIndex(sliceIndex)
|
|
viewport.render()
|
|
this.$nextTick(() => {
|
|
this.applyFitMode(canvasIndex, this.isFitToWindowMode)
|
|
this.updateZoomDisplay(canvasIndex)
|
|
})
|
|
// this.updateViewportInfos()
|
|
},
|
|
setActiveCanvasImages(obj) {
|
|
if (!obj || Object.keys(obj).length === 0) return
|
|
this.serie = obj
|
|
const i = this.viewportInfos.findIndex(i => i.index === this.activeCanvasIndex)
|
|
if (i === -1) return
|
|
if (obj.studyId === this.viewportInfos[i].studyId && this.imageType.includes(this.viewportInfos[i].fileType) && this.imageType.includes(obj.fileInfo.FileType) && !obj.isReset) {
|
|
const fileIndex = this.viewportInfos[i].fileList.findIndex(i => i.Path === obj.fileInfo.Path)
|
|
this.sliceIndex(fileIndex)
|
|
} else {
|
|
if (!this.imageType.includes(obj.fileInfo.FileType)) {
|
|
this.fullScreenIndex = null
|
|
}
|
|
this.updateViewportInfos(this.activeCanvasIndex, obj)
|
|
}
|
|
this.setToolsPassive()
|
|
},
|
|
// 激活视图
|
|
activeCanvas(index) {
|
|
if (this.activeCanvasIndex === index) return
|
|
const i = this.viewportInfos.findIndex(i => i.index === index)
|
|
if (i === -1) return
|
|
this.activeCanvasIndex = index
|
|
this.setToolsPassive()
|
|
},
|
|
// 更新视图信息
|
|
updateViewportInfos(index, obj) {
|
|
const i = this.viewportInfos.findIndex(i => i.index === index)
|
|
if (i === -1) return
|
|
|
|
this.viewportInfos[i].taskInfo = obj.visitTaskInfo
|
|
|
|
this.viewportInfos[i].currentFileName = obj.fileInfo.FileName
|
|
this.viewportInfos[i].studyId = obj.studyId
|
|
this.viewportInfos[i].fileType = obj.fileInfo.FileType
|
|
if (this.imageType.includes(obj.fileInfo.FileType)) {
|
|
const arr = obj.fileList.filter(i => this.imageType.includes(i.FileType))
|
|
this.viewportInfos[i].fileList = arr
|
|
const fileIndex = this.viewportInfos[i].fileList.findIndex(i => i.Path === obj.fileInfo.Path)
|
|
this.viewportInfos[i].currentImageIdIndex = fileIndex
|
|
const imageIds = []
|
|
for (let i = 0; i < arr.length; i++) {
|
|
const path = arr[i].Path
|
|
imageIds.push(`web:${this.OSSclientConfig.basePath}${path}`)
|
|
}
|
|
this.viewportInfos[i].imageIds = imageIds
|
|
if (imageIds.length > 0) {
|
|
this.renderImage(imageIds, index, fileIndex)
|
|
}
|
|
this.$nextTick(() => {
|
|
const renderingEngine = getRenderingEngine(renderingEngineId)
|
|
if (renderingEngine) {
|
|
renderingEngine.resize(true, false)
|
|
}
|
|
})
|
|
} else {
|
|
this.viewportInfos[i].currentFilePath = obj.fileInfo.Path
|
|
this.viewportInfos[i].zoomText = ''
|
|
}
|
|
},
|
|
// 切换图片
|
|
sliceIndex(index) {
|
|
const i = this.viewportInfos.findIndex(i => i.index === this.activeCanvasIndex)
|
|
if (i === -1) return
|
|
if (index < 0 || index >= this.viewportInfos[i].imageIds.length) return
|
|
const renderingEngine = getRenderingEngine(renderingEngineId)
|
|
const viewport = renderingEngine.getViewport(
|
|
this.viewportInfos[i].viewportId
|
|
)
|
|
this.setToolsPassive()
|
|
viewport.setImageIdIndex(index)
|
|
viewport.render()
|
|
},
|
|
// 更改视图布局
|
|
handleCommand(command) {
|
|
this.fullScreenIndex = null
|
|
this.layout = command
|
|
this.rows = parseInt(command.split('*')[0])
|
|
this.cols = parseInt(command.split('*')[1])
|
|
if (this.rows === 1 && this.cols === 1) {
|
|
this.$nextTick(() => {
|
|
this.activeCanvas(0)
|
|
})
|
|
}
|
|
},
|
|
handleLayoutChange(event) {
|
|
this.handleCommand(event.target.value.replace('x', '*'))
|
|
},
|
|
getCellStyle(index) {
|
|
return {
|
|
...this.cellStyle,
|
|
display: index < this.cells.length ? this.cellStyle.display : 'none'
|
|
}
|
|
},
|
|
// 切换全屏
|
|
toggleFullScreen(e, index) {
|
|
const i = this.viewportInfos.findIndex(i => i.index === index)
|
|
if (i === -1) return
|
|
if (!this.viewportInfos[i].currentFileName) return
|
|
if (this.imageType.includes(this.viewportInfos[i].fileType)) {
|
|
this.fullScreenIndex = this.fullScreenIndex === index ? null : index
|
|
this.activeCanvasIndex = index
|
|
}
|
|
},
|
|
// 激活工具
|
|
setToolActive(toolName) {
|
|
const i = this.viewportInfos.findIndex(i => i.index === this.activeCanvasIndex)
|
|
if (i === -1) return
|
|
const toolGroupId = `canvas-${this.viewportInfos[i].index}`
|
|
const toolGroup = ToolGroupManager.getToolGroup(toolGroupId)
|
|
if (this.activeTool === toolName) {
|
|
toolGroup.setToolPassive(this.activeTool)
|
|
this.activeTool = ''
|
|
} else {
|
|
if (this.activeTool) {
|
|
toolGroup.setToolPassive(this.activeTool)
|
|
}
|
|
toolGroup.setToolActive(toolName, {
|
|
bindings: [{ mouseButton: MouseBindings.Primary }]
|
|
})
|
|
this.activeTool = toolName
|
|
}
|
|
},
|
|
setToolsPassive() {
|
|
if (!this.activeTool) return
|
|
const toolGroupIds = ['canvas-0', 'canvas-1', 'canvas-2', 'canvas-3']
|
|
toolGroupIds.forEach(toolGroupId => {
|
|
const toolGroup = ToolGroupManager.getToolGroup(toolGroupId)
|
|
toolGroup.setToolPassive(this.activeTool)
|
|
})
|
|
this.activeTool = ''
|
|
},
|
|
// 重置视图
|
|
resetViewport() {
|
|
this.setToolsPassive()
|
|
const renderingEngine = getRenderingEngine(renderingEngineId)
|
|
const viewportId = `canvas-${this.activeCanvasIndex}`
|
|
const viewport = (renderingEngine.getViewport(viewportId))
|
|
viewport.resetCamera({ resetPan: true, resetZoom: true, resetToCenter: true })
|
|
renderingEngine.render()
|
|
this.updateZoomDisplay(this.activeCanvasIndex)
|
|
},
|
|
toggleFitMode() {
|
|
this.setToolsPassive()
|
|
this.isFitToWindowMode = !this.isFitToWindowMode
|
|
this.applyFitMode(this.activeCanvasIndex, this.isFitToWindowMode)
|
|
},
|
|
applyFitMode(canvasIndex = this.activeCanvasIndex, isFitToWindowMode = this.isFitToWindowMode) {
|
|
const viewportInfo = this.viewportInfos[canvasIndex]
|
|
if (!viewportInfo || !this.imageType.includes(viewportInfo.fileType) || !viewportInfo.imageIds.length) return
|
|
const renderingEngine = getRenderingEngine(renderingEngineId)
|
|
const viewport = renderingEngine?.getViewport(`canvas-${canvasIndex}`)
|
|
if (!viewport) return
|
|
|
|
viewport.resetCamera({ resetPan: true, resetZoom: true, resetToCenter: true })
|
|
if (isFitToWindowMode) {
|
|
viewport.render()
|
|
return
|
|
}
|
|
|
|
const canvas = viewport.getCanvas() || this.$refs[`canvas-${canvasIndex}`]?.[0]
|
|
const imageData = viewport.getImageData?.()?.imageData
|
|
const dimensions = imageData?.getDimensions?.()
|
|
const imageWidth = dimensions?.[0]
|
|
const imageHeight = dimensions?.[1]
|
|
const canvasWidth = canvas?.clientWidth
|
|
const canvasHeight = canvas?.clientHeight
|
|
|
|
if (!imageWidth || !imageHeight || !canvasWidth || !canvasHeight) {
|
|
viewport.render()
|
|
return
|
|
}
|
|
|
|
const fitScale = Math.min(canvasWidth / imageWidth, canvasHeight / imageHeight)
|
|
if (fitScale > 0) {
|
|
viewport.setZoom(1 / fitScale)
|
|
}
|
|
viewport.render()
|
|
this.updateZoomDisplay(canvasIndex)
|
|
},
|
|
reapplyFitModeForVisibleViewports() {
|
|
this.viewportInfos.forEach((viewportInfo, index) => {
|
|
if (index >= this.cells.length) return
|
|
if (!this.imageType.includes(viewportInfo.fileType) || !viewportInfo.imageIds.length) return
|
|
this.applyFitMode(index, this.isFitToWindowMode)
|
|
})
|
|
},
|
|
setZoomScale(isZoomIn) {
|
|
this.setToolsPassive()
|
|
const renderingEngine = getRenderingEngine(renderingEngineId)
|
|
const viewportId = `canvas-${this.activeCanvasIndex}`
|
|
const viewport = renderingEngine?.getViewport(viewportId)
|
|
if (!viewport) return
|
|
const camera = viewport.getCamera()
|
|
const factor = 1.1
|
|
const current = Number(camera.parallelScale)
|
|
if (!Number.isFinite(current) || current <= 0) return
|
|
const next = isZoomIn ? current / factor : current * factor
|
|
const parallelScale = Math.max(0.0001, Math.min(1000000, next))
|
|
viewport.setCamera({ parallelScale })
|
|
viewport.render()
|
|
this.updateZoomDisplay(this.activeCanvasIndex)
|
|
},
|
|
// 滚动条
|
|
clickSlider(e, index) {
|
|
const i = this.viewportInfos.findIndex(i => i.index === index)
|
|
if (i === -1) return
|
|
const sliderBox = this.$refs[`sliderBox-${index}`] && this.$refs[`sliderBox-${index}`][0]
|
|
if (!sliderBox || !this.imageType.includes(this.viewportInfos[i].fileType)) return
|
|
const boxHeight = sliderBox.clientHeight
|
|
if (!boxHeight || !this.viewportInfos[i].imageIds.length) return
|
|
const height = e.offsetY * 100 / boxHeight
|
|
this.viewportInfos[i].height = height
|
|
let sliceIdx = Math.trunc(this.viewportInfos[i].imageIds.length * height / 100)
|
|
sliceIdx = sliceIdx >= this.viewportInfos[i].imageIds.length ? this.viewportInfos[i].imageIds.length - 1 : sliceIdx < 0 ? 0 : sliceIdx
|
|
const renderingEngine = getRenderingEngine(renderingEngineId)
|
|
const viewport = renderingEngine.getViewport(
|
|
this.viewportInfos[i].viewportId
|
|
)
|
|
this.setToolsPassive()
|
|
viewport.setImageIdIndex(sliceIdx)
|
|
viewport.render()
|
|
this.updateZoomDisplay(index)
|
|
},
|
|
sliderMouseup(e, index) {
|
|
const i = this.viewportInfos.findIndex(i => i.index === index)
|
|
if (i === -1 || !this.imageType.includes(this.viewportInfos[i].fileType)) return
|
|
this.viewportInfos[i].isMove = false
|
|
},
|
|
sliderMousemove(e, index) {
|
|
const i = this.viewportInfos.findIndex(i => i.index === index)
|
|
if (i === -1 || !this.imageType.includes(this.viewportInfos[i].fileType)) return
|
|
if (!this.viewportInfos[i].isMove) return
|
|
const sliderBox = this.$refs[`sliderBox-${index}`] && this.$refs[`sliderBox-${index}`][0]
|
|
if (!sliderBox || !this.viewportInfos[i].imageIds.length) return
|
|
const delta = this.viewportInfos[i].oldB - (this.viewportInfos[i].oldM - e.clientY)
|
|
const boxHeight = sliderBox.clientHeight
|
|
if (delta < 0) return
|
|
if (delta > boxHeight) return
|
|
const height = delta * 100 / boxHeight
|
|
let sliceIdx = Math.trunc(this.viewportInfos[i].imageIds.length * height / 100)
|
|
sliceIdx = sliceIdx >= this.viewportInfos[i].imageIds.length ? this.viewportInfos[i].imageIds.length - 1 : sliceIdx < 0 ? 0 : sliceIdx
|
|
this.viewportInfos[i].height = height
|
|
// if (this.viewportInfos[i].currentImageIdIndex !== i) {
|
|
const renderingEngine = getRenderingEngine(renderingEngineId)
|
|
const viewport = renderingEngine.getViewport(
|
|
this.viewportInfos[i].viewportId
|
|
)
|
|
this.setToolsPassive()
|
|
viewport.setImageIdIndex(sliceIdx)
|
|
viewport.render()
|
|
this.updateZoomDisplay(index)
|
|
// }
|
|
// this.$emit('toggleImage', { taskId: this.viewportInfos[i].taskInfo.VisitTaskId, studyId: this.viewportInfos[i].studyId, imageIndex: sliceIdx })
|
|
},
|
|
sliderMouseleave(e, index) {
|
|
const i = this.viewportInfos.findIndex(i => i.index === index)
|
|
if (i === -1 || !this.imageType.includes(this.viewportInfos[i].fileType)) return
|
|
if (!this.viewportInfos[i].isMove) return
|
|
this.viewportInfos[i].isMove = false
|
|
},
|
|
sliderMousedown(e, index) {
|
|
const i = this.viewportInfos.findIndex(i => i.index === index)
|
|
if (i === -1 || !this.imageType.includes(this.viewportInfos[i].fileType)) return
|
|
const sliderBox = this.$refs[`sliderBox-${index}`] && this.$refs[`sliderBox-${index}`][0]
|
|
if (!sliderBox || !this.viewportInfos[i].imageIds.length) return
|
|
const boxHeight = sliderBox.clientHeight
|
|
const sliderTop = parseFloat(e.currentTarget.style.top) || 0
|
|
this.viewportInfos[i].oldB = sliderTop * boxHeight / 100
|
|
this.viewportInfos[i].oldM = e.clientY
|
|
this.viewportInfos[i].isMove = true
|
|
e.stopImmediatePropagation()
|
|
e.stopPropagation()
|
|
e.preventDefault()
|
|
}
|
|
}
|
|
}
|
|
</script>
|
|
<style lang="scss" scoped>
|
|
.content {
|
|
cursor: default !important;
|
|
}
|
|
|
|
.dropdown {
|
|
position: relative;
|
|
display: inline-block;
|
|
|
|
.text {
|
|
text-align: center;
|
|
}
|
|
}
|
|
|
|
.dropdown-content {
|
|
display: none;
|
|
position: absolute;
|
|
background-color: #383838;
|
|
color: #fff;
|
|
box-shadow: 0px 8px 16px 0px rgba(0, 0, 0, 0.2);
|
|
z-index: 9999;
|
|
font-size: 12px;
|
|
|
|
ul {
|
|
list-style: none;
|
|
margin: 0;
|
|
padding: 0;
|
|
text-align: center;
|
|
|
|
li {
|
|
a {
|
|
display: block;
|
|
padding: 5px;
|
|
}
|
|
}
|
|
}
|
|
|
|
ul li a:hover {
|
|
background-color: #727272;
|
|
}
|
|
|
|
.customize-standards-list {
|
|
width: max-content;
|
|
white-space: nowrap;
|
|
|
|
li a {
|
|
display: flex;
|
|
align-items: center;
|
|
padding: 8px !important;
|
|
box-sizing: border-box;
|
|
}
|
|
}
|
|
}
|
|
|
|
.none-dicom-viewer {
|
|
display: flex;
|
|
flex-direction: row;
|
|
width: 100%;
|
|
height: 100%;
|
|
user-select: none;
|
|
background: #000;
|
|
|
|
.dicom-tools {
|
|
width: 300px;
|
|
height: 100%;
|
|
background-color: #323232;
|
|
margin: 0 0 0 2px;
|
|
padding: 0;
|
|
color: #d0d0d0;
|
|
font-size: 13px;
|
|
overflow-y: auto;
|
|
}
|
|
|
|
.sideTool-title {
|
|
padding: 5px 8px;
|
|
background-color: #525252;
|
|
color: #bebdbd;
|
|
font-size: 14px;
|
|
margin: 4px;
|
|
}
|
|
|
|
.sideTool-wrapper {
|
|
border-bottom: 1px solid gray;
|
|
margin: 0 4px;
|
|
padding: 4px;
|
|
font-size: 12px;
|
|
}
|
|
|
|
.sidetool-select {
|
|
height: 30px;
|
|
background-color: rgba(0, 0, 0, 0);
|
|
color: #d0d0d0;
|
|
border-radius: 4px;
|
|
border: 1px solid #5b5b5b;
|
|
}
|
|
|
|
.sidetool-select>option {
|
|
background-color: #323232;
|
|
}
|
|
|
|
.sideTool-wrapper button.btn-link {
|
|
height: 40px;
|
|
padding: 8px !important;
|
|
border: 1px solid rgba(37, 37, 37, 1);
|
|
margin: 1px 1px;
|
|
}
|
|
|
|
.sideTool-wrapper .btn-link {
|
|
display: inline-flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
min-width: 40px;
|
|
color: #cccccc;
|
|
background-color: transparent;
|
|
cursor: pointer;
|
|
}
|
|
|
|
.activeTool {
|
|
background: #16477b90 !important;
|
|
border: none !important;
|
|
}
|
|
|
|
.sideTool-wrapper label {
|
|
display: inline-block;
|
|
min-width: 44px;
|
|
margin-right: 6px;
|
|
}
|
|
|
|
.viewports-wrapper {
|
|
flex: 1;
|
|
min-width: 0;
|
|
position: relative;
|
|
|
|
.grid-container {
|
|
display: grid;
|
|
height: 100%;
|
|
width: 100%;
|
|
position: relative;
|
|
}
|
|
|
|
.grid-cell {
|
|
border: 1px dashed #ccc;
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
overflow: hidden;
|
|
min-width: 0;
|
|
min-height: 0;
|
|
z-index: 1;
|
|
}
|
|
|
|
.cell_active {
|
|
border-color: #fafa00 !important;
|
|
}
|
|
|
|
.cell-full-screen {
|
|
grid-column: 1 / -1;
|
|
grid-row: 1 / -1;
|
|
}
|
|
|
|
.flex_col {
|
|
display: flex;
|
|
flex-direction: column;
|
|
}
|
|
|
|
.content {
|
|
width: 100%;
|
|
height: 100%;
|
|
position: relative;
|
|
|
|
.left-top-text {
|
|
position: absolute;
|
|
left: 5px;
|
|
top: 5px;
|
|
color: #ddd;
|
|
z-index: 1;
|
|
font-size: 14px;
|
|
|
|
.cd-info {
|
|
color: #ddd;
|
|
font-size: 18px;
|
|
}
|
|
|
|
.subject-info {
|
|
color: #f44336;
|
|
padding: 5px 0px;
|
|
margin: 0;
|
|
}
|
|
}
|
|
|
|
.left-bottom-text {
|
|
position: absolute;
|
|
left: 5px;
|
|
bottom: 5px;
|
|
color: #ddd;
|
|
z-index: 1;
|
|
font-size: 14px;
|
|
}
|
|
|
|
.top-center-tool {
|
|
position: absolute;
|
|
left: 50%;
|
|
top: 5px;
|
|
transform: translateX(-50%);
|
|
z-index: 1;
|
|
|
|
.toggle-visit-container {
|
|
display: flex;
|
|
}
|
|
|
|
.arrw_icon {
|
|
width: 20px;
|
|
height: 20px;
|
|
background-color: #3f3f3f;
|
|
text-align: center;
|
|
line-height: 20px;
|
|
border-radius: 10%;
|
|
}
|
|
|
|
.arrow_text {
|
|
height: 20px;
|
|
line-height: 20px;
|
|
background-color: #00000057;
|
|
color: #fff;
|
|
padding: 0 10px;
|
|
font-size: 14px;
|
|
}
|
|
}
|
|
|
|
.right-slider-box {
|
|
position: absolute;
|
|
right: 1px;
|
|
height: calc(100% - 140px);
|
|
transform: translateY(-50%);
|
|
top: calc(50% - 30px);
|
|
width: 10px;
|
|
background: #333;
|
|
z-index: 1;
|
|
cursor: pointer;
|
|
}
|
|
|
|
.right-slider-box:after {
|
|
content: '';
|
|
position: absolute;
|
|
bottom: -20px;
|
|
left: 0;
|
|
height: 20px;
|
|
width: 100%;
|
|
background: #333;
|
|
}
|
|
|
|
.slider {
|
|
height: 20px;
|
|
width: 100%;
|
|
position: absolute;
|
|
top: 0;
|
|
z-index: 10;
|
|
background: #9e9e9e;
|
|
cursor: move
|
|
}
|
|
|
|
.content-main {
|
|
position: relative;
|
|
overflow: hidden;
|
|
background: #1e1e1e;
|
|
}
|
|
|
|
video {
|
|
display: block;
|
|
width: 100%;
|
|
height: 100%;
|
|
object-fit: contain;
|
|
object-position: center center;
|
|
background: transparent;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
.Anonymous {
|
|
position: absolute;
|
|
border-radius: 5px;
|
|
bottom: 30px;
|
|
left: 5%;
|
|
right: 5%;
|
|
width: 90%;
|
|
height: 60px;
|
|
padding: 0 10px;
|
|
background-color: rgba(255, 255, 255, .2);
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: space-between;
|
|
z-index: 2000;
|
|
|
|
.btn {
|
|
width: 12%;
|
|
text-align: center;
|
|
height: 40px;
|
|
line-height: 30px;
|
|
border-radius: 15px;
|
|
cursor: pointer;
|
|
padding: 5px 10px;
|
|
color: #428bca;
|
|
background: #ecf3fa;
|
|
border-color: #b3d1ea;
|
|
}
|
|
|
|
.activeBtn {
|
|
background: #428bca;
|
|
border-color: #428bca;
|
|
color: #fff;
|
|
}
|
|
|
|
.isNoted {
|
|
cursor: not-allowed;
|
|
}
|
|
|
|
// &:hover {
|
|
// background-color: rgba(255, 255, 255, .5);
|
|
// }
|
|
}
|
|
|
|
|
|
|
|
|
|
.dicom-tools .btnBox {
|
|
display: inline-block;
|
|
width: 80px;
|
|
text-align: center;
|
|
height: 30px;
|
|
line-height: 20px;
|
|
border-radius: 15px;
|
|
color: #428bca;
|
|
background: #ecf3fa;
|
|
border-color: #b3d1ea;
|
|
cursor: pointer;
|
|
padding: 5px 10px;
|
|
border: 1px solid rgba(255, 255, 255, .7);
|
|
margin: 5px;
|
|
}
|
|
|
|
.dicom-tools .activeBtnBox {
|
|
background: #428bca;
|
|
border-color: #428bca;
|
|
color: #fff;
|
|
}
|
|
</style>
|