2072 lines
		
	
	
		
			70 KiB
		
	
	
	
		
			Plaintext
		
	
	
			
		
		
	
	
			2072 lines
		
	
	
		
			70 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" -->
 | 
						||
      <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 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 } // 自定义调窗
 | 
						||
    }
 | 
						||
  },
 | 
						||
  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() {
 | 
						||
    console.log(vtkColorMaps)
 | 
						||
    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)
 | 
						||
      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 viewport = renderingEngine.getViewport('PT_AXIAL')
 | 
						||
        if (viewport) {
 | 
						||
          var annotations = annotation.state.getAnnotations('CircleROI', viewport.element)
 | 
						||
          if (annotations && annotations.length > 0) {
 | 
						||
            annotations.map(annotation => {
 | 
						||
              if (annotations.metadata.toolName === 'CircleROI') {
 | 
						||
                annotation.state.removeAnnotation(annotations.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, {
 | 
						||
        //   overlayMarkerType: 2
 | 
						||
        // })
 | 
						||
        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)
 | 
						||
 | 
						||
        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 = ''
 | 
						||
      }
 | 
						||
      // 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度
 | 
						||
      // ],
 | 
						||
      // Get the rendering engine
 | 
						||
      const renderingEngine = getRenderingEngine(renderingEngineId)
 | 
						||
      const viewportIds = [
 | 
						||
        'CT_AXIAL',
 | 
						||
        'PT_AXIAL',
 | 
						||
        'FUSION_AXIAL'
 | 
						||
      ]
 | 
						||
      viewportIds.forEach(viewportId => {
 | 
						||
        const viewport = renderingEngine.getViewport(viewportId)
 | 
						||
        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) {
 | 
						||
          viewport.setCamera({ viewAngle: -90 })
 | 
						||
        } else if (v === 5) {
 | 
						||
          viewport.setCamera({ viewAngle: 90 })
 | 
						||
        }
 | 
						||
 | 
						||
        viewport.render()
 | 
						||
      })
 | 
						||
      document.onselectstart = function() { return false }// 解决拖动会选中文字的问题
 | 
						||
      document.ondragstart = function() { return false }
 | 
						||
    },
 | 
						||
    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()
 | 
						||
    },
 | 
						||
    reloadViewport(e) {
 | 
						||
      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'
 | 
						||
        }
 | 
						||
      }
 | 
						||
      if (this.activeIndex === 1) {
 | 
						||
        const renderingEngine = getRenderingEngine(renderingEngineId)
 | 
						||
        // renderingEngine.render()
 | 
						||
        const viewport = (
 | 
						||
          renderingEngine.getViewport(viewportIds.CT.AXIAL)
 | 
						||
        )
 | 
						||
        viewport.resetCamera()
 | 
						||
        viewport.render()
 | 
						||
      }
 | 
						||
    },
 | 
						||
    receiveMsg(event) {
 | 
						||
      if (event.data.type === 'readingPageUpdate') {
 | 
						||
        this.$refs['questions'].initList()
 | 
						||
        this.$refs['tableQuestions'].initList()
 | 
						||
        this.isLocate = true
 | 
						||
        this.getAnnotations()
 | 
						||
      } 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>
 |