2153 lines
		
	
	
		
			72 KiB
		
	
	
	
		
			Plaintext
		
	
	
			
		
		
	
	
			2153 lines
		
	
	
		
			72 KiB
		
	
	
	
		
			Plaintext
		
	
	
| <template>
 | ||
|   <div
 | ||
|     v-loading="loading"
 | ||
|     class="dicom-viewer-container"
 | ||
|     @contextmenu="rightClick"
 | ||
|   >
 | ||
|     <!-- 工具条 -->
 | ||
|     <div class="dicom-tools">
 | ||
|       <!-- 窗宽窗位 -->
 | ||
|       <el-tooltip class="item" effect="dark" :content="`${$t('trials:reading:button:wwwc')}`" placement="bottom">
 | ||
|         <div class="tool-wrapper" @click.stop="showPanel($event)" @mouseleave="handleMouseout">
 | ||
|           <div class="dropdown">
 | ||
|             <div
 | ||
|               class="icon"
 | ||
|               :class="[activeTool==='WindowLevel'?'tool_active':'']"
 | ||
|               data-tool="WindowLevel"
 | ||
|             >
 | ||
|               <svg-icon icon-class="reverse" class="svg-icon" @click.prevent="setBasicToolActive('WindowLevel')" />
 | ||
|               <i class="el-icon-arrow-down" style="color:#fff;" />
 | ||
|             </div>
 | ||
|             <!-- 移动 -->
 | ||
|             <div class="text">{{ $t('trials:reading:button:rotate') }}</div>
 | ||
|             <div class="dropdown-content">
 | ||
|               <ul style="width:130px;">
 | ||
|                 <li v-for="item in defaultWwwc" :key="item.label" style="text-align:left;">
 | ||
|                   <a href="#" @click.prevent="setDicomCanvasWwwc(item)">
 | ||
|                     <div v-if="item.wc" style="display:flex;flex-direction: row;justify-content: space-between;">
 | ||
|                       <div>{{ item.label }}</div>
 | ||
|                       <div>{{ item.ww }}/{{ item.wc }}</div>
 | ||
|                     </div>
 | ||
|                     <div v-else style="text-align:left;">
 | ||
|                       {{ item.label }}
 | ||
|                     </div>
 | ||
|                   </a>
 | ||
|                 </li>
 | ||
|               </ul>
 | ||
|             </div>
 | ||
|           </div>
 | ||
|         </div>
 | ||
|       </el-tooltip>
 | ||
|       <!-- <el-tooltip class="item" effect="dark" :content="`${$t('trials:reading:button:wwwc')}`" placement="bottom">
 | ||
|         <div class="tool-wrapper">
 | ||
|           <div
 | ||
|             class="icon"
 | ||
|             :class="[activeTool==='WindowLevel'?'tool_active':'']"
 | ||
|             data-tool="Zoom"
 | ||
|           >
 | ||
|             <svg-icon icon-class="reverse" class="svg-icon" @click.prevent="setBasicToolActive('WindowLevel')" />
 | ||
|           </div>
 | ||
|           <div class="text">{{ $t('trials:reading:button:wwwc') }}</div>
 | ||
|         </div>
 | ||
|       </el-tooltip> -->
 | ||
|       <!-- 反色 -->
 | ||
|       <el-tooltip class="item" effect="dark" :content="`${$t('trials:reading:button:reverseColor')}`" placement="bottom">
 | ||
|         <div class="tool-wrapper">
 | ||
|           <div
 | ||
|             class="icon"
 | ||
|             data-tool="reverse"
 | ||
|           >
 | ||
|             <svg-icon icon-class="reversecolor" class="svg-icon" @click.prevent="toggleInvert" />
 | ||
|           </div>
 | ||
|           <!-- 调窗 -->
 | ||
|           <div class="text">{{ $t('trials:reading:button:reverseColor') }}</div>
 | ||
|         </div>
 | ||
|       </el-tooltip>
 | ||
|       <!-- 缩放 -->
 | ||
|       <el-tooltip class="item" effect="dark" :content="`${$t('trials:reading:button:zoom')}`" placement="bottom">
 | ||
|         <div class="tool-wrapper">
 | ||
|           <div
 | ||
|             class="icon"
 | ||
|             :class="[activeTool==='Zoom'?'tool_active':'']"
 | ||
|             data-tool="Zoom"
 | ||
|           >
 | ||
|             <svg-icon icon-class="magnifier" class="svg-icon" @click.prevent="setBasicToolActive('Zoom')" />
 | ||
|           </div>
 | ||
|           <!-- 缩放 -->
 | ||
|           <div class="text">{{ $t('trials:reading:button:zoom') }}</div>
 | ||
|         </div>
 | ||
|       </el-tooltip>
 | ||
|       <!-- 移动 -->
 | ||
|       <el-tooltip class="item" effect="dark" :content="`${$t('trials:reading:button:move')}`" placement="bottom">
 | ||
|         <div class="tool-wrapper">
 | ||
|           <div
 | ||
|             class="icon"
 | ||
|             :class="[activeTool==='Pan'?'tool_active':'']"
 | ||
|             data-tool="Pan"
 | ||
|           >
 | ||
|             <svg-icon icon-class="move" class="svg-icon" @click.prevent="setBasicToolActive('Pan')" />
 | ||
|           </div>
 | ||
|           <!-- 移动 -->
 | ||
|           <div class="text">{{ $t('trials:reading:button:move') }}</div>
 | ||
|         </div>
 | ||
|       </el-tooltip>
 | ||
|       <!-- 旋转 -->
 | ||
|       <el-tooltip class="item" effect="dark" :content="`${$t('trials:reading:button:rotate')}`" placement="bottom">
 | ||
|         <div class="tool-wrapper" @click.stop="showPanel($event)" @mouseleave="handleMouseout">
 | ||
|           <div class="dropdown">
 | ||
|             <div
 | ||
|               class="icon"
 | ||
|               :class="[activeTool==='Rotate'?'tool_active':'']"
 | ||
|               data-tool="Pan"
 | ||
|             >
 | ||
|               <svg-icon icon-class="rotate" class="svg-icon" @click.prevent="setBasicToolActive('TrackballRotate')" />
 | ||
|               <i class="el-icon-arrow-down" style="color:#fff;" />
 | ||
|             </div>
 | ||
|             <!-- 移动 -->
 | ||
|             <div class="text">{{ $t('trials:reading:button:rotate') }}</div>
 | ||
|             <div class="dropdown-content">
 | ||
|               <ul style="width:100px;">
 | ||
|                 <li v-for="rotate in rotateArr" :key="rotate.label" style="text-align:left;">
 | ||
|                   <a href="#" @click.prevent="setDicomCanvasRotate(rotate.val)">{{ rotate.label }}</a>
 | ||
|                 </li>
 | ||
|               </ul>
 | ||
|             </div>
 | ||
|           </div>
 | ||
|         </div>
 | ||
|       </el-tooltip>
 | ||
|       <!-- 椭圆oval -->
 | ||
|       <template v-for="tool in measuredTools">
 | ||
|         <el-tooltip v-if="isCurrentTask && readingTaskState !== 2" :key="tool.toolName" class="item" effect="dark" :content="tool.text" placement="bottom">
 | ||
|           <div class="tool-wrapper">
 | ||
|             <div
 | ||
|               class="icon"
 | ||
|               :class="[activeTool===tool.toolName?'tool_active':'']"
 | ||
|             >
 | ||
|               <svg-icon :icon-class="tool.icon" class="svg-icon" @click.prevent="setMeasureToolActive(tool.toolName)" />
 | ||
|             </div>
 | ||
|             <div class="text">{{ tool.text }}</div>
 | ||
|           </div>
 | ||
|         </el-tooltip>
 | ||
|       </template>
 | ||
| 
 | ||
|       <!-- <el-tooltip v-if="isCurrentTask" class="item" effect="dark" content="圆形测量" placement="bottom">
 | ||
|         <div class="tool-wrapper">
 | ||
|           <div
 | ||
|             class="icon"
 | ||
|             :class="[activeTool==='Probe'?'tool_active':'']"
 | ||
|             data-tool="Probe"
 | ||
|           >
 | ||
|             <svg-icon icon-class="oval" class="svg-icon" @click.prevent="setBasicToolActive('Probe')" />
 | ||
|           </div>
 | ||
|           <div class="text">探针</div>
 | ||
|         </div>
 | ||
|       </el-tooltip> -->
 | ||
|       <!-- 重置 -->
 | ||
|       <el-tooltip class="item" effect="dark" :content="`${$t('trials:reading:button:reset')}`" placement="bottom">
 | ||
|         <div class="tool-wrapper">
 | ||
|           <div
 | ||
|             class="icon"
 | ||
|             @click.prevent="resetViewport"
 | ||
|           >
 | ||
|             <svg-icon icon-class="refresh" class="svg-icon" />
 | ||
|           </div>
 | ||
|           <div class="text">{{ $t('trials:reading:button:reset') }}</div>
 | ||
|         </div>
 | ||
|       </el-tooltip>
 | ||
|       <el-tooltip class="item" effect="dark" content="伪彩" placement="bottom">
 | ||
|         <div class="colorBar" style="display:flex;justify-content: flex-start;align-items: center;position: relative;" @mouseleave="isSlideMoving = false">
 | ||
|           <div
 | ||
|             class="tool-wrapper"
 | ||
|             style="margin-right:0px"
 | ||
|             @click.stop="showColorBarPanel($event)"
 | ||
|             @mouseleave="handleColorBarMouseout"
 | ||
|           >
 | ||
|             <div>
 | ||
|               <!-- <canvas id="colorBarCanvas" /> -->
 | ||
|               <div class="dropdown">
 | ||
|                 <div
 | ||
|                   id="colorBar"
 | ||
|                   class="icon"
 | ||
|                   style="display: flex;align-items: center;width:160px"
 | ||
|                 >
 | ||
|                   <canvas id="colorBarCanvas" />
 | ||
| 
 | ||
|                 </div>
 | ||
|                 <!-- 移动 -->
 | ||
|                 <div class="text">伪彩</div>
 | ||
|                 <div class="dropdown-content">
 | ||
|                   <ul>
 | ||
|                     <li v-for="(colorMap,index) in colorMaps" :key="colorMap" style="display: flex;align-items: center;margin-bottom:5px;padding:0 5px;" @click="setColorMap(colorMap)">
 | ||
|                       <canvas :id="`colorBarCanvas${index}`" />
 | ||
|                       <span style="margin-left:5px;font-size: 10px;">{{ colorMap }}</span>
 | ||
| 
 | ||
|                     </li>
 | ||
|                   </ul>
 | ||
|                 </div>
 | ||
|               </div>
 | ||
|             </div>
 | ||
|           </div>
 | ||
|           <div style="margin-left:-1px;border: 1px solid #424242;">
 | ||
|             <el-input
 | ||
|               v-model="range"
 | ||
|               size="mini"
 | ||
|               style="width:120px"
 | ||
|               maxlength="3"
 | ||
|               oninput="if(value){value=value.replace(/[^\d]/g,'')} if(value<=0){value=''}"
 | ||
|               @change="upperRangeChange"
 | ||
|             >
 | ||
|               <template slot="append">g/ml</template>
 | ||
|             </el-input>
 | ||
|           </div>
 | ||
|           <div id="slider" style="position: absolute;left: 6px;top:5px;cursor: pointer;">
 | ||
|             <div id="sliderBox" class="slider" style="height: 17px;width: 10px;background-color: #909399;" />
 | ||
|             <div id="slider-position" style="color:#ddd;font-size: 12px;">0</div>
 | ||
|           </div>
 | ||
|         </div>
 | ||
|       </el-tooltip>
 | ||
| 
 | ||
|       <!-- 截屏 -->
 | ||
|       <!-- <el-tooltip class="item" effect="dark" :content="`${$t('trials:reading:button:screenShot')}`" placement="bottom">
 | ||
|         <div class="tool-wrapper">
 | ||
|           <div
 | ||
|             class="icon"
 | ||
|             @click.prevent="saveImage"
 | ||
|           >
 | ||
|             <svg-icon icon-class="image" class="svg-icon" />
 | ||
|           </div>
 | ||
|           <div class="text">{{ $t('trials:reading:button:screenShot') }}</div>
 | ||
|         </div>
 | ||
|       </el-tooltip> -->
 | ||
|       <!-- 椭圆oval -->
 | ||
| 
 | ||
|     </div>
 | ||
|     <div class="dicom-datas">
 | ||
|       <!-- 影像 -->
 | ||
|       <!-- <div class="dicom-container box box_1_1">
 | ||
|         <Viewport
 | ||
|           :ref="activeRef"
 | ||
|           :index="activeIndex"
 | ||
|           :active-index="activeIndex"
 | ||
|           :is-reading-show-subject-info="isReadingShowSubjectInfo"
 | ||
|           :series-info="activeSeries"
 | ||
|           :rendering-engine-id="renderingEngineId"
 | ||
|           :viewport-id="activeViewportId"
 | ||
|           :volume="activeVolume"
 | ||
|           :measure-datas="measureDatas"
 | ||
|         />
 | ||
|       </div> -->
 | ||
|       <!-- @dblclick="reloadViewport('CT_AXIAL')" -->
 | ||
