<template>
  <div v-loading="loading" :element-loading-text="loadingText" element-loading-spinner="el-icon-loading"
    element-loading-background="rgba(0, 0, 0, 0.8)" 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"
              @click.prevent="setBasicToolActive('WindowLevel')">
              <svg-icon icon-class="reverse" class="svg-icon" />
              <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="fitType===1?`${$t('trials:reading:button:fitWindow')}`:`${$t('trials:reading:button:fitImage')}`" placement="bottom">
        <div class="tool-wrapper">
          <div
            class="icon"
            @click.prevent="fitToType(fitType===1?'fitToWindow':'fitToImage')"
          >
            <svg-icon v-if="fitType===1" icon-class="fitToWindow" class="svg-icon" />
            <svg-icon v-else icon-class="fitToImage" class="svg-icon" />
          </div>
          <div class="text">{{ fitType===1?$t('trials:reading:button:fitWindow'):$t('trials:reading:button:fitImage') }}</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" @click.prevent="toggleInvert">
            <svg-icon icon-class="reversecolor" class="svg-icon" />
          </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"
            @click.prevent="setBasicToolActive('Zoom')">
            <svg-icon icon-class="magnifier" class="svg-icon" />
          </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"
            @click.prevent="setBasicToolActive('Pan')">
            <svg-icon icon-class="move" class="svg-icon" />
          </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"
              @click.prevent="setBasicToolActive('TrackballRotate')">
              <svg-icon icon-class="rotate" class="svg-icon" />
              <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>
      <el-tooltip v-if="isFusion" class="item" effect="dark" :content="$t('trials:reading:button:crosshairsPosition')" placement="bottom">
        <div class="tool-wrapper">
          <div class="icon" :class="[activeTool === 'FusionJumpToPointTool' ? 'tool_active' : '']"
            @click.prevent="setFusionJumpToolActive">
            <svg-icon icon-class="position" class="svg-icon" />
          </div>
          <div class="text">{{ $t('trials:reading:button:crosshairsPosition') }}</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"
          placement="bottom">
          <div slot="content">
            <div v-if="tool.disabledReason">
              <h4 style="margin:0;padding-bottom:2px;">{{ tool.text }}</h4>
              <br>{{ tool.disabledReason }}
            </div>
            <div v-else>{{ tool.text }}</div>

          </div>
          <div class="tool-wrapper">
            <div class="icon" :class="[activeTool === tool.toolName ? 'tool_active' : '']"
              @mouseenter="enter($event, tool.toolName)" @click.prevent="setMeasureToolActive(tool.toolName)">
              <svg-icon :icon-class="tool.icon" class="svg-icon" />
            </div>
            <div class="text">{{ tool.text }}</div>
          </div>
        </el-tooltip>
      </template>

      <!-- 重置 -->
      <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 v-if="!isBaseLineTask" class="item" effect="dark" :content="$t('trials:lugano:button:record')"
        placement="bottom">
        <div class="tool-wrapper">
          <div class="icon" @click.prevent="historyRecord">
            <svg-icon icon-class="record" class="svg-icon" />
          </div>
          <div class="text">{{ $t('trials:lugano:button:record') }}</div>
        </div>
      </el-tooltip>
      <!-- 伪彩 -->
      <colorMap v-show="isFusion" ref="colorMap" :unit="fusionOverlayModality === 'NM' ? '' : 'g/ml'"
        :modality="fusionOverlayModality" @setColorMap="setColorMap" @voiChange="voiChange" />

      <!-- 截屏 -->
      <!-- <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.native="reloadViewport('CT_AXIAL')" -->
      <div ref="dicomContainer" class="dicom-container box box_2_2" style="position: relative;"
        @dblclick="reloadViewport">
        <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 : {}"
          @fusionSlicePointChange="handleFusionSlicePointChange" />
        <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" :style="2 === activeIndex ? viewportStyle : {}"
          @upperRangeChange="upperRangeChange" @fusionSlicePointChange="handleFusionSlicePointChange" />
        <Viewport ref="FUSION_AXIAL" :index="3" :active-index="activeIndex"
          :is-reading-show-subject-info="isReadingShowSubjectInfo" :series-info="petSeries" :ct-series-info="ctSeries"
          :rendering-engine-id="renderingEngineId" viewport-id="FUSION_AXIAL" :volume="ptVolume"
          :measure-datas="measureDatas" :rgb-preset-name="rgbPresetName" :style="3 === activeIndex ? viewportStyle : {}"
          @upperRangeChange="upperRangeChange" @fusionSlicePointChange="handleFusionSlicePointChange" />
        <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"
          :style="4 === activeIndex ? viewportStyle : {}" @upperRangeChange="upperRangeChange" />
      </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" @handleReadingChart="handleReadingChart" />
          <Questions ref="questions" @setNonTargetMeasurementStatus="setNonTargetMeasurementStatus"
            @handleReadingChart="handleReadingChart" />
        </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">
      <custom-wwwc-form :ww="activeCanvasWW" :wc="activeCanvasWC" @close="customWwc.visible = false"
        @setWwwc="setWwwc" />
    </el-dialog>
    <el-dialog :visible.sync="fusion.visible" :close-on-click-modal="false" :title="$t('trials:lugano:button:record')"
      width="850px">
      <fusion-form @close="fusion.visible = false" />
    </el-dialog>
    <readingChart ref="readingChart" />
  </div>
