Skip to content

Commit

Permalink
feat: Add ArrowTool and remove toolName from drawing API (#88)
Browse files Browse the repository at this point in the history
* feat: Add ArrowTool to annotation tools

* fix: remove toolName from drawing API

* fix: use lineDash in the Length tool

* apply review comments
  • Loading branch information
sedghi authored May 3, 2022
1 parent d1e7bc7 commit 217637c
Show file tree
Hide file tree
Showing 28 changed files with 899 additions and 66 deletions.
99 changes: 90 additions & 9 deletions common/reviews/api/tools.api.md
Original file line number Diff line number Diff line change
Expand Up @@ -216,6 +216,82 @@ export abstract class AnnotationTool extends BaseTool {
abstract toolSelectedCallback(evt: EventTypes_2.MouseDownEventType, annotation: Annotation, interactionType: InteractionTypes): void;
}

// @public (undocumented)
interface ArrowAnnotation extends Annotation {
// (undocumented)
data: {
text: string;
handles: {
points: Types_2.Point3[];
activeHandleIndex: number | null;
textBox: {
hasMoved: boolean;
worldPosition: Types_2.Point3;
worldBoundingBox: {
topLeft: Types_2.Point3;
topRight: Types_2.Point3;
bottomLeft: Types_2.Point3;
bottomRight: Types_2.Point3;
};
};
};
};
}

// @public (undocumented)
export class ArrowTool extends AnnotationTool {
constructor(toolProps?: PublicToolProps, defaultToolProps?: ToolProps);
// (undocumented)
_activateDraw: (element: HTMLDivElement) => void;
// (undocumented)
_activateModify: (element: HTMLDivElement) => void;
// (undocumented)
addNewAnnotation: (evt: EventTypes_2.MouseDownActivateEventType) => ArrowAnnotation;
// (undocumented)
cancel: (element: HTMLDivElement) => any;
// (undocumented)
_deactivateDraw: (element: HTMLDivElement) => void;
// (undocumented)
_deactivateModify: (element: HTMLDivElement) => void;
// (undocumented)
doubleClickCallback: (evt: EventTypes_2.MouseUpEventType) => void;
// (undocumented)
editData: {
annotation: any;
viewportIdsToRender: string[];
handleIndex?: number;
movingTextBox?: boolean;
newAnnotation?: boolean;
hasMoved?: boolean;
} | null;
// (undocumented)
handleSelectedCallback(evt: EventTypes_2.MouseDownEventType, annotation: ArrowAnnotation, handle: ToolHandle, interactionType?: string): void;
// (undocumented)
isDrawing: boolean;
// (undocumented)
isHandleOutsideImage: boolean;
// (undocumented)
_isInsideVolume(index1: any, index2: any, dimensions: any): boolean;
// (undocumented)
isPointNearTool: (element: HTMLDivElement, annotation: ArrowAnnotation, canvasCoords: Types_2.Point2, proximity: number) => boolean;
// (undocumented)
mouseDragCallback: any;
// (undocumented)
_mouseDragCallback: (evt: EventTypes_2.MouseDragEventType | EventTypes_2.MouseMoveEventType) => void;
// (undocumented)
_mouseUpCallback: (evt: EventTypes_2.MouseUpEventType | EventTypes_2.MouseClickEventType) => void;
// (undocumented)
renderAnnotation: (enabledElement: Types_2.IEnabledElement, svgDrawingHelper: any) => void;
// (undocumented)
_throttledCalculateCachedStats: any;
// (undocumented)
static toolName: string;
// (undocumented)
toolSelectedCallback: (evt: EventTypes_2.MouseDownEventType, annotation: ArrowAnnotation, interactionType: InteractionTypes) => void;
// (undocumented)
touchDragCallback: any;
}

// @public (undocumented)
export abstract class BaseTool implements IBaseTool {
constructor(toolProps: PublicToolProps, defaultToolProps: ToolProps);
Expand Down Expand Up @@ -929,13 +1005,16 @@ function distanceToPointSquared(lineStart: Types_2.Point2, lineEnd: Types_2.Poin
function draw(element: HTMLDivElement, fn: (svgDrawingElement: any) => any): void;

// @public (undocumented)
function drawCircle(svgDrawingHelper: any, toolName: string, annotationUID: string, circleUID: string, center: Types_2.Point2, radius: number, options?: {}): void;
function drawArrow(svgDrawingHelper: any, annotationUID: string, arrowUID: string, start: Types_2.Point2, end: Types_2.Point2, options?: {}): void;

// @public (undocumented)
function drawCircle(svgDrawingHelper: any, annotationUID: string, circleUID: string, center: Types_2.Point2, radius: number, options?: {}): void;

// @public (undocumented)
function drawEllipse(svgDrawingHelper: any, toolName: string, annotationUID: string, ellipseUID: string, corner1: Types_2.Point2, corner2: Types_2.Point2, options?: {}): void;
function drawEllipse(svgDrawingHelper: any, annotationUID: string, ellipseUID: string, corner1: Types_2.Point2, corner2: Types_2.Point2, options?: {}): void;

// @public (undocumented)
function drawHandles(svgDrawingHelper: any, toolName: string, annotationUID: string, handleGroupUID: string, handlePoints: Array<Types_2.Point2>, options?: {}): void;
function drawHandles(svgDrawingHelper: any, annotationUID: string, handleGroupUID: string, handlePoints: Array<Types_2.Point2>, options?: {}): void;

declare namespace drawing {
export {
Expand All @@ -946,7 +1025,8 @@ declare namespace drawing {
drawLine,
drawLinkedTextBox,
drawRect,
drawTextBox
drawTextBox,
drawArrow
}
}
export { drawing }
Expand All @@ -958,16 +1038,16 @@ declare namespace drawing_2 {
}

// @public (undocumented)
function drawLine(svgDrawingHelper: any, toolName: string, annotationUID: string, lineUID: string, start: Types_2.Point2, end: Types_2.Point2, options?: {}): void;
function drawLine(svgDrawingHelper: any, annotationUID: string, lineUID: string, start: Types_2.Point2, end: Types_2.Point2, options?: {}): void;

// @public (undocumented)
function drawLinkedTextBox(svgDrawingHelper: Record<string, unknown>, toolName: string, annotationUID: string, textBoxUID: string, textLines: Array<string>, textBoxPosition: Types_2.Point2, annotationAnchorPoints: Array<Types_2.Point2>, textBox: unknown, options?: {}): SVGRect;
function drawLinkedTextBox(svgDrawingHelper: Record<string, unknown>, annotationUID: string, textBoxUID: string, textLines: Array<string>, textBoxPosition: Types_2.Point2, annotationAnchorPoints: Array<Types_2.Point2>, textBox: unknown, options?: {}): SVGRect;

// @public (undocumented)
function drawRect(svgDrawingHelper: any, toolName: string, annotationUID: string, rectangleUID: string, start: Types_2.Point2, end: Types_2.Point2, options?: {}): void;
function drawRect(svgDrawingHelper: any, annotationUID: string, rectangleUID: string, start: Types_2.Point2, end: Types_2.Point2, options?: {}): void;

// @public (undocumented)
function drawTextBox(svgDrawingHelper: Record<string, unknown>, toolName: string, annotationUID: string, textUID: string, textLines: Array<string>, position: Types_2.Point2, options?: {}): SVGRect;
function drawTextBox(svgDrawingHelper: Record<string, unknown>, annotationUID: string, textUID: string, textLines: Array<string>, position: Types_2.Point2, options?: {}): SVGRect;

declare namespace elementCursor {
export {
Expand Down Expand Up @@ -3430,7 +3510,8 @@ declare namespace ToolSpecificAnnotationTypes {
EllipticalROIAnnotation,
BidirectionalAnnotation,
RectangleROIThresholdAnnotation,
RectangleROIStartEndThresholdAnnotation
RectangleROIStartEndThresholdAnnotation,
ArrowAnnotation
}
}

Expand Down
3 changes: 1 addition & 2 deletions packages/tools/src/drawingSvg/_getHash.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
function _getHash(
toolName: string,
annotationUID: string,
drawingElementType: string,
nodeUID: string
): string {
return `${toolName}::${annotationUID}::${drawingElementType}::${nodeUID}`;
return `${annotationUID}::${drawingElementType}::${nodeUID}`;
}

export default _getHash;
83 changes: 83 additions & 0 deletions packages/tools/src/drawingSvg/drawArrow.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
import type { Types } from '@cornerstonejs/core';
import drawLine from './drawLine';

export default function drawArrow(
svgDrawingHelper: any,
annotationUID: string,
arrowUID: string,
start: Types.Point2,
end: Types.Point2,
options = {}
): void {
// if length is NaN return
if (isNaN(start[0]) || isNaN(start[1]) || isNaN(end[0]) || isNaN(end[1])) {
return;
}

const { color, width, lineWidth, lineDash } = Object.assign(
{
color: 'dodgerblue',
width: '2',
lineWidth: undefined,
lineDash: undefined,
},
options
);

// The line itself
drawLine(svgDrawingHelper, annotationUID, arrowUID, start, end, {
color,
width,
lineWidth,
lineDash,
});

// Drawing the head arrow with two lines
// Variables to be used when creating the arrow
const headLength = 10;
const angle = Math.atan2(end[1] - start[1], end[0] - start[0]);

const firstLine = {
start: [
end[0] - headLength * Math.cos(angle - Math.PI / 7),
end[1] - headLength * Math.sin(angle - Math.PI / 7),
] as Types.Point2,
end: end,
};

const secondLine = {
start: [
end[0] - headLength * Math.cos(angle + Math.PI / 7),
end[1] - headLength * Math.sin(angle + Math.PI / 7),
] as Types.Point2,
end: end,
};

drawLine(
svgDrawingHelper,
annotationUID,
'2',
firstLine.start,
firstLine.end,
{
color,
width,
lineWidth,
lineDash,
}
);

drawLine(
svgDrawingHelper,
annotationUID,
'3',
secondLine.start,
secondLine.end,
{
color,
width,
lineWidth,
lineDash,
}
);
}
3 changes: 1 addition & 2 deletions packages/tools/src/drawingSvg/drawCircle.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ import _setNewAttributesIfValid from './_setNewAttributesIfValid';

function drawCircle(
svgDrawingHelper: any,
toolName: string,
annotationUID: string,
circleUID: string,
center: Types.Point2,
Expand All @@ -29,7 +28,7 @@ function drawCircle(

// variable for the namespace
const svgns = 'http://www.w3.org/2000/svg';
const svgNodeHash = _getHash(toolName, annotationUID, 'circle', circleUID);
const svgNodeHash = _getHash(annotationUID, 'circle', circleUID);
const existingCircleElement = svgDrawingHelper._getSvgNode(svgNodeHash);

const attributes = {
Expand Down
3 changes: 1 addition & 2 deletions packages/tools/src/drawingSvg/drawEllipse.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ import _setNewAttributesIfValid from './_setNewAttributesIfValid';

function drawEllipse(
svgDrawingHelper: any,
toolName: string,
annotationUID: string,
ellipseUID: string,
corner1: Types.Point2,
Expand All @@ -27,7 +26,7 @@ function drawEllipse(
const strokeWidth = lineWidth || width;

const svgns = 'http://www.w3.org/2000/svg';
const svgNodeHash = _getHash(toolName, annotationUID, 'ellipse', ellipseUID);
const svgNodeHash = _getHash(annotationUID, 'ellipse', ellipseUID);
const existingEllipse = svgDrawingHelper._getSvgNode(svgNodeHash);

const w = Math.abs(corner1[0] - corner2[0]);
Expand Down
2 changes: 0 additions & 2 deletions packages/tools/src/drawingSvg/drawHandles.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ import _setAttributesIfNecessary from './_setAttributesIfNecessary';

function drawHandles(
svgDrawingHelper: any,
toolName: string,
annotationUID: string,
handleGroupUID: string,
handlePoints: Array<Types.Point2>,
Expand All @@ -33,7 +32,6 @@ function drawHandles(
// variable for the namespace
const svgns = 'http://www.w3.org/2000/svg';
const svgNodeHash = _getHash(
toolName,
annotationUID,
'handle',
`hg-${handleGroupUID}-index-${i}`
Expand Down
3 changes: 1 addition & 2 deletions packages/tools/src/drawingSvg/drawLine.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ import _setAttributesIfNecessary from './_setAttributesIfNecessary';

export default function drawLine(
svgDrawingHelper: any,
toolName: string,
annotationUID: string,
lineUID: string,
start: Types.Point2,
Expand All @@ -32,7 +31,7 @@ export default function drawLine(
const strokeWidth = lineWidth || width;

const svgns = 'http://www.w3.org/2000/svg';
const svgNodeHash = _getHash(toolName, annotationUID, 'line', lineUID);
const svgNodeHash = _getHash(annotationUID, 'line', lineUID);
const existingLine = svgDrawingHelper._getSvgNode(svgNodeHash);

const attributes = {
Expand Down
2 changes: 0 additions & 2 deletions packages/tools/src/drawingSvg/drawLink.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ import { PlanarBoundingBox } from '../types';
*/
function drawLink(
svgDrawingHelper: Record<string, unknown>,
toolName: string,
annotationUID: string,
linkUID: string,
// Find closest point to approx. bounding box
Expand Down Expand Up @@ -44,7 +43,6 @@ function drawLink(

drawLine(
svgDrawingHelper,
toolName,
annotationUID,
`link-${linkUID}`,
start,
Expand Down
4 changes: 0 additions & 4 deletions packages/tools/src/drawingSvg/drawLinkedTextBox.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,6 @@ import drawLink from './drawLink';

function drawLinkedTextBox(
svgDrawingHelper: Record<string, unknown>,
//
toolName: string,
annotationUID: string,
textBoxUID: string,
//
Expand All @@ -31,7 +29,6 @@ function drawLinkedTextBox(
// Draw the text box
const canvasBoundingBox = drawTextBox(
svgDrawingHelper,
toolName,
annotationUID,
textBoxUID,
textLines,
Expand All @@ -42,7 +39,6 @@ function drawLinkedTextBox(
// // Draw dashed link line between tool and text
drawLink(
svgDrawingHelper,
toolName,
annotationUID,
textBoxUID,
annotationAnchorPoints, // annotationAnchorPoints
Expand Down
3 changes: 1 addition & 2 deletions packages/tools/src/drawingSvg/drawRect.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ import _setNewAttributesIfValid from './_setNewAttributesIfValid';
// <rect x="120" y="100" width="100" height="100" />
export default function drawRect(
svgDrawingHelper: any,
toolName: string,
annotationUID: string,
rectangleUID: string,
start: Types.Point2,
Expand All @@ -33,7 +32,7 @@ export default function drawRect(
const strokeWidth = lineWidth || _width;

const svgns = 'http://www.w3.org/2000/svg';
const svgNodeHash = _getHash(toolName, annotationUID, 'rect', rectangleUID);
const svgNodeHash = _getHash(annotationUID, 'rect', rectangleUID);
const existingRect = svgDrawingHelper._getSvgNode(svgNodeHash);

const tlhc = [Math.min(start[0], end[0]), Math.min(start[1], end[1])];
Expand Down
5 changes: 1 addition & 4 deletions packages/tools/src/drawingSvg/drawTextBox.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@ import _setAttributesIfNecessary from './_setAttributesIfNecessary';
*/
function drawTextBox(
svgDrawingHelper: Record<string, unknown>,
toolName: string,
annotationUID: string,
textUID: string,
textLines: Array<string>,
Expand All @@ -36,7 +35,6 @@ function drawTextBox(
// Draw each of the text lines on top of the background box
const textGroupBoundingBox = _drawTextGroup(
svgDrawingHelper,
toolName,
annotationUID,
textUID,
textLines,
Expand All @@ -49,7 +47,6 @@ function drawTextBox(

function _drawTextGroup(
svgDrawingHelper: any,
toolName: any,
annotationUID: string,
textUID: string,
textLines: Array<string>,
Expand All @@ -61,7 +58,7 @@ function _drawTextGroup(
let textGroupBoundingBox;
const [x, y] = [position[0] + padding, position[1] + padding];
const svgns = 'http://www.w3.org/2000/svg';
const svgNodeHash = _getHash(toolName, annotationUID, 'text', textUID);
const svgNodeHash = _getHash(annotationUID, 'text', textUID);
const existingTextGroup = svgDrawingHelper._getSvgNode(svgNodeHash);

// Todo: right now textBox gets a re-render even if the textBox has not changed
Expand Down
Loading

0 comments on commit 217637c

Please sign in to comment.