质控数据匿名
parent
47b05526a2
commit
f0eb814492
|
|
@ -407,4 +407,20 @@ export function changeSegmentationSavedStatus(data) {
|
||||||
method: 'post',
|
method: 'post',
|
||||||
data
|
data
|
||||||
})
|
})
|
||||||
|
}
|
||||||
|
// 图像数据匿名
|
||||||
|
export function studyMaskImage(data) {
|
||||||
|
return request({
|
||||||
|
url: `/Study/studyMaskImage`,
|
||||||
|
method: 'post',
|
||||||
|
data
|
||||||
|
})
|
||||||
|
}
|
||||||
|
// 撤销匿名
|
||||||
|
export function studyUndoMaskImage(data) {
|
||||||
|
return request({
|
||||||
|
url: `/Study/studyUndoMaskImage`,
|
||||||
|
method: 'post',
|
||||||
|
data
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
@ -1,15 +1,7 @@
|
||||||
<template>
|
<template>
|
||||||
<div
|
<div id="canvas" ref="canvas" v-loading="loading" :element-loading-text="NSTip"
|
||||||
id="canvas"
|
element-loading-background="rgba(0, 0, 0, 0.8)" style="width:100%;height:100%;position:relative;"
|
||||||
ref="canvas"
|
class="cornerstone-element" @contextmenu.prevent="onContextmenu" @mouseup="sliderMouseup">
|
||||||
v-loading="loading"
|
|
||||||
:element-loading-text="NSTip"
|
|
||||||
element-loading-background="rgba(0, 0, 0, 0.8)"
|
|
||||||
style="width:100%;height:100%;position:relative;"
|
|
||||||
class="cornerstone-element"
|
|
||||||
@contextmenu.prevent="onContextmenu"
|
|
||||||
@mouseup="sliderMouseup"
|
|
||||||
>
|
|
||||||
<div v-show="dicomInfo.series" class="info-series">
|
<div v-show="dicomInfo.series" class="info-series">
|
||||||
<div>Series #{{ dicomInfo.series }}</div>
|
<div>Series #{{ dicomInfo.series }}</div>
|
||||||
<div>Image #{{ dicomInfo.frame }}</div>
|
<div>Image #{{ dicomInfo.frame }}</div>
|
||||||
|
|
@ -27,14 +19,13 @@
|
||||||
<!-- <div v-show="toolState.clipPlaying">FPS {{ dicomInfo.fps }}</div> -->
|
<!-- <div v-show="toolState.clipPlaying">FPS {{ dicomInfo.fps }}</div> -->
|
||||||
<div v-show="mousePosition.mo">
|
<div v-show="mousePosition.mo">
|
||||||
Pos: {{ mousePosition.x ? mousePosition.x.toFixed(0) : '' }}, {{ mousePosition.y ? mousePosition.y.toFixed(0) :
|
Pos: {{ mousePosition.x ? mousePosition.x.toFixed(0) : '' }}, {{ mousePosition.y ? mousePosition.y.toFixed(0) :
|
||||||
'' }}
|
'' }}
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
v-if="(dicomInfo.modality === 'CT' || dicomInfo.modality === 'DR' || dicomInfo.modality === 'CR') && mousePosition.mo"
|
v-if="(dicomInfo.modality === 'CT' || dicomInfo.modality === 'DR' || dicomInfo.modality === 'CR') && mousePosition.mo">
|
||||||
>HU: {{ mousePosition.mo }}</div>
|
HU: {{ mousePosition.mo }}</div>
|
||||||
<div
|
<div v-else-if="(dicomInfo.modality === 'PT' && mousePosition.suv)">SUVbw(g/ml): {{ mousePosition.suv.toFixed(3)
|
||||||
v-else-if="(dicomInfo.modality === 'PT' && mousePosition.suv)"
|
}}</div>
|
||||||
>SUVbw(g/ml): {{ mousePosition.suv.toFixed(3) }}</div>
|
|
||||||
<div v-else-if="mousePosition.mo">Density: {{ mousePosition.mo }}</div>
|
<div v-else-if="mousePosition.mo">Density: {{ mousePosition.mo }}</div>
|
||||||
<div>W*H: {{ dicomInfo.size }}</div>
|
<div>W*H: {{ dicomInfo.size }}</div>
|
||||||
|
|
||||||
|
|
@ -52,17 +43,12 @@
|
||||||
<!-- <div v-show="dicomInfo.acc">ACC {{ dicomInfo.acc }}</div> -->
|
<!-- <div v-show="dicomInfo.acc">ACC {{ dicomInfo.acc }}</div> -->
|
||||||
<!-- <div>{{ dicomInfo.time }}</div> -->
|
<!-- <div>{{ dicomInfo.time }}</div> -->
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div ref="sliderBox" class="my_slider_box"
|
||||||
ref="sliderBox"
|
|
||||||
class="my_slider_box"
|
|
||||||
style="position: absolute;right: 1px;height: calc(100% - 100px);transform: translateY(-50%);top: calc(50% - 30px);width: 10px;background: #333;cursor: pointer"
|
style="position: absolute;right: 1px;height: calc(100% - 100px);transform: translateY(-50%);top: calc(50% - 30px);width: 10px;background: #333;cursor: pointer"
|
||||||
@click.stop="goViewer($event)"
|
@click.stop="goViewer($event)">
|
||||||
>
|
<div :style="{ top: height + '%' }"
|
||||||
<div
|
|
||||||
:style="{ top: height + '%' }"
|
|
||||||
style="z-index:10;background: #9e9e9e;height: 20px;width: 100%;position: absolute;top: 0;cursor: move"
|
style="z-index:10;background: #9e9e9e;height: 20px;width: 100%;position: absolute;top: 0;cursor: move"
|
||||||
@mousedown="sliderMousedown($event)"
|
@mousedown="sliderMousedown($event)" />
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
<div style="position: absolute;left: 50%;top: 15px;color: #f44336;">{{ markers.top }}</div>
|
<div style="position: absolute;left: 50%;top: 15px;color: #f44336;">{{ markers.top }}</div>
|
||||||
<div style="position: absolute;top: 50%;right: 15px;color: #f44336;">{{ markers.right }}</div>
|
<div style="position: absolute;top: 50%;right: 15px;color: #f44336;">{{ markers.right }}</div>
|
||||||
|
|
@ -81,19 +67,9 @@
|
||||||
<!-- <div v-show="stack.firstImageLoading" class="load-indicator">
|
<!-- <div v-show="stack.firstImageLoading" class="load-indicator">
|
||||||
Loading Series #{{ stack.seriesNumber }}...
|
Loading Series #{{ stack.seriesNumber }}...
|
||||||
</div>-->
|
</div>-->
|
||||||
<el-dialog
|
<el-dialog v-if="dcmTag.visible" :visible.sync="dcmTag.visible" :close-on-click-modal="false" :title="dcmTag.title"
|
||||||
v-if="dcmTag.visible"
|
width="1000px" custom-class="base-dialog-wrapper" append-to-body>
|
||||||
:visible.sync="dcmTag.visible"
|
<dicom-tags :image-id="stack.imageIds[stack.currentImageIdIndex]" @close="dcmTag.visible = false" />
|
||||||
:close-on-click-modal="false"
|
|
||||||
:title="dcmTag.title"
|
|
||||||
width="1000px"
|
|
||||||
custom-class="base-dialog-wrapper"
|
|
||||||
append-to-body
|
|
||||||
>
|
|
||||||
<dicom-tags
|
|
||||||
:image-id="stack.imageIds[stack.currentImageIdIndex]"
|
|
||||||
@close="dcmTag.visible = false"
|
|
||||||
/>
|
|
||||||
</el-dialog>
|
</el-dialog>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
@ -228,7 +204,7 @@ export default {
|
||||||
this.stack.imageIds = dicomSeries.imageIds
|
this.stack.imageIds = dicomSeries.imageIds
|
||||||
this.stack.currentImageIdIndex =
|
this.stack.currentImageIdIndex =
|
||||||
dicomSeries.imageIdIndex &&
|
dicomSeries.imageIdIndex &&
|
||||||
dicomSeries.imageIdIndex < dicomSeries.imageIds.length
|
dicomSeries.imageIdIndex < dicomSeries.imageIds.length
|
||||||
? dicomSeries.imageIdIndex
|
? dicomSeries.imageIdIndex
|
||||||
: 0
|
: 0
|
||||||
this.stack.firstImageLoading = true
|
this.stack.firstImageLoading = true
|
||||||
|
|
@ -316,12 +292,14 @@ export default {
|
||||||
if (
|
if (
|
||||||
!cornerstoneTools.getToolForElement(element, Note_RectangleRoiTool)
|
!cornerstoneTools.getToolForElement(element, Note_RectangleRoiTool)
|
||||||
) {
|
) {
|
||||||
console.log(
|
cornerstoneTools.addToolForElement(element, Note_RectangleRoiTool, {
|
||||||
Note_RectangleRoiTool.name,
|
configuration: {
|
||||||
'Note_RectangleRoiTool is add'
|
color: '#f00',
|
||||||
)
|
lineWidth: 0.5,
|
||||||
console.log(element, 'element')
|
drawHandles: false,
|
||||||
cornerstoneTools.addToolForElement(element, Note_RectangleRoiTool)
|
fillColor: 'rgba(0, 0, 0, 1)',
|
||||||
|
},
|
||||||
|
})
|
||||||
}
|
}
|
||||||
if (
|
if (
|
||||||
!cornerstoneTools.getToolForElement(
|
!cornerstoneTools.getToolForElement(
|
||||||
|
|
@ -412,9 +390,8 @@ export default {
|
||||||
data.string('x00080030')
|
data.string('x00080030')
|
||||||
)
|
)
|
||||||
this.dicomInfo.series = data.string('x00200011')
|
this.dicomInfo.series = data.string('x00200011')
|
||||||
this.dicomInfo.frame = `${this.stack.currentImageIdIndex + 1}/${
|
this.dicomInfo.frame = `${this.stack.currentImageIdIndex + 1}/${this.stack.imageIds.length
|
||||||
this.stack.imageIds.length
|
}`
|
||||||
}`
|
|
||||||
this.dicomInfo.size = `${data.uint16('x00280011')}x${data.uint16(
|
this.dicomInfo.size = `${data.uint16('x00280011')}x${data.uint16(
|
||||||
'x00280010'
|
'x00280010'
|
||||||
)}`
|
)}`
|
||||||
|
|
@ -624,8 +601,8 @@ export default {
|
||||||
index > this.stack.imageIds.length
|
index > this.stack.imageIds.length
|
||||||
? this.stack.imageIds.length
|
? this.stack.imageIds.length
|
||||||
: index < 0
|
: index < 0
|
||||||
? 0
|
? 0
|
||||||
: index
|
: index
|
||||||
// if (!cornerstone.imageCache.getImageLoadObject(this.stack.imageIds[index])) return
|
// if (!cornerstone.imageCache.getImageLoadObject(this.stack.imageIds[index])) return
|
||||||
this.height = height
|
this.height = height
|
||||||
if (this.stack.currentImageIdIndex !== index) {
|
if (this.stack.currentImageIdIndex !== index) {
|
||||||
|
|
@ -853,8 +830,108 @@ export default {
|
||||||
setToolPassive(toolName) {
|
setToolPassive(toolName) {
|
||||||
cornerstoneTools.setToolPassiveForElement(this.canvas, toolName)
|
cornerstoneTools.setToolPassiveForElement(this.canvas, toolName)
|
||||||
},
|
},
|
||||||
|
async reloadImage(newImageId = null) {
|
||||||
|
// 1. 获取当前imageId(如果未指定新imageId)
|
||||||
|
let element = this.canvas
|
||||||
|
this.stack.imageIds.splice(this.stack.currentImageIdIndex, 1, newImageId)
|
||||||
|
const currentImageId =
|
||||||
|
newImageId || cornerstone.getImage(element)?.imageId
|
||||||
|
|
||||||
|
if (!currentImageId) {
|
||||||
|
console.error('没有找到可用的imageId')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2. 清除该影像关联的工具状态(标注数据)
|
||||||
|
this.clearToolStateForImage(element, currentImageId)
|
||||||
|
|
||||||
|
// 3. 从缓存中移除该影像
|
||||||
|
this.removeImageFromCache(currentImageId)
|
||||||
|
|
||||||
|
// 4. 重新加载并渲染
|
||||||
|
await this.loadAndRenderImage(element, currentImageId)
|
||||||
|
},
|
||||||
|
clearToolStateForImage(element, imageId) {
|
||||||
|
// 获取全局状态管理器
|
||||||
|
const globalToolStateManager =
|
||||||
|
cornerstoneTools.globalImageIdSpecificToolStateManager
|
||||||
|
|
||||||
|
if (globalToolStateManager) {
|
||||||
|
// 方式1:清空该影像的全部工具数据
|
||||||
|
globalToolStateManager.clearImageIdToolState(imageId)
|
||||||
|
console.log(`已清除影像 ${imageId} 的所有标注数据`)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 方式2:如果使用元素级别的状态管理器
|
||||||
|
const elementToolStateManager =
|
||||||
|
cornerstoneTools.getElementToolStateManager(element)
|
||||||
|
if (elementToolStateManager && elementToolStateManager.get(element)) {
|
||||||
|
// 清空该元素上当前显示影像的数据
|
||||||
|
elementToolStateManager.clear(element)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
removeImageFromCache(imageId) {
|
||||||
|
const imageCache = cornerstone.imageCache
|
||||||
|
|
||||||
|
if (imageCache && imageCache[imageId]) {
|
||||||
|
// 从缓存中移除
|
||||||
|
delete imageCache[imageId]
|
||||||
|
console.log(`已从缓存中移除影像: ${imageId}`)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 也可以使用官方API(如果可用)
|
||||||
|
if (typeof cornerstone.imageCache.removeImage === 'function') {
|
||||||
|
cornerstone.imageCache.removeImageLoadObject(imageId)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
async loadAndRenderImage(element, imageId) {
|
||||||
|
try {
|
||||||
|
// 1. 清除当前画布内容(可选)
|
||||||
|
const canvas = element.querySelector('canvas')
|
||||||
|
if (canvas) {
|
||||||
|
const ctx = canvas.getContext('2d')
|
||||||
|
ctx.clearRect(0, 0, canvas.width, canvas.height)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2. 重新加载图像(强制从源头重新获取)
|
||||||
|
const image = await cornerstone.loadAndCacheImage(imageId)
|
||||||
|
|
||||||
|
// 3. 获取或创建视口设置
|
||||||
|
let viewport = cornerstone.getViewport(element)
|
||||||
|
if (!viewport) {
|
||||||
|
viewport = cornerstone.getDefaultViewport(element, image)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 4. 显示图像
|
||||||
|
cornerstone.displayImage(element, image, viewport)
|
||||||
|
|
||||||
|
// 5. 触发重绘
|
||||||
|
cornerstone.updateImage(element)
|
||||||
|
|
||||||
|
console.log(`影像 ${imageId} 重新加载并渲染完成`)
|
||||||
|
|
||||||
|
return image
|
||||||
|
} catch (error) {
|
||||||
|
console.error('加载图像失败:', error)
|
||||||
|
throw error
|
||||||
|
}
|
||||||
|
},
|
||||||
|
getNote_RectangleRoi() {
|
||||||
|
return new Promise(resolve => {
|
||||||
|
let toolInfo = cornerstoneTools.getToolState(this.canvas, 'Note_RectangleRoi')
|
||||||
|
let image = cornerstone.getImage(this.canvas)
|
||||||
|
resolve({ toolInfo, image })
|
||||||
|
})
|
||||||
|
// console.log(
|
||||||
|
// cornerstoneTools.getToolState(this.canvas, 'Note_RectangleRoi')
|
||||||
|
// )
|
||||||
|
// console.log(cornerstone.getImage(this.canvas))
|
||||||
|
// let image = cornerstone.getImage(this.canvas)
|
||||||
|
// // cornerstone.imageCache.removeImageLoadObject(image.imageId)
|
||||||
|
|
||||||
|
// this.reloadImage(this.canvas, image.imageId)
|
||||||
|
},
|
||||||
setToolActive(toolName) {
|
setToolActive(toolName) {
|
||||||
console.log(this.canvas, 'this.canvas')
|
|
||||||
cornerstoneTools.setToolActiveForElement(this.canvas, toolName, {
|
cornerstoneTools.setToolActiveForElement(this.canvas, toolName, {
|
||||||
mouseButtonMask: 1,
|
mouseButtonMask: 1,
|
||||||
})
|
})
|
||||||
|
|
|
||||||
|
|
@ -6,102 +6,68 @@
|
||||||
<dicom-canvas ref="dicomCanvas" style="width:100%;height:100%" />
|
<dicom-canvas ref="dicomCanvas" style="width:100%;height:100%" />
|
||||||
</div>
|
</div>
|
||||||
</div>-->
|
</div>-->
|
||||||
|
<div class="Anonymous" v-if="isAnonymous">
|
||||||
<div v-show="layoutRow>=1" class="dicom-row" :style="{height: rowHeight}">
|
<div :class="{ btn: true, activeBtn: activeTool === 'Note_RectangleRoi' }"
|
||||||
<div
|
@click="setToolActive($event, 'Note_RectangleRoi')">矩形</div>
|
||||||
v-show="layoutRow>=1&&layoutCol>=1"
|
<div :class="{ btn: true, activeBtn: activeTool === 'Eraser' }" @click="setToolActive($event, 'Eraser')">清除
|
||||||
class="dicom-item"
|
</div>
|
||||||
:class="{'activeItem':activeItem=='dicomCanvas0'}"
|
<div class="btn" @click="anonymousImage">应用</div>
|
||||||
data-index="0"
|
<div class="btn">应用整个序列</div>
|
||||||
@click="activateDicomCanvas(0)"
|
<!-- <div class="btn">刷新图像</div> -->
|
||||||
@dblclick="setFullScreen($event)"
|
<div class="btn" v-if="!isComparison">对比</div>
|
||||||
>
|
<div class="btn" v-else>退出</div>
|
||||||
|
<div class="btn">恢复</div>
|
||||||
|
</div>
|
||||||
|
<div v-show="layoutRow >= 1" class="dicom-row" :style="{ height: rowHeight }">
|
||||||
|
<div v-show="layoutRow >= 1 && layoutCol >= 1" class="dicom-item"
|
||||||
|
:class="{ 'activeItem': activeItem == 'dicomCanvas0' }" data-index="0" @click="activateDicomCanvas(0)"
|
||||||
|
@dblclick="setFullScreen($event)">
|
||||||
<dicom-canvas ref="dicomCanvas0" style="width:100%;height:100%" />
|
<dicom-canvas ref="dicomCanvas0" style="width:100%;height:100%" />
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div v-show="layoutRow >= 1 && layoutCol >= 2" class="dicom-item"
|
||||||
v-show="layoutRow>=1&&layoutCol>=2"
|
:class="{ 'activeItem': activeItem == 'dicomCanvas1' }" data-index="1" @click="activateDicomCanvas(1)"
|
||||||
class="dicom-item"
|
@dblclick="setFullScreen($event)">
|
||||||
:class="{'activeItem':activeItem=='dicomCanvas1'}"
|
|
||||||
data-index="1"
|
|
||||||
@click="activateDicomCanvas(1)"
|
|
||||||
@dblclick="setFullScreen($event)"
|
|
||||||
>
|
|
||||||
<dicom-canvas ref="dicomCanvas1" style="width:100%;height:100%" />
|
<dicom-canvas ref="dicomCanvas1" style="width:100%;height:100%" />
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div v-show="layoutRow >= 1 && layoutCol >= 3" class="dicom-item"
|
||||||
v-show="layoutRow>=1&&layoutCol>=3"
|
:class="{ 'activeItem': activeItem == 'dicomCanvas2' }" data-index="2" @click="activateDicomCanvas(2)"
|
||||||
class="dicom-item"
|
@dblclick="setFullScreen($event)">
|
||||||
:class="{'activeItem':activeItem=='dicomCanvas2'}"
|
|
||||||
data-index="2"
|
|
||||||
@click="activateDicomCanvas(2)"
|
|
||||||
@dblclick="setFullScreen($event)"
|
|
||||||
>
|
|
||||||
<dicom-canvas ref="dicomCanvas2" style="width:100%;height:100%" />
|
<dicom-canvas ref="dicomCanvas2" style="width:100%;height:100%" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div v-show="layoutRow>=2" class="dicom-row" :style="{height: rowHeight}">
|
<div v-show="layoutRow >= 2" class="dicom-row" :style="{ height: rowHeight }">
|
||||||
<div
|
<div v-show="layoutRow >= 2 && layoutCol >= 1" class="dicom-item"
|
||||||
v-show="layoutRow>=2&&layoutCol>=1"
|
:class="{ 'activeItem': activeItem == 'dicomCanvas3' }" data-index="3" @click="activateDicomCanvas(3)"
|
||||||
class="dicom-item"
|
@dblclick="setFullScreen($event)">
|
||||||
:class="{'activeItem':activeItem=='dicomCanvas3'}"
|
|
||||||
data-index="3"
|
|
||||||
@click="activateDicomCanvas(3)"
|
|
||||||
@dblclick="setFullScreen($event)"
|
|
||||||
>
|
|
||||||
<dicom-canvas ref="dicomCanvas3" style="width:100%;height:100%" />
|
<dicom-canvas ref="dicomCanvas3" style="width:100%;height:100%" />
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div v-show="layoutRow >= 2 && layoutCol >= 2" class="dicom-item"
|
||||||
v-show="layoutRow>=2&&layoutCol>=2"
|
:class="{ 'activeItem': activeItem == 'dicomCanvas4' }" data-index="4" @click="activateDicomCanvas(4)"
|
||||||
class="dicom-item"
|
@dblclick="setFullScreen($event)">
|
||||||
:class="{'activeItem':activeItem=='dicomCanvas4'}"
|
|
||||||
data-index="4"
|
|
||||||
@click="activateDicomCanvas(4)"
|
|
||||||
@dblclick="setFullScreen($event)"
|
|
||||||
>
|
|
||||||
<dicom-canvas ref="dicomCanvas4" style="width:100%;height:100%" />
|
<dicom-canvas ref="dicomCanvas4" style="width:100%;height:100%" />
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div v-show="layoutRow >= 2 && layoutCol >= 3" class="dicom-item"
|
||||||
v-show="layoutRow>=2&&layoutCol>=3"
|
:class="{ 'activeItem': activeItem == 'dicomCanvas5' }" data-index="5" @click="activateDicomCanvas(5)"
|
||||||
class="dicom-item"
|
@dblclick="setFullScreen($event)">
|
||||||
:class="{'activeItem':activeItem=='dicomCanvas5'}"
|
|
||||||
data-index="5"
|
|
||||||
@click="activateDicomCanvas(5)"
|
|
||||||
@dblclick="setFullScreen($event)"
|
|
||||||
>
|
|
||||||
<dicom-canvas ref="dicomCanvas5" style="width:100%;height:100%" />
|
<dicom-canvas ref="dicomCanvas5" style="width:100%;height:100%" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div v-show="layoutRow==3" class="dicom-row" :style="{height: rowHeight}">
|
<div v-show="layoutRow == 3" class="dicom-row" :style="{ height: rowHeight }">
|
||||||
<div
|
<div v-show="layoutRow == 3 && layoutCol >= 1" class="dicom-item"
|
||||||
v-show="layoutRow==3&&layoutCol>=1"
|
:class="{ 'activeItem': activeItem == 'dicomCanvas6' }" data-index="6" @click="activateDicomCanvas(6)"
|
||||||
class="dicom-item"
|
@dblclick="setFullScreen($event)">
|
||||||
:class="{'activeItem':activeItem=='dicomCanvas6'}"
|
|
||||||
data-index="6"
|
|
||||||
@click="activateDicomCanvas(6)"
|
|
||||||
@dblclick="setFullScreen($event)"
|
|
||||||
>
|
|
||||||
<dicom-canvas ref="dicomCanvas6" style="width:100%;height:100%" />
|
<dicom-canvas ref="dicomCanvas6" style="width:100%;height:100%" />
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div v-show="layoutRow == 3 && layoutCol >= 2" class="dicom-item"
|
||||||
v-show="layoutRow==3&&layoutCol>=2"
|
:class="{ 'activeItem': activeItem == 'dicomCanvas7' }" data-index="7" @click="activateDicomCanvas(7)"
|
||||||
class="dicom-item"
|
@dblclick="setFullScreen($event)">
|
||||||
:class="{'activeItem':activeItem=='dicomCanvas7'}"
|
|
||||||
data-index="7"
|
|
||||||
@click="activateDicomCanvas(7)"
|
|
||||||
@dblclick="setFullScreen($event)"
|
|
||||||
>
|
|
||||||
<dicom-canvas ref="dicomCanvas7" style="width:100%;height:100%" />
|
<dicom-canvas ref="dicomCanvas7" style="width:100%;height:100%" />
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div v-show="layoutRow == 3 && layoutCol >= 3" class="dicom-item"
|
||||||
v-show="layoutRow==3&&layoutCol>=3"
|
:class="{ 'activeItem': activeItem == 'dicomCanvas8' }" data-index="8" @click="activateDicomCanvas(8)"
|
||||||
class="dicom-item"
|
@dblclick="setFullScreen($event)">
|
||||||
:class="{'activeItem':activeItem=='dicomCanvas8'}"
|
|
||||||
data-index="8"
|
|
||||||
@click="activateDicomCanvas(8)"
|
|
||||||
@dblclick="setFullScreen($event)"
|
|
||||||
>
|
|
||||||
<dicom-canvas ref="dicomCanvas8" style="width:100%;height:100%" />
|
<dicom-canvas ref="dicomCanvas8" style="width:100%;height:100%" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -113,7 +79,7 @@
|
||||||
<div class="sideTool-title">{{ $t('trials:reading:button:layout') }}</div>
|
<div class="sideTool-title">{{ $t('trials:reading:button:layout') }}</div>
|
||||||
<div class="sideTool-wrapper">
|
<div class="sideTool-wrapper">
|
||||||
<label>{{ $t('trials:reading:button:layout') }}:</label>
|
<label>{{ $t('trials:reading:button:layout') }}:</label>
|
||||||
<select class="sidetool-select" style="width:90px" @change="changeLayout($event)">
|
<select class="sidetool-select" style="width:90px" :disabled="isAnonymous" @change="changeLayout($event)">
|
||||||
<option value="1x1" selected>1x1</option>
|
<option value="1x1" selected>1x1</option>
|
||||||
<option value="1x2">1x2</option>
|
<option value="1x2">1x2</option>
|
||||||
<option value="2x1">2x1</option>
|
<option value="2x1">2x1</option>
|
||||||
|
|
@ -124,18 +90,15 @@
|
||||||
<option value="3x2">3x2</option>
|
<option value="3x2">3x2</option>
|
||||||
<option value="3x3">3x3</option>
|
<option value="3x3">3x3</option>
|
||||||
</select>
|
</select>
|
||||||
|
<div class="btnBox" @click="openAnonymous">像素匿名</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<!-- 图像变换 -->
|
<!-- 图像变换 -->
|
||||||
<div class="measureTool-wrapper">
|
<div class="measureTool-wrapper">
|
||||||
<div class="sideTool-title">{{ $t('trials:dicom-show:transform') }}</div>
|
<div class="sideTool-title">{{ $t('trials:dicom-show:transform') }}</div>
|
||||||
<div class="sideTool-wrapper">
|
<div class="sideTool-wrapper">
|
||||||
<button
|
<button :title="$t('trials:reading:button:wwwc')" class="btn-link" data-tool="Wwwc"
|
||||||
:title="$t('trials:reading:button:wwwc')"
|
@click="setToolActive($event, 'Wwwc')">
|
||||||
class="btn-link"
|
|
||||||
data-tool="Wwwc"
|
|
||||||
@click="setToolActive($event,'Wwwc')"
|
|
||||||
>
|
|
||||||
<svg-icon icon-class="reverse" style="font-size:20px;" />
|
<svg-icon icon-class="reverse" style="font-size:20px;" />
|
||||||
</button>
|
</button>
|
||||||
<!-- <button
|
<!-- <button
|
||||||
|
|
@ -146,75 +109,37 @@
|
||||||
>
|
>
|
||||||
<svg-icon icon-class="wwwcRegion" style="font-size:20px;" />
|
<svg-icon icon-class="wwwcRegion" style="font-size:20px;" />
|
||||||
</button>-->
|
</button>-->
|
||||||
<button
|
<button :title="$t('trials:reading:button:reverseColor')" class="btn-link" @click="toggleInvert">
|
||||||
:title="$t('trials:reading:button:reverseColor')"
|
|
||||||
class="btn-link"
|
|
||||||
@click="toggleInvert"
|
|
||||||
>
|
|
||||||
<svg-icon icon-class="reversecolor" style="font-size:20px;" />
|
<svg-icon icon-class="reversecolor" style="font-size:20px;" />
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button :title="$t('trials:reading:button:zoom')" class="btn-link" data-tool="Zoom"
|
||||||
:title="$t('trials:reading:button:zoom')"
|
@click="setToolActive($event, 'Zoom')">
|
||||||
class="btn-link"
|
|
||||||
data-tool="Zoom"
|
|
||||||
@click="setToolActive($event,'Zoom')"
|
|
||||||
>
|
|
||||||
<svg-icon icon-class="magnifier" style="font-size:20px;" />
|
<svg-icon icon-class="magnifier" style="font-size:20px;" />
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button :title="$t('trials:dicom-show:lens')" class="btn-link" data-tool="Magnify"
|
||||||
:title="$t('trials:dicom-show:lens')"
|
@click="setToolActive($event, 'Magnify')">
|
||||||
class="btn-link"
|
|
||||||
data-tool="Magnify"
|
|
||||||
@click="setToolActive($event,'Magnify')"
|
|
||||||
>
|
|
||||||
<svg-icon icon-class="zoom" style="font-size:20px;" />
|
<svg-icon icon-class="zoom" style="font-size:20px;" />
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button :title="$t('trials:reading:button:rotate')" class="btn-link dropdown" data-tool="Rotate">
|
||||||
:title="$t('trials:reading:button:rotate')"
|
|
||||||
class="btn-link dropdown"
|
|
||||||
data-tool="Rotate"
|
|
||||||
>
|
|
||||||
<svg-icon icon-class="rotate" style="font-size:20px;" />
|
<svg-icon icon-class="rotate" style="font-size:20px;" />
|
||||||
<div class="dropdown-content">
|
<div class="dropdown-content">
|
||||||
<div
|
<div @click.stop="setDicomCanvasRotate(1)">{{ $t('trials:reading:button:rotateDefault') }}</div>
|
||||||
@click.stop="setDicomCanvasRotate(1)"
|
<div @click.stop="setDicomCanvasRotate(2)">{{ $t('trials:reading:button:rotateHorizontal') }}</div>
|
||||||
>{{ $t('trials:reading:button:rotateDefault') }}</div>
|
<div @click.stop="setDicomCanvasRotate(3)">{{ $t('trials:reading:button:rotateVertical') }}</div>
|
||||||
<div
|
<div @click.stop="setDicomCanvasRotate(4)">{{ $t('trials:reading:button:rotateTurnLeft') }}</div>
|
||||||
@click.stop="setDicomCanvasRotate(2)"
|
<div @click.stop="setDicomCanvasRotate(5)">{{ $t('trials:reading:button:rotateTurnRight') }}</div>
|
||||||
>{{ $t('trials:reading:button:rotateHorizontal') }}</div>
|
|
||||||
<div
|
|
||||||
@click.stop="setDicomCanvasRotate(3)"
|
|
||||||
>{{ $t('trials:reading:button:rotateVertical') }}</div>
|
|
||||||
<div
|
|
||||||
@click.stop="setDicomCanvasRotate(4)"
|
|
||||||
>{{ $t('trials:reading:button:rotateTurnLeft') }}</div>
|
|
||||||
<div
|
|
||||||
@click.stop="setDicomCanvasRotate(5)"
|
|
||||||
>{{ $t('trials:reading:button:rotateTurnRight') }}</div>
|
|
||||||
</div>
|
</div>
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button :title="$t('trials:reading:button:move')" class="btn-link" data-tool="Pan"
|
||||||
:title="$t('trials:reading:button:move')"
|
@click="setToolActive($event, 'Pan')">
|
||||||
class="btn-link"
|
|
||||||
data-tool="Pan"
|
|
||||||
@click="setToolActive($event,'Pan')"
|
|
||||||
>
|
|
||||||
<svg-icon icon-class="move" style="font-size:20px;" />
|
<svg-icon icon-class="move" style="font-size:20px;" />
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button :title="$t('trials:reading:button:fitWindow')" class="btn-link" data-tool="fitToWindow"
|
||||||
:title="$t('trials:reading:button:fitWindow')"
|
@click="fitToType($event, 'fitToWindow')">
|
||||||
class="btn-link"
|
|
||||||
data-tool="fitToWindow"
|
|
||||||
@click="fitToType($event,'fitToWindow')"
|
|
||||||
>
|
|
||||||
<svg-icon icon-class="fitToWindow" style="font-size:20px;" />
|
<svg-icon icon-class="fitToWindow" style="font-size:20px;" />
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button :title="$t('trials:reading:button:fitImage')" class="btn-link" data-tool="fitToImage"
|
||||||
:title="$t('trials:reading:button:fitImage')"
|
@click="fitToType($event, 'fitToImage')">
|
||||||
class="btn-link"
|
|
||||||
data-tool="fitToImage"
|
|
||||||
@click="fitToType($event,'fitToImage')"
|
|
||||||
>
|
|
||||||
<svg-icon icon-class="fitToImage" style="font-size:20px;" />
|
<svg-icon icon-class="fitToImage" style="font-size:20px;" />
|
||||||
</button>
|
</button>
|
||||||
<!-- <button title="旋转" class="btn-link dropdown" data-tool="Rotate" @click="setToolActive($event,'Rotate')"> -->
|
<!-- <button title="旋转" class="btn-link dropdown" data-tool="Rotate" @click="setToolActive($event,'Rotate')"> -->
|
||||||
|
|
@ -225,169 +150,94 @@
|
||||||
<div class="sideTool-title">{{ $t('trials:dicom-show:measurementLabeling') }}</div>
|
<div class="sideTool-title">{{ $t('trials:dicom-show:measurementLabeling') }}</div>
|
||||||
<div class="sideTool-wrapper">
|
<div class="sideTool-wrapper">
|
||||||
<!-- 探针 -->
|
<!-- 探针 -->
|
||||||
<button
|
<button :title="$t('trials:dicom-show:Probe')" class="btn-link" data-tool="Probe"
|
||||||
:title="$t('trials:dicom-show:Probe')"
|
@click="setToolActive($event, 'Probe')">
|
||||||
class="btn-link"
|
|
||||||
data-tool="Probe"
|
|
||||||
@click="setToolActive($event,'Probe')"
|
|
||||||
>
|
|
||||||
<svg-icon icon-class="pixel" style="font-size:20px;" />
|
<svg-icon icon-class="pixel" style="font-size:20px;" />
|
||||||
</button>
|
</button>
|
||||||
<!-- 长度测量 -->
|
<!-- 长度测量 -->
|
||||||
<button
|
<button :title="$t('trials:dicom-show:Length')" class="btn-link" data-tool="Length"
|
||||||
:title="$t('trials:dicom-show:Length')"
|
@click="setToolActive($event, 'Length')">
|
||||||
class="btn-link"
|
|
||||||
data-tool="Length"
|
|
||||||
@click="setToolActive($event,'Length')"
|
|
||||||
>
|
|
||||||
<svg-icon icon-class="length" style="font-size:20px;" />
|
<svg-icon icon-class="length" style="font-size:20px;" />
|
||||||
</button>
|
</button>
|
||||||
<!-- 角度测量 -->
|
<!-- 角度测量 -->
|
||||||
<button
|
<button :title="$t('trials:dicom-show:Angle')" class="btn-link" data-tool="Angle"
|
||||||
:title="$t('trials:dicom-show:Angle')"
|
@click="setToolActive($event, 'Angle')">
|
||||||
class="btn-link"
|
|
||||||
data-tool="Angle"
|
|
||||||
@click="setToolActive($event,'Angle')"
|
|
||||||
>
|
|
||||||
<svg-icon icon-class="angle" style="font-size:20px;" />
|
<svg-icon icon-class="angle" style="font-size:20px;" />
|
||||||
</button>
|
</button>
|
||||||
<!-- Cobb测量 -->
|
<!-- Cobb测量 -->
|
||||||
<button
|
<button :title="$t('trials:dicom-show:CobbAngle')" class="btn-link" data-tool="CobbAngle"
|
||||||
:title="$t('trials:dicom-show:CobbAngle')"
|
@click="setToolActive($event, 'CobbAngle')">
|
||||||
class="btn-link"
|
|
||||||
data-tool="CobbAngle"
|
|
||||||
@click="setToolActive($event,'CobbAngle')"
|
|
||||||
>
|
|
||||||
<svg-icon icon-class="cobb" style="font-size:20px;" />
|
<svg-icon icon-class="cobb" style="font-size:20px;" />
|
||||||
</button>
|
</button>
|
||||||
<!-- 椭圆测量 -->
|
<!-- 椭圆测量 -->
|
||||||
<button
|
<button :title="$t('trials:dicom-show:EllipticalRoi')" class="btn-link" data-tool="EllipticalRoi"
|
||||||
:title="$t('trials:dicom-show:EllipticalRoi')"
|
@click="setToolActive($event, 'EllipticalRoi')">
|
||||||
class="btn-link"
|
|
||||||
data-tool="EllipticalRoi"
|
|
||||||
@click="setToolActive($event,'EllipticalRoi')"
|
|
||||||
>
|
|
||||||
<svg-icon icon-class="oval" style="font-size:20px;" />
|
<svg-icon icon-class="oval" style="font-size:20px;" />
|
||||||
</button>
|
</button>
|
||||||
<!-- 矩形测量 -->
|
<!-- 矩形测量 -->
|
||||||
<button
|
<button :title="$t('trials:dicom-show:RectangleRoi')" class="btn-link" data-tool="RectangleRoi"
|
||||||
:title="$t('trials:dicom-show:RectangleRoi')"
|
@click="setToolActive($event, 'RectangleRoi')">
|
||||||
class="btn-link"
|
|
||||||
data-tool="RectangleRoi"
|
|
||||||
@click="setToolActive($event,'RectangleRoi')"
|
|
||||||
>
|
|
||||||
<svg-icon icon-class="rectangle" style="font-size:20px;" />
|
<svg-icon icon-class="rectangle" style="font-size:20px;" />
|
||||||
</button>
|
</button>
|
||||||
<!-- 多边形标记 -->
|
<!-- 多边形标记 -->
|
||||||
<button
|
<button :title="$t('trials:dicom-show:FreehandRoi')" class="btn-link" data-tool="FreehandRoi"
|
||||||
:title="$t('trials:dicom-show:FreehandRoi')"
|
@click="setToolActive($event, 'FreehandRoi')">
|
||||||
class="btn-link"
|
|
||||||
data-tool="FreehandRoi"
|
|
||||||
@click="setToolActive($event,'FreehandRoi')"
|
|
||||||
>
|
|
||||||
<svg-icon icon-class="polygon" style="font-size:20px;" />
|
<svg-icon icon-class="polygon" style="font-size:20px;" />
|
||||||
</button>
|
</button>
|
||||||
<!-- 十字线 -->
|
<!-- 十字线 -->
|
||||||
<button
|
<button :title="$t('trials:dicom-show:Bidirectional')" class="btn-link" data-tool="Bidirectional"
|
||||||
:title="$t('trials:dicom-show:Bidirectional')"
|
@click="setToolActive($event, 'Bidirectional')">
|
||||||
class="btn-link"
|
|
||||||
data-tool="Bidirectional"
|
|
||||||
@click="setToolActive($event,'Bidirectional')"
|
|
||||||
>
|
|
||||||
<svg-icon icon-class="bidirection" style="font-size:20px;" />
|
<svg-icon icon-class="bidirection" style="font-size:20px;" />
|
||||||
</button>
|
</button>
|
||||||
<!-- 文字标注 -->
|
<!-- 文字标注 -->
|
||||||
<button
|
<button :title="$t('trials:dicom-show:ArrowAnnotate')" class="btn-link" data-tool="ArrowAnnotate"
|
||||||
:title="$t('trials:dicom-show:ArrowAnnotate')"
|
@click="setToolActive($event, 'ArrowAnnotate')">
|
||||||
class="btn-link"
|
|
||||||
data-tool="ArrowAnnotate"
|
|
||||||
@click="setToolActive($event,'ArrowAnnotate')"
|
|
||||||
>
|
|
||||||
<svg-icon icon-class="label" style="font-size:20px;" />
|
<svg-icon icon-class="label" style="font-size:20px;" />
|
||||||
</button>
|
</button>
|
||||||
<!-- 清除测量和标记 -->
|
<!-- 清除测量和标记 -->
|
||||||
<button
|
<button :title="$t('trials:dicom-show:Eraser')" class="btn-link" data-tool="Eraser"
|
||||||
:title="$t('trials:dicom-show:Eraser')"
|
@click="setToolActive($event, 'Eraser')">
|
||||||
class="btn-link"
|
|
||||||
data-tool="Eraser"
|
|
||||||
@click="setToolActive($event,'Eraser')"
|
|
||||||
>
|
|
||||||
<svg-icon icon-class="clear" style="font-size:20px;" />
|
<svg-icon icon-class="clear" style="font-size:20px;" />
|
||||||
</button>
|
</button>
|
||||||
<!-- 截屏 -->
|
<!-- 截屏 -->
|
||||||
<button
|
<button :title="$t('trials:dicom-show:image')" class="btn-link" @click="currentDicomCanvas.saveImage()">
|
||||||
:title="$t('trials:dicom-show:image')"
|
|
||||||
class="btn-link"
|
|
||||||
@click="currentDicomCanvas.saveImage()"
|
|
||||||
>
|
|
||||||
<svg-icon icon-class="image" style="font-size:20px;" />
|
<svg-icon icon-class="image" style="font-size:20px;" />
|
||||||
</button>
|
</button>
|
||||||
<!-- 标签 -->
|
<!-- 标签 -->
|
||||||
<button
|
<button :title="$t('trials:dicom-show:tags')" class="btn-link" @click="currentDicomCanvas.showTags()">
|
||||||
:title="$t('trials:dicom-show:tags')"
|
|
||||||
class="btn-link"
|
|
||||||
@click="currentDicomCanvas.showTags()"
|
|
||||||
>
|
|
||||||
<svg-icon icon-class="dictionary" style="font-size:20px;" />
|
<svg-icon icon-class="dictionary" style="font-size:20px;" />
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="measureTool-wrapper">
|
<div class="measureTool-wrapper">
|
||||||
<button
|
|
||||||
:title="$t('trials:dicom-show:EllipticalRoi')"
|
|
||||||
class="btn-link"
|
|
||||||
@click="setToolActive($event,'Note_RectangleRoi')"
|
|
||||||
>
|
|
||||||
<svg-icon icon-class="oval" style="font-size:20px;" />
|
|
||||||
</button>
|
|
||||||
<!-- 播放 -->
|
<!-- 播放 -->
|
||||||
<div class="sideTool-title">{{ $t('trials:dicom-show:play') }}</div>
|
<div class="sideTool-title">{{ $t('trials:dicom-show:play') }}</div>
|
||||||
<div class="sideTool-wrapper">
|
<div class="sideTool-wrapper">
|
||||||
<!-- 第一帧 -->
|
<!-- 第一帧 -->
|
||||||
<button
|
<button class="btn-link" :title="$t('trials:dicom-show:firstframe')"
|
||||||
class="btn-link"
|
@click="currentDicomCanvas.scrollPage(-9999)">
|
||||||
:title="$t('trials:dicom-show:firstframe')"
|
|
||||||
@click="currentDicomCanvas.scrollPage(-9999)"
|
|
||||||
>
|
|
||||||
<svg-icon icon-class="firstframe" style="font-size:20px;" />
|
<svg-icon icon-class="firstframe" style="font-size:20px;" />
|
||||||
</button>
|
</button>
|
||||||
<!-- 显示上一张影像 -->
|
<!-- 显示上一张影像 -->
|
||||||
<button
|
<button class="btn-link" :title="$t('trials:dicom-show:previousframe')"
|
||||||
class="btn-link"
|
@click="currentDicomCanvas.scrollPage(-1)">
|
||||||
:title="$t('trials:dicom-show:previousframe')"
|
|
||||||
@click="currentDicomCanvas.scrollPage(-1)"
|
|
||||||
>
|
|
||||||
<svg-icon icon-class="previousframe" style="font-size:20px;" />
|
<svg-icon icon-class="previousframe" style="font-size:20px;" />
|
||||||
</button>
|
</button>
|
||||||
<!-- 播放 -->
|
<!-- 播放 -->
|
||||||
<button class="btn-link" :title="$t('trials:dicom-show:play')" @click="clipPlay">
|
<button class="btn-link" :title="$t('trials:dicom-show:play')" @click="clipPlay">
|
||||||
<svg-icon
|
<svg-icon :icon-class="currentDicomCanvas.toolState.clipPlaying ? 'stop' : 'play'"
|
||||||
:icon-class="currentDicomCanvas.toolState.clipPlaying ? 'stop' : 'play'"
|
style="font-size:20px;" />
|
||||||
style="font-size:20px;"
|
|
||||||
/>
|
|
||||||
</button>
|
</button>
|
||||||
<!-- 下一帧 -->
|
<!-- 下一帧 -->
|
||||||
<button
|
<button class="btn-link" :title="$t('trials:dicom-show:nextframe')" @click="currentDicomCanvas.scrollPage(1)">
|
||||||
class="btn-link"
|
|
||||||
:title="$t('trials:dicom-show:nextframe')"
|
|
||||||
@click="currentDicomCanvas.scrollPage(1)"
|
|
||||||
>
|
|
||||||
<svg-icon icon-class="nextframe" style="font-size:20px;" />
|
<svg-icon icon-class="nextframe" style="font-size:20px;" />
|
||||||
</button>
|
</button>
|
||||||
<!-- 最后一帧 -->
|
<!-- 最后一帧 -->
|
||||||
<button
|
<button class="btn-link" :title="$t('trials:dicom-show:lastframe')"
|
||||||
class="btn-link"
|
@click="currentDicomCanvas.scrollPage(9999)">
|
||||||
:title="$t('trials:dicom-show:lastframe')"
|
|
||||||
@click="currentDicomCanvas.scrollPage(9999)"
|
|
||||||
>
|
|
||||||
<svg-icon icon-class="lastframe" style="font-size:20px;" />
|
<svg-icon icon-class="lastframe" style="font-size:20px;" />
|
||||||
</button>
|
</button>
|
||||||
<select
|
<select v-model="fps" class="sidetool-select" style="width:60px" @change="setDicomCanvasfps($event)">
|
||||||
v-model="fps"
|
|
||||||
class="sidetool-select"
|
|
||||||
style="width:60px"
|
|
||||||
@change="setDicomCanvasfps($event)"
|
|
||||||
>
|
|
||||||
<!-- 默认值 -->
|
<!-- 默认值 -->
|
||||||
<option :value="5">5</option>
|
<option :value="5">5</option>
|
||||||
<option :value="10">10</option>
|
<option :value="10">10</option>
|
||||||
|
|
@ -403,21 +253,15 @@
|
||||||
<div class="sideTool-wrapper">
|
<div class="sideTool-wrapper">
|
||||||
<!-- 预设窗位值 -->
|
<!-- 预设窗位值 -->
|
||||||
<label>{{ $t('trials:dicom-show:dicomCanvasWwwc') }}:</label>
|
<label>{{ $t('trials:dicom-show:dicomCanvasWwwc') }}:</label>
|
||||||
<select
|
<select v-model="wwwcList[currentDicomCanvasIndex]" class="sidetool-select" style="width:100px"
|
||||||
v-model="wwwcList[currentDicomCanvasIndex]"
|
@change="setDicomCanvasWwwc($event)">
|
||||||
class="sidetool-select"
|
|
||||||
style="width:100px"
|
|
||||||
@change="setDicomCanvasWwwc($event)"
|
|
||||||
>
|
|
||||||
<!-- 默认值 -->
|
<!-- 默认值 -->
|
||||||
<option :value="-1">{{ $t('trials:dicom-show:default') }}</option>
|
<option :value="-1">{{ $t('trials:dicom-show:default') }}</option>
|
||||||
<!-- 自定义 -->
|
<!-- 自定义 -->
|
||||||
<option :value="0">{{ $t('trials:dicom-show:custom') }}</option>
|
<option :value="0">{{ $t('trials:dicom-show:custom') }}</option>
|
||||||
<!-- 区域窗宽 -->
|
<!-- 区域窗宽 -->
|
||||||
<option
|
<option :value="1" style="border-bottom:1px solid #fff;">{{ $t('trials:reading:button:wwwcRegion') }}
|
||||||
:value="1"
|
</option>
|
||||||
style="border-bottom:1px solid #fff;"
|
|
||||||
>{{ $t('trials:reading:button:wwwcRegion') }}</option>
|
|
||||||
<option :value="2">CT Abdomen</option>
|
<option :value="2">CT Abdomen</option>
|
||||||
<option :value="3">CT Angio</option>
|
<option :value="3">CT Angio</option>
|
||||||
<option :value="4">CT Bone</option>
|
<option :value="4">CT Bone</option>
|
||||||
|
|
@ -430,32 +274,17 @@
|
||||||
<div class="sideTool-wrapper">
|
<div class="sideTool-wrapper">
|
||||||
<!-- 伪彩色 -->
|
<!-- 伪彩色 -->
|
||||||
<label>{{ $t('trials:dicom-show:pseudocolor') }}:</label>
|
<label>{{ $t('trials:dicom-show:pseudocolor') }}:</label>
|
||||||
<select
|
<select v-model="colorList[currentDicomCanvasIndex]" class="sidetool-select" style="width:90px"
|
||||||
v-model="colorList[currentDicomCanvasIndex]"
|
@change="setColormap($event)">
|
||||||
class="sidetool-select"
|
|
||||||
style="width:90px"
|
|
||||||
@change="setColormap($event)"
|
|
||||||
>
|
|
||||||
<!-- 默认值 -->
|
<!-- 默认值 -->
|
||||||
<option value>{{ $t('trials:dicom-show:default') }}</option>
|
<option value>{{ $t('trials:dicom-show:default') }}</option>
|
||||||
<option
|
<option v-for="(item, index) in colormapsList" :key="index" :value="item.id">{{ item.name }}</option>
|
||||||
v-for="(item,index) in colormapsList"
|
|
||||||
:key="index"
|
|
||||||
:value="item.id"
|
|
||||||
>{{ item.name }}</option>
|
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<el-dialog
|
<el-dialog v-if="customWwc.visible" :visible.sync="customWwc.visible" :close-on-click-modal="false"
|
||||||
v-if="customWwc.visible"
|
:title="customWwc.title" width="400px" custom-class="base-dialog-wrapper" append-to-body>
|
||||||
:visible.sync="customWwc.visible"
|
|
||||||
:close-on-click-modal="false"
|
|
||||||
:title="customWwc.title"
|
|
||||||
width="400px"
|
|
||||||
custom-class="base-dialog-wrapper"
|
|
||||||
append-to-body
|
|
||||||
>
|
|
||||||
<CustomWwwcForm @close="customWwc.visible = false" @setWwwc="setWwwc" />
|
<CustomWwwcForm @close="customWwc.visible = false" @setWwwc="setWwwc" />
|
||||||
</el-dialog>
|
</el-dialog>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -473,16 +302,26 @@ import Hammer from 'hammerjs'
|
||||||
cornerstoneTools.external.cornerstone = cornerstone
|
cornerstoneTools.external.cornerstone = cornerstone
|
||||||
cornerstoneTools.external.Hammer = Hammer
|
cornerstoneTools.external.Hammer = Hammer
|
||||||
cornerstoneTools.external.cornerstoneMath = cornerstoneMath
|
cornerstoneTools.external.cornerstoneMath = cornerstoneMath
|
||||||
|
console.log(cornerstoneTools, 'cornerstoneTools')
|
||||||
|
console.log(cornerstone, 'cornerstone')
|
||||||
import '@/utils/dialog'
|
import '@/utils/dialog'
|
||||||
|
import { studyMaskImage, studyUndoMaskImage } from "@/api/reading"
|
||||||
export default {
|
export default {
|
||||||
name: 'DicomsViewer',
|
name: 'DicomsViewer',
|
||||||
components: {
|
components: {
|
||||||
DicomCanvas,
|
DicomCanvas,
|
||||||
CustomWwwcForm,
|
CustomWwwcForm,
|
||||||
},
|
},
|
||||||
|
props: {
|
||||||
|
loading: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
}
|
||||||
|
},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
|
isAnonymous: false,
|
||||||
|
isComparison: false,
|
||||||
activeTool: '',
|
activeTool: '',
|
||||||
activeItem: 'dicomCanvas0',
|
activeItem: 'dicomCanvas0',
|
||||||
layoutRow: 1,
|
layoutRow: 1,
|
||||||
|
|
@ -503,6 +342,7 @@ export default {
|
||||||
wwwcList: [],
|
wwwcList: [],
|
||||||
layout: null,
|
layout: null,
|
||||||
seriesList: [],
|
seriesList: [],
|
||||||
|
series: {},
|
||||||
customWwc: { visible: false, title: null },
|
customWwc: { visible: false, title: null },
|
||||||
fps: 15,
|
fps: 15,
|
||||||
}
|
}
|
||||||
|
|
@ -520,11 +360,83 @@ export default {
|
||||||
},
|
},
|
||||||
|
|
||||||
methods: {
|
methods: {
|
||||||
|
anonymousImage() {
|
||||||
|
console.log(this.series, 'this.series')
|
||||||
|
this.$refs[`dicomCanvas0`].getNote_RectangleRoi().then(async obj => {
|
||||||
|
let { toolInfo, image } = obj
|
||||||
|
console.log(image, 'image')
|
||||||
|
if (!toolInfo || toolInfo.data.length <= 0) return this.$confirm(this.$t("DicomViewer:anonymous:notMark"))
|
||||||
|
let instanceInfo = this.series.instanceInfoList.find(item => item.ImageId === image.imageId)
|
||||||
|
let data = {
|
||||||
|
// SeriesId: this.series.seriesId,
|
||||||
|
instanceIdList: [instanceInfo.Id],
|
||||||
|
MaskRegionList: []
|
||||||
|
}
|
||||||
|
toolInfo.data.forEach(item => {
|
||||||
|
let currentStart = item.handles.start
|
||||||
|
let currentEnd = item.handles.end
|
||||||
|
let start = {
|
||||||
|
x: currentStart.x > currentEnd.x ? Math.round(currentEnd.x) : Math.round(currentStart.x),
|
||||||
|
y: currentStart.y > currentEnd.y ? Math.round(currentEnd.y) : Math.round(currentStart.y),
|
||||||
|
}
|
||||||
|
let end = {
|
||||||
|
x: currentStart.x > currentEnd.x ? Math.round(currentStart.x) : Math.round(currentEnd.x),
|
||||||
|
y: currentStart.y > currentEnd.y ? Math.round(currentStart.y) : Math.round(currentEnd.y),
|
||||||
|
}
|
||||||
|
let width = end.x - start.x
|
||||||
|
let height = end.y - start.y
|
||||||
|
data.MaskRegionList.push({
|
||||||
|
X: start.x,
|
||||||
|
Y: start.y,
|
||||||
|
Width: width,
|
||||||
|
Height: height
|
||||||
|
})
|
||||||
|
})
|
||||||
|
let res = await this.studyMaskImage(data)
|
||||||
|
if (!res) return false
|
||||||
|
// this.$emit("update:loading", true)
|
||||||
|
// let strs = image.imageId.split("?")
|
||||||
|
// let newImageId = `${strs[0]}-MaskImage?${strs[1]}`
|
||||||
|
// console.log(newImageId, 'newImageId')
|
||||||
|
// this.$refs[`dicomCanvas0`].reloadImage(newImageId)
|
||||||
|
})
|
||||||
|
},
|
||||||
|
openAnonymous() {
|
||||||
|
this.isAnonymous = !this.isAnonymous
|
||||||
|
if (!this.isAnonymous) {
|
||||||
|
const elements = document.querySelectorAll('.dicom-item')
|
||||||
|
const scope = this
|
||||||
|
scope.activeTool = null
|
||||||
|
Array.from(elements).forEach((element, index) => {
|
||||||
|
if (element.style.display !== 'none') {
|
||||||
|
scope.$refs[`dicomCanvas${index}`].setToolPassive(toolName)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
this.activateDicomCanvas(0)
|
||||||
|
this.changeLayout('1x1')
|
||||||
|
}
|
||||||
|
},
|
||||||
|
async studyMaskImage(data) {
|
||||||
|
try {
|
||||||
|
this.$emit("update:loading", true)
|
||||||
|
let res = await studyMaskImage(data)
|
||||||
|
this.$emit("update:loading", false)
|
||||||
|
if (res.IsSuccess) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
} catch (err) {
|
||||||
|
console.log(err)
|
||||||
|
this.$emit("update:loading", false)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
},
|
||||||
loadImageStack(dicomSeries) {
|
loadImageStack(dicomSeries) {
|
||||||
this.currentDicomCanvas.toolState.clipPlaying = false
|
this.currentDicomCanvas.toolState.clipPlaying = false
|
||||||
this.$nextTick(() => {
|
this.$nextTick(() => {
|
||||||
const series = Object.assign({}, dicomSeries)
|
this.series = Object.assign({}, dicomSeries)
|
||||||
this.currentDicomCanvas.loadImageStack(series)
|
this.currentDicomCanvas.loadImageStack(this.series)
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
loadOtherImageStack(seriesList) {
|
loadOtherImageStack(seriesList) {
|
||||||
|
|
@ -573,7 +485,7 @@ export default {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
changeLayout(event) {
|
changeLayout(event) {
|
||||||
const arr = event.target.value.split('x')
|
const arr = event.target ? event.target.value.split('x') : event.split('x')
|
||||||
this.layoutRow = parseInt(arr[0])
|
this.layoutRow = parseInt(arr[0])
|
||||||
this.layoutCol = parseInt(arr[1])
|
this.layoutCol = parseInt(arr[1])
|
||||||
this.rowHeight = 100 / this.layoutRow + '%'
|
this.rowHeight = 100 / this.layoutRow + '%'
|
||||||
|
|
@ -610,11 +522,21 @@ export default {
|
||||||
cornerstone.resize(e.currentTarget.children[0])
|
cornerstone.resize(e.currentTarget.children[0])
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
fillColor() {
|
||||||
|
const elements = document.querySelectorAll('.dicom-item')
|
||||||
|
const scope = this
|
||||||
|
Array.from(elements).forEach((element, index) => {
|
||||||
|
if (element.style.display !== 'none') {
|
||||||
|
scope.$refs[`dicomCanvas${index}`].fillColor()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
},
|
||||||
setToolActive(e, toolName) {
|
setToolActive(e, toolName) {
|
||||||
const elements = document.querySelectorAll('.dicom-item')
|
const elements = document.querySelectorAll('.dicom-item')
|
||||||
if (e.currentTarget.classList.contains('activeTool')) {
|
if (e.currentTarget.classList.contains('activeTool')) {
|
||||||
e.currentTarget.classList.remove('activeTool')
|
e.currentTarget.classList.remove('activeTool')
|
||||||
const scope = this
|
const scope = this
|
||||||
|
scope.activeTool = null
|
||||||
Array.from(elements).forEach((element, index) => {
|
Array.from(elements).forEach((element, index) => {
|
||||||
if (element.style.display !== 'none') {
|
if (element.style.display !== 'none') {
|
||||||
scope.$refs[`dicomCanvas${index}`].setToolPassive(toolName)
|
scope.$refs[`dicomCanvas${index}`].setToolPassive(toolName)
|
||||||
|
|
@ -628,6 +550,7 @@ export default {
|
||||||
e.currentTarget.classList.add('activeTool')
|
e.currentTarget.classList.add('activeTool')
|
||||||
|
|
||||||
const scope = this
|
const scope = this
|
||||||
|
scope.activeTool = toolName
|
||||||
Array.from(elements).forEach((element, index) => {
|
Array.from(elements).forEach((element, index) => {
|
||||||
if (element.style.display !== 'none') {
|
if (element.style.display !== 'none') {
|
||||||
scope.$refs[`dicomCanvas${index}`].setToolActive(toolName)
|
scope.$refs[`dicomCanvas${index}`].setToolActive(toolName)
|
||||||
|
|
@ -769,6 +692,7 @@ export default {
|
||||||
.dicom-wrapper {
|
.dicom-wrapper {
|
||||||
display: flex;
|
display: flex;
|
||||||
}
|
}
|
||||||
|
|
||||||
.dicom-wrapper .case-dialog-class {
|
.dicom-wrapper .case-dialog-class {
|
||||||
position: fixed;
|
position: fixed;
|
||||||
left: 25%;
|
left: 25%;
|
||||||
|
|
@ -780,28 +704,84 @@ export default {
|
||||||
.dicom-wrapper .case-dialog-div {
|
.dicom-wrapper .case-dialog-div {
|
||||||
pointer-events: none;
|
pointer-events: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
.dicom-wrapper .case-dialog-class .el-dialog__body {
|
.dicom-wrapper .case-dialog-class .el-dialog__body {
|
||||||
max-height: 300px;
|
max-height: 300px;
|
||||||
overflow-y: auto;
|
overflow-y: auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
.dicom-wrapper .el-dialog__header {
|
.dicom-wrapper .el-dialog__header {
|
||||||
padding: 15px;
|
padding: 15px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.dicom-wrapper .el-dialog__body {
|
.dicom-wrapper .el-dialog__body {
|
||||||
padding: 10px 20px;
|
padding: 10px 20px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.dicom-viewer {
|
.dicom-viewer {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
flex: 1;
|
flex: 1;
|
||||||
position: relative;
|
position: relative;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.Anonymous {
|
||||||
|
position: absolute;
|
||||||
|
border-radius: 5px;
|
||||||
|
bottom: 30px;
|
||||||
|
left: 5%;
|
||||||
|
right: 5%;
|
||||||
|
width: 90%;
|
||||||
|
height: 60px;
|
||||||
|
padding: 0 10px;
|
||||||
|
background-color: rgba(255, 255, 255, .2);
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
z-index: 9999;
|
||||||
|
|
||||||
|
.btn {
|
||||||
|
width: 15%;
|
||||||
|
text-align: center;
|
||||||
|
height: 40px;
|
||||||
|
line-height: 30px;
|
||||||
|
border-radius: 15px;
|
||||||
|
background-color: rgba(255, 255, 255, .3);
|
||||||
|
cursor: pointer;
|
||||||
|
padding: 5px 10px;
|
||||||
|
border: 1px solid rgba(255, 255, 255, .7);
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background-color: rgba(255, 255, 255, .5);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.activeBtn {
|
||||||
|
background-color: rgba(255, 255, 255, .5);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.btnBox {
|
||||||
|
display: inline-block;
|
||||||
|
width: 80px;
|
||||||
|
text-align: center;
|
||||||
|
height: 30px;
|
||||||
|
line-height: 20px;
|
||||||
|
border-radius: 15px;
|
||||||
|
background-color: rgba(255, 255, 255, .3);
|
||||||
|
cursor: pointer;
|
||||||
|
padding: 5px 10px;
|
||||||
|
border: 1px solid rgba(255, 255, 255, .7);
|
||||||
|
margin: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
.dicom-wrapper .dicom-row {
|
.dicom-wrapper .dicom-row {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: row;
|
flex-direction: row;
|
||||||
flex: 1;
|
flex: 1;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
.dicom-wrapper .dicom-item {
|
.dicom-wrapper .dicom-item {
|
||||||
position: relative;
|
position: relative;
|
||||||
width: 0;
|
width: 0;
|
||||||
|
|
@ -811,9 +791,11 @@ export default {
|
||||||
padding: 5px;
|
padding: 5px;
|
||||||
border: 1px solid #c8c8c8;
|
border: 1px solid #c8c8c8;
|
||||||
}
|
}
|
||||||
|
|
||||||
.dicom-wrapper .activeItem {
|
.dicom-wrapper .activeItem {
|
||||||
border: 2px solid chocolate;
|
border: 2px solid chocolate;
|
||||||
}
|
}
|
||||||
|
|
||||||
.dicom-item-fullscreen {
|
.dicom-item-fullscreen {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
left: 0;
|
left: 0;
|
||||||
|
|
@ -822,14 +804,17 @@ export default {
|
||||||
height: 100%;
|
height: 100%;
|
||||||
z-index: 1;
|
z-index: 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
.dicom-wrapper ::-webkit-scrollbar {
|
.dicom-wrapper ::-webkit-scrollbar {
|
||||||
width: 7px;
|
width: 7px;
|
||||||
height: 7px;
|
height: 7px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.dicom-wrapper ::-webkit-scrollbar-thumb {
|
.dicom-wrapper ::-webkit-scrollbar-thumb {
|
||||||
border-radius: 10px;
|
border-radius: 10px;
|
||||||
background: gray;
|
background: gray;
|
||||||
}
|
}
|
||||||
|
|
||||||
.dicom-wrapper .dicom-tools {
|
.dicom-wrapper .dicom-tools {
|
||||||
/* display: flex;
|
/* display: flex;
|
||||||
flex-direction: column; */
|
flex-direction: column; */
|
||||||
|
|
@ -844,25 +829,30 @@ export default {
|
||||||
font-size: 13px;
|
font-size: 13px;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
}
|
}
|
||||||
|
|
||||||
.dicom-wrapper .measure-wrapper {
|
.dicom-wrapper .measure-wrapper {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
flex: 1;
|
flex: 1;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
}
|
}
|
||||||
|
|
||||||
.measure-wrapper .measure-list {
|
.measure-wrapper .measure-list {
|
||||||
flex: 1;
|
flex: 1;
|
||||||
overflow-y: auto;
|
overflow-y: auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
.measure-list-header {
|
.measure-list-header {
|
||||||
padding: 2px 0px;
|
padding: 2px 0px;
|
||||||
border-bottom: 1px solid gray;
|
border-bottom: 1px solid gray;
|
||||||
}
|
}
|
||||||
|
|
||||||
.measure-wrapper ul {
|
.measure-wrapper ul {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
padding: 0 5px;
|
padding: 0 5px;
|
||||||
list-style: none;
|
list-style: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
.measure-wrapper ul li {
|
.measure-wrapper ul li {
|
||||||
height: 20px;
|
height: 20px;
|
||||||
display: flex;
|
display: flex;
|
||||||
|
|
@ -879,9 +869,11 @@ export default {
|
||||||
font-size: 13px;
|
font-size: 13px;
|
||||||
color: #606626;
|
color: #606626;
|
||||||
}
|
}
|
||||||
.measure-wrapper select > option {
|
|
||||||
|
.measure-wrapper select>option {
|
||||||
color: #323232;
|
color: #323232;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* .measure-wrapper select {
|
/* .measure-wrapper select {
|
||||||
height: 20px;
|
height: 20px;
|
||||||
background-color: rgba(0, 0, 0, 0);
|
background-color: rgba(0, 0, 0, 0);
|
||||||
|
|
@ -901,6 +893,7 @@ export default {
|
||||||
.dicom-canvas.active {
|
.dicom-canvas.active {
|
||||||
border: 1px solid #337ab7;
|
border: 1px solid #337ab7;
|
||||||
}
|
}
|
||||||
|
|
||||||
.sideTool-title {
|
.sideTool-title {
|
||||||
padding: 5px 8px;
|
padding: 5px 8px;
|
||||||
background-color: #525252;
|
background-color: #525252;
|
||||||
|
|
@ -908,30 +901,36 @@ export default {
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
margin: 4px;
|
margin: 4px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.sideTool-wrapper {
|
.sideTool-wrapper {
|
||||||
border-bottom: 1px solid gray;
|
border-bottom: 1px solid gray;
|
||||||
margin: 0px 4px;
|
margin: 0px 4px;
|
||||||
padding: 4px;
|
padding: 4px;
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.sideTool-wrapper .btn {
|
.sideTool-wrapper .btn {
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.sidetool-select {
|
.sidetool-select {
|
||||||
height: 30px;
|
height: 30px;
|
||||||
background-color: rgba(0, 0, 0, 0);
|
background-color: rgba(0, 0, 0, 0);
|
||||||
color: #d0d0d0;
|
color: #d0d0d0;
|
||||||
border-radius: 4px;
|
border-radius: 4px;
|
||||||
}
|
}
|
||||||
.sidetool-select > option {
|
|
||||||
|
.sidetool-select>option {
|
||||||
background-color: #323232;
|
background-color: #323232;
|
||||||
}
|
}
|
||||||
|
|
||||||
.sideTool-wrapper button.btn-link {
|
.sideTool-wrapper button.btn-link {
|
||||||
height: 40px;
|
height: 40px;
|
||||||
padding: 8px !important;
|
padding: 8px !important;
|
||||||
border: 1px solid rgba(37, 37, 37, 1);
|
border: 1px solid rgba(37, 37, 37, 1);
|
||||||
margin: 1px 1px;
|
margin: 1px 1px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.sideTool-wrapper .btn-link {
|
.sideTool-wrapper .btn-link {
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
height: 40px;
|
height: 40px;
|
||||||
|
|
@ -939,6 +938,7 @@ export default {
|
||||||
border: 1px solid rgba(37, 37, 37, 1);
|
border: 1px solid rgba(37, 37, 37, 1);
|
||||||
margin: 1px 1px;
|
margin: 1px 1px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.dicom-wrapper .btn-group {
|
.dicom-wrapper .btn-group {
|
||||||
position: relative;
|
position: relative;
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
|
|
@ -955,6 +955,7 @@ export default {
|
||||||
border: 1px solid rgba(37, 37, 37, 1);
|
border: 1px solid rgba(37, 37, 37, 1);
|
||||||
min-height: 30px;
|
min-height: 30px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.dicom-wrapper .btn-group .btn-left {
|
.dicom-wrapper .btn-group .btn-left {
|
||||||
position: relative;
|
position: relative;
|
||||||
float: left;
|
float: left;
|
||||||
|
|
@ -963,15 +964,18 @@ export default {
|
||||||
border-bottom-right-radius: 0;
|
border-bottom-right-radius: 0;
|
||||||
border-top-right-radius: 0;
|
border-top-right-radius: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.dicom-wrapper .activeTool {
|
.dicom-wrapper .activeTool {
|
||||||
background: #16477b90 !important;
|
background: #16477b90 !important;
|
||||||
border: none;
|
border: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
.dicom-wrapper .btn-link {
|
.dicom-wrapper .btn-link {
|
||||||
color: #cccccc;
|
color: #cccccc;
|
||||||
background-color: #ffffff00;
|
background-color: #ffffff00;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
|
|
||||||
.dicom-wrapper .btn-submit {
|
.dicom-wrapper .btn-submit {
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
/* background-color: #eeeeee; */
|
/* background-color: #eeeeee; */
|
||||||
|
|
@ -991,10 +995,12 @@ export default {
|
||||||
.dicom-wrapper .iconHover:hover {
|
.dicom-wrapper .iconHover:hover {
|
||||||
color: red;
|
color: red;
|
||||||
}
|
}
|
||||||
|
|
||||||
.dicom-wrapper .dropdown {
|
.dicom-wrapper .dropdown {
|
||||||
position: relative;
|
position: relative;
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
}
|
}
|
||||||
|
|
||||||
.dicom-wrapper .dropdown-content {
|
.dicom-wrapper .dropdown-content {
|
||||||
display: none;
|
display: none;
|
||||||
position: absolute;
|
position: absolute;
|
||||||
|
|
@ -1007,14 +1013,17 @@ export default {
|
||||||
border: 1px solid #4e4e4e;
|
border: 1px solid #4e4e4e;
|
||||||
padding: 5px;
|
padding: 5px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.dicom-wrapper .dropdown:hover .dropdown-content {
|
.dicom-wrapper .dropdown:hover .dropdown-content {
|
||||||
display: block;
|
display: block;
|
||||||
}
|
}
|
||||||
|
|
||||||
.dicom-wrapper .dropdown-content div {
|
.dicom-wrapper .dropdown-content div {
|
||||||
height: 25px;
|
height: 25px;
|
||||||
line-height: 25px;
|
line-height: 25px;
|
||||||
cursor: point;
|
cursor: point;
|
||||||
}
|
}
|
||||||
|
|
||||||
.dicom-wrapper .dropdown-content div:hover {
|
.dicom-wrapper .dropdown-content div:hover {
|
||||||
background-color: #16477b90;
|
background-color: #16477b90;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -123,7 +123,7 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="viewerContent">
|
<div class="viewerContent">
|
||||||
<dicom-viewer id="dicomViewer" ref="dicomViewer" style="height:100%" />
|
<dicom-viewer id="dicomViewer" ref="dicomViewer" style="height:100%" :loading.sync="loading" />
|
||||||
</div>
|
</div>
|
||||||
<!-- <div class="viewerRightSidePanel">
|
<!-- <div class="viewerRightSidePanel">
|
||||||
<dicom-tools />
|
<dicom-tools />
|
||||||
|
|
|
||||||
|
|
@ -1,110 +1,97 @@
|
||||||
import cornerstone from 'cornerstone-core';
|
// Note_RectangleRoiTool.js
|
||||||
import cornerstoneTools from 'cornerstone-tools';
|
import * as cornerstoneTools from 'cornerstone-tools';
|
||||||
|
|
||||||
const BaseAnnotationTool = cornerstoneTools.importInternal('base/BaseAnnotationTool');
|
export default class Note_RectangleRoiTool extends cornerstoneTools.RectangleRoiTool {
|
||||||
const getToolState = cornerstoneTools.getToolState;
|
|
||||||
const drawHandles = cornerstoneTools.importInternal('drawing/drawHandles');
|
|
||||||
|
|
||||||
export default class Note_RectangleRoiTool extends BaseAnnotationTool {
|
|
||||||
constructor(props = {}) {
|
constructor(props = {}) {
|
||||||
super({
|
const defaultProps = {
|
||||||
name: 'Note_RectangleRoi',
|
name: 'Note_RectangleRoi',
|
||||||
supportedInteractionTypes: ['Mouse'],
|
|
||||||
configuration: {
|
configuration: {
|
||||||
customColor: '#FF4444',
|
fillColor: 'rgba(255, 255, 0, 0.3)', // 默认填充颜色:半透明黄色
|
||||||
showLabel: true,
|
strokeColor: 'yellow', // 边框颜色
|
||||||
handleRadius: 6,
|
lineWidth: 2, // 边框宽度
|
||||||
...props.configuration
|
drawHandles: true, // 是否绘制控制点
|
||||||
}
|
handleColor: 'white', // 控制点颜色
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
createNewMeasurement(eventData) {
|
|
||||||
const { currentPoints } = eventData;
|
|
||||||
const startPoint = currentPoints.canvas;
|
|
||||||
|
|
||||||
return {
|
|
||||||
visible: true,
|
|
||||||
active: true,
|
|
||||||
color: this.configuration.customColor,
|
|
||||||
handles: {
|
|
||||||
start: { x: startPoint.x, y: startPoint.y, highlight: true, active: false },
|
|
||||||
end: { x: startPoint.x, y: startPoint.y, highlight: true, active: false },
|
|
||||||
textBox: {
|
|
||||||
active: false, hasMoved: false, movesIndependently: false,
|
|
||||||
drawnIndependently: true, allowedOutsideImage: true, hasBoundingBox: true
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
super({ ...defaultProps, ...props });
|
||||||
}
|
}
|
||||||
|
|
||||||
pointNearTool(element, data, coords) {
|
|
||||||
const minX = Math.min(data.handles.start.x, data.handles.end.x);
|
|
||||||
const maxX = Math.max(data.handles.start.x, data.handles.end.x);
|
|
||||||
const minY = Math.min(data.handles.start.y, data.handles.end.y);
|
|
||||||
const maxY = Math.max(data.handles.start.y, data.handles.end.y);
|
|
||||||
const threshold = 5;
|
|
||||||
|
|
||||||
return coords.x >= minX - threshold && coords.x <= maxX + threshold &&
|
|
||||||
coords.y >= minY - threshold && coords.y <= maxY + threshold;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 稳健的 renderToolData 实现
|
|
||||||
renderToolData(evt) {
|
renderToolData(evt) {
|
||||||
// 1. 获取 element(尝试多种来源)
|
const eventData = evt.detail;
|
||||||
const element = evt.detail?.element || evt.element || evt?.detail?.eventData?.element;
|
const { element } = eventData;
|
||||||
if (!element) {
|
|
||||||
console.warn('renderToolData: Cannot find element');
|
// 获取工具状态
|
||||||
|
const toolData = cornerstoneTools.getToolState(element, this.name);
|
||||||
|
|
||||||
|
if (!toolData || !toolData.data || !toolData.data.length) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 2. 获取工具数据
|
const canvas = eventData.canvasContext.canvas;
|
||||||
const toolData = getToolState(element, this.name);
|
const context = canvas.getContext('2d');
|
||||||
if (!toolData || !toolData.data || toolData.data.length === 0) return;
|
|
||||||
|
|
||||||
// 3. 获取 canvas context
|
|
||||||
const enabledElement = cornerstone.getEnabledElement(element);
|
|
||||||
const context = enabledElement.canvas.getContext('2d');
|
|
||||||
if (!context) return;
|
|
||||||
|
|
||||||
// 4. 绘制所有标注
|
|
||||||
context.save();
|
context.save();
|
||||||
|
|
||||||
toolData.data.forEach(data => {
|
// 获取配置
|
||||||
if (!data.visible) return;
|
const fillColor = this.configuration.fillColor || 'rgba(255, 255, 0, 0.3)';
|
||||||
|
const strokeColor = this.configuration.strokeColor || 'yellow';
|
||||||
|
const lineWidth = this.configuration.lineWidth || 2;
|
||||||
|
const drawHandles = this.configuration.drawHandles !== false;
|
||||||
|
|
||||||
context.strokeStyle = data.color || this.configuration.customColor;
|
// 遍历所有矩形标注
|
||||||
context.fillStyle = 'transparent';
|
toolData.data.forEach((measurement) => {
|
||||||
context.lineWidth = 2;
|
if (!measurement.handles?.start || !measurement.handles?.end) {
|
||||||
|
return;
|
||||||
const start = data.handles.start;
|
|
||||||
const end = data.handles.end;
|
|
||||||
const width = end.x - start.x;
|
|
||||||
const height = end.y - start.y;
|
|
||||||
|
|
||||||
context.strokeRect(start.x, start.y, width, height);
|
|
||||||
|
|
||||||
if (data.active) {
|
|
||||||
drawHandles(context, { element }, [start, end], {
|
|
||||||
handleRadius: this.configuration.handleRadius,
|
|
||||||
color: data.color
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.configuration.showLabel) {
|
const start = measurement.handles.start;
|
||||||
const area = Math.abs(width * height);
|
const end = measurement.handles.end;
|
||||||
const text = `${area.toFixed(0)}px²`;
|
|
||||||
const textCoords = {
|
|
||||||
x: (start.x + end.x) / 2,
|
|
||||||
y: Math.min(start.y, end.y) - 10
|
|
||||||
};
|
|
||||||
|
|
||||||
context.font = '12px Arial';
|
// 计算矩形坐标和尺寸
|
||||||
context.fillStyle = data.color;
|
const x = Math.min(start.x, end.x);
|
||||||
context.fillText(text, textCoords.x, textCoords.y);
|
const y = Math.min(start.y, end.y);
|
||||||
|
const width = Math.abs(end.x - start.x);
|
||||||
|
const height = Math.abs(end.y - start.y);
|
||||||
|
|
||||||
|
// 1. 绘制填充
|
||||||
|
if (fillColor) {
|
||||||
|
context.fillStyle = fillColor;
|
||||||
|
context.fillRect(x, y, width, height);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2. 绘制边框
|
||||||
|
context.strokeStyle = strokeColor;
|
||||||
|
context.lineWidth = lineWidth;
|
||||||
|
context.strokeRect(x, y, width, height);
|
||||||
|
|
||||||
|
// 3. 绘制控制点(可选)
|
||||||
|
if (drawHandles) {
|
||||||
|
this.drawHandles(context, measurement, eventData);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
context.restore();
|
context.restore();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 绘制控制点
|
||||||
|
*/
|
||||||
|
drawHandles(context, measurement, eventData) {
|
||||||
|
const handles = measurement.handles;
|
||||||
|
const handleColor = this.configuration.handleColor || 'white';
|
||||||
|
|
||||||
|
// 绘制所有控制点
|
||||||
|
Object.keys(handles).forEach(key => {
|
||||||
|
const handle = handles[key];
|
||||||
|
if (handle && typeof handle.x === 'number' && typeof handle.y === 'number') {
|
||||||
|
context.beginPath();
|
||||||
|
context.arc(handle.x, handle.y, 5, 0, 2 * Math.PI);
|
||||||
|
context.fillStyle = handleColor;
|
||||||
|
context.fill();
|
||||||
|
context.strokeStyle = 'black';
|
||||||
|
context.lineWidth = 1;
|
||||||
|
context.stroke();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Loading…
Reference in New Issue