|       <div ref="dicomContainer" class="dicom-container box box_2_2" style="position: relative;">
 | ||
|         <Viewport
 | ||
|           ref="CT_AXIAL"
 | ||
|           :index="1"
 | ||
|           :active-index="activeIndex"
 | ||
|           :is-reading-show-subject-info="isReadingShowSubjectInfo"
 | ||
|           :series-info="ctSeries"
 | ||
|           :rendering-engine-id="renderingEngineId"
 | ||
|           viewport-id="CT_AXIAL"
 | ||
|           :volume="ctVolume"
 | ||
|           :measure-datas="measureDatas"
 | ||
|           :style="1===activeIndex ? viewportStyle : {}"
 | ||
|         />
 | ||
|         <Viewport
 | ||
|           ref="PT_AXIAL"
 | ||
|           :index="2"
 | ||
|           :active-index="activeIndex"
 | ||
|           :is-reading-show-subject-info="isReadingShowSubjectInfo"
 | ||
|           :series-info="petSeries"
 | ||
|           :rendering-engine-id="renderingEngineId"
 | ||
|           viewport-id="PT_AXIAL"
 | ||
|           :volume="ptVolume"
 | ||
|           :measure-datas="measureDatas"
 | ||
|         />
 | ||
|         <Viewport
 | ||
|           ref="FUSION_AXIAL"
 | ||
|           :index="3"
 | ||
|           :active-index="activeIndex"
 | ||
|           :is-reading-show-subject-info="isReadingShowSubjectInfo"
 | ||
|           :series-info="petSeries"
 | ||
|           :rendering-engine-id="renderingEngineId"
 | ||
|           viewport-id="FUSION_AXIAL"
 | ||
|           :volume="ptVolume"
 | ||
|           :measure-datas="measureDatas"
 | ||
|           :rgb-preset-name="rgbPresetName"
 | ||
|         />
 | ||
|         <Viewport
 | ||
|           ref="PET_MIP_CORONAL"
 | ||
|           :index="4"
 | ||
|           :active-index="activeIndex"
 | ||
|           :is-reading-show-subject-info="isReadingShowSubjectInfo"
 | ||
|           :series-info="petSeries"
 | ||
|           :rendering-engine-id="renderingEngineId"
 | ||
|           viewport-id="PET_MIP_CORONAL"
 | ||
|           :measure-datas="measureDatas"
 | ||
|         />
 | ||
|       </div>
 | ||
|       <!-- 表单 -->
 | ||
|       <div class="form-container" style="overflow-y: auto;">
 | ||
|         <div style="color:#fff;padding: 0 5px;">
 | ||
|           <h3 v-if="isReadingShowSubjectInfo" style="color: #ddd;padding: 5px 0px;margin: 0;">
 | ||
|             <span v-if="subjectCode">{{ subjectCode }} </span>
 | ||
|             <span style="margin-left:5px;">{{ taskBlindName }}</span>
 | ||
|           </h3>
 | ||
| 
 | ||
|           <TableQuestions ref="tableQuestions" />
 | ||
|           <Questions ref="questions" @setNonTargetMeasurementStatus="setNonTargetMeasurementStatus" />
 | ||
|         </div>
 | ||
|       </div>
 | ||
|     </div>
 | ||
|     <el-dialog
 | ||
|       v-if="customWwc.visible"
 | ||
|       :visible.sync="customWwc.visible"
 | ||
|       :close-on-click-modal="false"
 | ||
|       :title="customWwc.title"
 | ||
|       width="400px"
 | ||
|       custom-class="base-dialog-wrapper"
 | ||
|     >
 | ||
|       <CustomWwwcForm @close="customWwc.visible = false" @setWwwc="setWwwc" />
 | ||
|     </el-dialog>
 | ||
|   </div>
 | ||
| </template>
 | ||
| <script>
 | ||
| import {
 | ||
|   RenderingEngine,
 | ||
|   Enums,
 | ||
|   // CONSTANTS,
 | ||
|   setVolumesForViewports,
 | ||
|   volumeLoader,
 | ||
|   getRenderingEngine,
 | ||
|   eventTarget,
 | ||
|   // eslint-disable-next-line no-unused-vars
 | ||
|   cache,
 | ||
|   imageLoader,
 | ||
|   utilities as csUtils
 | ||
| 
 | ||
| } from '@cornerstonejs/core'
 | ||
| import * as cornerstone3D from '@cornerstonejs/core'
 | ||
| import * as cornerstoneTools from '@cornerstonejs/tools'
 | ||
| import initLibraries from './js/initLibraries'
 | ||
| 
 | ||
| import { createImageIdsAndCacheMetaData } from './js/createImageIdsAndCacheMetaData'
 | ||
| import setCtTransferFunctionForVolumeActor from './js/setCtTransferFunctionForVolumeActor'
 | ||
| import { setCtMappingRange } from './js/setCtTransferFunctionForVolumeActor'
 | ||
| import setPetTransferFunctionForVolumeActor from './js/setPetTransferFunctionForVolumeActor'
 | ||
| // eslint-disable-next-line no-unused-vars
 | ||
| import { setPetColorMapTransferFunctionForVolumeActor, setColorPreset } from './js/setPetColorMapTransferFunctionForVolumeActor'
 | ||
| import store from '@/store'
 | ||
| import { mapGetters, mapMutations } from 'vuex'
 | ||
| import { changeURLStatic } from '@/utils/history.js'
 | ||
| import Viewport from './Viewport'
 | ||
| import Questions from './Questions'
 | ||
| import TableQuestions from './TableQuestions'
 | ||
| import CustomWwwcForm from './../CustomWwwcForm'
 | ||
| import { getTableAnswerRowInfoList } from '@/api/trials'
 | ||
| import FusionEvent from './FusionEvent'
 | ||
| // import { ColorMaps } from '@kitware/vtk.js/Common/Core/ColorMaps'
 | ||
| import vtkColorMaps from '@kitware/vtk.js/Rendering/Core/ColorTransferFunction/ColorMaps'
 | ||
| import vtkColorTransferFunction from '@kitware/vtk.js/Rendering/Core/ColorTransferFunction'
 | ||
| import vtkPiecewiseFunction from '@kitware/vtk.js/Common/DataModel/PiecewiseFunction'
 | ||
| import vtkOrientationMarkerWidget from '@kitware/vtk.js/Interaction/Widgets/OrientationMarkerWidget'
 | ||
| import { mat4, vec3 } from 'gl-matrix'
 | ||
| // import vtkColorTransferFunction from '@kitware/vtk.js/Rendering/Core/ColorTransferFunction'
 | ||
| // import vtkMath from '@kitware/vtk.js/Common/Core/Math'
 | ||
| // import CircleROITool from './tools/CircleROITool'
 | ||
| // import ScaleOverlayTool from './tools/ScaleOverlayTool'
 | ||
| const {
 | ||
|   ToolGroupManager,
 | ||
|   Enums: csToolsEnums,
 | ||
|   WindowLevelTool,
 | ||
|   PanTool,
 | ||
|   ZoomTool,
 | ||
|   StackScrollMouseWheelTool,
 | ||
|   synchronizers,
 | ||
|   MIPJumpToClickTool,
 | ||
|   VolumeRotateMouseWheelTool,
 | ||
|   OrientationMarkerTool,
 | ||
|   // SynchronizerManager,
 | ||
|   // LengthTool,
 | ||
|   EllipticalROITool,
 | ||
|   CircleROITool,
 | ||
|   CrosshairsTool,
 | ||
|   TrackballRotateTool,
 | ||
|   ProbeTool,
 | ||
|   ScaleOverlayTool,
 | ||
|   utilities,
 | ||
|   // eslint-disable-next-line no-unused-vars
 | ||
|   annotation,
 | ||
|   // eslint-disable-next-line no-unused-vars
 | ||
|   cursors
 | ||
|   // stateManagement
 | ||
| 
 | ||
| } = cornerstoneTools
 | ||
| 
 | ||
| const { MouseBindings } = csToolsEnums
 | ||
| const { ViewportType, BlendModes } = Enums
 | ||
| const { createCameraPositionSynchronizer, createVOISynchronizer } = synchronizers
 | ||
| let renderingEngine
 | ||
| const renderingEngineId = 'myRenderingEngine'
 | ||
| const volumeLoaderScheme = 'cornerstoneStreamingImageVolume' // Loader id which defines which volume loader to use
 | ||
| const ctVolumeName = 'CT_VOLUME_ID' // Id of the volume less loader prefix
 | ||
| const ctVolumeId = `${volumeLoaderScheme}:${ctVolumeName}` // VolumeId with loader id + volume id
 | ||
| const ptVolumeName = 'PT_VOLUME_ID'
 | ||
| const ptVolumeId = `${volumeLoaderScheme}:${ptVolumeName}`
 | ||
| const ctToolGroupId = 'CT_TOOLGROUP_ID'
 | ||
| const ptToolGroupId = 'PT_TOOLGROUP_ID'
 | ||
| const fusionToolGroupId = 'FUSION_TOOLGROUP_ID'
 | ||
| const mipToolGroupUID = 'MIP_TOOLGROUP_ID'
 | ||
| var axialCameraPositionSynchronizer
 | ||
| var ctVoiSynchronizer
 | ||
| var ptVoiSynchronizer
 | ||
| const viewportIds = {
 | ||
|   CT: { AXIAL: 'CT_AXIAL', SAGITTAL: 'CT_SAGITTAL', CORONAL: 'CT_CORONAL' },
 | ||
|   PT: { AXIAL: 'PT_AXIAL', SAGITTAL: 'PT_SAGITTAL', CORONAL: 'PT_CORONAL' },
 | ||
|   FUSION: {
 | ||
|     AXIAL: 'FUSION_AXIAL',
 | ||
|     SAGITTAL: 'FUSION_SAGITTAL',
 | ||
|     CORONAL: 'FUSION_CORONAL'
 | ||
|   },
 | ||
|   PETMIP: {
 | ||
|     CORONAL: 'PET_MIP_CORONAL'
 | ||
|   }
 | ||
| }
 | ||
| var element_ct
 | ||
| var element_pet
 | ||
| var element_fusion
 | ||
| var element_mip
 | ||
| var ctToolGroup
 | ||
| var ptToolGroup
 | ||
| var fusionToolGroup
 | ||
| var mipToolGroup
 | ||
| 
 | ||
| const axialCameraSynchronizerId = 'AXIAL_CAMERA_SYNCHRONIZER_ID'
 | ||
| const ctVoiSynchronizerId = 'CT_VOI_SYNCHRONIZER_ID'
 | ||
| const ptVoiSynchronizerId = 'PT_VOI_SYNCHRONIZER_ID'
 | ||
| 
 | ||
