irc_web/.svn/pristine/b0/b0347f7705f7bd2d48ff28590fd...

407 lines
12 KiB
Plaintext

/* eslint no-alert: 0 */
import * as cornerstoneTools from 'cornerstone-tools'
const external = cornerstoneTools.external
const EVENTS = cornerstoneTools.EVENTS
const toolStyle = cornerstoneTools.toolStyle
const textStyle = cornerstoneTools.textStyle
const toolColors = cornerstoneTools.toolColors
const pointInsideBoundingBox = cornerstoneTools.import('util/pointInsideBoundingBox')
const lineSegDistance = cornerstoneTools.import('util/lineSegDistance')
const triggerEvent = cornerstoneTools.import('util/triggerEvent')
const moveNewHandle = cornerstoneTools.import('manipulators/moveNewHandle')
const addToolState = cornerstoneTools.addToolState
const getToolState = cornerstoneTools.getToolState
const removeToolState = cornerstoneTools.removeToolState
// Drawing
const drawLinkedTextBox = cornerstoneTools.import('drawing/drawLinkedTextBox')
const getNewContext = cornerstoneTools.import('drawing/getNewContext')
const draw = cornerstoneTools.import('drawing/draw')
// import textBoxWidth from './textBoxWidth'
const setShadow = cornerstoneTools.import('drawing/setShadow')
const drawArrow = cornerstoneTools.import('drawing/drawArrow')
const drawHandles = cornerstoneTools.import('drawing/drawHandles')
const { arrowAnnotateCursor } = cornerstoneTools.import('tools/cursors')
const getModule = cornerstoneTools.getModule
/**
* @public
* @class ArrowAnnotateTool
* @memberof Tools.Annotation
* @classdesc Create and position an arrow and label
* @extends Tools.Base.BaseAnnotationTool
*/
export default class ArrowAnnotateTool extends cornerstoneTools.ArrowAnnotateTool {
constructor(props = {}) {
const defaultProps = {
name: 'ArrowAnnotate',
supportedInteractionTypes: ['Mouse', 'Touch'],
configuration: {
getTextCallback,
changeTextCallback,
drawHandles: true,
drawHandlesOnHover: false,
hideHandlesIfMoving: false,
arrowFirst: true,
renderDashed: false,
allowEmptyLabel: false
},
svgCursor: arrowAnnotateCursor
}
super(props, defaultProps)
this.preventNewMeasurement = false
}
textBoxWidth(context, text, padding) {
const font = textStyle.getFont()
const origFont = context.font
if (font && font !== origFont) {
context.font = font
}
const width = context.measureText(text).width
if (font && font !== origFont) {
context.font = origFont
}
return width + 2 * padding
}
createNewMeasurement(evt) {
// Create the measurement data for this tool with the end handle activated
return {
visible: true,
active: true,
color: undefined,
text: '',
handles: {
start: {
x: evt.detail.currentPoints.image.x,
y: evt.detail.currentPoints.image.y,
highlight: true,
active: false
},
end: {
x: evt.detail.currentPoints.image.x,
y: evt.detail.currentPoints.image.y,
highlight: true,
active: false
},
textBox: {
active: false,
hasMoved: false,
movesIndependently: false,
drawnIndependently: true,
allowedOutsideImage: true,
hasBoundingBox: true
}
}
}
}
pointNearTool(element, data, coords) {
if (data.visible === false) {
return false
}
return (
lineSegDistance(element, data.handles.start, data.handles.end, coords) <
25
)
}
updateCachedStats() {
// Implementing to satisfy BaseAnnotationTool
}
renderToolData(evt) {
const { element, enabledElement } = evt.detail
const {
handleRadius,
drawHandlesOnHover,
hideHandlesIfMoving,
renderDashed
} = this.configuration
// If we have no toolData for this element, return immediately as there is nothing to do
const toolData = getToolState(element, this.name)
if (!toolData) {
return
}
// We have tool data for this element - iterate over each one and draw it
const canvas = evt.detail.canvasContext.canvas
const context = getNewContext(canvas)
const lineWidth = toolStyle.getToolWidth()
let lineDash
if (renderDashed) {
lineDash = getModule('globalConfiguration').configuration.lineDash
}
for (let i = 0; i < toolData.data.length; i++) {
const data = toolData.data[i]
if (data.visible === false) {
continue
}
draw(context, context => {
setShadow(context, this.configuration)
const color = toolColors.getColorIfActive(data)
// Draw the arrow
const handleStartCanvas = external.cornerstone.pixelToCanvas(
element,
data.handles.start
)
const handleEndCanvas = external.cornerstone.pixelToCanvas(
element,
data.handles.end
)
// Config.arrowFirst = false;
if (this.configuration.arrowFirst) {
drawArrow(
context,
handleEndCanvas,
handleStartCanvas,
color,
lineWidth,
lineDash
)
} else {
drawArrow(
context,
handleStartCanvas,
handleEndCanvas,
color,
lineWidth,
lineDash
)
}
const handleOptions = {
color,
handleRadius,
drawHandlesIfActive: drawHandlesOnHover,
hideHandlesIfMoving
}
if (this.configuration.drawHandles) {
drawHandles(context, evt.detail, data.handles, handleOptions)
}
const text = []
if (data.hasOwnProperty('remark')) {
text.push(data.remark)
}
text.push(textBoxText(data))
// Draw the text
if (text && text !== '') {
// Calculate the text coordinates.
const padding = 5
const textWidth = this.textBoxWidth(context, text, padding)
const textHeight = textStyle.getFontSize() + 10
let distance = Math.max(textWidth, textHeight) / 2 + 5
if (handleEndCanvas.x < handleStartCanvas.x) {
distance = -distance
}
if (!data.handles.textBox.hasMoved) {
let textCoords
if (this.configuration.arrowFirst) {
textCoords = {
x: handleEndCanvas.x - textWidth / 2 + distance,
y: handleEndCanvas.y - textHeight / 2
}
} else {
// If the arrow is at the End position, the text should
// Be placed near the Start position
textCoords = {
x: handleStartCanvas.x - textWidth / 2 - distance,
y: handleStartCanvas.y - textHeight / 2
}
}
const transform = external.cornerstone.internal.getTransform(
enabledElement
)
transform.invert()
const coords = transform.transformPoint(textCoords.x, textCoords.y)
data.handles.textBox.x = coords.x
data.handles.textBox.y = coords.y
}
drawLinkedTextBox(
context,
element,
data.handles.textBox,
text,
data.handles,
textBoxAnchorPoints,
color,
lineWidth,
0,
false
)
}
})
}
function textBoxText(data) {
return data.text
}
function textBoxAnchorPoints(handles) {
const midpoint = {
x: (handles.start.x + handles.end.x) / 2,
y: (handles.start.y + handles.end.y) / 2
}
return [handles.start, midpoint, handles.end]
}
}
addNewMeasurement(evt, interactionType) {
const element = evt.detail.element
const measurementData = this.createNewMeasurement(evt)
const { allowEmptyLabel } = this.configuration
// Associate this data with this imageId so we can render it and manipulate it
addToolState(element, this.name, measurementData)
external.cornerstone.updateImage(element)
moveNewHandle(
evt.detail,
this.name,
measurementData,
measurementData.handles.end,
this.options,
interactionType,
success => {
if (success) {
if (!allowEmptyLabel && measurementData.text === undefined) {
this.configuration.getTextCallback(text => {
if (text || allowEmptyLabel) {
measurementData.text = text
measurementData.active = false
const modifiedEventData = {
toolName: this.name,
toolType: this.name, // Deprecation notice: toolType will be replaced by toolName
element,
measurementData
}
external.cornerstone.updateImage(element)
triggerEvent(
element,
EVENTS.MEASUREMENT_COMPLETED,
modifiedEventData
)
} else {
removeToolState(element, this.name, measurementData)
}
}, evt.detail)
}
} else {
removeToolState(element, this.name, measurementData)
}
triggerEvent(element, EVENTS.MEASUREMENT_COMPLETED, {
toolName: this.name,
toolType: this.name, // Deprecation notice: toolType will be replaced by toolName
element,
measurementData
})
external.cornerstone.updateImage(element)
}
)
}
doubleClickCallback(evt) {
return this._updateTextForNearbyAnnotation(evt)
}
touchPressCallback(evt) {
return this._updateTextForNearbyAnnotation(evt)
}
_updateTextForNearbyAnnotation(evt) {
const element = evt.detail.element
const coords = evt.detail.currentPoints.canvas
const toolState = getToolState(element, this.name)
if (!toolState) {
return false
}
for (let i = 0; i < toolState.data.length; i++) {
const data = toolState.data[i]
if (
this.pointNearTool(element, data, coords) ||
pointInsideBoundingBox(data.handles.textBox, coords)
) {
data.active = true
external.cornerstone.updateImage(element)
// Allow relabelling via a callback
this.configuration.changeTextCallback(
data,
evt.detail,
this._doneChangingTextCallback.bind(this, element, data)
)
evt.stopImmediatePropagation()
evt.preventDefault()
evt.stopPropagation()
return true
}
}
}
_doneChangingTextCallback(element, measurementData, updatedText, deleteTool) {
if (deleteTool === true) {
removeToolState(element, this.name, measurementData)
} else {
measurementData.text = updatedText
}
measurementData.active = false
external.cornerstone.updateImage(element)
triggerEvent(element, EVENTS.MEASUREMENT_MODIFIED, {
toolName: this.name,
toolType: this.name, // Deprecation notice: toolType will be replaced by toolName
element,
measurementData
})
}
}
function getTextCallback(doneChangingTextCallback) {
doneChangingTextCallback(prompt('Enter your annotation:'))
}
function changeTextCallback(data, eventData, doneChangingTextCallback) {
doneChangingTextCallback(prompt('Change your annotation:'))
}