</template>
<script>
import {
  RenderingEngine,
  Enums,
  // CONSTANTS,
  setVolumesForViewports,
  volumeLoader,
  resetInitialization,
  getRenderingEngine,
  eventTarget,
  // eslint-disable-next-line no-unused-vars
  cache,
  imageLoader,
  // eslint-disable-next-line no-unused-vars
  triggerEvent,
  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'
import colormaps from './js/colormaps'
// 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 FusionForm from './FusionForm.vue'
import { getTableAnswerRowInfoList, getDicomSeriesInfo } from '@/api/trials'
import FusionEvent from './FusionEvent'
import FusionJumpToPointTool from '../../../dicoms3D/components/tools/FusionJumpToPointTool'
// import { ColorMaps } from '@kitware/vtk.js/Common/Core/ColorMaps'
import vtkColorMaps from '@kitware/vtk.js/Rendering/Core/ColorTransferFunction/ColorMaps'
import vtkColorTransferFunction from '@kitware/vtk.js/Rendering/Core/ColorTransferFunction'
import vtkPiecewiseFunction from '@kitware/vtk.js/Common/DataModel/PiecewiseFunction'
// import vtkOrientationMarkerWidget from '@kitware/vtk.js/Interaction/Widgets/OrientationMarkerWidget'
import { mat4, vec3 } from 'gl-matrix'
import html2canvas from 'html2canvas'
import readingChart from '@/components/readingChart'
import colorMap from '@/views/trials/trials-panel/reading/dicoms3D/components/colorMap.vue'
// 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 { registerColormap, getColormapNames, getColormap } = csUtils.colormap
const {
  ToolGroupManager,
  Enums: csToolsEnums,
  WindowLevelTool,
  PanTool,
  ZoomTool,
  // StackScrollMouseWheelTool,
  StackScrollTool,
  synchronizers,
  // VolumeRotateMouseWheelTool,
  VolumeRotateTool,
  OrientationMarkerTool,
  // SynchronizerManager,
  // LengthTool,
  EllipticalROITool,
  CircleROITool,
  CrosshairsTool,
  TrackballRotateTool,
  ProbeTool,
  MIPJumpToClickTool,
  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 ptVolumeId2 = `${volumeLoaderScheme}:${ptVolumeName}2`
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
var fusionVoiSynchronizer
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'
const fusionVoiSynchronizerId = 'FUSION_VOI_SYNCHRONIZER_ID'
const timeout = 5 * 60 * 1000
let timerId
export default {
  name: 'Fusion',
  components: {
    Viewport,
    Questions,
    TableQuestions,
    CustomWwwcForm,
    FusionForm,
    readingChart,
    colorMap
  },
  data() {
    return {
      activeIndex: 1,
      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,
      isBaseLineTask: false,
      ctSeries: {},
      petSeries: {},
      renderingEngineId: renderingEngineId,
      ctVolumeId: `${volumeLoaderScheme}:${ctVolumeName}`,
      ptVolumeId: `${volumeLoaderScheme}:${ptVolumeName}`,
      ptVolumeId2: `${volumeLoaderScheme}:${ptVolumeName}2`,
      ctVolume: null,
      ptVolume: null,
      ptVolume2: null,
      isReadingShowSubjectInfo: false,
      subjectCode: '',
      taskBlindName: '',
      measuredTools: [
        // 圆形测量
        { toolName: 'CircleROI', text: this.$t('trials:lugano:button:circleROI'), 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'],
      colorMaps: [],
      rgbPresetName: 'siemens',
      range: 40,
      upper: 6,
      isSlideMoving: false,
      viewportStyle: {},
      isFusion: true,
      fusionOverlayModality: 'PT',
      defaultWwwc: [
        { label: this.$t('trials:reading:button:wwwcDefault'), val: -1, ww: null, wc: null }, // 默认值
        { label: this.$t('trials:reading:button:wwwcCustom'), val: 0, ww: null, wc: null }, // 自定义
        { label: 'CT Brain', wc: 40, ww: 80 },
        { label: 'CT Lungs', wc: -400, ww: 1500 },
        { label: 'CT Abdomen', wc: 60, ww: 400 },
        { label: 'CT Liver', wc: 40, ww: 400 },
        { label: 'CT Bone', wc: 300, ww: 1500 }
      ],
      customWwc: { visible: false, title: null }, // 自定义调窗
      defaultCamera: null,
      baseViewportSize: { width: null, height: null },
      loadingText: '',
      initAnnotations: [],
      activeCanvasWW: null,
      activeCanvasWC: null,
      fusion: { visible: false }, // 历史记录融合调窗
      screenshotWindow: null,
      hasVoiChanged: false,
      lastUpper: null,
      fusionCrosshairStyle: {
        lineWidth: 2,
        lineLength: 20,
        centerHoleSize: 20,
      },
      fusionJumpEnabled: false
      // initFirstAnnotation:false
    }
  },
  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() {
    document.documentElement.style.userSelect = 'none'
    window.addEventListener('message', this.receiveMsg)
    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.isCurrentTask === 'true'
    this.isBaseLineTask = this.$route.query.isBaseLineTask === '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', '')
    }
    colormaps.forEach(colormap => {
      registerColormap(colormap)
    })
    this.colorMaps = getColormapNames()
    this.colorMaps.unshift('hsv')
      this.$nextTick(() => {
        // 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) => {
      this.imageLocation(obj)
    })
    FusionEvent.$on('getScreenshots', async (measuredData, callback) => {
      // var base64Str = await this.$refs['FUSION_AXIAL'].getScreenshots()
      if (!measuredData) {
        callback()
      } else {
        const loading = this.$loading({ fullscreen: true })
        await this.imageLocation(measuredData)
        const divForDownloadViewport = document.querySelector(
          '.dicom-container'
        )
        var canvas = await html2canvas(divForDownloadViewport)
        var pictureBaseStr = canvas.toDataURL('image/png', 1)
        loading.close()
        callback(pictureBaseStr)
      }
    })
    FusionEvent.$on('viewHistoryScreenshot', (path) => {
      if (this.screenshotWindow) {
        this.screenshotWindow.close()
      }
      const routeData = this.$router.resolve({ path })
      this.screenshotWindow = window.open(routeData.href, '_blank')
    })
    window.addEventListener('beforeunload', e => { this.beforeUnloadHandler(e) })
    document.addEventListener("click", this.foo);
  },
  beforeDestroy() {
    if (this.screenshotWindow) {
      this.screenshotWindow.close()
    }
    cornerstoneTools.destroy()
    // eventTarget.reset()
    // cache.purgeCache()
    // renderingEngine.destroy()
    resetInitialization()
    renderingEngine.destroy()
    cache.purgeCache()
    imageLoader.unregisterAllImageLoaders()
    ToolGroupManager.destroyToolGroup('volume')
    FusionEvent.$off('getAnnotations')
    FusionEvent.$off('addOrUpdateAnnotations')
    FusionEvent.$off('removeAnnotation')
    FusionEvent.$off('imageLocation')
    FusionEvent.$off('getScreenshots')
    window.removeEventListener('beforeunload', e => { this.beforeUnloadHandler(e) })
  },
  methods: {
    handleReadingChart(row) {
      let { e, data } = row
      let obj = Object.assign({}, data)
      obj.TrialId = this.$route.query.trialId
      obj.VisitTaskId = this.$route.query.visitTaskId
      let zIndex = 9
      if (obj.RowIndex) {
        zIndex = 9999
      }
      this.$refs.readingChart.init(e, obj, zIndex)
    },
    foo() {
      if (!this.$refs.readingChart) return false
      this.$refs.readingChart.foo()
    },
    initPage() {
      const resizeObserver = new ResizeObserver(() => {
        if (element_ct.style.width) {
          console.log('Size changed')

          renderingEngine = getRenderingEngine(renderingEngineId)

          if (renderingEngine) {
            this.$nextTick(() => {
              renderingEngine.resize(true, true)
            })
          }
        }
      })

      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和相关库
      // this.loadingText = '初始化中...'
      await initLibraries()

      // console.log(colormaps, registerColormap)
      // colormaps.forEach(registerColormap)
      renderingEngine = new RenderingEngine(renderingEngineId)
      var ctseriesId = this.$route.query.ctseriesId
      this.ctSeries = await this.getSeriesInfo(ctseriesId)

      var ptseriesId = this.$route.query.ptseriesId
      this.petSeries = await this.getSeriesInfo(ptseriesId)
      const maxCount = Math.max(this.ctSeries.imageIds.length, this.petSeries.imageIds.length)
      this.$set(this.ctSeries, 'imageMaxLength', maxCount)
      this.$set(this.petSeries, 'imageMaxLength', maxCount)

      await this.getImages()

      // 设置viewport
      await this.setUpDisplay()

      // 设置viewportTools and synchronizers
      this.setUpToolGroups()

      this.setUpSynchronizers()
      this.dispatchFusionCenterPoint()
      // this.$refs['CT_AXIAL'].scroll(0)
      // this.$refs['PT_AXIAL'].scroll(0)
      // this.$refs['FUSION_AXIAL'].scroll(0)
      const viewport = renderingEngine.getViewport('CT_AXIAL')
      if (viewport) {
        this.defaultCamera = viewport.getCamera()
      }
      this.baseViewportSize.width = document.querySelector('.cornerstone-canvas').clientWidth
      this.baseViewportSize.height = document.querySelector('.cornerstone-canvas').clientHeight

      await this.getAnnotations()
      var annotations = [...this.measureDatas]
      annotations.map(i => {
        if (i.OtherMeasureData) {
          this.initAnnotations.push({ orderMark: i.OrderMarkName, isInit: false })
        }
      })
      eventTarget.addEventListener(cornerstoneTools.Enums.Events.ANNOTATION_ADDED, (e) => {
        console.log('ANNOTATION_ADDED')
        this.onAnnotationAdded(e)
      })

      const debouncedCallback = this.debounce((e) => {
        this.onAnnotationModified(e)
        // const { annotation } = e.detail
        // const { remark } = annotation.data
        // var idx = this.initAnnotations.findIndex(i => i.orderMark === remark)
        // if (this.initAnnotations.length > 0 && idx > -1 && this.initAnnotations[idx].orderMark === remark && !this.initAnnotations[idx].isInit) {
        //   this.initAnnotations[idx].isInit = true
        // } else {
        //   this.onAnnotationModified(e)
        // }
        // 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 (!annotation.isHandleOutsideImage) {
        //   this.onAnnotationModified(e)
        // } else {
        //   // console.log('异常标记：', annotation)
        //   // const { remark } = annotation.data
        //   // if (remark === 'Liver' || remark === 'Mediastinum') {
        //   //   this.$refs['questions'].setOutsideMeasuredData(annotation)
        //   // } else {
        //   //   this.$refs['tableQuestions'].setOutsideMeasuredData(annotation)
        //   // }
        //   // 移除标记
        //   // 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) => {
        // console.log('ANNOTATION_MODIFIED')
        debouncedCallback(e)
      })
      eventTarget.addEventListener(cornerstoneTools.Enums.Events.ANNOTATION_SELECTION_CHANGE, (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.loadingText = ''
      this.loading = false
    },
    getSeriesInfo(seriesId) {
      return new Promise(resolve => {
        getDicomSeriesInfo({ seriesId }).then(res => {
          var series = res.Result
          this.fusionOverlayModality = series.Modality
          var imageIds = []
          var instanceList = []
          series.InstanceInfoList.forEach(instance => {
            if (instance.NumberOfFrames && instance.NumberOfFrames > 1) {
              for (let i = 0; i < instance.NumberOfFrames; i++) {
                const imageId = `wadouri:${localStorage.getItem('location') !== 'USA' ? this.OSSclientConfig.basePath : this.OSSclientConfig.basePath}${instance.Path}?frame=${i}`
                imageIds.push(imageId)
              }
            } else {
              const imageId = `wadouri:${localStorage.getItem('location') !== 'USA' ? this.OSSclientConfig.basePath : this.OSSclientConfig.basePath}${instance.Path}`
              imageIds.push(imageId)
            }
            instanceList.push(instance.Id)
          })
          resolve({
            imageIds: imageIds,
            instanceList: instanceList,
            seriesId: series.Id,
            imageIdIndex: 0,
            seriesUid: series.SeriesInstanceUid,
            seriesNumber: series.SeriesNumber,
            sliceThickness: series.SliceThickness,
            modality: series.Modality,
            description: series.Description,
            instanceCount: series.InstanceCount,
            studyId: this.$route.query.studyId,
            taskBlindName: this.$route.query.taskBlindName,
            visitTaskId: this.$route.query.visitTaskId
          })
        })
      })
      // var idx = series.findIndex(i => i.seriesId === seriesId)
      // if (idx > -1) {
      //   return series[idx]
      // } else {
      //   return {}
      // }
    },
    getAnnotations() {
      return new Promise(resolve => {
        const viewportIds = ['FUSION_AXIAL']
        viewportIds.map(v => {
          const viewport = renderingEngine.getViewport(v)
          if (viewport) {
            var annotations = annotation.state.getAnnotations('CircleROI', viewport.element)

            if (annotations && annotations.length > 0) {
              annotations.map(i => {
                if (i.metadata.toolName === 'CircleROI') {
                  annotation.state.removeAnnotation(i.annotationUID)
                }
              })
            }
          }
        })

        // annotation.state.removeAllAnnotations()
        this.isInitMeasureDatas = false
        var visitTaskId = this.$route.query.visitTaskId
        getTableAnswerRowInfoList(visitTaskId).then(res => {
          var arr = []
          res.Result.forEach(el => {
            if (el.OtherMeasureData) {
              el.OtherMeasureData = JSON.parse(el.OtherMeasureData)
              el.OtherMeasureData.invalidated = false
              // el.OtherMeasureData.highlighted = false
              if (this.readingTaskState === 2) {
                el.OtherMeasureData.isLocked = true
              }
              el.OtherMeasureData.data.remark = el.OrderMarkName
              const viewport = renderingEngine.getViewport('PT_AXIAL')
              annotation.state.addAnnotation(el.OtherMeasureData, viewport.element)
            }
            arr.push(el)
          })
          this.measureDatas = arr
          this.isInitMeasureDatas = true

          resolve()
        })
      })
    },
    addOrUpdateAnnotations(obj) {
      var idx = this.measureDatas.findIndex(item => item.OrderMarkName === obj.data.OrderMarkName)
      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
      if (!otherMeasureData || !otherMeasureData.data) return
      const { data } = otherMeasureData
      const i = this.measureDatas.findIndex(item => item.OtherMeasureData && item.OtherMeasureData.data.remark === data.remark)
      if (i > -1) {
        annotation.state.removeAnnotation(this.measureDatas[i].OtherMeasureData.annotationUID)
        if (type === 'delete') {
          // this.measureDatas.splice(i, 1)
          this.measureDatas[i].OtherMeasureData = ''
        } else {
          if (this.measureDatas[i].FristAddTaskId) {
            this.measureDatas[i].OtherMeasureData = ''
          } else {
            // this.measureDatas.splice(i, 1)
            this.measureDatas[i].OtherMeasureData = ''
          }
        }
        renderingEngine.render()
      }
    },
    onAnnotationAdded(e) {
      this.isLocate = false
      const { detail } = e
      const { annotation } = detail
      const { metadata } = annotation
      if (!metadata || metadata.toolName === FusionJumpToPointTool.toolName) {
        return
      }
      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) {
      const { detail } = e
      const { annotation } = detail
      const { metadata, data } = annotation
      if (!metadata || metadata.toolName === FusionJumpToPointTool.toolName) {
        return
      }
      // var i = this.initAnnotations.findIndex(i => i.orderMark === data.remark && !i.isInit)
      // if (i > -1) {
      //   console.log(data.remark)
      //   this.initAnnotations[i].isInit = true
      //   return
      // }
      // if (this.isLocate) {
      //   setTimeout(() => {
      //     this.isLocate = false
      //   }, 1000)
      // } else {

      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
        let obj = null
        for (let key in data.cachedStats) {
          if (key.includes(`volumeId:${ptVolumeId}`)) {
            obj = data.cachedStats[key]
            break;
          }
        }
        measureData.suvMax = obj && obj.max ? obj.max.toFixed(this.digitPlaces) : null
        measureData.modalityUnit = obj.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) {
        var toolGroupIds = [ctToolGroupId, ptToolGroupId, fusionToolGroupId]
        if (this.readingTaskState < 2) {
          toolGroupIds.forEach((toolGroupId) => {
            const toolGroup = ToolGroupManager.getToolGroup(toolGroupId)
            if (this.activeTool) {
              toolGroup.setToolPassive(this.activeTool)
            }
            toolGroup.setToolActive(obj.toolName, {
              bindings: [
                {
                  mouseButton: MouseBindings.Primary // Left Click
                }
              ]
            })
          })
          this.activeTool = 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() {
      try {
        // 开始计时器
        this.startTimer()
        // '影像加载中...'
        this.loadingText = this.$t('trials:lugano:message:loadImages')

        const ctImageIds = await createImageIdsAndCacheMetaData({
          modality: 'CT',
          imageIds: this.ctSeries.imageIds
        })
        const ptImageIds = await createImageIdsAndCacheMetaData({
          modality: 'PT',
          imageIds: this.petSeries.imageIds
        })
        // '体数据构建中...'
        this.loadingText = this.$t('trials:lugano:message:loadVolumes')

        this.ctVolume = await volumeLoader.createAndCacheVolume(ctVolumeId, {
          imageIds: ctImageIds
        })
        this.ptVolume = await volumeLoader.createAndCacheVolume(ptVolumeId, {
          imageIds: ptImageIds
        })
        this.ptVolume2 = await volumeLoader.createAndCacheVolume(ptVolumeId2, {
          imageIds: ptImageIds
        })
        // 重置计时器
        this.resetTimer()
      } catch (error) {
        // 重置计时器
        this.resetTimer()
        console.log(error)
      }
    },
    setUpToolGroups() {
      cornerstoneTools.addTool(WindowLevelTool)
      cornerstoneTools.addTool(ZoomTool)
      cornerstoneTools.addTool(StackScrollTool)
      cornerstoneTools.addTool(FusionJumpToPointTool)
      cornerstoneTools.addTool(MIPJumpToClickTool)
      cornerstoneTools.addTool(VolumeRotateTool)
      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 = 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(StackScrollTool.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)
        toolGroup.addTool(FusionJumpToPointTool.toolName, this.getFusionJumpToolConfiguration())
      })

      fusionToolGroup.addTool(PanTool.toolName)
      fusionToolGroup.addTool(ZoomTool.toolName)
      fusionToolGroup.addTool(StackScrollTool.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)
      fusionToolGroup.addTool(FusionJumpToPointTool.toolName, this.getFusionJumpToolConfiguration())
      // 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: ptVolumeId2
      });

      [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(StackScrollTool.toolName)
        toolGroup.setToolActive(StackScrollTool.toolName, {
          bindings: [{ mouseButton: MouseBindings.Wheel }],
        });
        // toolGroup.setToolPassive(EllipticalROITool.toolName)
        if (this.readingTaskState === 2) {
          toolGroup.setToolEnabled(CircleROITool.toolName)
        } else {
          toolGroup.setToolPassive(CircleROITool.toolName)
        }

        // toolGroup.setToolPassive(ProbeTool.toolName)
        // toolGroup.setToolPassive(WindowLevelTool.toolName)
        toolGroup.setToolConfiguration(
          ScaleOverlayTool.toolName,
          {
            scaleLocation: 'bottom'
          },
          true // overwrite
        )
        toolGroup.setToolEnabled(ScaleOverlayTool.toolName)
       
        // toolGroup.setToolConfiguration(OrientationMarkerTool.toolName, {
        //   orientationWidget: {
        //     enabled: true,
        //     viewportCorner: vtkOrientationMarkerWidget.Corners.BOTTOM_RIGHT,
        //     viewportSize: 0.15,
        //     minPixelSize: 15,
        //     maxPixelSize: 45
        //   },
        //   overlayConfiguration: {
        //     [OrientationMarkerTool.OVERLAY_MARKER_TYPES.ANNOTATED_CUBE]: {
        //       faceProperties: {
        //         xPlus: { text: 'R', faceColor: '#ffff00', faceRotation: 90 },
        //         xMinus: { text: 'L', faceColor: '#ffff00', faceRotation: 270 },
        //         yPlus: {
        //           text: 'P',
        //           faceColor: '#00ffff',
        //           fontColor: 'white',
        //           faceRotation: 180
        //         },
        //         yMinus: { text: 'A', faceColor: '#00ffff', fontColor: 'white' },
        //         zPlus: { text: 'S' },
        //         zMinus: { text: 'I' }
        //       },
        //       defaultStyle: {
        //         fontStyle: 'bold',
        //         fontFamily: 'Arial',
        //         fontColor: 'black',
        //         fontSizeScale: (res) => res / 2,
        //         faceColor: '#0000ff',
        //         edgeThickness: 0.1,
        //         edgeColor: 'blue',
        //         resolution: 400
        //       }
        //     }
        //   }
        // })
        // toolGroup.setToolActive(OrientationMarkerTool.toolName)
      })

      // MIP Tool Groups
      mipToolGroup = null
      if (!ToolGroupManager.getToolGroup(mipToolGroupUID)) {
        mipToolGroup = ToolGroupManager.createToolGroup(mipToolGroupUID)
      } else {
        mipToolGroup = ToolGroupManager.getToolGroup(mipToolGroupUID)
      }

      mipToolGroup.addTool(VolumeRotateTool.toolName)
      mipToolGroup.setToolActive(VolumeRotateTool.toolName, {
        bindings: [{ mouseButton: MouseBindings.Wheel }],
      });
      mipToolGroup.addTool(PanTool.toolName)
      mipToolGroup.addTool(ZoomTool.toolName)
      mipToolGroup.setToolActive(PanTool.toolName, {
        bindings: [{ mouseButton: MouseBindings.Auxiliary }]
      })
      mipToolGroup.setToolActive(ZoomTool.toolName, {
        bindings: [{ mouseButton: MouseBindings.Secondary }]
      })
      mipToolGroup.addTool(FusionJumpToPointTool.toolName, this.getFusionJumpToolConfiguration())
      mipToolGroup.addTool(MIPJumpToClickTool.toolName, {
        targetViewportIds: this.getFusionJumpToolConfiguration().targetViewportIds
      })

      // Set the initial state of the tools, here we set one tool active on left click.
      // This means left click will draw that tool.
      
      // 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)
      this.setFusionMipClickEnabled(!this.fusionJumpEnabled && this.isFusion)
    },
    getFusionJumpToolConfiguration() {
      return {
        targetViewportIds: [
          viewportIds.CT.AXIAL,
          viewportIds.PT.AXIAL,
          viewportIds.FUSION.AXIAL,
          viewportIds.PETMIP.CORONAL
        ],
        useBrightestPoint: true,
        jumpToTargetViewports: true,
        dispatchEventName: 'fusion-mip-point-selected',
        getReferenceLineColor: this.setFusionCrosshairsToolLineColor,
        style: this.fusionCrosshairStyle,
        referenceLinesCenterGapRadius: this.fusionCrosshairStyle.centerHoleSize,
        minimal: {
          enabled: true,
          lineLengthInPx: this.fusionCrosshairStyle.lineLength,
        },
        mipViewportIds: [viewportIds.PETMIP.CORONAL]
      }
    },
    setFusionCrosshairsToolLineColor(viewportId) {
      const colors = {
        [viewportIds.CT.AXIAL]: '#0000ff',
        [viewportIds.PT.AXIAL]: '#0000ff',
        [viewportIds.FUSION.AXIAL]: '#0000ff',
        [viewportIds.PETMIP.CORONAL]: '#ff0000'
      }
      return colors[viewportId] || '#0000ff'
    },
    handleFusionSlicePointChange({ viewportId, worldPoint }) {
      if (!this.fusionJumpEnabled) return
      if (!this.isFusion) return
      if (!viewportId || !Array.isArray(worldPoint) || worldPoint.length < 3) return
      if (viewportId === viewportIds.PETMIP.CORONAL) return

      const activeViewportId = this.activeIndex === 1
        ? viewportIds.CT.AXIAL
        : this.activeIndex === 2
          ? viewportIds.PT.AXIAL
          : this.activeIndex === 3
            ? viewportIds.FUSION.AXIAL
            : viewportIds.PETMIP.CORONAL
      if (viewportId !== activeViewportId) return

      const renderEngine = getRenderingEngine(renderingEngineId)
      if (!renderEngine) return
      const toolGroupCandidates = [fusionToolGroupId, mipToolGroupUID, ptToolGroupId, ctToolGroupId]
      let instance = null
      for (const toolGroupId of toolGroupCandidates) {
        const toolGroup = ToolGroupManager.getToolGroup(toolGroupId)
        if (!toolGroup || !toolGroup.getToolInstance) continue
        instance = toolGroup.getToolInstance(FusionJumpToPointTool.toolName)
        if (instance && instance.setPoint) break
      }
      if (!instance || !instance.setPoint) return

      instance.setPoint(worldPoint, viewportId, renderEngine.id, {
        jumpToTargetViewports: false,
        dispatchEvent: false,
      })
    },
    dispatchFusionCenterPoint(retryCount = 0) {
      if (!this.fusionJumpEnabled) return
      const renderEngine = getRenderingEngine(renderingEngineId)
      if (!renderEngine) return
      const toolGroupCandidates = [fusionToolGroupId, mipToolGroupUID, ptToolGroupId, ctToolGroupId]
      let instance = null
      for (const toolGroupId of toolGroupCandidates) {
        const toolGroup = ToolGroupManager.getToolGroup(toolGroupId)
        if (!toolGroup || !toolGroup.getToolInstance) continue
        instance = toolGroup.getToolInstance(FusionJumpToPointTool.toolName)
        if (instance && instance.setPoint) break
      }
      if (!instance || !instance.setPoint) {
        if (retryCount < 10) {
          setTimeout(() => {
            this.dispatchFusionCenterPoint(retryCount + 1)
          }, 120)
        }
        return
      }

      const candidates = [viewportIds.FUSION.AXIAL, viewportIds.PT.AXIAL, viewportIds.CT.AXIAL]
      for (const viewportId of candidates) {
        const viewport = renderEngine.getViewport(viewportId)
        if (!viewport) continue
        const width = viewport.element ? viewport.element.clientWidth : null
        const height = viewport.element ? viewport.element.clientHeight : null
        let worldPoint = null
        if (width && height && viewport.canvasToWorld) {
          worldPoint = viewport.canvasToWorld([width / 2, height / 2])
        }
        if ((!worldPoint || worldPoint.length < 3) && viewport.getCamera) {
          const camera = viewport.getCamera()
          if (camera && camera.focalPoint) {
            worldPoint = camera.focalPoint
          }
        }
        if (!worldPoint || worldPoint.length < 3) continue
        instance.setPoint(worldPoint, viewportId, renderEngine.id, {
          jumpToTargetViewports: true,
          dispatchEvent: false,
        })
        return
      }
      if (retryCount < 10) {
        setTimeout(() => {
          this.dispatchFusionCenterPoint(retryCount + 1)
        }, 120)
      }
    },
    setFusionJumpToolActive() {
      if (this.activeTool === FusionJumpToPointTool.toolName) {
        this.setFusionJumpEnabled(false)
        this.activeTool = ''
        return
      }
      if (this.activeTool) {
        this.setToolMode('passive', this.activeTool)
      }
      this.setFusionJumpEnabled(true)
      this.activeTool = FusionJumpToPointTool.toolName
    },
    setFusionMipClickEnabled(enabled) {
      const toolGroup = ToolGroupManager.getToolGroup(mipToolGroupUID)
      if (!toolGroup || !toolGroup.hasTool(MIPJumpToClickTool.toolName)) return
      if (enabled && this.isFusion) {
        toolGroup.setToolActive(MIPJumpToClickTool.toolName, {
          bindings: [{ mouseButton: MouseBindings.Primary }]
        })
      } else {
        toolGroup.setToolDisabled(MIPJumpToClickTool.toolName)
      }
    },
    setFusionJumpEnabled(enabled) {
      this.fusionJumpEnabled = !!enabled
      const toolGroupIds = [ctToolGroupId, ptToolGroupId, fusionToolGroupId, mipToolGroupUID]
      if (enabled) {
        this.setFusionMipClickEnabled(false)
        toolGroupIds.forEach((toolGroupId) => {
          const toolGroup = ToolGroupManager.getToolGroup(toolGroupId)
          if (!toolGroup || !toolGroup.hasTool(FusionJumpToPointTool.toolName)) return
          toolGroup.setToolActive(FusionJumpToPointTool.toolName, {
            bindings: [{ mouseButton: MouseBindings.Primary }]
          })
        })
        this.dispatchFusionCenterPoint()
        return
      }
      this.setFusionMipClickEnabled(this.isFusion)
      toolGroupIds.forEach((toolGroupId) => {
        const toolGroup = ToolGroupManager.getToolGroup(toolGroupId)
        if (!toolGroup || !toolGroup.hasTool(FusionJumpToPointTool.toolName)) return
        toolGroup.setToolDisabled(FusionJumpToPointTool.toolName)
      })
      this.clearFusionJumpToPointAnnotations()
    },
    clearFusionJumpToPointAnnotations() {
      const annotations = cornerstoneTools.annotation.state.getAllAnnotations() || []
      const removeList = []
      for (let i = 0; i < annotations.length; i++) {
        const item = annotations[i]
        if (!item || !item.metadata) continue
        if (item.metadata.toolName !== FusionJumpToPointTool.toolName) continue
        removeList.push(item)
      }
      if (!removeList.length) return
      removeList.forEach(i => {
        cornerstoneTools.annotation.state.removeAnnotation(i.annotationUID)
      })
      const renderEngine = getRenderingEngine(renderingEngineId)
      if (!renderEngine) return
      const viewportIdsToRender = [
        viewportIds.CT.AXIAL,
        viewportIds.PT.AXIAL,
        viewportIds.FUSION.AXIAL,
        viewportIds.PETMIP.CORONAL
      ]
      viewportIdsToRender.forEach(viewportId => {
        const viewport = renderEngine.getViewport(viewportId)
        if (viewport && viewport.render) {
          viewport.render()
        }
      })
    },
    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, mipToolGroupUID]
      if (toolName !== FusionJumpToPointTool.toolName && this.fusionJumpEnabled) {
        this.setFusionJumpEnabled(false)
      }
      toolGroupIds.forEach((toolGroupId) => {
        const toolGroup = ToolGroupManager.getToolGroup(toolGroupId)
        if (!toolGroup || !toolGroup.hasTool(toolName)) return
        if (this.activeTool === toolName) {
          if (toolGroup.hasTool(toolName)) {
            toolGroup.setToolPassive(toolName)
          }
        } else {
          if (this.activeTool) {
            if (toolGroup.hasTool(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.isCanActiveTool) return
      this.isNonTargetMeasurement = false
      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, mipToolGroupUID]
      toolGroupIds.forEach((toolGroupId) => {
        const toolGroup = ToolGroupManager.getToolGroup(toolGroupId)
        if (!toolGroup || !toolGroup.hasTool(toolName)) return
        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, {
        syncInvertState: false,
        syncColormap: false,
      });
      ptVoiSynchronizer = createVOISynchronizer(ptVoiSynchronizerId, {
        syncInvertState: false,
        syncColormap: false,
      });
      fusionVoiSynchronizer = createVOISynchronizer(fusionVoiSynchronizerId, {
        syncInvertState: false,
        syncColormap: false,
      });
      // 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,
        viewportIds.PETMIP.CORONAL,
        viewportIds.PT.AXIAL
      ].forEach((viewportId) => {
        ptVoiSynchronizer.add({
          renderingEngineId,
          viewportId
        })
      });
      [
        viewportIds.FUSION.AXIAL
      ].forEach((viewportId) => {
        fusionVoiSynchronizer.add({
          renderingEngineId,
          viewportId,
        })
        ctVoiSynchronizer.addTarget({
          renderingEngineId,
          viewportId
        })
        ptVoiSynchronizer.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()
      // console.log(this.ctVolume.cornerstoneImageMetaData)
      // 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: ptVolumeId2,
            callback: setPetColorMapTransferFunctionForVolumeActor
          },
          {
            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 = ''
      }

      const viewports = [
        'CT_AXIAL',
        'PT_AXIAL',
        'FUSION_AXIAL'
      ]
      viewports.map(viewportId => {
        const renderingEngine = getRenderingEngine(renderingEngineId)
        const viewport = renderingEngine.getViewport(viewportId)
        viewport.resetCamera(true, true, false)
        if (this.defaultCamera) {
          viewport.setCamera(this.defaultCamera)
        }
        viewport.render()
        this.$refs[viewportId].resetMarks()
      })

      // document.onselectstart = function() { return false }// 解决拖动会选中文字的问题
      // document.ondragstart = function() { return false }
    },
    fitToType(toolName) {
      if (this.activeTool !== 'fitToWindow' && this.activeTool !== 'fitToImage') {
        this.setToolMode('passive', this.activeTool)
      }
      if (toolName === 'fitToWindow') {
        this.fitType = 0
      } else if (toolName === 'fitToImage') {
        this.fitType = 1
      }
      const viewports = [
        'CT_AXIAL',
        'PT_AXIAL',
        'FUSION_AXIAL'
      ]
      viewports.map(viewportId => {
        const renderingEngine = getRenderingEngine(renderingEngineId)
        const viewport = renderingEngine.getViewport(viewportId)
        viewport.resetCamera(true, true, false)
        if (this.fitType && this.defaultCamera) {
          viewport.setCamera(this.defaultCamera)
        }
        viewport.render()
        this.$refs[viewportId].resetMarks()
      })
      this.activeTool = toolName
    },
    initSlider() {
      var slider = document.getElementById('slider')
      var sliderBox = document.getElementById('sliderBox')
      var container = document.getElementById('colorBarCanvas')
      
      if (!slider || !sliderBox || !container) return
      
      slider.addEventListener('mousedown', (e) => {
        this.isSlideMoving = true
        e.stopPropagation()
        // document.onselectstart = function() { return false }// 解决拖动会选中文字的问题
        // document.ondragstart = function() { return false }
      })
      document.addEventListener('mousemove', (e) => {
        if (this.isSlideMoving) {
          var colorBarContainer = document.getElementById('colorBar')
          if (!colorBarContainer) return
          
          var containerWidth = colorBarContainer.clientWidth
          var sliderWidth = sliderBox.clientWidth
          var maxLeft = containerWidth - sliderWidth
          
          // 获取相对于整个父容器的外边距位置
          var rect = colorBarContainer.getBoundingClientRect()
          var left = e.clientX - rect.left - (sliderWidth / 2)
          
          if (left < 0) {
            left = 0
          } else if (left > maxLeft) {
            left = maxLeft
          }

          slider.style.left = left + 'px'
          var positionValue = document.getElementById('slider-position')
          var upper = this.range
          var position = parseInt((left / maxLeft) * upper)
          
          if (positionValue) {
            positionValue.textContent = position
          }
          this.upper = position
          
          if (this.sliderTimeout) {
            cancelAnimationFrame(this.sliderTimeout)
          }
          this.sliderTimeout = requestAnimationFrame(() => {
            this.voiChange(position)
          })
        }
      })
      document.addEventListener('mouseup', (e) => {
        if (this.isSlideMoving) {
          this.isSlideMoving = false
          if (this.sliderTimeout) {
            cancelAnimationFrame(this.sliderTimeout)
          }
          this.voiChange(this.upper)
        }
        // document.onselectstart = null
        // document.ondragstart = null
      })
    },
    voiChange(v) {
      // console.log(this.lastUpper, this.hasVoiChanged, v)
      if (this.lastUpper === v && this.hasVoiChanged) return;
      this.lastUpper = v;
      this.hasVoiChanged = true;
      let viewportIds = ['FUSION_AXIAL', 'PT_AXIAL', 'PET_MIP_CORONAL']
      viewportIds.map(viewportId => {
        // const volumeId = viewportId === 'viewportId' ? ptVolumeId : ctVolumeId
        const volumeId = viewportId === 'FUSION_AXIAL' ? ptVolumeId2 : ptVolumeId
        const voiRange = { lower: 0, upper: v }
        const viewport = (
          renderingEngine.getViewport(viewportId)
        )
        if (!viewport) return
        
        viewport.setProperties({ voiRange }, volumeId)
        viewport.render()
        this.$refs[viewport.id] && this.$refs[viewport.id].setWwWc()
      })
      // 反向同步到 colorMap 组件，更新滑块
      if (this.$refs.colorMap) {
        this.$refs.colorMap.changeVoi(v)
      }
    },
    // async setColorMap(rgbPresetName) {
    //   this.rgbPresetName = rgbPresetName
    //   if (this.$refs.FUSION_AXIAL) {
    //     this.$refs.FUSION_AXIAL.setPreset(this.rgbPresetName)
    //     this.$refs.FUSION_AXIAL.renderColorBar(this.rgbPresetName)
    //   }

    //   const viewport = getRenderingEngine(renderingEngineId)?.getViewport('FUSION_AXIAL')
    //   if (!viewport) return

    //   const actorEntry = viewport.getActors()?.find(e => String(e.uid || '').includes('PT_VOLUME_ID2'))
    //   if (!actorEntry?.actor) return

    //   const preset = rgbPresetName === 'hsv' ? vtkColorMaps.getPresetByName(rgbPresetName) : getColormap(rgbPresetName)
    //   const cfun = vtkColorTransferFunction.newInstance()
    //   const rgbPoints = preset?.RGBPoints
    //   if (Array.isArray(rgbPoints)) {
    //     for (let i = 0; i < rgbPoints.length; i += 4) {
    //       cfun.addRGBPoint(rgbPoints[i], rgbPoints[i + 1], rgbPoints[i + 2], rgbPoints[i + 3])
    //     }
    //   }
    //   cfun.setMappingRange(0, 5)
    //   actorEntry.actor.getProperty().setRGBTransferFunction(0, cfun)

    //   const ofun = vtkPiecewiseFunction.newInstance()
    //   ofun.addPoint(0, 0.0)
    //   ofun.addPoint(0.1, 0.9)
    //   ofun.addPoint(5, 1.0)
    //   actorEntry.actor.getProperty().setScalarOpacity(0, ofun)

    //   viewport.render()
    // },
    async setColorMap(rgbPresetName) {
      this.rgbPresetName = rgbPresetName
      let viewports = ['FUSION_AXIAL']
      viewports.map(v => {
        this.$refs[v] && this.$refs[v].setPreset(this.rgbPresetName)
        this.$refs[v] && this.$refs[v].setColorMap(rgbPresetName)
        
      })
    },
    upperRangeChange(v) {
      if (this.upper === v) return
      this.upper = v;

      if (v === 0) {
        return
      }
      this.voiChange(v)
      // 反向同步到 colorMap 组件，更新滑块
      if (this.$refs.colorMap) {
        this.$refs.colorMap.changeVoi(v)
      }
    },
    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()
      var colorMap = null
      if (rgbPresetName === 'hsv') {
        colorMap = vtkColorMaps.getPresetByName(rgbPresetName)
      } else {
        colorMap = getColormap(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 = ''
      }
      let viewporId = this.activeIndex === 1 ? 'CT_AXIAL' : this.activeIndex === 2 ? 'PT_AXIAL' : this.activeIndex === 3 ? 'FUSION_AXIAL' : 'PET_MIP_CORONAL'
      let volumeId = this.activeIndex === 1 ? ctVolumeId : ptVolumeId
      const renderingEngine = getRenderingEngine(renderingEngineId)
      const viewport = renderingEngine.getViewport(viewporId)
      const { invert } = viewport.getProperties()
      if (this.isFusion) {
        viewport.setProperties({ invert: !invert }, volumeId)
      }
      viewport.setProperties({ invert: !invert })
      viewport.render()
    },
    showPanel(e) {
      e.currentTarget.firstChild.lastChild.style.display = 'block'
      // document.onselectstart = function() { return false }// 解决拖动会选中文字的问题
      // document.ondragstart = function() { return false }
    },
    handleMouseout(e) {
      e.currentTarget.firstChild.lastChild.style.display = 'none'
    },
    showColorBarPanel(e) {
      e.currentTarget.firstChild.firstChild.lastChild.style.display = 'block'
      // document.onselectstart = function() { return false }// 解决拖动会选中文字的问题
      // document.ondragstart = function() { return false }
    },
    handleColorBarMouseout(e) {
      e.currentTarget.firstChild.firstChild.lastChild.style.display = 'none'
    },

    setDicomCanvasRotate(v) {
      if (this.activeTool) {
        this.setToolMode('passive', this.activeTool)
        this.activeTool = ''
      }

      // Get the rendering engine
      const renderingEngine = getRenderingEngine(renderingEngineId)

      const viewport = renderingEngine.getViewport('CT_AXIAL')
      const { flipHorizontal, flipVertical } = viewport.getCamera()
      // Flip the viewport horizontally
      if (v === 2) {
        viewport.setCamera({ flipVertical: !flipVertical })
      } else if (v === 3) {
        viewport.setCamera({ flipHorizontal: !flipHorizontal })
      } else if (v === 4) {
        this.setRotate(viewport, -Math.PI / 2)
      } else if (v === 5) {
        this.setRotate(viewport, Math.PI / 2)
      }

      viewport.render()
      if (v === 4 || v === 5) {
        this.resetViewportMarks(v)
      }

      // document.onselectstart = function() { return false }// 解决拖动会选中文字的问题
      // document.ondragstart = function() { return false }
    },
    resetViewportMarks(rotateType) {
      ['CT_AXIAL', 'PT_AXIAL', 'FUSION_AXIAL'].map(v => {
        this.$refs[v].rotateMarkers(rotateType)
      })
    },
    setRotate(viewport, rotateIncrementDegrees) {
      const camera = viewport.getCamera()
      const { viewUp, position, focalPoint } = camera
      const [cx, cy, cz] = focalPoint
      const direction = [0, 0, -1]
      const [ax, ay, az] = direction

      const angle = rotateIncrementDegrees
      const newPosition = [0, 0, 0]
      const newFocalPoint = [0, 0, 0]
      const newViewUp = [0, 0, 0]

      const transform = mat4.identity(new Float32Array(16))
      mat4.translate(transform, transform, [cx, cy, cz])
      mat4.rotate(transform, transform, angle, [ax, ay, az])
      mat4.translate(transform, transform, [-cx, -cy, -cz])
      vec3.transformMat4(newPosition, position, transform)
      vec3.transformMat4(newFocalPoint, focalPoint, transform)

      mat4.identity(transform)
      mat4.rotate(transform, transform, angle, [ax, ay, az])
      vec3.transformMat4(newViewUp, viewUp, transform)

      viewport.setCamera({
        position: newPosition,
        viewUp: newViewUp,
        focalPoint: newFocalPoint
      })
    },
    setDicomCanvasWwwc(v) {
      if (v.val === 0) {
        // 自定义
        var refName = this.activeIndex === 1 ? 'CT_AXIAL' : this.activeIndex === 2 ? 'PT_AXIAL' : this.activeIndex === 2 ? 'FUSION_AXIAL' : ''
        if (refName) {
          var wwwc = this.$refs[refName].imageInfo.wwwc
          this.activeCanvasWW = wwwc ? parseInt(wwwc.split('/')[0]) : null
          this.activeCanvasWC = wwwc ? parseInt(wwwc.split('/')[1]) : null
        } else {
          this.activeCanvasWW = null
          this.activeCanvasWC = null
        }

        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)
        const viewport = (
          renderingEngine.getViewport(viewportIds.CT.AXIAL)
        )
        viewport.resetProperties()
        viewport.render()
      } 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)
    //   const renderingEngine = getRenderingEngine(renderingEngineId)
    //   let viewportId = this.activeIndex === 1 ? 'CT_AXIAL' : this.activeIndex === 2 ? 'PT_AXIAL' : this.activeIndex === 3 ? 'FUSION_AXIAL' : 'PET_MIP_CORONAL'
    //   const viewport = renderingEngine.getViewport(viewportId)
    //   const lower = v.wc - v.ww / 2
    //   const upper = v.wc + v.ww / 2 - 1
    //   viewport.setProperties({ voiRange: { upper: upper, lower: lower } })
    //   viewport.render()
    //   if (viewportId !== 'CT_AXIAL') {
    //     const nextUpper = Math.round(upper)
    //     this.upper = nextUpper
    //     if (this.$refs.colorMap) {
    //       this.$refs.colorMap.changeVoi(nextUpper)
    //     }
    //   }
    //   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) {
      return new Promise(resolve => {
        console.log('imageLocation')
        obj.markTool = obj.markTool ? obj.markTool : 'CircleROI'
        this.setToolToTarget(obj)
        if (!obj.otherMeasureData) {
          resolve()
          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)
        } else {
          index = this.ctSeries.instanceList.findIndex(i => i === instanceId)
          if (index > -1) {
            viewportId = 'CT_AXIAL'
            this.$refs[viewportId].scroll(index)
          }
        }

        resolve()
      })
    },
    setToolToTarget(obj) {
      var toolGroupIds = [ctToolGroupId, ptToolGroupId, fusionToolGroupId]
      if (this.readingTaskState < 2 && obj.markTool && !obj.otherMeasureData) {
        toolGroupIds.forEach((toolGroupId) => {
          const toolGroup = ToolGroupManager.getToolGroup(toolGroupId)
          if (this.activeTool) {
            toolGroup.setToolPassive(this.activeTool)
          }
          toolGroup.setToolActive(obj.markTool, {
            bindings: [
              {
                mouseButton: MouseBindings.Primary // Left Click
              }
            ]
          })
        })
        this.activeTool = obj.markTool
      } else {
        if (this.activeTool === obj.markTool) {
          toolGroupIds.forEach((toolGroupId) => {
            const toolGroup = ToolGroupManager.getToolGroup(toolGroupId)

            toolGroup.setToolPassive(this.activeTool)
          })
          this.activeTool = ''
        }
      }
      this.isNonTargetMeasurement = false
    },
    getTargetIdImage(
      targetId,
      renderingEngine
    ) {
      if (targetId.startsWith('imageId:')) {
        const imageId = targetId.split('imageId:')[1]
        const imageURI = utilities.imageIdToURI(imageId)
        let viewports = utilities.getViewportsWithImageURI(
          imageURI,
          renderingEngine.id
        )

        if (!viewports || !viewports.length) {
          return
        }

        viewports = viewports.filter((viewport) => {
          return viewport.getCurrentImageId() === imageId
        })

        if (!viewports || !viewports.length) {
          return
        }

        return viewports[0].getImageData()
      } else if (targetId.startsWith('volumeId:')) {
        const volumeId = targetId.split('volumeId:')[1]
        const viewports = utilities.getViewportsWithVolumeId(
          volumeId,
          renderingEngine.id
        )

        if (!viewports || !viewports.length) {
          return
        }

        return viewports[0].getImageData()
      } else {
        throw new Error(
          'getTargetIdImage: targetId must start with "imageId:" or "volumeId:"'
        )
      }
    },
    rightClick(e) {
      e.preventDefault()
    },
    async reloadViewport() {
      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: 1000,
          width: width + 'px',
          height: height - 1 + 'px'
        }
      }
      const renderEngine = getRenderingEngine(renderingEngineId)
      renderEngine.resize(true, true)
    },

    viewportRender() {
      const viewportIds = ['PT_AXIAL', 'CT_AXIAL', 'FUSION_AXIAL']
      viewportIds.map(v => {
        const viewport = renderingEngine.getViewport(v)
        if (viewport) {
          viewport.render()
        }
      })
    },
    historyRecord() {
      this.fusion.visible = true
    },
    beforeUnloadHandler() {
      if (this.screenshotWindow) {
        this.screenshotWindow.close()
      }
    },
    async clearAnnotations() {
      const viewportIds = ['PT_AXIAL', 'CT_AXIAL', 'FUSION_AXIAL']
      viewportIds.map(v => {
        const viewport = renderingEngine.getViewport(v)
        if (viewport) {
          var annotations = annotation.state.getAnnotations('CircleROI', viewport.element)

          if (annotations && annotations.length > 0) {
            annotations.map(i => {
              if (i.metadata.toolName === 'CircleROI') {
                annotation.state.removeAnnotation(i.annotationUID)
              }
            })
          }
        }
        viewport.render()
      })
      try {
        const visitTaskId = this.$route.query.visitTaskId
        const res = await getTableAnswerRowInfoList(visitTaskId)
        if (res.IsSuccess) {
          var arr = []
          res.Result.forEach(el => {
            if (el.OtherMeasureData) {
              el.OtherMeasureData = JSON.parse(el.OtherMeasureData)
              el.OtherMeasureData.invalidated = 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
        }
      } catch (e) {

      }
    },
    async receiveMsg(event) {
      // console.log(event.data.type)
      if (event.data.type === 'readingPageUpdate') {
        // this.$refs['questions'].initList()
        this.$refs['tableQuestions'].initList(true)
        this.isLocate = true
        // await this.getAnnotations()
        this.viewportRender()
      } else if (event.data.type === 'readingPageStateUpdate') {
        this.readingTaskState = event.data.data.readingTaskState
        if (this.readingTaskState === 2) {
          FusionEvent.$emit('closeHistoryScreenshot')
          if (this.screenshotWindow) {
            this.screenshotWindow.close()
          }
          window.close()
        }
      } else if (event.data.type === 'setReadingState') {
        this.readingTaskState = event.data.data.readingTaskState
        if (this.readingTaskState === 2) {
          FusionEvent.$emit('closeHistoryScreenshot')
          window.close()
        }
      } else if (event.data.type === 'resetPage') {
        if (this.screenshotWindow) {
          this.screenshotWindow.close()
        }
        this.$refs['tableQuestions'].initList(true)
        this.$refs['questions'].initList(true)
        this.isLocate = true
        this.clearAnnotations()
      }
    },
    startTimer() {
      timerId = setTimeout(() => {
        // '当前pet-ct图像融合耗时过长，是否继续等待？'
        this.$confirm(this.$t('trials:lugano:message:fusionMsg'), this.$t('trials:lugano:message:fusiontip'), {
          type: 'warning'
        }).then(() => {

        }).catch(() => {
          window.close()
        })
      }, timeout)
    },
    resetTimer() {
      clearTimeout(timerId)
    },
    ...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;

  ::v-deep .el-dialog {
    background: #1e1e1e;
    border: 1px solid #ddd;
    color: #ddd;

    .el-dialog__title {
      color: #fff;
    }

    .el-input .el-input__inner {
      background-color: transparent;
      color: #ddd;
      border: 1px solid #5e5e5e;
    }

    .el-input.is-disabled .el-input__inner {
      background-color: #646464a1;
    }

    .el-form-item__label {
      color: #dfdfdf
    }
  }
}

::-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: 25px;
        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;
  }

  .activeLi {
    background-color: #919295;
  }

}

.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 rgb(250, 250, 0);

      }
    }
  }

  .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 {
  ::v-deep .el-input--mini .el-input__inner {
    height: 25px;
    line-height: 25px;
    border: none;
    background-color: transparent;
    color: #ddd;
  }
}
</style>