| export default {
 | ||
|   name: 'Fusion',
 | ||
|   components: {
 | ||
|     Viewport,
 | ||
|     Questions,
 | ||
|     TableQuestions,
 | ||
|     CustomWwwcForm
 | ||
|   },
 | ||
|   data() {
 | ||
|     return {
 | ||
|       activeIndex: 0,
 | ||
|       activeTool: '',
 | ||
|       loading: false,
 | ||
|       fitType: 0,
 | ||
|       rotateArr: [
 | ||
|         // { label: this.$t('trials:reading:button:rotateDefault'), val: 1 }, // 默认值
 | ||
|         { label: this.$t('trials:reading:button:rotateVertical'), val: 2 }, // 垂直翻转
 | ||
|         { label: this.$t('trials:reading:button:rotateHorizontal'), val: 3 }, // 水平翻转
 | ||
|         { label: this.$t('trials:reading:button:rotateTurnLeft'), val: 4 }, // 左转90度
 | ||
|         { label: this.$t('trials:reading:button:rotateTurnRight'), val: 5 }// 右转90度
 | ||
|       ],
 | ||
|       isCurrentTask: false,
 | ||
|       ctSeries: {},
 | ||
|       petSeries: {},
 | ||
|       renderingEngineId: renderingEngineId,
 | ||
|       ctVolumeId: `${volumeLoaderScheme}:${ctVolumeName}`,
 | ||
|       ptVolumeId: `${volumeLoaderScheme}:${ptVolumeName}`,
 | ||
|       ctVolume: null,
 | ||
|       ptVolume: null,
 | ||
|       isReadingShowSubjectInfo: false,
 | ||
|       subjectCode: '',
 | ||
|       taskBlindName: '',
 | ||
|       measuredTools: [
 | ||
|         // 直径测量
 | ||
|         { toolName: 'CircleROI', text: '圆形测量', icon: 'oval', isDisabled: false,
 | ||
|           disabledReason: '' }
 | ||
| 
 | ||
|       ],
 | ||
|       measureDatas: [],
 | ||
|       isInitMeasureDatas: false,
 | ||
|       isNonTargetMeasurement: false,
 | ||
|       readingTaskState: 2,
 | ||
|       isLocate: true,
 | ||
|       colorMaps: ['BLUE-WHITE', 'BkBu', 'BkCy', 'BkMa', 'Blues', 'Cool to Warm', 'GBBr', 'Grayscale', 'Greens', 'Haze', 'Haze_green', 'Oranges', 'Purples', 'Warm to Cool', 'X Ray', 'blue2yellow', 'coolwarm', 'hsv', 'jet', 'rainbow', 'magenta', '2hot'],
 | ||
|       rgbPresetName: 'hsv',
 | ||
|       range: 40,
 | ||
|       upper: 6,
 | ||
|       isSlideMoving: false,
 | ||
|       viewportStyle: {},
 | ||
|       defaultWwwc: [
 | ||
|         { label: this.$t('trials:reading:button:wwwcDefault'), val: -1, ww: null, wc: null }, // 默认值
 | ||
|         { label: this.$t('trials:reading:button:wwwcCustom'), val: 0, ww: null, wc: null }, // 自定义
 | ||
|         { label: 'CT Brain', wc: 40, ww: 80 },
 | ||
|         { label: 'CT Lungs', wc: -400, ww: 1500 },
 | ||
|         { label: 'CT Abdomen', wc: 60, ww: 400 },
 | ||
|         { label: 'CT Liver', wc: 40, ww: 400 },
 | ||
|         { label: 'CT Bone', wc: 300, ww: 1500 }
 | ||
|       ],
 | ||
|       customWwc: { visible: false, title: null }, // 自定义调窗
 | ||
|       defaultCamera: null
 | ||
|     }
 | ||
|   },
 | ||
|   computed: {
 | ||
|     ...mapGetters(['visitTaskList'])
 | ||
|   },
 | ||
|   watch: {
 | ||
|     // activeTool: {
 | ||
|     //   deep: true,
 | ||
|     //   immediate: false,
 | ||
|     //   handler(v) {
 | ||
|     //     if (!v) {
 | ||
|     //       const elements = [element_ct, element_pet, element_fusion]
 | ||
|     //       elements.map(el => {
 | ||
|     //         console.log(cursors)
 | ||
|     //         // cursors.setCursorForElement(el, 'default')
 | ||
|     //         // cursors.elementCursor.hideElementCursor(el)
 | ||
|     //       })
 | ||
|     //     }
 | ||
|     //   }
 | ||
|     // }
 | ||
| 
 | ||
|   },
 | ||
|   mounted() {
 | ||
|     window.addEventListener('message', this.receiveMsg)
 | ||
|     console.log(cornerstoneTools)
 | ||
|     console.log(cornerstone3D)
 | ||
|     this.$i18n.locale = this.$route.query.lang
 | ||
|     this.setLanguage(this.$route.query.lang)
 | ||
|     this.readingTaskState = parseInt(this.$route.query.readingTaskState)
 | ||
|     this.isReadingShowSubjectInfo = this.$route.query.isReadingShowSubjectInfo === 'true'
 | ||
|     this.subjectCode = this.$route.query.subjectCode
 | ||
|     this.taskBlindName = this.$route.query.taskBlindName
 | ||
|     this.isCurrentTask = this.$route.query.isReadingShowSubjectInfo === 'true'
 | ||
|     this.customWwc = { visible: false, title: this.$t('trials:reading:dagTitle:wwwcCustom') }
 | ||
|     const digitPlaces = parseInt(this.$route.query.digitPlaces)
 | ||
|     this.digitPlaces = digitPlaces === -1 ? 2 : digitPlaces
 | ||
|     element_ct = document.getElementById('viewport1')
 | ||
|     element_pet = document.getElementById('viewport2')
 | ||
|     element_fusion = document.getElementById('viewport3')
 | ||
|     element_mip = document.getElementById('viewport4')
 | ||
|     if (this.$router.currentRoute.query.TokenKey) {
 | ||
|       store.dispatch('user/setToken', this.$route.query.TokenKey)
 | ||
|       changeURLStatic('TokenKey', '')
 | ||
|     }
 | ||
|     this.renderColorMaps()
 | ||
|     this.handleElementsClick()
 | ||
|     this.initPage()
 | ||
|     this.upperRangeChange(this.range)
 | ||
|     this.initSlider()
 | ||
| 
 | ||
|     FusionEvent.$on('getAnnotations', () => {
 | ||
|       console.log('getAnnotations')
 | ||
|       this.getAnnotations()
 | ||
|     })
 | ||
|     FusionEvent.$on('addOrUpdateAnnotations', (obj) => {
 | ||
|       console.log('addOrUpdateAnnotations')
 | ||
|       this.addOrUpdateAnnotations(obj)
 | ||
|     })
 | ||
|     FusionEvent.$on('removeAnnotation', (obj) => {
 | ||
|       console.log('removeAnnotation')
 | ||
|       this.removeAnnotation(obj)
 | ||
|     })
 | ||
|     FusionEvent.$on('imageLocation', (obj) => {
 | ||
|       console.log('imageLocation')
 | ||
|       this.imageLocation(obj)
 | ||
|     })
 | ||
|   },
 | ||
|   destroyed() {
 | ||
|     cornerstoneTools.destroy()
 | ||
|     eventTarget.reset()
 | ||
|     cache.purgeCache()
 | ||
|     renderingEngine.destroy()
 | ||
|     imageLoader.unregisterAllImageLoaders()
 | ||
|     ToolGroupManager.destroyToolGroup('volume')
 | ||
|     FusionEvent.$off('getAnnotations')
 | ||
|     FusionEvent.$off('addOrUpdateAnnotations')
 | ||
|     FusionEvent.$off('removeAnnotation')
 | ||
|     FusionEvent.$off('imageLocation')
 | ||
|   },
 | ||
|   methods: {
 | ||
| 
 | ||
|     initPage() {
 | ||
|       const resizeObserver = new ResizeObserver(() => {
 | ||
|         if (element_ct.style.width) {
 | ||
|           console.log('Size changed')
 | ||
| 
 | ||
|           renderingEngine = getRenderingEngine(renderingEngineId)
 | ||
| 
 | ||
|           if (renderingEngine) {
 | ||
|             this.$nextTick(() => {
 | ||
|               // renderingEngine.resize(true, false)
 | ||
|             })
 | ||
|           }
 | ||
|         }
 | ||
|       })
 | ||
| 
 | ||
|       const elements = [
 | ||
|         element_ct,
 | ||
|         element_pet,
 | ||
|         element_fusion
 | ||
|       ]
 | ||
| 
 | ||
|       elements.forEach((element) => {
 | ||
|         element.oncontextmenu = (e) => e.preventDefault()
 | ||
| 
 | ||
|         resizeObserver.observe(element)
 | ||
|       })
 | ||
|       element_mip.oncontextmenu = (e) => e.preventDefault()
 | ||
|       resizeObserver.observe(element_mip)
 | ||
|       this.$nextTick(() => {
 | ||
|         this.run()
 | ||
|       })
 | ||
|     },
 | ||
|     async run() {
 | ||
|       this.loading = true
 | ||
|       // 初始化Cornerstone和相关库
 | ||
|       await initLibraries()
 | ||
|       renderingEngine = new RenderingEngine(renderingEngineId)
 | ||
| 
 | ||
|       this.ctSeries = JSON.parse(sessionStorage.getItem('ctSeriesInfo'))
 | ||
|       this.petSeries = JSON.parse(sessionStorage.getItem('petSeriesInfo'))
 | ||
|       await this.getImages()
 | ||
| 
 | ||
|       // 设置viewport
 | ||
|       await this.setUpDisplay()
 | ||
| 
 | ||
|       // 设置viewportTools and synchronizers
 | ||
|       this.setUpToolGroups()
 | ||
| 
 | ||
|       this.setUpSynchronizers()
 | ||
|       this.$refs['CT_AXIAL'].scroll(0)
 | ||
|       this.$refs['PT_AXIAL'].scroll(0)
 | ||
|       this.$refs['FUSION_AXIAL'].scroll(0)
 | ||
|       const viewport = renderingEngine.getViewport('CT_AXIAL')
 | ||
|       if (viewport) {
 | ||
|         this.defaultCamera = viewport.getCamera()
 | ||
|       }
 | ||
|       await this.getAnnotations()
 | ||
| 
 | ||
|       eventTarget.addEventListener(cornerstoneTools.Enums.Events.ANNOTATION_ADDED, (e) => {
 | ||
|         this.onAnnotationAdded(e)
 | ||
|       })
 | ||
| 
 | ||
|       const debouncedCallback = this.debounce((e) => {
 | ||
|         const { annotation } = e.detail
 | ||
|         const { cachedStats } = annotation.data
 | ||
|         var isNotValidAnnotationNum = 0
 | ||
|         for (const volumeId in cachedStats) {
 | ||
|           var statObj = cachedStats[volumeId]
 | ||
|           var arr = Object.keys(statObj)
 | ||
|           if (arr.length < 2) {
 | ||
|             ++isNotValidAnnotationNum
 | ||
|           }
 | ||
|         }
 | ||
|         if (isNotValidAnnotationNum === 0) {
 | ||
|           this.onAnnotationModified(e)
 | ||
|         } else {
 | ||
|           // 移除标记
 | ||
|           this.removeAnnotation({ otherMeasureData: annotation })
 | ||
|           const { remark } = annotation.data
 | ||
|           // 清除病灶上的标记信息
 | ||
|           if (remark === 'Liver' || remark === 'Mediastinum') {
 | ||
|             this.$refs['questions'].clearMeasuredData(remark)
 | ||
|             // 激活工具
 | ||
|             this.setNonTargetMeasurementStatus({ status: true, toolName: 'CircleROI' })
 | ||
|           } else {
 | ||
|             this.$refs['tableQuestions'].clearMeasuredData()
 | ||
|             // 激活工具
 | ||
|             this.setBasicToolActive('CircleROI')
 | ||
|           }
 | ||
|         }
 | ||
|       }, 120)
 | ||
|       eventTarget.addEventListener(cornerstoneTools.Enums.Events.ANNOTATION_MODIFIED, (e) => {
 | ||
|         debouncedCallback(e)
 | ||
|       })
 | ||
|       eventTarget.addEventListener(cornerstoneTools.Enums.Events.ANNOTATION_SELECTION_CHANGE, (e) => {
 | ||
|         console.log(e)
 | ||
|         const { detail } = e
 | ||
|         const { selection } = detail
 | ||
|         if (selection && selection.length > 0) {
 | ||
|           const annotationUID = selection[0]
 | ||
|           const i = this.measureDatas.findIndex(item => item.OtherMeasureData.annotationUID === annotationUID)
 | ||
|           if (i > -1) {
 | ||
|             this.$refs['tableQuestions'].setActiveCollapse(this.measureDatas[i])
 | ||
|           }
 | ||
|         }
 | ||
|       })
 | ||
| 
 | ||
|       this.loading = false
 | ||
|     },
 | ||
|     getAnnotations() {
 | ||
|       return new Promise(resolve => {
 | ||
|         const viewportIds = ['PT_AXIAL', 'CT_AXIAL', 'FUSION_AXIAL']
 | ||
|         viewportIds.map(v => {
 | ||
|           const viewport = renderingEngine.getViewport(v)
 | ||
|           if (viewport) {
 | ||
|             var annotations = annotation.state.getAnnotations('CircleROI', viewport.element)
 | ||
| 
 | ||
|             if (annotations && annotations.length > 0) {
 | ||
|               annotations.map(i => {
 | ||
|                 if (i.metadata.toolName === 'CircleROI') {
 | ||
|                   annotation.state.removeAnnotation(i.annotationUID)
 | ||
|                 }
 | ||
|               })
 | ||
|             }
 | ||
|           }
 | ||
|         })
 | ||
| 
 | ||
|         // annotation.state.removeAllAnnotations()
 | ||
|         this.isInitMeasureDatas = false
 | ||
|         var visitTaskId = this.$route.query.visitTaskId
 | ||
|         getTableAnswerRowInfoList(visitTaskId).then(res => {
 | ||
|           var arr = []
 | ||
|           res.Result.forEach(el => {
 | ||
|             if (el.OtherMeasureData) {
 | ||
|               el.OtherMeasureData = JSON.parse(el.OtherMeasureData)
 | ||
|               el.OtherMeasureData.invalidated = false
 | ||
|               // el.OtherMeasureData.highlighted = false
 | ||
|               if (this.readingTaskState === 2) {
 | ||
|                 el.OtherMeasureData.isLocked = true
 | ||
|               }
 | ||
|               el.OtherMeasureData.data.remark = el.OrderMarkName
 | ||
|               const viewport = renderingEngine.getViewport('PT_AXIAL')
 | ||
| 
 | ||
|               annotation.state.addAnnotation(el.OtherMeasureData, viewport.element)
 | ||
|             }
 | ||
|             arr.push(el)
 | ||
|           })
 | ||
|           this.measureDatas = arr
 | ||
|           this.isInitMeasureDatas = true
 | ||
| 
 | ||
|           resolve()
 | ||
|         })
 | ||
|       })
 | ||
|     },
 | ||
|     addOrUpdateAnnotations(obj) {
 | ||
|       var idx = this.measureDatas.findIndex(item => item.QuestionId === obj.data.QuestionId)
 | ||
|       if (idx > -1) {
 | ||
|         for (const k in this.measureDatas[idx]) {
 | ||
|           if (obj.data[k]) {
 | ||
|             this.measureDatas[idx][k] = obj.data[k]
 | ||
|           }
 | ||
|         }
 | ||
|         console.log('更新标记成功', idx)
 | ||
|       } else {
 | ||
|         this.measureDatas.push(obj.data)
 | ||
|         console.log('新增标记成功')
 | ||
|       }
 | ||
|     },
 | ||
|     removeAnnotation(obj) {
 | ||
|       const { otherMeasureData, type } = obj
 | ||
|       const { annotationUID } = otherMeasureData
 | ||
|       const i = this.measureDatas.findIndex(item => item.OtherMeasureData.annotationUID === annotationUID)
 | ||
|       if (i > -1) {
 | ||
|         if (type === 'delete') {
 | ||
|           this.measureDatas.splice(i, 1)
 | ||
|         } else {
 | ||
|           if (this.measureDatas[i].FristAddTaskId) {
 | ||
|             this.measureDatas[i].OtherMeasureData = ''
 | ||
|           } else {
 | ||
|             this.measureDatas.splice(i, 1)
 | ||
|           }
 | ||
|         }
 | ||
|         annotation.state.removeAnnotation(annotationUID)
 | ||
|         renderingEngine.render()
 | ||
|       }
 | ||
|     },
 | ||
|     onAnnotationAdded(e) {
 | ||
|       this.isLocate = false
 | ||
|       const { detail } = e
 | ||
|       const { annotation } = detail
 | ||
|       const { metadata } = annotation
 | ||
|       const measureData = {}
 | ||
|       measureData.frame = 0
 | ||
|       measureData.data = annotation
 | ||
|       measureData.type = metadata.toolName
 | ||
|       if (this.isNonTargetMeasurement || annotation.data.remark === 'Liver' || annotation.data.remark === 'Mediastinum') {
 | ||
|         this.$refs['questions'].setMeasuredData(measureData)
 | ||
|       } else {
 | ||
|         this.$refs['tableQuestions'] && this.$refs['tableQuestions'].setMeasuredData(measureData)
 | ||
|       }
 | ||
| 
 | ||
|       this.setToolMode('passive', metadata.toolName)
 | ||
|       this.activeTool = ''
 | ||
|     },
 | ||
|     onAnnotationModified(e) {
 | ||
|       if (this.isLocate) {
 | ||
|         this.isLocate = false
 | ||
|         return
 | ||
|       }
 | ||
|       const { detail } = e
 | ||
|       const { annotation } = detail
 | ||
|       const { metadata, data } = annotation
 | ||
|       var idx = this.measureDatas.findIndex(item => item.OtherMeasureData && item.OtherMeasureData.data.remark === data.remark)
 | ||
|       if (idx > -1) {
 | ||
|         var questionInfo = this.measureDatas[idx]
 | ||
|         const measureData = {}
 | ||
|         measureData.frame = 0
 | ||
|         measureData.data = annotation
 | ||
|         measureData.type = metadata.toolName
 | ||
|         measureData.suvMax = data.cachedStats[`volumeId:${ptVolumeId}`] && data.cachedStats[`volumeId:${ptVolumeId}`].max ? data.cachedStats[`volumeId:${ptVolumeId}`].max.toFixed(this.digitPlaces) : null
 | ||
|         measureData.modalityUnit = data.cachedStats[`volumeId:${ptVolumeId}`].modalityUnit
 | ||
|         if (data.remark === 'Liver' || data.remark === 'Mediastinum') {
 | ||
|           this.$refs['questions'].setMeasuredData(measureData)
 | ||
|           this.isNonTargetMeasurement = false
 | ||
|         } else {
 | ||
|           this.$refs['tableQuestions'].modifyMeasuredData({ measureData, questionInfo })
 | ||
|         }
 | ||
| 
 | ||
|         this.setToolMode('passive', metadata.toolName)
 | ||
|         if (this.activeTool) {
 | ||
|           this.activeTool = ''
 | ||
|         }
 | ||
|       }
 | ||
|     },
 | ||
|     setNonTargetMeasurementStatus(obj) {
 | ||
|       this.isNonTargetMeasurement = obj.status
 | ||
|       if (obj.toolName) {
 | ||
|         // this.setMeasureToolActive(obj.toolName)
 | ||
|         this.setBasicToolActive(obj.toolName)
 | ||
|       }
 | ||
|     },
 | ||
|     getImageInfo(viewportId, referencedImageId) {
 | ||
|       if (!viewportId || !referencedImageId) return
 | ||
|       var imageArr = referencedImageId.split('/')
 | ||
|       var instanceId = imageArr[imageArr.length - 1]
 | ||
|       if (viewportId === 'CT_AXIAL') {
 | ||
|         return { studyId: this.ctSeries.studyId, seriesId: this.ctSeries.seriesId, instanceId, viewportId }
 | ||
|       } else if (viewportId === 'PT_AXIAL') {
 | ||
|         return { studyId: this.petSeries.studyId, seriesId: this.petSeries.seriesId, instanceId, viewportId }
 | ||
|       } else {
 | ||
|         return { studyId: this.petSeries.studyId, seriesId: this.petSeries.seriesId, instanceId, viewportId }
 | ||
|       }
 | ||
|     },
 | ||
|     debounce(callback, delay) {
 | ||
|       let timerId
 | ||
|       return function() {
 | ||
|         clearTimeout(timerId)
 | ||
|         timerId = setTimeout(() => {
 | ||
|           callback.apply(this, arguments)
 | ||
|         }, delay)
 | ||
|       }
 | ||
|     },
 | ||
|     async getImages() {
 | ||
|       // .splice(0, 10)
 | ||
|       const ctImageIds = await createImageIdsAndCacheMetaData({
 | ||
|         modality: 'CT',
 | ||
|         imageIds: this.ctSeries.imageIds
 | ||
|       })
 | ||
|       const ptImageIds = await createImageIdsAndCacheMetaData({
 | ||
|         modality: 'PT',
 | ||
|         imageIds: this.petSeries.imageIds
 | ||
|       })
 | ||
|       this.ctVolume = await volumeLoader.createAndCacheVolume(ctVolumeId, {
 | ||
|         imageIds: ctImageIds
 | ||
|       })
 | ||
|       this.ptVolume = await volumeLoader.createAndCacheVolume(ptVolumeId, {
 | ||
|         imageIds: ptImageIds
 | ||
|       })
 | ||
|     },
 | ||
|     setUpToolGroups() {
 | ||
|       cornerstoneTools.addTool(WindowLevelTool)
 | ||
|       cornerstoneTools.addTool(ZoomTool)
 | ||
|       cornerstoneTools.addTool(StackScrollMouseWheelTool)
 | ||
|       cornerstoneTools.addTool(MIPJumpToClickTool)
 | ||
|       cornerstoneTools.addTool(VolumeRotateMouseWheelTool)
 | ||
|       cornerstoneTools.addTool(EllipticalROITool)
 | ||
|       cornerstoneTools.addTool(CircleROITool)
 | ||
|       cornerstoneTools.addTool(CrosshairsTool)
 | ||
|       cornerstoneTools.addTool(TrackballRotateTool)
 | ||
|       cornerstoneTools.addTool(ProbeTool)
 | ||
|       cornerstoneTools.addTool(PanTool)
 | ||
|       cornerstoneTools.addTool(ScaleOverlayTool)
 | ||
|       cornerstoneTools.addTool(OrientationMarkerTool)
 | ||
|       ctToolGroup = ctToolGroup = ToolGroupManager.createToolGroup(ctToolGroupId)
 | ||
|       ctToolGroup.addViewport(viewportIds.CT.AXIAL, renderingEngineId)
 | ||
| 
 | ||
|       ptToolGroup = ToolGroupManager.createToolGroup(ptToolGroupId)
 | ||
|       ptToolGroup.addViewport(viewportIds.PT.AXIAL, renderingEngineId)
 | ||
| 
 | ||
|       fusionToolGroup = ToolGroupManager.createToolGroup(fusionToolGroupId)
 | ||
|       fusionToolGroup.addViewport(viewportIds.FUSION.AXIAL, renderingEngineId)
 | ||
| 
 | ||
|       const toolGroups = [ctToolGroup, ptToolGroup]
 | ||
|       toolGroups.forEach((toolGroup) => {
 | ||
|         toolGroup.addTool(PanTool.toolName)
 | ||
|         toolGroup.addTool(ZoomTool.toolName)
 | ||
|         toolGroup.addTool(StackScrollMouseWheelTool.toolName)
 | ||
|         toolGroup.addTool(EllipticalROITool.toolName)
 | ||
|         toolGroup.addTool(CircleROITool.toolName, {
 | ||
|           getTextLines: this.getTextLines
 | ||
|         })
 | ||
|         toolGroup.addTool(WindowLevelTool.toolName)
 | ||
|         toolGroup.addTool(ProbeTool.toolName)
 | ||
|         toolGroup.addTool(ScaleOverlayTool.toolName)
 | ||
|         toolGroup.addTool(OrientationMarkerTool.toolName)
 | ||
|       })
 | ||
| 
 | ||
|       fusionToolGroup.addTool(PanTool.toolName)
 | ||
|       fusionToolGroup.addTool(ZoomTool.toolName)
 | ||
|       fusionToolGroup.addTool(StackScrollMouseWheelTool.toolName)
 | ||
|       fusionToolGroup.addTool(EllipticalROITool.toolName, {
 | ||
|         volumeId: ptVolumeId
 | ||
|       })
 | ||
|       fusionToolGroup.addTool(CircleROITool.toolName, {
 | ||
|         volumeId: ptVolumeId,
 | ||
|         getTextLines: this.getTextLines
 | ||
|       })
 | ||
|       fusionToolGroup.addTool(ProbeTool.toolName)
 | ||
|       fusionToolGroup.addTool(ScaleOverlayTool.toolName)
 | ||
|       fusionToolGroup.addTool(OrientationMarkerTool.toolName)
 | ||
|       // Here is the difference in the toolGroups used, that we need to specify the
 | ||
|       // volume to use for the WindowLevelTool for the fusion viewports
 | ||
| 
 | ||
|       fusionToolGroup.addTool(WindowLevelTool.toolName, {
 | ||
|         volumeId: ptVolumeId
 | ||
|       });
 | ||
| 
 | ||
|       [ctToolGroup, ptToolGroup, fusionToolGroup].forEach((toolGroup) => {
 | ||
|         // toolGroup.setToolActive(ProbeTool.toolName, {
 | ||
|         //   bindings: [
 | ||
|         //     {
 | ||
|         //       mouseButton: MouseBindings.Primary // Left Click
 | ||
|         //     }
 | ||
|         //   ]
 | ||
|         // })
 | ||
|         toolGroup.setToolActive(PanTool.toolName, {
 | ||
|           bindings: [
 | ||
|             {
 | ||
|               mouseButton: MouseBindings.Auxiliary // Middle Click
 | ||
|             }
 | ||
|           ]
 | ||
|         })
 | ||
|         toolGroup.setToolActive(ZoomTool.toolName, {
 | ||
|           bindings: [
 | ||
|             {
 | ||
|               mouseButton: MouseBindings.Secondary // Right Click
 | ||
|             }
 | ||
|           ]
 | ||
|         })
 | ||
| 
 | ||
|         toolGroup.setToolActive(StackScrollMouseWheelTool.toolName)
 | ||
|         // toolGroup.setToolPassive(EllipticalROITool.toolName)
 | ||
|         if (this.readingTaskState === 2) {
 | ||
|           toolGroup.setToolEnabled(CircleROITool.toolName)
 | ||
|         } else {
 | ||
|           toolGroup.setToolPassive(CircleROITool.toolName)
 | ||
|         }
 | ||
| 
 | ||
|         // toolGroup.setToolPassive(ProbeTool.toolName)
 | ||
|         // toolGroup.setToolPassive(WindowLevelTool.toolName)
 | ||
|         toolGroup.setToolConfiguration(
 | ||
|           ScaleOverlayTool.toolName,
 | ||
|           {
 | ||
|             scaleLocation: 'bottom'
 | ||
|           },
 | ||
|           true // overwrite
 | ||
|         )
 | ||
|         toolGroup.setToolEnabled(ScaleOverlayTool.toolName)
 | ||
|         toolGroup.setToolConfiguration(OrientationMarkerTool.toolName, {
 | ||
|           orientationWidget: {
 | ||
|             enabled: true,
 | ||
|             viewportCorner: vtkOrientationMarkerWidget.Corners.BOTTOM_RIGHT,
 | ||
|             viewportSize: 0.15,
 | ||
|             minPixelSize: 15,
 | ||
|             maxPixelSize: 45
 | ||
|           },
 | ||
|           overlayConfiguration: {
 | ||
|             [OrientationMarkerTool.OVERLAY_MARKER_TYPES.ANNOTATED_CUBE]: {
 | ||
|               faceProperties: {
 | ||
|                 xPlus: { text: 'R', faceColor: '#ffff00', faceRotation: 90 },
 | ||
|                 xMinus: { text: 'L', faceColor: '#ffff00', faceRotation: 270 },
 | ||
|                 yPlus: {
 | ||
|                   text: 'P',
 | ||
|                   faceColor: '#00ffff',
 | ||
|                   fontColor: 'white',
 | ||
|                   faceRotation: 180
 | ||
|                 },
 | ||
|                 yMinus: { text: 'A', faceColor: '#00ffff', fontColor: 'white' },
 | ||
|                 zPlus: { text: 'S' },
 | ||
|                 zMinus: { text: 'I' }
 | ||
|               },
 | ||
|               defaultStyle: {
 | ||
|                 fontStyle: 'bold',
 | ||
|                 fontFamily: 'Arial',
 | ||
|                 fontColor: 'black',
 | ||
|                 fontSizeScale: (res) => res / 2,
 | ||
|                 faceColor: '#0000ff',
 | ||
|                 edgeThickness: 0.1,
 | ||
|                 edgeColor: 'blue',
 | ||
|                 resolution: 400
 | ||
|               }
 | ||
|             }
 | ||
|           }
 | ||
|         })
 | ||
|         toolGroup.setToolActive(OrientationMarkerTool.toolName)
 | ||
|       })
 | ||
| 
 | ||
|       // MIP Tool Groups
 | ||
|       mipToolGroup = null
 | ||
|       if (!ToolGroupManager.getToolGroup(mipToolGroupUID)) {
 | ||
|         mipToolGroup = ToolGroupManager.createToolGroup(mipToolGroupUID)
 | ||
|       } else {
 | ||
|         mipToolGroup = ToolGroupManager.getToolGroup(mipToolGroupUID)
 | ||
|       }
 | ||
| 
 | ||
|       mipToolGroup.addTool('VolumeRotateMouseWheel')
 | ||
|       mipToolGroup.addTool('MIPJumpToClickTool', {
 | ||
|         //
 | ||
|         toolGroupId: ptToolGroupId
 | ||
|       })
 | ||
| 
 | ||
|       // Set the initial state of the tools, here we set one tool active on left click.
 | ||
|       // This means left click will draw that tool.
 | ||
|       mipToolGroup.setToolActive('MIPJumpToClickTool', {
 | ||
|         bindings: [
 | ||
|           {
 | ||
|             mouseButton: MouseBindings.Primary // Left ClickR
 | ||
|           }
 | ||
|         ]
 | ||
|       })
 | ||
|       // As the Stack Scroll mouse wheel is a tool using the `mouseWheelCallback`
 | ||
|       // hook instead of mouse buttons, it does not need to assign any mouse button.
 | ||
|       mipToolGroup.setToolActive('VolumeRotateMouseWheel')
 | ||
|       // mipToolGroup.addTool(OrientationMarkerTool.toolName)
 | ||
|       // mipToolGroup.setToolActive(OrientationMarkerTool.toolName)
 | ||
|       mipToolGroup.addViewport(viewportIds.PETMIP.CORONAL, renderingEngineId)
 | ||
|     },
 | ||
|     getTextLines(data, targetId) {
 | ||
|       const cachedVolumeStats = data.cachedStats[targetId]
 | ||
|       const {
 | ||
|         radius,
 | ||
|         radiusUnit,
 | ||
|         area,
 | ||
|         mean,
 | ||
|         stdDev,
 | ||
|         max,
 | ||
|         isEmptyArea,
 | ||
|         // Modality,
 | ||
|         areaUnit,
 | ||
|         modalityUnit
 | ||
|       } = cachedVolumeStats
 | ||
|       var unit = modalityUnit
 | ||
|       if (modalityUnit === 'raw') {
 | ||
|         unit = 'SUV'
 | ||
|       } else {
 | ||
|         unit = modalityUnit
 | ||
|       }
 | ||
|       const textLines = []
 | ||
|       if (data.remark) {
 | ||
|         textLines.push(data.remark)
 | ||
|       }
 | ||
|       if (radius) {
 | ||
|         const radiusLine = isEmptyArea
 | ||
|           ? `Radius: Oblique not supported`
 | ||
|           : `Radius: ${this.roundNumber(radius)} ${radiusUnit}`
 | ||
|         textLines.push(radiusLine)
 | ||
|       }
 | ||
| 
 | ||
|       if (area) {
 | ||
|         const areaLine = isEmptyArea
 | ||
|           ? `Area: Oblique not supported`
 | ||
|           : `Area: ${this.roundNumber(area)} ${areaUnit}`
 | ||
|         textLines.push(areaLine)
 | ||
|       }
 | ||
| 
 | ||
|       if (mean) {
 | ||
|         textLines.push(`Mean: ${this.roundNumber(mean)} ${unit}`)
 | ||
|       }
 | ||
| 
 | ||
|       if (max) {
 | ||
|         textLines.push(`Max: ${this.roundNumber(max)} ${unit}`)
 | ||
|       }
 | ||
| 
 | ||
|       if (stdDev) {
 | ||
|         textLines.push(`Std Dev: ${this.roundNumber(stdDev)} ${unit}`)
 | ||
|       }
 | ||
| 
 | ||
|       return textLines
 | ||
|     },
 | ||
|     roundNumber(value) {
 | ||
|       if (value === undefined || value === null || value === '') {
 | ||
|         return 'NaN'
 | ||
|       }
 | ||
|       value = Number(value)
 | ||
| 
 | ||
|       return value.toFixed(this.digitPlaces)
 | ||
|     },
 | ||
|     // 设置测量工具启用(不会对输入作出反应)
 | ||
|     setBasicToolActive(toolName) {
 | ||
|       var toolGroupIds = [ctToolGroupId, ptToolGroupId, fusionToolGroupId]
 | ||
|       toolGroupIds.forEach((toolGroupId) => {
 | ||
|         const toolGroup = ToolGroupManager.getToolGroup(toolGroupId)
 | ||
|         if (this.activeTool === toolName) {
 | ||
|           toolGroup.setToolPassive(toolName)
 | ||
|         } else {
 | ||
|           if (this.activeTool) {
 | ||
|             toolGroup.setToolPassive(this.activeTool)
 | ||
|           }
 | ||
|           var bindings = []
 | ||
|           if (toolName === 'Pan') {
 | ||
|             bindings = [
 | ||
|               {
 | ||
|                 mouseButton: MouseBindings.Auxiliary // Middle Click
 | ||
|               },
 | ||
|               {
 | ||
|                 mouseButton: MouseBindings.Primary // Left Click
 | ||
|               }
 | ||
|             ]
 | ||
|           } else if (toolName === 'Zoom') {
 | ||
|             bindings = [
 | ||
|               {
 | ||
|                 mouseButton: MouseBindings.Secondary // Right Click
 | ||
|               },
 | ||
|               {
 | ||
|                 mouseButton: MouseBindings.Primary // Left Click
 | ||
|               }
 | ||
|             ]
 | ||
|           } else {
 | ||
|             bindings = [
 | ||
|               {
 | ||
|                 mouseButton: MouseBindings.Primary // Left Click
 | ||
|               }
 | ||
|             ]
 | ||
|           }
 | ||
|           toolGroup.setToolActive(toolName, {
 | ||
|             bindings: bindings
 | ||
|           })
 | ||
|           // if (toolName === 'CircleROI') {
 | ||
|           //   toolGroup.setToolConfiguration(CircleROITool.toolName, {
 | ||
|           //     // centerPointRadius: 4,
 | ||
|           //     disableCursor: true
 | ||
|           //   })
 | ||
|           // }
 | ||
|         }
 | ||
|       })
 | ||
|       if (this.activeTool === toolName) {
 | ||
|         this.activeTool = ''
 | ||
|       } else {
 | ||
|         this.activeTool = toolName
 | ||
|       }
 | ||
|       document.onselectstart = function() { return false }// 解决拖动会选中文字的问题
 | ||
|       document.ondragstart = function() { return false }
 | ||
|     },
 | ||
|     setMeasureToolActive(toolName) {
 | ||
|       var toolObj = this.$refs['tableQuestions'].isCanActiveTool(toolName)
 | ||
|       if (!toolObj || toolObj.isDisabled) return
 | ||
|       this.setBasicToolActive(toolName)
 | ||
|     },
 | ||
|     // 鼠标移入测量工具时,判断工具是否可激活
 | ||
|     enter(e, toolName) {
 | ||
|       var i = this.measuredTools.findIndex(item => item.toolName === toolName)
 | ||
|       if (i === -1) return
 | ||
|       var isCurrentTask = this.isCurrentTask
 | ||
|       var readingTaskState = this.readingTaskState
 | ||
|       if (!isCurrentTask || readingTaskState >= 2) {
 | ||
|         this.measuredTools[i].isDisabled = true
 | ||
|         e.target.style.cursor = 'not-allowed'
 | ||
|         if (this.activeTool) {
 | ||
|           this.setToolMode('enabled', toolName)
 | ||
|           this.activeTool = ''
 | ||
|         }
 | ||
|       } else {
 | ||
|         var obj = this.$refs['tableQuestions'].isCanActiveTool(toolName, true)
 | ||
|         this.measuredTools[i].disabledReason = obj.reason
 | ||
|         if (!obj.isCanActiveTool) {
 | ||
|           if (this.activeTool === toolName) {
 | ||
|             this.setToolMode('passive', toolName)
 | ||
|             this.activeTool = ''
 | ||
|           }
 | ||
|           this.measuredTools[i].isDisabled = true
 | ||
|           e.target.style.cursor = 'not-allowed'
 | ||
|         } else {
 | ||
|           this.measuredTools[i].isDisabled = false
 | ||
|           e.target.style.cursor = 'pointer'
 | ||
|         }
 | ||
|       }
 | ||
|     },
 | ||
|     setToolMode(mode, toolName) {
 | ||
|       var toolGroupIds = [ctToolGroupId, ptToolGroupId, fusionToolGroupId]
 | ||
|       toolGroupIds.forEach((toolGroupId) => {
 | ||
|         const toolGroup = ToolGroupManager.getToolGroup(toolGroupId)
 | ||
|         toolGroup.setToolPassive(toolName)
 | ||
|         if (mode === 'enabled') {
 | ||
|           toolGroup.setToolEnabled(toolName)
 | ||
|         } else if (mode === 'passive') {
 | ||
|           toolGroup.setToolPassive(toolName)
 | ||
|         }
 | ||
|       })
 | ||
|     },
 | ||
|     // 截屏
 | ||
|     saveImage() {
 | ||
|       // const canvas = this.canvas.querySelector('canvas')
 | ||
|       // var pictureBaseStr = canvas.toDataURL('image/png', 1)
 | ||
|       // return pictureBaseStr
 | ||
|     },
 | ||
|     setUpSynchronizers() {
 | ||
|       // const axialCameraSynchronizerId = 'AXIAL_CAMERA_SYNCHRONIZER_ID'
 | ||
|       // const ctVoiSynchronizerId = 'CT_VOI_SYNCHRONIZER_ID'
 | ||
|       // const ptVoiSynchronizerId = 'PT_VOI_SYNCHRONIZER_ID'
 | ||
| 
 | ||
|       axialCameraPositionSynchronizer = createCameraPositionSynchronizer(
 | ||
|         axialCameraSynchronizerId
 | ||
|       )
 | ||
|       ctVoiSynchronizer = createVOISynchronizer(ctVoiSynchronizerId)
 | ||
|       ptVoiSynchronizer = createVOISynchronizer(ptVoiSynchronizerId);
 | ||
| 
 | ||
|       // Add viewports to camera synchronizers
 | ||
|       [
 | ||
|         viewportIds.CT.AXIAL,
 | ||
|         viewportIds.PT.AXIAL,
 | ||
|         viewportIds.FUSION.AXIAL
 | ||
|       ].forEach((viewportId) => {
 | ||
|         axialCameraPositionSynchronizer.add({
 | ||
|           renderingEngineId,
 | ||
|           viewportId
 | ||
|         })
 | ||
|       });
 | ||
| 
 | ||
|       // Add viewports to VOI synchronizers
 | ||
|       [
 | ||
|         viewportIds.CT.AXIAL
 | ||
|       ].forEach((viewportId) => {
 | ||
|         ctVoiSynchronizer.add({
 | ||
|           renderingEngineId,
 | ||
|           viewportId
 | ||
|         })
 | ||
|       });
 | ||
|       [
 | ||
|         viewportIds.FUSION.AXIAL
 | ||
|       ].forEach((viewportId) => {
 | ||
|         // In this example, the fusion viewports are only targets for CT VOI
 | ||
|         // synchronization, not sources
 | ||
|         ctVoiSynchronizer.addTarget({
 | ||
|           renderingEngineId,
 | ||
|           viewportId
 | ||
|         })
 | ||
|       });
 | ||
|       [
 | ||
|         viewportIds.PT.AXIAL,
 | ||
|         viewportIds.FUSION.AXIAL,
 | ||
|         viewportIds.PETMIP.CORONAL
 | ||
|       ].forEach((viewportId) => {
 | ||
|         ptVoiSynchronizer.add({
 | ||
|           renderingEngineId,
 | ||
|           viewportId
 | ||
|         })
 | ||
|       })
 | ||
|     },
 | ||
| 
 | ||
|     async setUpDisplay() {
 | ||
|       // 创建 viewports
 | ||
|       const viewportInputArray = [
 | ||
|         {
 | ||
|           viewportId: viewportIds.CT.AXIAL,
 | ||
|           type: ViewportType.ORTHOGRAPHIC,
 | ||
|           element: element_ct,
 | ||
|           defaultOptions: {
 | ||
|             orientation: Enums.OrientationAxis.AXIAL
 | ||
|             // background: [0, 0, 0]
 | ||
|           }
 | ||
|         },
 | ||
|         {
 | ||
|           viewportId: viewportIds.PT.AXIAL,
 | ||
|           type: ViewportType.ORTHOGRAPHIC,
 | ||
|           element: element_pet,
 | ||
|           defaultOptions: {
 | ||
|             orientation: Enums.OrientationAxis.AXIAL,
 | ||
|             background: [1, 1, 1]
 | ||
|           }
 | ||
|         },
 | ||
|         {
 | ||
|           viewportId: viewportIds.FUSION.AXIAL,
 | ||
|           type: ViewportType.ORTHOGRAPHIC,
 | ||
|           element: element_fusion,
 | ||
|           defaultOptions: {
 | ||
|             orientation: Enums.OrientationAxis.AXIAL
 | ||
|             // background: [0, 0, 0]
 | ||
|           }
 | ||
|         },
 | ||
|         {
 | ||
|           viewportId: viewportIds.PETMIP.CORONAL,
 | ||
|           type: ViewportType.ORTHOGRAPHIC,
 | ||
|           element: element_mip,
 | ||
|           defaultOptions: {
 | ||
|             orientation: Enums.OrientationAxis.CORONAL,
 | ||
|             background: [1, 1, 1]
 | ||
|           }
 | ||
|         }
 | ||
|       ]
 | ||
| 
 | ||
|       renderingEngine.setViewports(viewportInputArray)
 | ||
| 
 | ||
|       // Set the volumes to load
 | ||
|       this.ptVolume.load()
 | ||
|       this.ctVolume.load()
 | ||
|       const windowCenter = this.ctVolume.cornerstoneImageMetaData.windowCenter[0]
 | ||
|       const windowWidth = this.ctVolume.cornerstoneImageMetaData.windowWidth[0]
 | ||
|       setCtMappingRange(windowWidth, windowCenter)
 | ||
|       // Set volumes on the viewports
 | ||
|       await setVolumesForViewports(
 | ||
|         renderingEngine,
 | ||
|         [
 | ||
|           {
 | ||
|             volumeId: ctVolumeId,
 | ||
|             callback: setCtTransferFunctionForVolumeActor
 | ||
|           }
 | ||
|         ],
 | ||
|         [viewportIds.CT.AXIAL]
 | ||
|       )
 | ||
| 
 | ||
|       await setVolumesForViewports(
 | ||
|         renderingEngine,
 | ||
|         [
 | ||
|           {
 | ||
|             volumeId: ptVolumeId,
 | ||
|             callback: setPetTransferFunctionForVolumeActor
 | ||
|           }
 | ||
|         ],
 | ||
|         [viewportIds.PT.AXIAL]
 | ||
|       )
 | ||
| 
 | ||
|       await setVolumesForViewports(
 | ||
|         renderingEngine,
 | ||
|         [
 | ||
|           {
 | ||
|             volumeId: ctVolumeId,
 | ||
|             callback: setCtTransferFunctionForVolumeActor
 | ||
|           },
 | ||
|           {
 | ||
|             volumeId: ptVolumeId,
 | ||
|             callback: setPetColorMapTransferFunctionForVolumeActor
 | ||
|           }
 | ||
|         ],
 | ||
|         [viewportIds.FUSION.AXIAL]
 | ||
|       )
 | ||
| 
 | ||
|       // Calculate size of fullBody pet mip
 | ||
|       const ptVolumeDimensions = this.ptVolume.dimensions
 | ||
| 
 | ||
|       // Only make the MIP as large as it needs to be.
 | ||
|       const slabThickness = Math.sqrt(
 | ||
|         ptVolumeDimensions[0] * ptVolumeDimensions[0] +
 | ||
|       ptVolumeDimensions[1] * ptVolumeDimensions[1] +
 | ||
|       ptVolumeDimensions[2] * ptVolumeDimensions[2]
 | ||
|       )
 | ||
|       setVolumesForViewports(
 | ||
|         renderingEngine,
 | ||
|         [
 | ||
|           {
 | ||
|             volumeId: ptVolumeId,
 | ||
|             callback: setPetTransferFunctionForVolumeActor,
 | ||
|             blendMode: BlendModes.MAXIMUM_INTENSITY_BLEND,
 | ||
|             slabThickness
 | ||
|           }
 | ||
|         ],
 | ||
|         [viewportIds.PETMIP.CORONAL]
 | ||
|       )
 | ||
| 
 | ||
|       await this.initializeCameraSync(renderingEngine)
 | ||
| 
 | ||
|       // Render the viewports
 | ||
|       renderingEngine.render()
 | ||
|     },
 | ||
|     initCameraSynchronization(sViewport, tViewport) {
 | ||
|       // Initialise the sync as they viewports will have
 | ||
|       // Different initial zoom levels for viewports of different sizes.
 | ||
| 
 | ||
|       const camera = sViewport.getCamera()
 | ||
| 
 | ||
|       tViewport.setCamera(camera)
 | ||
|     },
 | ||
|     async initializeCameraSync(renderingEngine) {
 | ||
|       return new Promise(resolve => {
 | ||
|       // The fusion scene is the target as it is scaled to both volumes.
 | ||
|       // TODO -> We should have a more generic way to do this,
 | ||
|       // So that when all data is added we can synchronize zoom/position before interaction.
 | ||
| 
 | ||
|         const axialCtViewport = renderingEngine.getViewport(viewportIds.CT.AXIAL)
 | ||
| 
 | ||
|         const axialPtViewport = renderingEngine.getViewport(viewportIds.PT.AXIAL)
 | ||
| 
 | ||
|         const axialFusionViewport = renderingEngine.getViewport(
 | ||
|           viewportIds.FUSION.AXIAL
 | ||
|         )
 | ||
| 
 | ||
|         this.initCameraSynchronization(axialFusionViewport, axialCtViewport)
 | ||
|         this.initCameraSynchronization(axialFusionViewport, axialPtViewport)
 | ||
| 
 | ||
|         renderingEngine.render()
 | ||
|         resolve()
 | ||
|       })
 | ||
|     },
 | ||
|     async resetViewport() {
 | ||
|       if (this.activeTool) {
 | ||
|         this.setToolMode('passive', this.activeTool)
 | ||
|         this.activeTool = ''
 | ||
|       }
 | ||
|       // Set volumes on the viewports
 | ||
|       // await setVolumesForViewports(
 | ||
|       //   renderingEngine,
 | ||
|       //   [
 | ||
|       //     {
 | ||
|       //       volumeId: ctVolumeId,
 | ||
|       //       callback: setCtTransferFunctionForVolumeActor
 | ||
|       //     }
 | ||
|       //   ],
 | ||
|       //   [viewportIds.CT.AXIAL]
 | ||
|       // )
 | ||
| 
 | ||
|       // await setVolumesForViewports(
 | ||
|       //   renderingEngine,
 | ||
|       //   [
 | ||
|       //     {
 | ||
|       //       volumeId: ptVolumeId,
 | ||
|       //       callback: setPetTransferFunctionForVolumeActor
 | ||
|       //     }
 | ||
|       //   ],
 | ||
|       //   [viewportIds.PT.AXIAL]
 | ||
|       // )
 | ||
| 
 | ||
|       // await this.initializeCameraSync(renderingEngine)
 | ||
|       // renderingEngine.render()
 | ||
| 
 | ||
|       // Render the viewports
 | ||
| 
 | ||
|       const viewports = [
 | ||
|         'CT_AXIAL',
 | ||
|         'PT_AXIAL',
 | ||
|         'FUSION_AXIAL'
 | ||
|       ]
 | ||
|       viewports.map(viewportId => {
 | ||
|         const renderingEngine = getRenderingEngine(renderingEngineId)
 | ||
|         const viewport = renderingEngine.getViewport(viewportId)
 | ||
|         viewport.resetCamera(true, true, false)
 | ||
|         if (this.defaultCamera) {
 | ||
|           viewport.setCamera(this.defaultCamera)
 | ||
|         }
 | ||
|         viewport.render()
 | ||
|       })
 | ||
|       document.onselectstart = function() { return false }// 解决拖动会选中文字的问题
 | ||
|       document.ondragstart = function() { return false }
 | ||
|     },
 | ||
|     initSlider() {
 | ||
|       var slider = document.getElementById('slider')
 | ||
|       var sliderBox = document.getElementById('sliderBox')
 | ||
|       var container = document.getElementById('colorBarCanvas')
 | ||
|       slider.addEventListener('mousedown', () => {
 | ||
|         this.isSlideMoving = true
 | ||
|         document.onselectstart = function() { return false }// 解决拖动会选中文字的问题
 | ||
|         document.ondragstart = function() { return false }
 | ||
|       })
 | ||
|       document.addEventListener('mousemove', (e) => {
 | ||
|         if (this.isSlideMoving) {
 | ||
|           var containerWidth = container.clientWidth
 | ||
|           var sliderWidth = sliderBox.clientWidth
 | ||
|           var maxLeft = containerWidth - sliderWidth
 | ||
|           var left = e.clientX - container.getBoundingClientRect().left
 | ||
|           var position = null
 | ||
|           position = left
 | ||
|           if (left < 0) {
 | ||
|             left = 6
 | ||
|             position = 0
 | ||
|           } else if (left > maxLeft) {
 | ||
|             left = maxLeft + 6
 | ||
|             position = maxLeft
 | ||
|           }
 | ||
| 
 | ||
|           slider.style.left = left + 'px'
 | ||
|           var positionValue = document.getElementById('slider-position')
 | ||
|           var upper = this.range
 | ||
|           position = parseInt((position / maxLeft) * upper)
 | ||
|           positionValue.textContent = position
 | ||
|           this.upper = position
 | ||
|           this.voiChange(position)
 | ||
|         }
 | ||
|       })
 | ||
|       document.addEventListener('mouseup', () => {
 | ||
|         this.isSlideMoving = false
 | ||
|         document.onselectstart = null
 | ||
|         document.ondragstart = null
 | ||
|       })
 | ||
|     },
 | ||
|     upperRangeChange(v) {
 | ||
|       if (v === 0 || v < this.upper) {
 | ||
|         return
 | ||
|       }
 | ||
|       var sliderBox = document.getElementById('sliderBox')
 | ||
|       var container = document.getElementById('colorBarCanvas')
 | ||
|       var containerWidth = container.clientWidth
 | ||
|       var sliderWidth = sliderBox.clientWidth
 | ||
|       var maxLeft = containerWidth - sliderWidth
 | ||
|       var left = (this.upper / this.range) * maxLeft
 | ||
|       if (left < 0) {
 | ||
|         left = 6
 | ||
|       } else if (left >= maxLeft) {
 | ||
|         left = maxLeft + 6
 | ||
|       }
 | ||
|       var slider = document.getElementById('slider')
 | ||
|       slider.style.left = left + 'px'
 | ||
|       var positionValue = document.getElementById('slider-position')
 | ||
|       positionValue.textContent = this.upper
 | ||
|     },
 | ||
|     renderColorMaps() {
 | ||
|       this.createColorBar(this.rgbPresetName, 'colorBarCanvas', 150, 15)
 | ||
|       this.$refs['FUSION_AXIAL'].setPreset(this.rgbPresetName)
 | ||
|       this.colorMaps.forEach((e, index) => {
 | ||
|         this.createColorBar(e, `colorBarCanvas${index}`, 110, 15)
 | ||
|       })
 | ||
|     },
 | ||
|     getVOIRange(viewportId, volumeId) {
 | ||
|       const defaultImageRange = { lower: -1000, upper: 1000 }
 | ||
|       const viewport = (
 | ||
|         renderingEngine.getViewport(viewportId)
 | ||
|       )
 | ||
|       const volumeActor = volumeId
 | ||
|         ? viewport.getActor(volumeId)
 | ||
|         : viewport.getDefaultActor()
 | ||
| 
 | ||
|       if (!volumeActor || !csUtils.isImageActor(volumeActor)) {
 | ||
|         return defaultImageRange
 | ||
|       }
 | ||
| 
 | ||
|       const voiRange = (volumeActor.actor)
 | ||
|         .getProperty()
 | ||
|         .getRGBTransferFunction(0)
 | ||
|         .getRange()
 | ||
| 
 | ||
|       return voiRange[0] === 0 && voiRange[1] === 0
 | ||
|         ? defaultImageRange
 | ||
|         : { lower: voiRange[0], upper: voiRange[1] }
 | ||
|     },
 | ||
|     voiChange(v) {
 | ||
|       const viewportId = viewportIds.FUSION.AXIAL
 | ||
|       const volumeId = ptVolumeId
 | ||
|       const voiRange = { lower: 0, upper: v }
 | ||
|       const viewport = (
 | ||
|         renderingEngine.getViewport(viewportId)
 | ||
|       )
 | ||
|       if (!viewport) return
 | ||
|       const viewportsContainingVolumeUID = csUtils.getViewportsWithVolumeId(
 | ||
|         volumeId,
 | ||
|         viewport.renderingEngineId
 | ||
|       )
 | ||
| 
 | ||
|       viewport.setProperties({ voiRange }, volumeId)
 | ||
|       viewportsContainingVolumeUID.forEach((vp) => {
 | ||
|         vp.render()
 | ||
|         this.$refs[vp.id].setWwWc()
 | ||
|       })
 | ||
|     },
 | ||
|     async setColorMap(rgbPresetName) {
 | ||
|       this.rgbPresetName = rgbPresetName
 | ||
|       this.$refs['FUSION_AXIAL'].setPreset(this.rgbPresetName)
 | ||
|       this.$refs['FUSION_AXIAL'].renderColorBar(this.rgbPresetName)
 | ||
|       this.createColorBar(this.rgbPresetName, 'colorBarCanvas', 150, 15)
 | ||
|       const renderingEngine = getRenderingEngine(renderingEngineId)
 | ||
| 
 | ||
|       const viewport = (
 | ||
|         renderingEngine.getViewport(viewportIds.FUSION.AXIAL)
 | ||
|       )
 | ||
| 
 | ||
|       viewport.setProperties({ colormap: { name: rgbPresetName }}, ptVolumeId)
 | ||
|       // viewport.setProperties({ colormap: { name: rgbPresetName }}, ctVolumeId)
 | ||
|       viewport.render()
 | ||
|       document.onselectstart = function() { return false }// 解决拖动会选中文字的问题
 | ||
|       document.ondragstart = function() { return false }
 | ||
|     },
 | ||
|     setPetColorMap(volumeInfo) {
 | ||
|       const { volumeActor } = volumeInfo
 | ||
|       const mapper = volumeActor.getMapper()
 | ||
|       mapper.setSampleDistance(1.0)
 | ||
| 
 | ||
|       const cfun = vtkColorTransferFunction.newInstance()
 | ||
|       const presetToUse = this.rgbPresetName
 | ||
|       cfun.applyColorMap(presetToUse)
 | ||
|       cfun.setMappingRange(0, 5)
 | ||
| 
 | ||
|       volumeActor.getProperty().setRGBTransferFunction(0, cfun)
 | ||
| 
 | ||
|       // Create scalar opacity function
 | ||
|       const ofun = vtkPiecewiseFunction.newInstance()
 | ||
|       ofun.addPoint(0, 0.0)
 | ||
|       ofun.addPoint(0.1, 0.9)
 | ||
|       ofun.addPoint(5, 1.0)
 | ||
| 
 | ||
|       volumeActor.getProperty().setScalarOpacity(0, ofun)
 | ||
|     },
 | ||
|     getApplicableVolumeActor(volumeId, viewportId) {
 | ||
|       const viewport = renderingEngine.getViewport(viewportId)
 | ||
|       const actorEntries = viewport.getActors()
 | ||
|       console.log(actorEntries)
 | ||
|       // const actorEntries = this.getActors();
 | ||
| 
 | ||
|       if (!actorEntries.length) {
 | ||
|         return
 | ||
|       }
 | ||
| 
 | ||
|       let volumeActor
 | ||
| 
 | ||
|       if (volumeId) {
 | ||
|         const i = actorEntries.findIndex(e => e.uid === volumeId)
 | ||
|         if (i > -1) {
 | ||
|           volumeActor = actorEntries[i].actor
 | ||
|         }
 | ||
|       // volumeActor = this.getActor(volumeId)?.actor as vtkVolume;
 | ||
|       }
 | ||
| 
 | ||
|       // // set it for the first volume (if there are more than one - fusion)
 | ||
|       if (!volumeActor) {
 | ||
|         volumeActor = actorEntries[0].actor
 | ||
|         volumeId = actorEntries[0].uid
 | ||
|       }
 | ||
| 
 | ||
|       return { volumeActor, volumeId }
 | ||
|     },
 | ||
|     createColorBar(rgbPresetName, elId, width, height) {
 | ||
|       // const ctf = vtkColorTransferFunction.newInstance()
 | ||
|       const colorMap = vtkColorMaps.getPresetByName(rgbPresetName)
 | ||
|       const rgbPoints = colorMap.RGBPoints
 | ||
|       // const range = ctf.getRange()
 | ||
|       const canvas = document.getElementById(elId)
 | ||
|       const ctx = canvas.getContext('2d')
 | ||
|       const canvasWidth = width
 | ||
|       const canvasHeight = height
 | ||
|       const rectWidth = width
 | ||
|       const rectHeight = canvasHeight
 | ||
|       canvas.width = canvasWidth
 | ||
|       canvas.height = canvasHeight
 | ||
|       const gradient = ctx.createLinearGradient(0, 0, rectWidth, 0)
 | ||
|       for (let i = 0; i < rgbPoints.length; i += 4) {
 | ||
|         let position = 0
 | ||
|         if (rgbPoints[0] === -1) {
 | ||
|           position = (rgbPoints[i] + 1) / 2
 | ||
|         } else {
 | ||
|           position = rgbPoints[i]
 | ||
|         }
 | ||
|         const color = `rgb(${parseInt(rgbPoints[i + 1] * 255)}, ${parseInt(rgbPoints[i + 2] * 255)}, ${parseInt(rgbPoints[i + 3] * 255)})`
 | ||
|         gradient.addColorStop(position, color)
 | ||
|       }
 | ||
|       ctx.fillStyle = gradient
 | ||
|       ctx.fillRect(0, 0, rectWidth, rectHeight)
 | ||
|     },
 | ||
|     toggleInvert() {
 | ||
|       if (this.activeTool) {
 | ||
|         this.setToolMode('passive', this.activeTool)
 | ||
|         this.activeTool = ''
 | ||
|       }
 | ||
|       const viewports = [
 | ||
|         { viewportId: 'CT_AXIAL', volumeId: ctVolumeId },
 | ||
|         { viewportId: 'PT_AXIAL', volumeId: ptVolumeId }
 | ||
|         // { viewportId: 'FUSION_AXIAL', volumeId: ptVolumeId }
 | ||
|       ]
 | ||
|       viewports.map(v => {
 | ||
|         const { viewportId, volumeId } = v
 | ||
|         const renderingEngine = getRenderingEngine(renderingEngineId)
 | ||
| 
 | ||
|         // Get the volume viewport
 | ||
|         const viewport = (
 | ||
|           renderingEngine.getViewport(viewportId)
 | ||
|         )
 | ||
| 
 | ||
|         // Get the volume actor from the viewport
 | ||
|         const actorEntry = viewport.getActor(volumeId)
 | ||
| 
 | ||
|         const volumeActor = actorEntry.actor
 | ||
|         const rgbTransferFunction = volumeActor
 | ||
|           .getProperty()
 | ||
|           .getRGBTransferFunction(0)
 | ||
| 
 | ||
|         // Todo: implement invert in setProperties
 | ||
|         csUtils.invertRgbTransferFunction(rgbTransferFunction)
 | ||
| 
 | ||
|         viewport.render()
 | ||
|       })
 | ||
|     },
 | ||
|     showPanel(e) {
 | ||
|       e.currentTarget.firstChild.lastChild.style.display = 'block'
 | ||
|       document.onselectstart = function() { return false }// 解决拖动会选中文字的问题
 | ||
|       document.ondragstart = function() { return false }
 | ||
|     },
 | ||
|     handleMouseout(e) {
 | ||
|       e.currentTarget.firstChild.lastChild.style.display = 'none'
 | ||
|     },
 | ||
|     showColorBarPanel(e) {
 | ||
|       e.currentTarget.firstChild.firstChild.lastChild.style.display = 'block'
 | ||
|       document.onselectstart = function() { return false }// 解决拖动会选中文字的问题
 | ||
|       document.ondragstart = function() { return false }
 | ||
|     },
 | ||
|     handleColorBarMouseout(e) {
 | ||
|       e.currentTarget.firstChild.firstChild.lastChild.style.display = 'none'
 | ||
|     },
 | ||
| 
 | ||
|     setDicomCanvasRotate(v) {
 | ||
|       if (this.activeTool) {
 | ||
|         this.setToolMode('passive', this.activeTool)
 | ||
|         this.activeTool = ''
 | ||
|       }
 | ||
| 
 | ||
|       // Get the rendering engine
 | ||
|       const renderingEngine = getRenderingEngine(renderingEngineId)
 | ||
| 
 | ||
|       const viewport = renderingEngine.getViewport('CT_AXIAL')
 | ||
|       console.log(viewport.getCamera())
 | ||
|       const { flipHorizontal, flipVertical } = viewport.getCamera()
 | ||
|       // Flip the viewport horizontally
 | ||
|       if (v === 2) {
 | ||
|         viewport.setCamera({ flipVertical: !flipVertical })
 | ||
|       } else if (v === 3) {
 | ||
|         viewport.setCamera({ flipHorizontal: !flipHorizontal })
 | ||
|       } else if (v === 4) {
 | ||
|         this.setRotate(viewport, -Math.PI / 2)
 | ||
|       } else if (v === 5) {
 | ||
|         this.setRotate(viewport, Math.PI / 2)
 | ||
|       }
 | ||
| 
 | ||
|       viewport.render()
 | ||
|       document.onselectstart = function() { return false }// 解决拖动会选中文字的问题
 | ||
|       document.ondragstart = function() { return false }
 | ||
|     },
 | ||
|     setRotate(viewport, rotateIncrementDegrees) {
 | ||
|       const camera = viewport.getCamera()
 | ||
|       const { viewUp, position, focalPoint } = camera
 | ||
|       const [cx, cy, cz] = focalPoint
 | ||
|       const direction = [0, 0, -1]
 | ||
|       const [ax, ay, az] = direction
 | ||
| 
 | ||
|       const angle = rotateIncrementDegrees
 | ||
|       const newPosition = [0, 0, 0]
 | ||
|       const newFocalPoint = [0, 0, 0]
 | ||
|       const newViewUp = [0, 0, 0]
 | ||
| 
 | ||
|       const transform = mat4.identity(new Float32Array(16))
 | ||
|       mat4.translate(transform, transform, [cx, cy, cz])
 | ||
|       mat4.rotate(transform, transform, angle, [ax, ay, az])
 | ||
|       mat4.translate(transform, transform, [-cx, -cy, -cz])
 | ||
|       vec3.transformMat4(newPosition, position, transform)
 | ||
|       vec3.transformMat4(newFocalPoint, focalPoint, transform)
 | ||
| 
 | ||
|       mat4.identity(transform)
 | ||
|       mat4.rotate(transform, transform, angle, [ax, ay, az])
 | ||
|       vec3.transformMat4(newViewUp, viewUp, transform)
 | ||
| 
 | ||
|       viewport.setCamera({
 | ||
|         position: newPosition,
 | ||
|         viewUp: newViewUp,
 | ||
|         focalPoint: newFocalPoint
 | ||
|       })
 | ||
|     },
 | ||
|     setDicomCanvasWwwc(v) {
 | ||
|       if (v.val === 0) {
 | ||
|         // 自定义
 | ||
|         this.customWwc.visible = true
 | ||
|       } else if (v.val === -1) {
 | ||
|         // 默认值
 | ||
|         const wc = this.ctVolume.cornerstoneImageMetaData.windowCenter[0]
 | ||
|         const ww = this.ctVolume.cornerstoneImageMetaData.windowWidth[0]
 | ||
|         this.changeMapperRange(wc, ww)
 | ||
|       } else {
 | ||
|         this.changeMapperRange(v.wc, v.ww)
 | ||
|       }
 | ||
| 
 | ||
|       document.onselectstart = function() { return false }// 解决拖动会选中文字的问题
 | ||
|       document.ondragstart = function() { return false }
 | ||
|     },
 | ||
|     setWwwc(v) {
 | ||
|       this.changeMapperRange(v.wc, v.ww)
 | ||
|       this.customWwc.visible = false
 | ||
|     },
 | ||
|     changeMapperRange(wc, ww) {
 | ||
|       var lower = wc - ww / 2.0
 | ||
|       var upper = wc + ww / 2.0
 | ||
|       const volumeId = ctVolumeId
 | ||
|       const voiRange = { lower, upper }
 | ||
| 
 | ||
|       const viewport = (
 | ||
|         renderingEngine.getViewport(viewportIds.CT.AXIAL)
 | ||
|       )
 | ||
|       viewport.setProperties({ voiRange }, volumeId)
 | ||
| 
 | ||
|       const viewportsContainingVolumeUID = csUtils.getViewportsWithVolumeId(
 | ||
|         volumeId,
 | ||
|         viewport.renderingEngineId
 | ||
|       )
 | ||
|       viewportsContainingVolumeUID.forEach((vp) => {
 | ||
|         vp.render()
 | ||
|         this.$refs[vp.id].setWwWc()
 | ||
|       })
 | ||
|     },
 | ||
|     handleElementsClick() {
 | ||
|       var elements = [element_ct, element_pet, element_fusion, element_mip]
 | ||
|       elements.forEach((el, index) => {
 | ||
|         el.addEventListener('click', () => {
 | ||
|           this.activeIndex = index + 1
 | ||
|         })
 | ||
|       })
 | ||
|     },
 | ||
|     imageLocation(obj) {
 | ||
|       this.setToolToTarget(obj)
 | ||
|       if (!obj.otherMeasureData) return
 | ||
|       this.isLocate = true
 | ||
|       const { metadata } = obj.otherMeasureData
 | ||
|       var imageArr = metadata.referencedImageId.split('/')
 | ||
|       var instanceId = imageArr[imageArr.length - 1]
 | ||
|       var viewportId = null
 | ||
|       // var seriesId = data.seriesId
 | ||
|       // var instanceId = data.instanceId
 | ||
|       var index = -1
 | ||
|       index = this.petSeries.instanceList.findIndex(i => i === instanceId)
 | ||
|       if (index > -1) {
 | ||
|         viewportId = 'PT_AXIAL'
 | ||
|         this.$refs[viewportId].scroll(index)
 | ||
|         return
 | ||
|       }
 | ||
|       index = this.ctSeries.instanceList.findIndex(i => i === instanceId)
 | ||
|       if (index > -1) {
 | ||
|         viewportId = 'CT_AXIAL'
 | ||
|         this.$refs[viewportId].scroll(index)
 | ||
|         return
 | ||
|       }
 | ||
|     },
 | ||
|     setToolToTarget(obj) {
 | ||
|       if (this.readingTaskState < 2 && obj.markTool && !obj.isMarked) {
 | ||
|         this.setBasicToolActive(obj.markTool)
 | ||
|       }
 | ||
|     },
 | ||
|     getTargetIdImage(
 | ||
|       targetId,
 | ||
|       renderingEngine
 | ||
|     ) {
 | ||
|       if (targetId.startsWith('imageId:')) {
 | ||
|         const imageId = targetId.split('imageId:')[1]
 | ||
|         const imageURI = utilities.imageIdToURI(imageId)
 | ||
|         let viewports = utilities.getViewportsWithImageURI(
 | ||
|           imageURI,
 | ||
|           renderingEngine.id
 | ||
|         )
 | ||
| 
 | ||
|         if (!viewports || !viewports.length) {
 | ||
|           return
 | ||
|         }
 | ||
| 
 | ||
|         viewports = viewports.filter((viewport) => {
 | ||
|           return viewport.getCurrentImageId() === imageId
 | ||
|         })
 | ||
| 
 | ||
|         if (!viewports || !viewports.length) {
 | ||
|           return
 | ||
|         }
 | ||
| 
 | ||
|         return viewports[0].getImageData()
 | ||
|       } else if (targetId.startsWith('volumeId:')) {
 | ||
|         const volumeId = targetId.split('volumeId:')[1]
 | ||
|         const viewports = utilities.getViewportsWithVolumeId(
 | ||
|           volumeId,
 | ||
|           renderingEngine.id
 | ||
|         )
 | ||
| 
 | ||
|         if (!viewports || !viewports.length) {
 | ||
|           return
 | ||
|         }
 | ||
| 
 | ||
|         return viewports[0].getImageData()
 | ||
|       } else {
 | ||
|         throw new Error(
 | ||
|           'getTargetIdImage: targetId must start with "imageId:" or "volumeId:"'
 | ||
|         )
 | ||
|       }
 | ||
|     },
 | ||
|     rightClick(e) {
 | ||
|       e.preventDefault()
 | ||
|     },
 | ||
|     async reloadViewport(activeIndex) {
 | ||
|       const viewportId = activeIndex === 1 ? 'CT_AXIAL' : ''
 | ||
|       const width = this.$refs.dicomContainer.offsetWidth
 | ||
|       const height = this.$refs.dicomContainer.offsetHeight
 | ||
| 
 | ||
|       if (this.viewportStyle.position) {
 | ||
|         this.viewportStyle = {}
 | ||
|       } else {
 | ||
|         this.viewportStyle = {
 | ||
|           position: 'absolute',
 | ||
|           top: 0,
 | ||
|           left: 0,
 | ||
|           zIndex: 10,
 | ||
|           width: width + 'px',
 | ||
|           height: height - 1 + 'px'
 | ||
|         }
 | ||
|       }
 | ||
|       await setVolumesForViewports(
 | ||
|         renderingEngine,
 | ||
|         [
 | ||
|           {
 | ||
|             volumeId: ctVolumeId,
 | ||
|             callback: setCtTransferFunctionForVolumeActor
 | ||
|           }
 | ||
|         ],
 | ||
|         [viewportIds.CT.AXIAL]
 | ||
|       )
 | ||
|       // renderingEngine.render()
 | ||
|       const viewport = (
 | ||
|         renderingEngine.getViewport(viewportId)
 | ||
|       )
 | ||
|       viewport.resetCamera(true, true, false)
 | ||
| 
 | ||
|       viewport.render()
 | ||
|     },
 | ||
|     viewportRender() {
 | ||
|       const viewportIds = ['PT_AXIAL', 'CT_AXIAL', 'FUSION_AXIAL']
 | ||
|       viewportIds.map(v => {
 | ||
|         const viewport = renderingEngine.getViewport(v)
 | ||
|         if (viewport) {
 | ||
|           viewport.render()
 | ||
|         }
 | ||
|       })
 | ||
|     },
 | ||
|     async receiveMsg(event) {
 | ||
|       if (event.data.type === 'readingPageUpdate') {
 | ||
|         this.$refs['questions'].initList()
 | ||
|         this.$refs['tableQuestions'].initList()
 | ||
|         this.isLocate = true
 | ||
|         await this.getAnnotations()
 | ||
|         this.viewportRender()
 | ||
|       } else if (event.data.type === 'readingPageStateUpdate') {
 | ||
|         this.readingTaskState = event.data.data.readingTaskState
 | ||
|       }
 | ||
|     },
 | ||
|     ...mapMutations({ setLanguage: 'lang/setLanguage' })
 | ||
|   }
 | ||
| }
 | ||
