-
-
+
+
-
+
-
+
{{ `${taskInfo.SubjectCode} ${v.taskInfo.TaskBlindName} ` }}
+
-
+ @dblclick.stop="preventDefault($event)">
{{ v.taskInfo.TaskBlindName }}
-
+ @dblclick.stop="preventDefault($event)">
-
{return}" @mousedown.stop="sliderMousedown($event, index)" />
+
- { return }"
+ @mousedown.stop="sliderMousedown($event, index)" />
+
-
+
@@ -244,13 +213,8 @@
-
+
@@ -277,6 +241,7 @@ import store from '@/store'
import Others from '@/views/trials/trials-panel/reading/dicoms/components/Others'
const { ViewportType } = Enums
const renderingEngineId = 'myRenderingEngine'
+import LengthscaleTool from "../tools/LengthscaleTool"
const {
ToolGroupManager,
Enums: csToolsEnums,
@@ -289,7 +254,10 @@ const {
PlanarFreehandROITool,
SplineROITool,
EraserTool,
- LengthTool
+ LengthTool,
+ EllipticalROITool,
+ CircleROITool,
+ AngleTool
// cursors
} = cornerstoneTools
const { MouseBindings, Events: toolsEvents } = csToolsEnums
@@ -480,10 +448,14 @@ export default {
cornerstoneTools.addTool(PlanarRotateTool)
cornerstoneTools.addTool(ArrowAnnotateTool)
cornerstoneTools.addTool(RectangleROITool)
+ cornerstoneTools.addTool(EllipticalROITool)
+ cornerstoneTools.addTool(CircleROITool)
+ cornerstoneTools.addTool(AngleTool)
cornerstoneTools.addTool(PlanarFreehandROITool)
cornerstoneTools.addTool(SplineROITool)
cornerstoneTools.addTool(EraserTool)
cornerstoneTools.addTool(LengthTool)
+ cornerstoneTools.addTool(LengthscaleTool)
viewportIds.forEach((viewportId, i) => {
const toolGroupId = `canvas-${i}`
@@ -495,10 +467,10 @@ export default {
toolGroup.addTool(PlanarRotateTool.toolName)
toolGroup.addTool(ArrowAnnotateTool.toolName, {
arrowHeadStyle: 'standard',
- changeTextCallback: async(data, eventData, doneChangingTextCallback) => {
+ changeTextCallback: async (data, eventData, doneChangingTextCallback) => {
return doneChangingTextCallback(await this.customPrompt())
},
- getTextCallback: async(doneChangingTextCallback) => {
+ getTextCallback: async (doneChangingTextCallback) => {
return doneChangingTextCallback(await this.customPrompt())
}
})
@@ -506,6 +478,15 @@ export default {
cachedStats: false,
getTextLines: this.getRectangleROIToolTextLines
})
+ toolGroup.addTool(EllipticalROITool.toolName, {
+ cachedStats: false,
+ getTextLines: this.getEllipticalROIToolTextLines
+ })
+ toolGroup.addTool(CircleROITool.toolName, {
+ cachedStats: false,
+ getTextLines: this.getCircleROIToolTextLines
+ })
+ toolGroup.addTool(AngleTool.toolName)
toolGroup.addTool(PlanarFreehandROITool.toolName, {
allowOpenContours: false,
cachedStats: false,
@@ -522,6 +503,10 @@ export default {
getTextLines: this.getLengthToolTextLines,
cachedStats: false
})
+ toolGroup.addTool(LengthscaleTool.toolName, {
+ getTextLines: this.getLengthscaleToolTextLines,
+ cachedStats: false
+ })
toolGroup.setToolActive(StackScrollTool.toolName, {
bindings: [{ mouseButton: MouseBindings.Wheel }]
@@ -532,15 +517,23 @@ export default {
if (this.readingTaskState < 2) {
toolGroup.setToolPassive(ArrowAnnotateTool.toolName)
toolGroup.setToolPassive(RectangleROITool.toolName)
+ toolGroup.setToolPassive(EllipticalROITool.toolName)
+ toolGroup.setToolPassive(CircleROITool.toolName)
+ toolGroup.setToolPassive(AngleTool.toolName)
toolGroup.setToolPassive(PlanarFreehandROITool.toolName)
toolGroup.setToolPassive(SplineROITool.toolName)
toolGroup.setToolPassive(LengthTool.toolName)
+ toolGroup.setToolPassive(LengthscaleTool.toolName)
} else {
toolGroup.setToolEnabled(ArrowAnnotateTool.toolName)
toolGroup.setToolEnabled(RectangleROITool.toolName)
+ toolGroup.setToolEnabled(EllipticalROITool.toolName)
+ toolGroup.setToolEnabled(CircleROITool.toolName)
+ toolGroup.setToolEnabled(AngleTool.toolName)
toolGroup.setToolEnabled(PlanarFreehandROITool.toolName)
toolGroup.setToolEnabled(SplineROITool.toolName)
toolGroup.setToolEnabled(LengthTool.toolName)
+ toolGroup.setToolEnabled(LengthscaleTool.toolName)
}
toolGroup.setToolPassive(EraserTool.toolName)
})
@@ -804,12 +797,12 @@ export default {
if (this.activeTool) {
toolGroup.setToolPassive(this.activeTool)
}
- if (toolName === 'Length') {
+ if (toolName === 'Lengthscale') {
const renderingEngine = getRenderingEngine(renderingEngineId)
const viewport = renderingEngine.getViewport(`canvas-${this.activeCanvasIndex}`)
const imageId = viewport.csImage.imageId
const annotations = cornerstoneTools.annotation.state.getAllAnnotations()
- const idx = annotations.findIndex(i => i.metadata.referencedImageId === imageId && i.metadata.toolName === 'Length')
+ const idx = annotations.findIndex(i => i.metadata.referencedImageId === imageId && i.metadata.toolName === 'Lengthscale')
if (idx > -1) {
this.activeTool = ''
// 当前图像已存在比例尺!
@@ -874,7 +867,7 @@ export default {
const path = imageId.split(`web:${this.OSSclientConfig.basePath}`)[1]
const fileList = this.viewportInfos[i].fileList
const fileIndex = fileList.findIndex(f => f.Path === path)
- if (annotation.metadata.toolName === 'Length') {
+ if (annotation.metadata.toolName === 'Lengthscale') {
this.$emit('setPS', { NoneDicomFileId: fileList[fileIndex].Id, Path: fileList[fileIndex].Path, PS: null })
}
},
@@ -893,7 +886,7 @@ export default {
const fileList = this.viewportInfos[i].fileList
const fileIndex = fileList.findIndex(f => f.Path === path)
if (fileIndex === -1) return
- if (annotation.metadata.toolName === 'Length') {
+ if (annotation.metadata.toolName === 'Lengthscale') {
const value = annotation.data.l
if (value) {
const cachedStats = Object.keys(annotation.data.cachedStats)
@@ -929,7 +922,7 @@ export default {
const fileList = this.viewportInfos[i].fileList
const fileIndex = fileList.findIndex(f => f.Path === path)
if (fileIndex === -1) return
- if (annotation.metadata.toolName === 'Length') {
+ if (annotation.metadata.toolName === 'Lengthscale') {
this.form.annotationObj = {
id: '',
visitTaskId: this.viewportInfos[i].taskInfo.VisitTaskId,
@@ -996,7 +989,7 @@ export default {
viewport.render()
this.dialogVisible = false
},
- getLengthToolTextLines(data, targetId) {
+ getLengthscaleToolTextLines(data, targetId) {
const cachedVolumeStats = data.cachedStats[targetId]
const { length, unit } = cachedVolumeStats
if (length === undefined || length === null || isNaN(length)) {
@@ -1013,6 +1006,27 @@ export default {
}
return textLines
},
+ // 直线工具注释
+ getLengthToolTextLines(data, targetId) {
+ const cachedVolumeStats = data.cachedStats[targetId]
+ const { length, unit } = cachedVolumeStats
+ if (length === undefined || length === null || isNaN(length)) {
+ return
+ }
+ let ps = null
+ const path = targetId.split(`web:${this.OSSclientConfig.basePath}`)[1]
+ const i = this.psArr.findIndex(i => i.Path === path)
+ if (i > -1 && this.psArr[i].PS) {
+ ps = parseFloat(this.psArr[i].PS).toFixed(3)
+ }
+ const textLines = []
+ if (ps) {
+ textLines.push(`${this.reRound(csUtils.roundNumber(length * ps), this.digitPlaces)} mm`)
+ } else {
+ textLines.push(`${this.reRound(csUtils.roundNumber(length), this.digitPlaces)} ${unit}`)
+ }
+ return textLines
+ },
getPlanarFreehandROIToolTextLines(data, targetId) {
const cachedVolumeStats = data.cachedStats[targetId]
const {
@@ -1044,7 +1058,7 @@ export default {
if (mean) {
textLines.push(`Mean: ${this.reRound(csUtils.roundNumber(mean), this.digitPlaces)} ${modalityUnit}`)
}
-
+
if (max) {
textLines.push(`Max: ${this.reRound(csUtils.roundNumber(max), this.digitPlaces)} ${modalityUnit}`)
}
@@ -1094,6 +1108,60 @@ export default {
return textLines
},
+ // 椭圆工具注释信息
+ getEllipticalROIToolTextLines(data, targetId) {
+ const cachedVolumeStats = data.cachedStats[targetId]
+ const { area, mean, max, stdDev, areaUnit, modalityUnit } = cachedVolumeStats
+
+ if (mean === undefined) {
+ return
+ }
+
+ const textLines = []
+ let ps = null
+ const path = targetId.split(`web:${this.OSSclientConfig.basePath}`)[1]
+ const i = this.psArr.findIndex(i => i.Path === path)
+ if (i > -1 && this.psArr[i].PS) {
+ ps = parseFloat(this.psArr[i].PS).toFixed(3)
+ }
+ if (ps) {
+ textLines.push(`Area: ${this.reRound(csUtils.roundNumber(area * ps * ps), this.digitPlaces)} ${'mm' + '\xb2'}`)
+ } else {
+ textLines.push(`Area: ${this.reRound(csUtils.roundNumber(area), this.digitPlaces)} ${areaUnit}`)
+ }
+ textLines.push(`Mean: ${this.reRound(csUtils.roundNumber(mean), this.digitPlaces)} ${modalityUnit}`)
+ textLines.push(`Max: ${this.reRound(csUtils.roundNumber(max), this.digitPlaces)} ${modalityUnit}`)
+ textLines.push(`Std Dev: ${this.reRound(csUtils.roundNumber(stdDev), this.digitPlaces)} ${modalityUnit}`)
+
+ return textLines
+ },
+ // 圆形工具注释信息
+ getCircleROIToolTextLines(data, targetId) {
+ const cachedVolumeStats = data.cachedStats[targetId]
+ const { area, mean, max, stdDev, areaUnit, modalityUnit } = cachedVolumeStats
+
+ if (mean === undefined) {
+ return
+ }
+
+ const textLines = []
+ let ps = null
+ const path = targetId.split(`web:${this.OSSclientConfig.basePath}`)[1]
+ const i = this.psArr.findIndex(i => i.Path === path)
+ if (i > -1 && this.psArr[i].PS) {
+ ps = parseFloat(this.psArr[i].PS).toFixed(3)
+ }
+ if (ps) {
+ textLines.push(`Area: ${this.reRound(csUtils.roundNumber(area * ps * ps), this.digitPlaces)} ${'mm' + '\xb2'}`)
+ } else {
+ textLines.push(`Area: ${this.reRound(csUtils.roundNumber(area), this.digitPlaces)} ${areaUnit}`)
+ }
+ textLines.push(`Mean: ${this.reRound(csUtils.roundNumber(mean), this.digitPlaces)} ${modalityUnit}`)
+ textLines.push(`Max: ${this.reRound(csUtils.roundNumber(max), this.digitPlaces)} ${modalityUnit}`)
+ textLines.push(`Std Dev: ${this.reRound(csUtils.roundNumber(stdDev), this.digitPlaces)} ${modalityUnit}`)
+
+ return textLines
+ },
reRound(result, finalPrecision) {
if (typeof result === 'string' && result.includes(', ')) {
const numStrs = result.split(', ')
@@ -1105,7 +1173,7 @@ export default {
processSingle(str, precision) {
const num = parseFloat(str)
if (isNaN(num)) return 'NaN'
-
+
// 保留原极小值处理逻辑
if (Math.abs(num) < 0.0001) return str
const factor = 10 ** precision
@@ -1113,7 +1181,7 @@ export default {
},
debounce(callback, delay) {
let timerId
- return function() {
+ return function () {
clearTimeout(timerId)
timerId = setTimeout(() => {
callback.apply(this, arguments)
@@ -1226,9 +1294,10 @@ export default {
.none-dicom-viewer {
display: flex;
flex-direction: column;
- width:100%;
+ width: 100%;
height: 100%;
user-select: none;
+
.tools-wrapper {
height: 50px;
display: flex;
@@ -1236,6 +1305,7 @@ export default {
border-bottom: 1px solid #727272;
color: #ddd;
padding: 0 5px;
+
.tools-left {
flex: 1;
display: flex;
@@ -1243,6 +1313,7 @@ export default {
justify-content: flex-start;
align-items: center;
}
+
.tool-item {
padding: 5px;
margin: 0 5px;
@@ -1250,15 +1321,19 @@ export default {
font-size: 20px;
cursor: pointer;
}
+
.tool-item-active {
background-color: #607d8b;
}
+
.tool-disabled {
cursor: not-allowed;
}
}
+
.viewports-wrapper {
flex: 1;
+
.grid-container {
display: grid;
height: 100%;
@@ -1267,26 +1342,32 @@ export default {
}
.grid-cell {
- border: 1px dashed #ccc;;
+ border: 1px dashed #ccc;
+ ;
display: flex;
align-items: center;
justify-content: center;
}
+
.cell_active {
- border-color: #fafa00!important;
+ border-color: #fafa00 !important;
}
+
.cell-full-screen {
grid-column: 1 / -1;
grid-row: 1 / -1;
}
+
.flex_col {
display: flex;
flex-direction: column;
}
+
.content {
width: 100%;
height: 100%;
position: relative;
+
.left-top-text {
position: absolute;
left: 5px;
@@ -1294,26 +1375,31 @@ export default {
color: #ddd;
z-index: 1;
font-size: 12px;
+
.cd-info {
color: #ddd;
font-size: 18px;
}
+
.subject-info {
- color:#f44336;
+ color: #f44336;
padding: 5px 0px;
margin: 0;
}
}
+
.top-center-tool {
position: absolute;
- left:50%;
+ left: 50%;
top: 5px;
transform: translateX(-50%);
z-index: 1;
+
.toggle-visit-container {
display: flex;
}
- .arrw_icon{
+
+ .arrw_icon {
width: 20px;
height: 20px;
background-color: #3f3f3f;
@@ -1321,15 +1407,17 @@ export default {
line-height: 20px;
border-radius: 10%;
}
- .arrow_text{
+
+ .arrow_text {
height: 20px;
line-height: 20px;
background-color: #00000057;
color: #fff;
- padding:0 10px;
+ padding: 0 10px;
font-size: 14px;
}
}
+
.right-slider-box {
position: absolute;
right: 1px;
@@ -1341,7 +1429,8 @@ export default {
z-index: 1;
cursor: pointer;
}
- .right-slider-box:after{
+
+ .right-slider-box:after {
content: '';
position: absolute;
bottom: -20px;
@@ -1350,33 +1439,39 @@ export default {
width: 100%;
background: #333;
}
+
.slider {
height: 20px;
width: 100%;
position: absolute;
top: 0;
- z-index:10;
+ z-index: 10;
background: #9e9e9e;
cursor: move
}
}
}
- ::v-deep .el-dialog{
+
+ ::v-deep .el-dialog {
background: #1e1e1e;
border: 1px solid #ddd;
color: #ddd;
- .el-dialog__title{
- color:#fff;
+
+ .el-dialog__title {
+ color: #fff;
}
- .el-input .el-input__inner{
+
+ .el-input .el-input__inner {
background-color: transparent;
color: #ddd;
border: 1px solid #5e5e5e;
}
- .el-input.is-disabled .el-input__inner{
+
+ .el-input.is-disabled .el-input__inner {
background-color: #646464a1;
}
- .el-form-item__label{
+
+ .el-form-item__label {
color: #dfdfdf
}
}
diff --git a/src/views/trials/trials-panel/reading/visit-review/components/ReadPage.vue b/src/views/trials/trials-panel/reading/visit-review/components/ReadPage.vue
index d65167fb..e99466ee 100644
--- a/src/views/trials/trials-panel/reading/visit-review/components/ReadPage.vue
+++ b/src/views/trials/trials-panel/reading/visit-review/components/ReadPage.vue
@@ -264,7 +264,7 @@ export default {
if (typeof i.MeasureData === 'string') {
i.MeasureData = JSON.parse(i.MeasureData)
}
- if (i.MeasureData.metadata.toolName === 'Length' && this.psArr.findIndex(p => p.NoneDicomFileId === i.NoneDicomFileId) === -1) {
+ if (i.MeasureData.metadata.toolName === 'Lengthscale' && this.psArr.findIndex(p => p.NoneDicomFileId === i.NoneDicomFileId) === -1) {
this.psArr.push({ NoneDicomFileId: i.NoneDicomFileId, Path: i.Path, PS: i.MeasureData.data.ps })
}
return i
diff --git a/src/views/trials/trials-panel/reading/visit-review/tools/LengthscaleTool.js b/src/views/trials/trials-panel/reading/visit-review/tools/LengthscaleTool.js
new file mode 100644
index 00000000..0f5b2d56
--- /dev/null
+++ b/src/views/trials/trials-panel/reading/visit-review/tools/LengthscaleTool.js
@@ -0,0 +1,11 @@
+import * as cornerstoneTools from '@cornerstonejs/tools'
+class LengthscaleTool extends cornerstoneTools.LengthTool {
+ static { this.toolName = 'Lengthscale'; }
+ constructor(
+ toolProps,
+ defaultToolProps
+ ) {
+ super(toolProps, defaultToolProps);
+ }
+}
+export default LengthscaleTool;
-
@@ -224,14 +199,8 @@
-
+
+
-
+
-
+
{{ `${taskInfo.SubjectCode} ${v.taskInfo.TaskBlindName} ` }}
-
+
+
-
+ @dblclick.stop="preventDefault($event)">
{{ v.taskInfo.TaskBlindName }}
-
+ @dblclick.stop="preventDefault($event)">
-
+