mpr阅片
continuous-integration/drone/push Build is passing
Details
continuous-integration/drone/push Build is passing
Details
parent
1b6f48a5a5
commit
ae536a7fc4
|
|
@ -161,7 +161,7 @@
|
|||
<svg-icon v-else icon-class="fitToImage" class="svg-icon" />
|
||||
</div>
|
||||
<!-- MPR -->
|
||||
<div class="tool-item" :title="`${$t('trials:reading:button:mpr')}`" @click.prevent="openMPRViewport"
|
||||
<div class="tool-item" :title="`${$t('trials:reading:button:mpr')}`" @click.prevent="openMPRViewport()"
|
||||
v-if="criterionType === 0 && readingTool === 0">
|
||||
<svg-icon icon-class="mpr" class="svg-icon" />
|
||||
</div>
|
||||
|
|
@ -308,7 +308,7 @@
|
|||
<div v-if="criterionType === 0 && readingTool === 0"
|
||||
:class="['viewports-box', !isMPR ? 'viewports-box-down' : '']" :style="gridStyle">
|
||||
<div v-for="(v, index) in 3" :key="`viewport-volume-${index}`" :style="cellStyle"
|
||||
:class="['grid-cell', isMPR && index === 2 ? 'grid-cell-3' : '', index === activeViewportIndex ? 'cell_active' : '', index === fullScreenIndex ? 'cell-full-screen' : '']"
|
||||
:class="['grid-cell', isMPR && index === 0 ? 'grid-cell-3' : '', index === activeViewportIndex ? 'cell_active' : '', index === fullScreenIndex ? 'cell-full-screen' : '']"
|
||||
@dblclick="toggleFullScreen($event, index)" @click="activeViewport(index)">
|
||||
<VolumeViewport :ref="`viewport-volume-${index}`" :data-viewport-uid="`viewport-volume-${index}`"
|
||||
:rendering-engine-id="renderingEngineId" :viewport-id="`viewport-volume-${index}`"
|
||||
|
|
@ -672,8 +672,8 @@ export default {
|
|||
gridStyle() {
|
||||
return {
|
||||
display: 'grid',
|
||||
gridTemplateRows: `repeat(${this.rows}, 1fr)`,
|
||||
gridTemplateColumns: `repeat(${this.cols}, 1fr)`,
|
||||
gridTemplateRows: `repeat(${this.isMPR ? 2 : this.rows}, 1fr)`,
|
||||
gridTemplateColumns: `repeat(${this.isMPR ? 2 : this.cols}, 1fr)`,
|
||||
height: '100%',
|
||||
width: '100%'
|
||||
}
|
||||
|
|
@ -1510,6 +1510,7 @@ export default {
|
|||
annotation.visitTaskId = series.TaskInfo.VisitTaskId
|
||||
annotation.studyId = series.StudyId
|
||||
annotation.seriesId = series.Id
|
||||
annotation.from = this.isMPR ? 'MPR' : this.isFusion ? "Fusion" : ''
|
||||
annotation.instanceId = params.instanceId
|
||||
annotation.sliceThickness = series.SliceThickness
|
||||
annotation.numberOfFrames = isNaN(parseInt(params.frame)) ? null : parseInt(params.frame)
|
||||
|
|
@ -2683,7 +2684,7 @@ export default {
|
|||
}
|
||||
return obj
|
||||
},
|
||||
getMarkedSeries(studyList, annotation) {
|
||||
getMarkedSeries(studyList, annotation, checkFrom = false) {
|
||||
let obj = {}
|
||||
const sIdx = studyList.findIndex(s => s.StudyId === annotation.studyId)
|
||||
if (sIdx > -1) {
|
||||
|
|
@ -2709,18 +2710,37 @@ export default {
|
|||
obj.IsMarked = true
|
||||
obj.MeasureData = annotation
|
||||
}
|
||||
if (annotation.from === 'MPR' && checkFrom) {
|
||||
obj = Object.assign({}, seriesList[seriesIdx])
|
||||
obj.SliceIndex = annotation?.metadata?.sliceIndex
|
||||
obj.IsMarked = true
|
||||
obj.MeasureData = annotation
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
return obj
|
||||
},
|
||||
viewCustomAnnotationSeries(obj) {
|
||||
async viewCustomAnnotationSeries(obj) {
|
||||
const i = this.visitTaskList.findIndex(i => i.VisitTaskId === obj.visitTaskId)
|
||||
if (i === -1) return
|
||||
const studyList = this.visitTaskList[i].StudyList
|
||||
const series = this.getMarkedSeries(studyList, obj.annotation)
|
||||
const series = this.getMarkedSeries(studyList, obj.annotation, true)
|
||||
if (series) {
|
||||
this.$refs[`${this.viewportKey}-${this.cells.length - 1}`][0].setSeriesInfo(series, true)
|
||||
this.activeViewportIndex = i
|
||||
this.activeViewportIndex = this.cells.length - 1
|
||||
if (obj.annotation.from === 'MPR') {
|
||||
let res = await this.openMPRViewport(series)
|
||||
let viewPlaneNormal = obj.annotation?.metadata?.viewPlaneNormal.map(i => i == 0 ? 0 : i).join(',')
|
||||
if (viewPlaneNormal === '0,0,-1') {
|
||||
this.activeViewportIndex = 0
|
||||
} else if (viewPlaneNormal === '0,-1,0') {
|
||||
this.activeViewportIndex = 1
|
||||
} else if (viewPlaneNormal === '1,0,0') {
|
||||
this.activeViewportIndex = 2
|
||||
}
|
||||
if (!res) return false
|
||||
}
|
||||
this.$refs[`${this.viewportKey}-${this.activeViewportIndex}`][0].setSeriesInfo(series, true)
|
||||
this.$refs[series.TaskInfo.VisitTaskId][0].setSeriesActive(series.StudyIndex, series.SeriesIndex)
|
||||
}
|
||||
},
|
||||
|
|
@ -2728,17 +2748,29 @@ export default {
|
|||
const i = this.visitTaskList.findIndex(i => i.VisitTaskId === obj.visitTaskId)
|
||||
if (i === -1) return
|
||||
const studyList = this.visitTaskList[i].StudyList
|
||||
const series = this.getMarkedSeries(studyList, obj.annotation)
|
||||
const series = this.getMarkedSeries(studyList, obj.annotation, true)
|
||||
if (series) {
|
||||
this.$refs[`${this.viewportKey}-${this.cells.length - 1}`][0].setSeriesInfo(series, true)
|
||||
this.activeViewportIndex = i
|
||||
this.activeViewportIndex = this.cells.length - 1
|
||||
if (obj.annotation.from === 'MPR') {
|
||||
let viewPlaneNormal = obj.annotation?.metadata?.viewPlaneNormal.map(i => i == 0 ? 0 : i).join(',')
|
||||
if (viewPlaneNormal === '0,0,-1') {
|
||||
this.activeViewportIndex = 0
|
||||
} else if (viewPlaneNormal === '0,-1,0') {
|
||||
this.activeViewportIndex = 1
|
||||
} else if (viewPlaneNormal === '1,0,0') {
|
||||
this.activeViewportIndex = 2
|
||||
}
|
||||
}
|
||||
this.$refs[`${this.viewportKey}-${this.activeViewportIndex}`][0].setSeriesInfo(series, true)
|
||||
this.$refs[series.TaskInfo.VisitTaskId][0].setSeriesActive(series.StudyIndex, series.SeriesIndex)
|
||||
const divForDownloadViewport = document.querySelector(
|
||||
`div[data-viewport-uid="${this.viewportKey}-${this.activeViewportIndex}"]`
|
||||
)
|
||||
const canvas = await html2canvas(divForDownloadViewport)
|
||||
const base64Str = canvas.toDataURL('image/png', 1)
|
||||
callback(base64Str)
|
||||
setTimeout(async () => {
|
||||
const divForDownloadViewport = document.querySelector(
|
||||
`div[data-viewport-uid="${this.viewportKey}-${this.activeViewportIndex}"]`
|
||||
)
|
||||
const canvas = await html2canvas(divForDownloadViewport)
|
||||
const base64Str = canvas.toDataURL('image/png', 1)
|
||||
callback(base64Str)
|
||||
}, 500)
|
||||
}
|
||||
},
|
||||
async getScreenshots(measureData, callback) {
|
||||
|
|
@ -3090,24 +3122,29 @@ export default {
|
|||
this.$refs[id][0].voiChange(v)
|
||||
})
|
||||
},
|
||||
async openMPRViewport() {
|
||||
this.isMPR = true
|
||||
this.rows = 2
|
||||
this.cols = 2
|
||||
this.loading = true
|
||||
this.loadingText = this.$t('trials:lugano:message:loadVolumes')
|
||||
const series = this.$refs[`viewport-${this.activeViewportIndex}`][0].series
|
||||
this.activeViewportIndex = 0
|
||||
this.$refs[`viewport-0`][0].setSeriesInfo(series)
|
||||
this.$refs[`viewport-1`][0].setSeriesInfo(series)
|
||||
this.$refs[`viewport-2`][0].setSeriesInfo(series)
|
||||
this.$refs[`viewport-3`][0].setSeriesInfo(series)
|
||||
await this.getVolume(series)
|
||||
this.loading = false
|
||||
this.loadingText = null
|
||||
this.$refs[`viewport-volume-0`][0].setSeriesInfo(Object.assign({ orientation: 'AXIAL' }, series))
|
||||
this.$refs[`viewport-volume-1`][0].setSeriesInfo(Object.assign({ orientation: 'CORONAL' }, series))
|
||||
this.$refs[`viewport-volume-2`][0].setSeriesInfo(Object.assign({ orientation: 'SAGITTAL' }, series))
|
||||
async openMPRViewport(data = null) {
|
||||
return new Promise(async (resolve, reject) => {
|
||||
if (this.isMPR) return resolve(true)
|
||||
this.isMPR = true
|
||||
this.rows = 3
|
||||
this.cols = 1
|
||||
this.loading = true
|
||||
this.loadingText = this.$t('trials:lugano:message:loadVolumes')
|
||||
const series = data ? data : this.$refs[`viewport-${this.activeViewportIndex}`][0].series
|
||||
this.activeViewportIndex = 0
|
||||
// this.$refs[`viewport-0`][0].setSeriesInfo(series)
|
||||
// this.$refs[`viewport-1`][0].setSeriesInfo(series)
|
||||
// this.$refs[`viewport-2`][0].setSeriesInfo(series)
|
||||
// this.$refs[`viewport-3`][0].setSeriesInfo(series)
|
||||
await this.getVolume(series)
|
||||
this.loading = false
|
||||
this.loadingText = null
|
||||
this.$refs[`viewport-volume-0`][0].setSeriesInfo(Object.assign({ orientation: 'AXIAL' }, series))
|
||||
this.$refs[`viewport-volume-1`][0].setSeriesInfo(Object.assign({ orientation: 'CORONAL' }, series))
|
||||
this.$refs[`viewport-volume-2`][0].setSeriesInfo(Object.assign({ orientation: 'SAGITTAL' }, series))
|
||||
resolve(false)
|
||||
})
|
||||
|
||||
},
|
||||
async handleFusion(data) {
|
||||
try {
|
||||
|
|
@ -3570,7 +3607,7 @@ export default {
|
|||
}
|
||||
|
||||
.grid-cell-3 {
|
||||
grid-column: 2 / 3;
|
||||
grid-column: 0 / 3;
|
||||
grid-row: 1 / 3;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@
|
|||
{{ `${series.TaskInfo.SubjectCode} ${series.TaskInfo.TaskBlindName} ` }}
|
||||
</h2>
|
||||
<div>Series: #{{ series.SeriesNumber }}</div>
|
||||
<div v-if="series.Stack">Image: #{{ `${series.SliceIndex + 1}/${imageInfo.total}` }}</div>
|
||||
<div v-if="imageInfo.total">Image: #{{ `${series.SliceIndex + 1}/${imageInfo.total}` }}</div>
|
||||
<div>{{ series.Modality }}</div>
|
||||
</div>
|
||||
<div v-if="series" class="right-top-text">
|
||||
|
|
@ -40,10 +40,10 @@
|
|||
<div v-if="series" class="right-bottom-text">
|
||||
<div v-show="imageInfo.location">Location: {{
|
||||
`${Number(imageInfo.location).toFixed(digitPlaces)} mm`
|
||||
}}</div>
|
||||
<div v-show="series.SliceThickness">Slice Thickness: {{
|
||||
`${Number(series.SliceThickness).toFixed(digitPlaces)} mm`
|
||||
}}</div>
|
||||
}}</div>
|
||||
<div v-show="imageInfo.sliceThickness">Slice Thickness: {{
|
||||
`${Number(imageInfo.sliceThickness).toFixed(digitPlaces)} mm`
|
||||
}}</div>
|
||||
<div v-show="imageInfo.wwwc">WW/WL: {{ imageInfo.wwwc }}</div>
|
||||
</div>
|
||||
<div class="orientation-top">
|
||||
|
|
@ -117,7 +117,8 @@ export default {
|
|||
location: null,
|
||||
sliceThickness: null,
|
||||
wwwc: null,
|
||||
total: 0
|
||||
total: 0,
|
||||
sliceThickness: 0
|
||||
},
|
||||
digitPlaces: 2,
|
||||
orientationMarkers: [],
|
||||
|
|
@ -194,21 +195,24 @@ export default {
|
|||
this.imageInfo.zoom = zoom.toFixed(4)
|
||||
let imageIds = viewport.getImageIds(this.volumeId)
|
||||
let imageId = imageIds[0]
|
||||
if (this.series.orientation === 'AXIAL') imageId = viewport.getCurrentImageId()
|
||||
// if (this.series.orientation === 'AXIAL') imageId = viewport.getCurrentImageId()
|
||||
if (imageId) {
|
||||
const imagePlaneModule = metaData.get('imagePlaneModule', imageId)
|
||||
if (this.series.orientation === 'AXIAL') {
|
||||
this.imageInfo.size = `${imagePlaneModule.columns}*${imagePlaneModule.rows}`
|
||||
this.imageInfo.location = imagePlaneModule.sliceLocation
|
||||
this.imageInfo.total = imageIds.length
|
||||
this.imageInfo.sliceThickness = imagePlaneModule.sliceThickness
|
||||
}
|
||||
if (this.series.orientation === 'CORONAL') {
|
||||
this.imageInfo.size = `${imagePlaneModule.columns}*${imageIds.length}`
|
||||
this.imageInfo.total = imagePlaneModule.rows
|
||||
this.imageInfo.sliceThickness = imagePlaneModule.rowPixelSpacing
|
||||
}
|
||||
if (this.series.orientation === 'SAGITTAL') {
|
||||
this.imageInfo.size = `${imagePlaneModule.rows}*${imageIds.length}`
|
||||
this.imageInfo.total = imagePlaneModule.columns
|
||||
this.imageInfo.sliceThickness = imagePlaneModule.columnPixelSpacing
|
||||
}
|
||||
|
||||
this.getOrientationMarker()
|
||||
|
|
@ -395,15 +399,16 @@ export default {
|
|||
})
|
||||
this.loading = false
|
||||
},
|
||||
async setSeriesInfo(obj) {
|
||||
async setSeriesInfo(obj, isLocate = false) {
|
||||
try {
|
||||
let data = obj
|
||||
if (this.series && data.Id === this.series.Id && data.Description === this.series.Description) {
|
||||
if (this.series && data.Id === this.series.Id && data.Description === this.series.Description && !isLocate) {
|
||||
data.SliceIndex = this.series.SliceIndex
|
||||
}
|
||||
this.series = {}
|
||||
const renderingEngine = getRenderingEngine(this.renderingEngineId)
|
||||
const viewport = renderingEngine.getViewport(this.viewportId)
|
||||
if (isLocate) return csUtils.jumpToSlice(viewport.element, { imageIndex: data.SliceIndex });
|
||||
this.series = {}
|
||||
this.volumeId = data.SeriesInstanceUid
|
||||
this.series = { ...data }
|
||||
viewport
|
||||
|
|
@ -456,8 +461,8 @@ export default {
|
|||
clickSlider(e) {
|
||||
const height = e.offsetY * 100 / this.$refs['sliderBox'].clientHeight
|
||||
this.sliderInfo.height = height
|
||||
let sliceIdx = Math.trunc(this.series.Stack.length * height / 100)
|
||||
sliceIdx = sliceIdx >= this.series.Stack.length ? this.series.Stack.length - 1 : sliceIdx < 0 ? 0 : sliceIdx
|
||||
let sliceIdx = Math.trunc(this.imageInfo.total * height / 100)
|
||||
sliceIdx = sliceIdx >= this.imageInfo.total ? this.imageInfo.total : sliceIdx < 0 ? 0 : sliceIdx
|
||||
const renderingEngine = getRenderingEngine(this.renderingEngineId)
|
||||
const viewport = renderingEngine.getViewport(
|
||||
this.viewportId
|
||||
|
|
@ -486,8 +491,8 @@ export default {
|
|||
if (delta < 0) return
|
||||
if (delta > boxHeight) return
|
||||
const height = delta * 100 / boxHeight
|
||||
let sliceIdx = Math.trunc(this.series.Stack.length * height / 100)
|
||||
sliceIdx = sliceIdx >= this.series.Stack.length ? this.series.Stack.length - 1 : sliceIdx < 0 ? 0 : sliceIdx
|
||||
let sliceIdx = Math.trunc(this.imageInfo.total * height / 100)
|
||||
sliceIdx = sliceIdx >= this.imageInfo.total ? this.imageInfo.total - 1 : sliceIdx < 0 ? 0 : sliceIdx
|
||||
this.sliderInfo.height = height
|
||||
const renderingEngine = getRenderingEngine(this.renderingEngineId)
|
||||
const viewport = renderingEngine.getViewport(
|
||||
|
|
|
|||
|
|
@ -1244,9 +1244,14 @@ export default {
|
|||
},
|
||||
getAnnotationProp(annotation, prop) {
|
||||
if (!annotation) return
|
||||
const referencedImageId = annotation?.metadata?.referencedImageId
|
||||
let referencedImageId = null
|
||||
if (annotation.from) {
|
||||
referencedImageId = `${annotation?.metadata?.volumeId}?sliceIndex=${annotation?.metadata?.sliceIndex}&viewPlaneNormal=${annotation?.metadata?.viewPlaneNormal.map(i => i == 0 ? 0 : i).join(',')}`
|
||||
} else {
|
||||
referencedImageId = annotation?.metadata?.referencedImageId
|
||||
}
|
||||
if (!referencedImageId) return null
|
||||
const cacheKey = `imageId:${referencedImageId}`
|
||||
const cacheKey = annotation.from ? `volumeId:${referencedImageId}` : `imageId:${referencedImageId}`
|
||||
const cachedStats = annotation.data?.cachedStats?.[cacheKey]
|
||||
const hasProp = cachedStats
|
||||
&& Object.prototype.hasOwnProperty.call(cachedStats, prop)
|
||||
|
|
|
|||
|
|
@ -943,9 +943,14 @@ export default {
|
|||
},
|
||||
getAnnotationProp(annotation, prop) {
|
||||
if (!annotation || !prop) return
|
||||
const referencedImageId = annotation?.metadata?.referencedImageId
|
||||
let referencedImageId = null
|
||||
if (annotation.from) {
|
||||
referencedImageId = `${annotation?.metadata?.volumeId}?sliceIndex=${annotation?.metadata?.sliceIndex}&viewPlaneNormal=${annotation?.metadata?.viewPlaneNormal.map(i => i == 0 ? 0 : i).join(',')}`
|
||||
} else {
|
||||
referencedImageId = annotation?.metadata?.referencedImageId
|
||||
}
|
||||
if (!referencedImageId) return null
|
||||
const cacheKey = `imageId:${referencedImageId}`
|
||||
const cacheKey = annotation.from ? `volumeId:${referencedImageId}` : `imageId:${referencedImageId}`
|
||||
const cachedStats = annotation.data?.cachedStats?.[cacheKey]
|
||||
const hasProp = cachedStats
|
||||
&& Object.prototype.hasOwnProperty.call(cachedStats, prop)
|
||||
|
|
|
|||
Loading…
Reference in New Issue