ohif-viewer/Packages/ohif-lesiontracker/client/compatibility/bidirectionalTool/onImageRendered/onImageRendered.js

204 lines
7.9 KiB
JavaScript

import { cornerstone, cornerstoneMath, cornerstoneTools } from 'meteor/ohif:cornerstone';
import { OHIF } from 'meteor/ohif:core';
import { toolType } from '../definitions';
import drawHandles from './drawHandles';
import calculateLongestAndShortestDiameters from '../calculateLongestAndShortestDiameters';
import updatePerpendicularLineHandles from '../updatePerpendicularLineHandles';
import drawPerpendicularLine from './drawPerpendicularLine';
import drawSelectedMarker from './drawSelectedMarker';
export default function onImageRendered(event) {
const eventData = event.detail;
const { element, canvasContext } = eventData;
// if we have no toolData for this element, return immediately as there is nothing to do
const toolData = cornerstoneTools.getToolState(element, toolType);
if (!toolData) return;
const imagePlane = cornerstone.metaData.get('imagePlaneModule', eventData.image.imageId);
let rowPixelSpacing;
let colPixelSpacing;
if (imagePlane) {
rowPixelSpacing = imagePlane.rowPixelSpacing || imagePlane.rowImagePixelSpacing;
colPixelSpacing = imagePlane.columnPixelSpacing || imagePlane.colImagePixelSpacing;
} else {
rowPixelSpacing = eventData.image.rowPixelSpacing;
colPixelSpacing = eventData.image.columnPixelSpacing;
}
// LT-29 Disable Target Measurements when pixel spacing is not available
if (!rowPixelSpacing || !colPixelSpacing) {
return;
}
// we have tool data for this element - iterate over each one and draw it
const context = canvasContext.canvas.getContext('2d');
context.setTransform(1, 0, 0, 1, 0, 0);
let color;
const lineWidth = cornerstoneTools.toolStyle.getToolWidth();
const config = cornerstoneTools[toolType].getConfiguration();
for (let i = 0; i < toolData.data.length; i++) {
const data = toolData.data[i];
if (data.visible === false) continue;
const { start, end, perpendicularStart, perpendicularEnd, textBox } = data.handles;
const strokeWidth = lineWidth;
context.save();
// configurable shadow from CornerstoneTools
const { shadow } = config;
if (shadow && shadow.shadow) {
context.shadowColor = shadow.shadowColor || '#000000';
context.shadowOffsetX = shadow.shadowOffsetX || 1;
context.shadowOffsetY = shadow.shadowOffsetY || 1;
}
const activeColor = cornerstoneTools.toolColors.getActiveColor();
if (data.active) {
color = activeColor;
} else {
color = cornerstoneTools.toolColors.getToolColor();
}
// Update the perpendicular handles to draw it correctly
updatePerpendicularLineHandles(eventData, data);
// Draw the line
const { pixelToCanvas } = cornerstone;
const handleStartCanvas = pixelToCanvas(element, start);
const handleEndCanvas = pixelToCanvas(element, end);
const handlePerpendicularStartCanvas = pixelToCanvas(element, perpendicularStart);
const handlePerpendicularEndCanvas = pixelToCanvas(element, perpendicularEnd);
const canvasTextLocation = pixelToCanvas(element, textBox);
context.beginPath();
context.strokeStyle = color;
context.lineWidth = strokeWidth;
context.moveTo(handleStartCanvas.x, handleStartCanvas.y);
context.lineTo(handleEndCanvas.x, handleEndCanvas.y);
context.stroke();
// Draw perpendicular line
drawPerpendicularLine(context, element, data, color, strokeWidth);
// Draw the handles
const handlesColor = color;
drawHandles(context, eventData, data.handles, handlesColor, { drawHandlesIfActive: true });
// Draw the selected marker
drawSelectedMarker(eventData, data.handles, '#FF9999');
// Calculate the longest and shortest diameters, storing it in the respective attributes
calculateLongestAndShortestDiameters(eventData, data);
if (data.measurementNumber) {
// Draw the textbox
let suffix = ' mm';
if (!rowPixelSpacing || !colPixelSpacing) {
suffix = ' pixels';
}
const lengthText = ' L ' + data.longestDiameter + suffix;
const widthText = ' W ' + data.shortestDiameter + suffix;
let textLines = [`Target ${data.measurementNumber}`, lengthText, widthText];
// Append extra text lines when applies
if (data.additionalData && Array.isArray(data.additionalData.extraTextLines)) {
textLines = textLines.concat(data.additionalData.extraTextLines);
}
const boundingBox = cornerstoneTools.drawTextBox(
context,
textLines,
canvasTextLocation.x,
canvasTextLocation.y,
color,
config.textBox
);
textBox.boundingBox = boundingBox;
OHIF.cornerstone.repositionTextBox(eventData, data, config.textBox);
// Draw linked line as dashed
const link = {
start: {},
end: {}
};
const longLine = {
start: handleStartCanvas,
end: handleEndCanvas
};
const perpendicularLine = {
start: handlePerpendicularStartCanvas,
end: handlePerpendicularEndCanvas
};
// Check if the perpendicular line has some length (start and end are not equal)
// Note: this check is needed to prevent NaN value on the intersection result
const { distance } = cornerstoneMath.point;
const lineHasLength = distance(perpendicularLine.start, perpendicularLine.end) > 0;
// Define the lines intersection point
let linesIntersection;
if (lineHasLength) {
// As the line has length, define it as the intersection between the lines
const { intersectLine } = cornerstoneMath.lineSegment;
linesIntersection = intersectLine(longLine, perpendicularLine);
} else {
// As the line has no length, the tool is in its start position
linesIntersection = longLine.start;
}
const points = [
handleStartCanvas,
handleEndCanvas,
handlePerpendicularStartCanvas,
handlePerpendicularEndCanvas,
linesIntersection
];
link.end.x = canvasTextLocation.x;
link.end.y = canvasTextLocation.y;
link.start = cornerstoneMath.point.findClosestPoint(points, link.end);
const boundingBoxPoints = [ {
// Top middle point of bounding box
x: boundingBox.left + boundingBox.width / 2,
y: boundingBox.top
}, {
// Left middle point of bounding box
x: boundingBox.left,
y: boundingBox.top + boundingBox.height / 2
}, {
// Bottom middle point of bounding box
x: boundingBox.left + boundingBox.width / 2,
y: boundingBox.top + boundingBox.height
}, {
// Right middle point of bounding box
x: boundingBox.left + boundingBox.width,
y: boundingBox.top + boundingBox.height / 2
},
];
link.end = cornerstoneMath.point.findClosestPoint(boundingBoxPoints, link.start);
context.beginPath();
context.strokeStyle = color;
context.lineWidth = lineWidth;
context.setLineDash([ 2, 3 ]);
context.moveTo(link.start.x, link.start.y);
context.lineTo(link.end.x, link.end.y);
context.stroke();
}
context.restore();
}
}