@cornerstonejs/tools 3.0.0-beta.5 → 3.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -4,7 +4,7 @@ import type { AnnotationRemovedEventDetail } from '../../../types/EventTypes';
4
4
  declare function triggerAnnotationAddedForElement(annotation: Annotation, element: HTMLDivElement): void;
5
5
  declare function triggerAnnotationAddedForFOR(annotation: Annotation): void;
6
6
  declare function triggerAnnotationRemoved(eventDetail: AnnotationRemovedEventDetail): void;
7
- declare function triggerAnnotationModified(annotation: Annotation, element: HTMLDivElement, changeType?: ChangeTypes): void;
7
+ declare function triggerAnnotationModified(annotation: Annotation, element?: HTMLDivElement, changeType?: ChangeTypes): void;
8
8
  declare function triggerAnnotationCompleted(annotation: Annotation): void;
9
9
  declare function triggerContourAnnotationCompleted(annotation: Annotation, contourHoleProcessingEnabled?: boolean): void;
10
10
  export { triggerAnnotationAddedForElement, triggerAnnotationAddedForFOR, triggerAnnotationRemoved, triggerAnnotationModified, triggerAnnotationCompleted, triggerContourAnnotationCompleted, };
@@ -45,8 +45,8 @@ function triggerAnnotationRemoved(eventDetail) {
45
45
  triggerEvent(eventTarget, eventType, eventDetail);
46
46
  }
