234 lines
6.1 KiB
JavaScript
234 lines
6.1 KiB
JavaScript
import { importInternal, getToolState, toolColors } from 'cornerstone-tools';
|
|
|
|
import TOOL_NAMES from '../constants/toolNames';
|
|
import SCOORD_TYPES from '../constants/scoordTypes';
|
|
import id from '../id';
|
|
|
|
// Cornerstone 3rd party dev kit imports
|
|
const draw = importInternal('drawing/draw');
|
|
const drawJoinedLines = importInternal('drawing/drawJoinedLines');
|
|
const drawCircle = importInternal('drawing/drawCircle');
|
|
const drawEllipse = importInternal('drawing/drawEllipse');
|
|
const drawHandles = importInternal('drawing/drawHandles');
|
|
const getNewContext = importInternal('drawing/getNewContext');
|
|
const BaseTool = importInternal('base/BaseTool');
|
|
const drawLinkedTextBox = importInternal('drawing/drawLinkedTextBox');
|
|
|
|
/**
|
|
* @class DICOMSRDisplayTool - Renders DICOMSR data in a read only manner (i.e. as an overlay).
|
|
* @extends cornerstoneTools.BaseTool
|
|
*/
|
|
export default class DICOMSRDisplayTool extends BaseTool {
|
|
constructor(props = {}) {
|
|
const defaultProps = {
|
|
mixins: ['enabledOrDisabledBinaryTool'],
|
|
name: TOOL_NAMES.DICOM_SR_DISPLAY_TOOL,
|
|
};
|
|
|
|
const initialProps = Object.assign(defaultProps, props);
|
|
|
|
super(initialProps);
|
|
|
|
this._module = cornerstoneTools.getModule(id);
|
|
}
|
|
|
|
renderToolData(evt) {
|
|
const eventData = evt.detail;
|
|
const { element } = eventData;
|
|
const module = this._module;
|
|
|
|
const toolState = getToolState(element, this.name);
|
|
|
|
if (!toolState) {
|
|
return;
|
|
}
|
|
|
|
const trackingUniqueIdentifiersForElement = module.getters.trackingUniqueIdentifiersForElement(
|
|
element
|
|
);
|
|
|
|
const {
|
|
activeIndex,
|
|
trackingUniqueIdentifiers,
|
|
} = trackingUniqueIdentifiersForElement;
|
|
|
|
const activeTrackingUniqueIdentifier =
|
|
trackingUniqueIdentifiers[activeIndex];
|
|
|
|
// Filter toolData to only render the data for the active SR.
|
|
const filteredToolData = toolState.data.filter(td =>
|
|
trackingUniqueIdentifiers.includes(td.TrackingUniqueIdentifier)
|
|
);
|
|
|
|
for (let i = 0; i < filteredToolData.length; i++) {
|
|
const data = filteredToolData[i];
|
|
const { renderableData, labels } = data;
|
|
|
|
const color =
|
|
data.TrackingUniqueIdentifier === activeTrackingUniqueIdentifier
|
|
? toolColors.getActiveColor()
|
|
: toolColors.getToolColor();
|
|
const lineWidth = 2;
|
|
const options = {
|
|
color,
|
|
lineWidth,
|
|
handleRadius: 6,
|
|
};
|
|
|
|
Object.keys(renderableData).forEach(GraphicType => {
|
|
const renderableDataForGraphicType = renderableData[GraphicType];
|
|
|
|
switch (GraphicType) {
|
|
case SCOORD_TYPES.POINT:
|
|
case SCOORD_TYPES.MULTIPOINT:
|
|
this.renderPointOrMultipoint(
|
|
renderableDataForGraphicType,
|
|
eventData,
|
|
options
|
|
);
|
|
break;
|
|
case SCOORD_TYPES.POLYLINE:
|
|
this.renderPolyLine(
|
|
renderableDataForGraphicType,
|
|
eventData,
|
|
options
|
|
);
|
|
break;
|
|
case SCOORD_TYPES.CIRCLE:
|
|
this.renderCircle(renderableDataForGraphicType, eventData, options);
|
|
break;
|
|
case SCOORD_TYPES.ELLIPSE:
|
|
this.renderEllipse(
|
|
renderableDataForGraphicType,
|
|
eventData,
|
|
options
|
|
);
|
|
break;
|
|
}
|
|
});
|
|
|
|
const { element } = eventData;
|
|
const context = getNewContext(eventData.canvasContext.canvas);
|
|
|
|
debugger;
|
|
|
|
const text = _getTextBoxLinesFromLabels(labels);
|
|
|
|
debugger;
|
|
|
|
function textBoxAnchorPoints() {
|
|
return [{ x: 1000, y: 1000 }];
|
|
}
|
|
|
|
draw(context, context => {
|
|
drawLinkedTextBox(
|
|
context,
|
|
element,
|
|
{
|
|
active: false,
|
|
hasMoved: false,
|
|
movesIndependently: false,
|
|
drawnIndependently: true,
|
|
allowedOutsideImage: true,
|
|
hasBoundingBox: true,
|
|
x: 256,
|
|
y: 256,
|
|
},
|
|
text,
|
|
null,
|
|
textBoxAnchorPoints,
|
|
color,
|
|
lineWidth,
|
|
10,
|
|
true
|
|
);
|
|
});
|
|
}
|
|
}
|
|
|
|
renderPolyLine(renderableData, eventData, options) {
|
|
const { element } = eventData;
|
|
const context = getNewContext(eventData.canvasContext.canvas);
|
|
|
|
renderableData.forEach(points => {
|
|
draw(context, context => {
|
|
drawJoinedLines(context, element, points[0], points, options);
|
|
});
|
|
});
|
|
}
|
|
|
|
renderPointOrMultipoint(renderableData, eventData, options) {
|
|
const context = getNewContext(eventData.canvasContext.canvas);
|
|
|
|
renderableData.forEach(points => {
|
|
draw(context, context => {
|
|
drawHandles(context, eventData, points, options);
|
|
});
|
|
});
|
|
}
|
|
|
|
renderCircle(renderableData, eventData, options) {
|
|
const { element } = eventData;
|
|
|
|
const context = getNewContext(eventData.canvasContext.canvas);
|
|
|
|
renderableData.forEach(circle => {
|
|
const { center, radius } = circle;
|
|
|
|
drawCircle(context, element, center, radius, options);
|
|
});
|
|
}
|
|
|
|
renderEllipse(renderableData, eventData, options) {
|
|
const { element } = eventData;
|
|
|
|
const context = getNewContext(eventData.canvasContext.canvas);
|
|
|
|
renderableData.forEach(ellipse => {
|
|
const { corner1, corner2 } = ellipse;
|
|
|
|
drawEllipse(
|
|
context,
|
|
element,
|
|
corner1,
|
|
corner2,
|
|
options,
|
|
'pixel',
|
|
0 // TODO -> Work our the initial rotation and add it here so we render appropriately rotated ellipses.
|
|
);
|
|
});
|
|
}
|
|
}
|
|
|
|
function _getTextBoxLinesFromLabels(labels) {
|
|
// TODO -> max 2 for now, need a generic solution for this!
|
|
|
|
const labelLength = Math.min(labels.length, 2);
|
|
|
|
const lines = [];
|
|
|
|
for (let i = 0; i < labelLength; i++) {
|
|
const labelEntry = labels[i];
|
|
lines.push(`${_labelToShorthand(labelEntry.label)}${labelEntry.value}`);
|
|
}
|
|
|
|
return lines;
|
|
}
|
|
|
|
const SHORT_HAND_MAP = {
|
|
'Short Axis': 'S ',
|
|
'Long Axis': 'L ',
|
|
AREA: 'Area ',
|
|
Length: '',
|
|
};
|
|
|
|
function _labelToShorthand(label) {
|
|
const shortHand = SHORT_HAND_MAP[label];
|
|
|
|
if (shortHand !== undefined) {
|
|
return shortHand;
|
|
}
|
|
|
|
return label;
|
|
}
|