| </script>
 | ||
| <style lang="scss" scoped>
 | ||
| 
 | ||
| .dicom-viewer-container{
 | ||
|     display:flex;
 | ||
|     flex-direction: column;
 | ||
|     height: 100%;
 | ||
|     background-color: #000;
 | ||
|     padding: 5px 2px;
 | ||
|   }
 | ||
|   ::-webkit-scrollbar {
 | ||
|     width: 5px;
 | ||
|     height: 5px;
 | ||
|   }
 | ||
|   ::-webkit-scrollbar-thumb {
 | ||
|     border-radius: 10px;
 | ||
|     background: #d0d0d0;
 | ||
|   }
 | ||
|   .dicom-tools{
 | ||
|     box-sizing: border-box;
 | ||
|     width: 100%;
 | ||
|     height: 61px;
 | ||
|     padding: 0 5px;
 | ||
|     border: 1px solid #727272;
 | ||
|     display: flex;
 | ||
|     flex-direction: row;
 | ||
|     justify-content: flex-start;
 | ||
|     align-items: center;
 | ||
|     .tool-wrapper{
 | ||
|       display: flex;
 | ||
|       flex-direction: column;
 | ||
|       justify-content: center;
 | ||
|       align-items: center;
 | ||
|       margin-right: 30px;
 | ||
|       .icon{
 | ||
|         padding: 5px;
 | ||
|         border: 1px solid #404040;
 | ||
|         cursor: pointer;
 | ||
|         text-align: center;
 | ||
|         .svg-icon{
 | ||
|           font-size:20px;
 | ||
|           color:#ddd;
 | ||
|         }
 | ||
|       }
 | ||
| 
 | ||
|       .text{
 | ||
|         position: relative;
 | ||
|         font-size: 12px;
 | ||
|         margin-top: 5px;
 | ||
|         color: #d0d0d0;
 | ||
|         display: none;
 | ||
|       }
 | ||
|     }
 | ||
|     .tool_active{
 | ||
|       background-color: #607d8b;
 | ||
|     }
 | ||
|     .tool_disabled{
 | ||
|       cursor:not-allowed
 | ||
|     }
 | ||
|     .icon:hover{
 | ||
|       background-color: #607d8b;
 | ||
|     }
 | ||
|     .dropdown {
 | ||
|       position: relative;
 | ||
|       display: inline-block;
 | ||
|       .icon-content{
 | ||
|         display: flex;
 | ||
|         align-items: center;
 | ||
|         border: 1px solid #404040;
 | ||
|       }
 | ||
|       .text{
 | ||
|         text-align: center;
 | ||
|       }
 | ||
|       .tool-icon{
 | ||
|         padding: 5px;
 | ||
|         cursor: pointer;
 | ||
|         text-align: center;
 | ||
|         .svg-icon{
 | ||
|           font-size:20px;
 | ||
|           color:#ddd;
 | ||
|         }
 | ||
|       }
 | ||
| 
 | ||
|       .arrow-icon{
 | ||
|         cursor: pointer;
 | ||
|         padding: 7px 2px 7px 0px;
 | ||
|       }
 | ||
|       .arrow-icon:hover{
 | ||
|         background-color: #607d8b;
 | ||
|       }
 | ||
|       .icon-content-d:hover{
 | ||
|         background-color: #607d8b;
 | ||
|       }
 | ||
|       .tool-icon-d{
 | ||
|         padding: 5px;
 | ||
|         .svg-icon{
 | ||
|           font-size:20px;
 | ||
|           color:#ddd;
 | ||
|         }
 | ||
|       }
 | ||
| 
 | ||
|     }
 | ||
| 
 | ||
|     .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:hover{
 | ||
|         background-color: #727272;
 | ||
|         cursor: pointer;
 | ||
|       }
 | ||
|     }
 | ||