47
47
  function triggerAnnotationModified(annotation, element, changeType = ChangeTypes.HandlesUpdated) {
48
- const enabledElement = getEnabledElement(element);
49
- const { viewportId, renderingEngineId } = enabledElement;
48
+ const enabledElement = element && getEnabledElement(element);
49
+ const { viewportId, renderingEngineId } = enabledElement || {};
50
50
  const eventType = Events.ANNOTATION_MODIFIED;
51
51
  const eventDetail = {
52
52
  annotation,
@@ -20,9 +20,6 @@ declare class CrosshairsTool extends AnnotationTool {
20
20
  _getReferenceLineControllable?: (viewportId: string) => boolean;
21
21
  _getReferenceLineDraggableRotatable?: (viewportId: string) => boolean;
22
22
  _getReferenceLineSlabThicknessControlsOn?: (viewportId: string) => boolean;
23
- editData: {
24
- annotation: Annotation;
25
- } | null;
26
23
  constructor(toolProps?: PublicToolProps, defaultToolProps?: ToolProps);
27
24
  initializeViewport: ({ renderingEngineId, viewportId, }: Types.IViewportId) => {
28
25
  normal: Types.Point3;
@@ -1,30 +1,33 @@
1
1
  import type { Types } from '@cornerstonejs/core';
2
2
  import { AnnotationTool } from '../base';
3
- import type { EventTypes, ToolHandle, PublicToolProps, ToolProps, SVGDrawingHelper, Annotation } from '../../types';
3
+ import type { EventTypes, PublicToolProps, ToolProps, SVGDrawingHelper, Annotation } from '../../types';
4
+ import type { KeyImageAnnotation } from '../../types/ToolSpecificAnnotationTypes';
4
5
  declare class KeyImageTool extends AnnotationTool {
5
6
  static toolName: string;
7
+ static dataSeries: {
8
+ data: {
9
+ seriesLevel: boolean;
10
+ };
11
+ };
12
+ static dataPoint: {
13
+ data: {
14
+ isPoint: boolean;
15
+ };
16
+ };
6
17
  _throttledCalculateCachedStats: Function;
7
- editData: {
8
- annotation: Annotation;
9
- viewportIdsToRender: string[];
10
- handleIndex?: number;
11
- movingTextBox?: boolean;
12
- newAnnotation?: boolean;
13
- hasMoved?: boolean;
14
- } | null;
15
- isDrawing: boolean;
16
- isHandleOutsideImage: boolean;
17
18
  constructor(toolProps?: PublicToolProps, defaultToolProps?: ToolProps);
18
19
  addNewAnnotation: (evt: EventTypes.InteractionEventType) => Annotation;
19
- cancel(): void;
20
20
  isPointNearTool: (element: HTMLDivElement, annotation: Annotation, canvasCoords: Types.Point2, proximity: number) => boolean;
21
21
  toolSelectedCallback: (evt: EventTypes.InteractionEventType, annotation: Annotation) => void;
22
- handleSelectedCallback(evt: EventTypes.InteractionEventType, annotation: Annotation, handle: ToolHandle): void;
22
+ handleSelectedCallback(evt: EventTypes.InteractionEventType, annotation: KeyImageAnnotation): void;
23
+ static setPoint(annotation: any, isPoint?: boolean, element?: any): void;
23
24
  _endCallback: (evt: EventTypes.InteractionEventType) => void;
24
25
  doubleClickCallback: (evt: EventTypes.TouchTapEventType) => void;
25
26
  _doneChangingTextCallback(element: any, annotation: any, updatedText: any): void;
26
- _activateModify: (element: HTMLDivElement) => void;
27
- _deactivateModify: (element: HTMLDivElement) => void;
27
+ _dragCallback: (evt: any) => void;
28
+ cancel(element: HTMLDivElement): string;
29
+ _activateModify: (element: any) => void;
30
+ _deactivateModify: (element: any) => void;
28
31
  renderAnnotation: (enabledElement: Types.IEnabledElement, svgDrawingHelper: SVGDrawingHelper) => boolean;
29
32
  _isInsideVolume(index1: any, index2: any, dimensions: any): boolean;
30
33
  }
@@ -3,13 +3,23 @@ import { getEnabledElement, utilities as csUtils } from '@cornerstonejs/core';
3
3
  import { AnnotationTool } from '../base';
4
4
  import { addAnnotation, getAnnotations, removeAnnotation, } from '../../stateManagement/annotation/annotationState';
5
5
  import { triggerAnnotationCompleted, triggerAnnotationModified, } from '../../stateManagement/annotation/helpers/state';
6
- import { drawArrow as drawArrowSvg } from '../../drawingSvg';
6
+ import { drawArrow as drawArrowSvg, drawHandles as drawHandlesSvg, } from '../../drawingSvg';
7
7
  import { state } from '../../store/state';
8
8
  import { getViewportIdsWithToolToRender } from '../../utilities/viewportFilters';
9
9
  import triggerAnnotationRenderForViewportIds from '../../utilities/triggerAnnotationRenderForViewportIds';
10
- import { resetElementCursor } from '../../cursors/elementCursor';
10
+ import { resetElementCursor, hideElementCursor, } from '../../cursors/elementCursor';
11
11
  class KeyImageTool extends AnnotationTool {
12
12
  static { this.toolName = 'KeyImage'; }
13
+ static { this.dataSeries = {
14
+ data: {
15
+ seriesLevel: true,
16
+ },
17
+ }; }
18
+ static { this.dataPoint = {
19
+ data: {
20
+ isPoint: true,
21
+ },
22
+ }; }
13
23
  constructor(toolProps = {}, defaultToolProps = {
14
24
  supportedInteractionTypes: ['Mouse', 'Touch'],
15
25
  configuration: {
@@ -17,15 +27,25 @@ class KeyImageTool extends AnnotationTool {
17
27
  changeTextCallback,
18
28
  canvasPosition: [10, 10],
19
29
  canvasSize: 10,
30
+ handleRadius: '6',
31
+ seriesLevel: false,
32
+ isPoint: false,
20
33
  },
21
34
  }) {
22
35
  super(toolProps, defaultToolProps);
23
36
  this.addNewAnnotation = (evt) => {
24
37
  const eventDetail = evt.detail;
25
- const { element } = eventDetail;
38
+ const { element, currentPoints } = eventDetail;
26
39
  const enabledElement = getEnabledElement(element);
27
40
  const { viewport } = enabledElement;
28
- const annotation = (this.constructor).createAnnotationForViewport(viewport);
41
+ const worldPos = currentPoints.world;
42
+ const annotation = (this.constructor).createAnnotationForViewport(viewport, {
43
+ data: {
44
+ handles: { points: [[...worldPos]] },
45
+ seriesLevel: this.configuration.seriesLevel,
46
+ isPoint: this.configuration.isPoint,
47
+ },
48
+ });
29
49
  addAnnotation(annotation, element);
30
50
  const viewportIdsToRender = getViewportIdsWithToolToRender(element, this.getToolName());
31
51
  evt.preventDefault();
@@ -48,6 +68,9 @@ class KeyImageTool extends AnnotationTool {
48
68
  const enabledElement = getEnabledElement(element);
49
69
  const { viewport } = enabledElement;
50
70
  const { data } = annotation;
71
+ if (!data?.isPoint) {
72
+ return false;
73
+ }
51
74
  const { canvasPosition, canvasSize } = this.configuration;
52
75
  if (!canvasPosition?.length) {
53
76
  return false;
@@ -67,9 +90,28 @@ class KeyImageTool extends AnnotationTool {
67
90
  this._endCallback = (evt) => {
68
91
  const eventDetail = evt.detail;
69
92
  const { element } = eventDetail;
70
- this.doneEditMemo();
93
+ const { annotation, viewportIdsToRender, newAnnotation } = this.editData;
94
+ const { viewportId, renderingEngine } = getEnabledElement(element);
95
+ this.eventDispatchDetail = {
96
+ viewportId,
97
+ renderingEngineId: renderingEngine.id,
98
+ };
71
99
  this._deactivateModify(element);
72
100
  resetElementCursor(element);
101
+ if (newAnnotation) {
102
+ this.createMemo(element, annotation, { newAnnotation });
103
+ }
104
+ this.editData = null;
105
+ this.isDrawing = false;
106
+ this.doneEditMemo();
107
+ if (this.isHandleOutsideImage &&
108
+ this.configuration.preventHandleOutsideImage) {
109
+ removeAnnotation(annotation.annotationUID);
110
+ }
111
+ triggerAnnotationRenderForViewportIds(viewportIdsToRender);
112
+ if (newAnnotation) {
113
+ triggerAnnotationCompleted(annotation);
114
+ }
73
115
  };
74
116
  this.doubleClickCallback = (evt) => {
75
117
  const eventDetail = evt.detail;
@@ -91,19 +133,35 @@ class KeyImageTool extends AnnotationTool {
91
133
  evt.stopImmediatePropagation();
92
134
  evt.preventDefault();
93
135
  };
136
+ this._dragCallback = (evt) => {
137
+ this.isDrawing = true;
138
+ const eventDetail = evt.detail;
139
+ const { currentPoints, element } = eventDetail;
140
+ const worldPos = currentPoints.world;
141
+ const { annotation, viewportIdsToRender, newAnnotation } = this.editData;
142
+ const { data } = annotation;
143
+ this.createMemo(element, annotation, { newAnnotation });
144
+ data.handles.points[0] = [...worldPos];
145
+ annotation.invalidated = true;
146
+ triggerAnnotationRenderForViewportIds(viewportIdsToRender);
147
+ };
94
148
  this._activateModify = (element) => {
95
149
  state.isInteractingWithTool = true;
96
150
  element.addEventListener(Events.MOUSE_UP, this._endCallback);
151
+ element.addEventListener(Events.MOUSE_DRAG, this._dragCallback);
97
152
  element.addEventListener(Events.MOUSE_CLICK, this._endCallback);
98
- element.addEventListener(Events.TOUCH_TAP, this._endCallback);
99
153
  element.addEventListener(Events.TOUCH_END, this._endCallback);
154
+ element.addEventListener(Events.TOUCH_DRAG, this._dragCallback);
155
+ element.addEventListener(Events.TOUCH_TAP, this._endCallback);
100
156
  };
101
157
  this._deactivateModify = (element) => {
102
158
  state.isInteractingWithTool = false;
103
159
  element.removeEventListener(Events.MOUSE_UP, this._endCallback);
160
+ element.removeEventListener(Events.MOUSE_DRAG, this._dragCallback);
104
161
  element.removeEventListener(Events.MOUSE_CLICK, this._endCallback);
105
- element.removeEventListener(Events.TOUCH_TAP, this._endCallback);
106
162
  element.removeEventListener(Events.TOUCH_END, this._endCallback);
163
+ element.removeEventListener(Events.TOUCH_DRAG, this._dragCallback);
164
+ element.removeEventListener(Events.TOUCH_TAP, this._endCallback);
107
165
  };
108
166
  this.renderAnnotation = (enabledElement, svgDrawingHelper) => {
109
167
  let renderStatus = false;
@@ -124,15 +182,24 @@ class KeyImageTool extends AnnotationTool {
124
182
  };
125
183
  for (let i = 0; i < annotations.length; i++) {
126
184
  const annotation = annotations[i];
127
- const { annotationUID } = annotation;
185
+ const { annotationUID, data } = annotation;
128
186
  styleSpecifier.annotationUID = annotationUID;
129
- const { color } = this.getAnnotationStyle({
187
+ const { color, lineWidth } = this.getAnnotationStyle({
130
188
  annotation,
131
189
  styleSpecifier,
132
190
  });
133
191
  const { canvasPosition, canvasSize } = this.configuration;
134
- if (canvasPosition?.length) {
135
- const arrowUID = '1';
192
+ const arrowUID = '1';
193
+ if (data?.isPoint) {
194
+ const point = data.handles.points[0];
195
+ const canvasCoordinates = viewport.worldToCanvas(point);
196
+ drawHandlesSvg(svgDrawingHelper, annotationUID, arrowUID, [canvasCoordinates], {
197
+ color,
198
+ lineWidth,
199
+ handleRadius: this.configuration.handleRadius,
200
+ });
201
+ }
202
+ else if (canvasPosition?.length) {
136
203
  drawArrowSvg(svgDrawingHelper, annotationUID, arrowUID, canvasPosition.map((it) => it + canvasSize), canvasPosition, {
137
204
  color,
138
205
  width: 1,
@@ -147,18 +214,47 @@ class KeyImageTool extends AnnotationTool {
147
214
  return renderStatus;
148
215
  };
149
216
  }
150
- cancel() {
217
+ handleSelectedCallback(evt, annotation) {
218
+ const eventDetail = evt.detail;
219
+ const { element } = eventDetail;
220
+ annotation.highlighted = true;
221
+ const viewportIdsToRender = getViewportIdsWithToolToRender(element, this.getToolName());
222
+ this.editData = {
223
+ annotation,
224
+ viewportIdsToRender,
225
+ };
226
+ this._activateModify(element);
227
+ hideElementCursor(element);
228
+ triggerAnnotationRenderForViewportIds(viewportIdsToRender);
229
+ evt.preventDefault();
151
230
  }
152
- handleSelectedCallback(evt, annotation, handle) {
231
+ static setPoint(annotation, isPoint = !annotation.data.isPoint, element) {
232
+ annotation.data.isPoint = isPoint;
233
+ triggerAnnotationModified(annotation, element);
153
234
  }
154
235
  _doneChangingTextCallback(element, annotation, updatedText) {
155
236
  annotation.data.text = updatedText;
156
- const enabledElement = getEnabledElement(element);
157
- const { renderingEngine } = enabledElement;
158
237
  const viewportIdsToRender = getViewportIdsWithToolToRender(element, this.getToolName());
159
238
  triggerAnnotationRenderForViewportIds(viewportIdsToRender);
160
239
  triggerAnnotationModified(annotation, element);
161
240
  }
241
+ cancel(element) {
242
+ if (this.isDrawing) {
243
+ this.isDrawing = false;
244
+ this._deactivateModify(element);
245
+ resetElementCursor(element);
246
+ const { annotation, viewportIdsToRender, newAnnotation } = this.editData;
247
+ const { data } = annotation;
248
+ annotation.highlighted = false;
249
+ data.handles.activeHandleIndex = null;
250
+ triggerAnnotationRenderForViewportIds(viewportIdsToRender);
251
+ if (newAnnotation) {
252
+ triggerAnnotationCompleted(annotation);
253
+ }
254
+ this.editData = null;
255
+ return annotation.annotationUID;
256
+ }
257
+ }
162
258
  _isInsideVolume(index1, index2, dimensions) {
163
259
  return (csUtils.indexWithinDimensions(index1, dimensions) &&
164
260
  csUtils.indexWithinDimensions(index2, dimensions));
@@ -1,21 +1,10 @@
1
1
  import type { Types } from '@cornerstonejs/core';
2
2
  import { AnnotationTool } from '../base';
3
3
  import { ChangeTypes } from '../../enums';
4
- import type { EventTypes, ToolHandle, PublicToolProps, SVGDrawingHelper, Annotation } from '../../types';
4
+ import type { EventTypes, ToolHandle, PublicToolProps, SVGDrawingHelper } from '../../types';
5
5
  import type { ProbeAnnotation } from '../../types/ToolSpecificAnnotationTypes';
6
6
  declare class ProbeTool extends AnnotationTool {
7
7
  static toolName: string;
8
- editData: {
9
- annotation: Annotation;
10
- viewportIdsToRender: string[];
11
- newAnnotation?: boolean;
12
- } | null;
13
- eventDispatchDetail: {
14
- viewportId: string;
15
- renderingEngineId: string;
16
- };
17
- isDrawing: boolean;
18
- isHandleOutsideImage: boolean;
19
8
  static probeDefaults: {
20
9
  supportedInteractionTypes: string[];
21
10
  configuration: {
@@ -3,6 +3,20 @@ import AnnotationDisplayTool from './AnnotationDisplayTool';
3
3
  import type { Annotation, Annotations, EventTypes, ToolHandle, InteractionTypes, ToolProps, PublicToolProps } from '../../types';
4
4
  import type { AnnotationStyle, StyleSpecifier } from '../../types/AnnotationStyle';
5
5
  declare abstract class AnnotationTool extends AnnotationDisplayTool {
6
+ protected eventDispatchDetail: {
7
+ viewportId: string;
8
+ renderingEngineId: string;
9
+ };
10
+ isDrawing: boolean;
11
+ isHandleOutsideImage: boolean;
12
+ editData: {
13
+ annotation: Annotation;
14
+ viewportIdsToRender?: string[];
15
+ newAnnotation?: boolean;
16
+ handleIndex?: number;
17
+ movingTextBox?: boolean;
18
+ hasMoved?: boolean;
19
+ } | null;
6
20
  static createAnnotation(...annotationBaseData: any[]): Annotation;
7
21
  static createAnnotationForViewport<T extends Annotation>(viewport: any, ...annotationBaseData: any[]): T;
8
22
  static createAndAddAnnotation(viewport: any, ...annotationBaseData: any[]): void;
@@ -61,10 +61,10 @@ type AnnotationCompletedEventDetail = {
61
61
  changeType?: ChangeTypes.Completed;
62
62
  };
63
63
  type AnnotationModifiedEventDetail = {
64
- viewportId: string;
65
- renderingEngineId: string;
66
64
  annotation: Annotation;
67
65
  changeType?: ChangeTypes;
66
+ viewportId?: string;
67
+ renderingEngineId?: string;
68
68
  };
69
69
  type AnnotationRemovedEventDetail = {
70
70
  annotation: Annotation;
@@ -52,6 +52,12 @@ export interface ProbeAnnotation extends Annotation {
52
52
  label: string;
53
53
  };
54
54
  }
55
+ export type KeyImageAnnotation = ProbeAnnotation & {
56
+ data: {
57
+ isPoint: boolean;
58
+ seriesLevel: boolean;
59
+ };
60
+ };
55
61
  export interface LengthAnnotation extends Annotation {
56
62
  data: {
57
63
  handles: {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cornerstonejs/tools",
3
- "version": "3.0.0-beta.5",
3
+ "version": "3.0.0",
4
4
  "description": "Cornerstone3D Tools",
5
5
  "types": "./dist/esm/index.d.ts",
6
6
  "module": "./dist/esm/index.js",
@@ -104,7 +104,7 @@
104
104
  "canvas": "^2.11.2"
105
105
  },
106
106
  "peerDependencies": {
107
- "@cornerstonejs/core": "^3.0.0-beta.5",
107
+ "@cornerstonejs/core": "^3.0.0",
108
108
  "@kitware/vtk.js": "32.9.0",
109
109
  "@types/d3-array": "^3.0.4",
110
110
  "@types/d3-interpolate": "^3.0.1",
@@ -123,5 +123,5 @@
123
123
  "type": "individual",
124
124
  "url": "https://ohif.org/donate"
125
125
  },
126
- "gitHead": "6edb49c79f664736747d8698c5bea8b30f78831d"
126
+ "gitHead": "8d0c264b0c0c5a3cf339dc986b5c524159def522"
127
127
  }