314 lines
8.0 KiB
Plaintext
314 lines
8.0 KiB
Plaintext
|
|
import * as cornerstoneTools from 'cornerstone-tools'
|
|
const external = cornerstoneTools.external
|
|
// Drawing
|
|
const getNewContext = cornerstoneTools.import('drawing/getNewContext')
|
|
const draw = cornerstoneTools.import('drawing/draw')
|
|
const setShadow = cornerstoneTools.import('drawing/setShadow')
|
|
const drawLine = cornerstoneTools.import('drawing/drawLine')
|
|
|
|
const toolStyle = cornerstoneTools.toolStyle
|
|
// const toolColors = cornerstoneTools.toolColors
|
|
const color = '#fff'
|
|
|
|
/**
|
|
* @public
|
|
* @class ScaleOverlayTool
|
|
* @memberof Tools
|
|
*
|
|
* @classdesc Tool for displaying a scale overlay on the image.
|
|
* @extends Tools.Base.BaseTool
|
|
*/
|
|
export default class ScaleOverlayTool extends cornerstoneTools.ScaleOverlayTool {
|
|
constructor(props = {}) {
|
|
const defaultProps = {
|
|
name: 'ScaleOverlay',
|
|
configuration: {
|
|
minorTickLength: 5,
|
|
majorTickLength: 10
|
|
},
|
|
mixins: ['enabledOrDisabledBinaryTool']
|
|
}
|
|
|
|
super(props, defaultProps)
|
|
}
|
|
|
|
enabledCallback(element) {
|
|
this.forceImageUpdate(element)
|
|
}
|
|
|
|
disabledCallback(element) {
|
|
this.forceImageUpdate(element)
|
|
}
|
|
|
|
forceImageUpdate(element) {
|
|
const enabledElement = external.cornerstone.getEnabledElement(element)
|
|
|
|
if (enabledElement.image) {
|
|
external.cornerstone.updateImage(element)
|
|
}
|
|
}
|
|
|
|
renderToolData(evt) {
|
|
const eventData = evt.detail
|
|
|
|
const context = getNewContext(eventData.canvasContext.canvas)
|
|
const { image, viewport, element } = eventData
|
|
|
|
let rowPixelSpacing = image.rowPixelSpacing
|
|
let colPixelSpacing = image.columnPixelSpacing
|
|
const imagePlane = external.cornerstone.metaData.get(
|
|
'imagePlaneModule',
|
|
image.imageId
|
|
)
|
|
|
|
if (imagePlane) {
|
|
rowPixelSpacing =
|
|
imagePlane.rowPixelSpacing || imagePlane.rowImagePixelSpacing
|
|
colPixelSpacing =
|
|
imagePlane.columnPixelSpacing || imagePlane.colImagePixelSpacing
|
|
}
|
|
|
|
// Check whether pixel spacing is defined
|
|
if (!rowPixelSpacing || !colPixelSpacing) {
|
|
// logger.warn(
|
|
// `unable to define rowPixelSpacing or colPixelSpacing from data on ${this.name}'s renderToolData`
|
|
// )
|
|
|
|
return
|
|
}
|
|
|
|
const canvasSize = {
|
|
width: context.canvas.width,
|
|
height: context.canvas.height
|
|
}
|
|
|
|
// Distance between intervals is 10mm
|
|
const verticalIntervalScale = (10.0 / rowPixelSpacing) * viewport.scale
|
|
const horizontalIntervalScale = (10.0 / colPixelSpacing) * viewport.scale
|
|
// 0.1 and 0.05 gives margin to horizontal and vertical lines
|
|
// const hscaleBounds = computeScaleBounds(canvasSize, 0.25, 0.05)
|
|
// const vscaleBounds = computeScaleBounds(canvasSize, 0.05, 0.15)
|
|
const hscaleBounds = computeScaleBounds(canvasSize, 0.4, 0.04)
|
|
const vscaleBounds = computeScaleBounds(canvasSize, 0.04, 0.4)
|
|
|
|
if (
|
|
!canvasSize.width ||
|
|
!canvasSize.height ||
|
|
!hscaleBounds ||
|
|
!vscaleBounds
|
|
) {
|
|
return
|
|
}
|
|
|
|
// const color = toolColors.getToolColor()
|
|
const lineWidth = toolStyle.getToolWidth()
|
|
|
|
const imageAttributes = Object.assign(
|
|
{},
|
|
{
|
|
hscaleBounds,
|
|
vscaleBounds,
|
|
verticalMinorTick: verticalIntervalScale,
|
|
horizontalMinorTick: horizontalIntervalScale,
|
|
verticalLine: {
|
|
start: {
|
|
x: vscaleBounds.bottomRight.x,
|
|
y: vscaleBounds.topLeft.y
|
|
},
|
|
end: {
|
|
x: vscaleBounds.bottomRight.x,
|
|
y: vscaleBounds.bottomRight.y
|
|
}
|
|
},
|
|
horizontalLine: {
|
|
start: {
|
|
x: hscaleBounds.topLeft.x,
|
|
y: hscaleBounds.bottomRight.y
|
|
},
|
|
end: {
|
|
x: hscaleBounds.bottomRight.x,
|
|
y: hscaleBounds.bottomRight.y
|
|
}
|
|
},
|
|
color,
|
|
lineWidth
|
|
},
|
|
this.configuration
|
|
)
|
|
|
|
draw(context, context => {
|
|
setShadow(context, imageAttributes)
|
|
|
|
// Draw vertical line
|
|
drawLine(
|
|
context,
|
|
element,
|
|
imageAttributes.verticalLine.start,
|
|
imageAttributes.verticalLine.end,
|
|
{
|
|
color: imageAttributes.color,
|
|
lineWidth: imageAttributes.lineWidth
|
|
},
|
|
'canvas'
|
|
)
|
|
drawVerticalScalebarIntervals(context, element, imageAttributes)
|
|
|
|
// Draw horizontal line
|
|
drawLine(
|
|
context,
|
|
element,
|
|
imageAttributes.horizontalLine.start,
|
|
imageAttributes.horizontalLine.end,
|
|
{
|
|
color: imageAttributes.color,
|
|
lineWidth: imageAttributes.lineWidth
|
|
},
|
|
'canvas'
|
|
)
|
|
drawHorizontalScalebarIntervals(context, element, imageAttributes)
|
|
})
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Computes the max bound for scales on the image
|
|
* @param {{width: number, height: number}} canvasSize
|
|
* @param {number} horizontalReduction
|
|
* @param {number} verticalReduction
|
|
* @returns {Object.<string, { x:number, y:number }>}
|
|
*/
|
|
const computeScaleBounds = (
|
|
canvasSize,
|
|
horizontalReduction,
|
|
verticalReduction
|
|
) => {
|
|
const hReduction = horizontalReduction * Math.min(1000, canvasSize.width)
|
|
const vReduction = verticalReduction * Math.min(1000, canvasSize.height)
|
|
const canvasBounds = {
|
|
left: hReduction,
|
|
top: vReduction,
|
|
width: canvasSize.width - 2 * hReduction,
|
|
height: canvasSize.height - 2 * vReduction
|
|
}
|
|
|
|
return {
|
|
topLeft: {
|
|
x: canvasBounds.left,
|
|
y: canvasBounds.top
|
|
},
|
|
bottomRight: {
|
|
x: canvasBounds.left + canvasBounds.width,
|
|
y: canvasBounds.top + canvasBounds.height
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @param {CanvasRenderingContext2D} context
|
|
* @param {HTMLElement} element
|
|
* @param {Object} imageAttributes
|
|
* @returns {void}
|
|
*/
|
|
const drawVerticalScalebarIntervals = (context, element, imageAttributes) => {
|
|
let i = 0
|
|
|
|
while (
|
|
imageAttributes.verticalLine.start.y +
|
|
i * imageAttributes.verticalMinorTick <=
|
|
imageAttributes.vscaleBounds.bottomRight.y
|
|
) {
|
|
const { color, lineWidth } = imageAttributes
|
|
const startPoint = {
|
|
x: imageAttributes.verticalLine.start.x,
|
|
y:
|
|
imageAttributes.verticalLine.start.y +
|
|
i * imageAttributes.verticalMinorTick
|
|
}
|
|
|
|
const endPoint = {
|
|
x: 0,
|
|
y:
|
|
imageAttributes.verticalLine.start.y +
|
|
i * imageAttributes.verticalMinorTick
|
|
}
|
|
|
|
if (i % 5 === 0) {
|
|
endPoint.x =
|
|
imageAttributes.verticalLine.start.x - imageAttributes.majorTickLength
|
|
} else {
|
|
endPoint.x =
|
|
imageAttributes.verticalLine.start.x - imageAttributes.minorTickLength
|
|
}
|
|
|
|
drawLine(
|
|
context,
|
|
element,
|
|
startPoint,
|
|
endPoint,
|
|
{
|
|
color,
|
|
lineWidth
|
|
},
|
|
'canvas'
|
|
)
|
|
|
|
i++
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @param {CanvasRenderingContext2D} context
|
|
* @param {HTMLElement} element
|
|
* @param {Object} imageAttributes
|
|
* @returns {void}
|
|
*/
|
|
const drawHorizontalScalebarIntervals = (context, element, imageAttributes) => {
|
|
let i = 0
|
|
|
|
while (
|
|
imageAttributes.horizontalLine.start.x +
|
|
i * imageAttributes.horizontalMinorTick <=
|
|
imageAttributes.hscaleBounds.bottomRight.x
|
|
) {
|
|
const { color, lineWidth } = imageAttributes
|
|
const startPoint = {
|
|
x:
|
|
imageAttributes.horizontalLine.start.x +
|
|
i * imageAttributes.horizontalMinorTick,
|
|
y: imageAttributes.horizontalLine.start.y
|
|
}
|
|
|
|
const endPoint = {
|
|
x:
|
|
imageAttributes.horizontalLine.start.x +
|
|
i * imageAttributes.horizontalMinorTick,
|
|
y: 0
|
|
}
|
|
|
|
if (i % 5 === 0) {
|
|
endPoint.y =
|
|
imageAttributes.horizontalLine.start.y -
|
|
imageAttributes.majorTickLength
|
|
} else {
|
|
endPoint.y =
|
|
imageAttributes.horizontalLine.start.y -
|
|
imageAttributes.minorTickLength
|
|
}
|
|
|
|
drawLine(
|
|
context,
|
|
element,
|
|
startPoint,
|
|
endPoint,
|
|
{
|
|
color,
|
|
lineWidth
|
|
},
|
|
'canvas'
|
|
)
|
|
|
|
i++
|
|
}
|
|
}
|