|     .layout-content ul li{
 | ||
|       border-top:1px solid #ddd;
 | ||
|       border-left:1px solid #ddd;
 | ||
|     }
 | ||
|     .layout-content ul  .flex_row{
 | ||
|       // border: 1px solid #ddd;
 | ||
|       display: flex;
 | ||
|       justify-content: space-between;
 | ||
|       flex-direction: row;
 | ||
|       align-items: center;
 | ||
|       // padding: 2px;
 | ||
|       margin-bottom: 2px;
 | ||
|     }
 | ||
|     .layout-content ul .flex_column{
 | ||
|       display: flex;
 | ||
|       justify-content: space-between;
 | ||
|       flex-direction: column;
 | ||
|       align-items: center;
 | ||
|       margin-bottom: 2px;
 | ||
|     }
 | ||
|     .layout_box_1_1{
 | ||
|       flex:1;
 | ||
|       // border: 1px solid #ddd;
 | ||
|       line-height: 30px;
 | ||
|       font-size: 12px;
 | ||
|       text-align: center;
 | ||
|       border-bottom:1px solid #ddd;
 | ||
|       border-right:1px solid #ddd;
 | ||
|       // padding: 0 5px;
 | ||
|     }
 | ||
|     .layout_box_1_2{
 | ||
|       flex:1;
 | ||
|       line-height: 15px;
 | ||
|       font-size: 10px;
 | ||
|       text-align: center;
 | ||
|       border-bottom:1px solid #ddd;
 | ||
|       border-right:1px solid #ddd;
 | ||
|     }
 | ||
|     .layout-content li .layout_box_1_1 :last-child{
 | ||
|       color: red;
 | ||
|     }
 | ||
|     .layout-content li:hover {
 | ||
|       cursor: pointer;
 | ||
|       background-color: #727272;
 | ||
|     }
 | ||
| 
 | ||
|   }
 | ||
|   .dicom-datas{
 | ||
|     box-sizing: border-box;
 | ||
|     flex: 1;
 | ||
|     margin-top: 5px;
 | ||
|     height: 100%;
 | ||
|     display: flex;
 | ||
|     flex-direction: row;
 | ||
|     justify-content: flex-start;
 | ||
|     overflow: hidden;
 | ||
|     .form-container{
 | ||
|       width: 350px;
 | ||
|       height: 100%;
 | ||
|       border: 1px solid #727272;
 | ||
|     }
 | ||
|     .dicom-container{
 | ||
|       box-sizing: border-box;
 | ||
|       flex: 1;
 | ||
|       height: 100%;
 | ||
|       border: 1px solid #727272;
 | ||
|     }
 | ||
| 
 | ||
|     .measurement-container{
 | ||
|       overflow-y: auto;
 | ||
|     }
 | ||
|     .box{
 | ||
|       display: grid;
 | ||
|       box-sizing: border-box;
 | ||
|       height: 100%;
 | ||
|       padding: 0;
 | ||
|       .item{
 | ||
|         box-sizing: border-box;
 | ||
|         position: relative;
 | ||
|         border: 1px solid rgba(255, 255, 255, 0.21);
 | ||
|         position: relative;
 | ||
|         &_active{
 | ||
|           // border: 2px solid #ffeb3b;fff
 | ||
|           border: 1px dashed #428bca;
 | ||
| 
 | ||
|         }
 | ||
|       }
 | ||
|     }
 | ||
|     .box_2_2{
 | ||
|       grid-template-columns: repeat(2, 50%); //1列,占50%
 | ||
|       grid-template-rows: repeat(2, 50%); //1行,占50%
 | ||
|     }
 | ||
|     .box_1_1{
 | ||
|       grid-template-columns: repeat(1, 100%);
 | ||
|       grid-template-rows: repeat(1, 100%);
 | ||
|     }
 | ||
| 
 | ||
|   }
 | ||
|   .colorBar{
 | ||
|    /deep/ .el-input--mini .el-input__inner{
 | ||
|       height: 25px;
 | ||
|       line-height: 25px;
 | ||
|       border: none;
 | ||
|       background-color: transparent;
 | ||
|       color:#ddd;
 | ||
|     }
 | ||
|   }
 | ||
| 
 | ||
| </style>
 |