@cornerstonejs/tools 1.31.0 → 1.32.1

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.
Files changed (167) hide show
  1. package/dist/cjs/index.d.ts +2 -2
  2. package/dist/cjs/index.js +3 -2
  3. package/dist/cjs/index.js.map +1 -1
  4. package/dist/cjs/stateManagement/annotation/AnnotationGroup.d.ts +18 -0
  5. package/dist/cjs/stateManagement/annotation/AnnotationGroup.js +73 -0
  6. package/dist/cjs/stateManagement/annotation/AnnotationGroup.js.map +1 -0
  7. package/dist/cjs/stateManagement/annotation/annotationState.js +1 -1
  8. package/dist/cjs/stateManagement/annotation/annotationState.js.map +1 -1
  9. package/dist/cjs/stateManagement/annotation/index.d.ts +2 -1
  10. package/dist/cjs/stateManagement/annotation/index.js +3 -1
  11. package/dist/cjs/stateManagement/annotation/index.js.map +1 -1
  12. package/dist/cjs/store/ToolGroupManager/ToolGroup.d.ts +1 -0
  13. package/dist/cjs/store/ToolGroupManager/ToolGroup.js +3 -1
  14. package/dist/cjs/store/ToolGroupManager/ToolGroup.js.map +1 -1
  15. package/dist/cjs/synchronizers/callbacks/stackImageSyncCallback.js +1 -1
  16. package/dist/cjs/synchronizers/callbacks/stackImageSyncCallback.js.map +1 -1
  17. package/dist/cjs/tools/annotation/KeyImageTool.d.ts +62 -0
  18. package/dist/cjs/tools/annotation/KeyImageTool.js +212 -0
  19. package/dist/cjs/tools/annotation/KeyImageTool.js.map +1 -0
  20. package/dist/cjs/tools/annotation/PlanarFreehandROITool.js +2 -5
  21. package/dist/cjs/tools/annotation/PlanarFreehandROITool.js.map +1 -1
  22. package/dist/cjs/tools/annotation/ProbeTool.js +15 -4
  23. package/dist/cjs/tools/annotation/ProbeTool.js.map +1 -1
  24. package/dist/cjs/tools/annotation/VideoRedactionTool.js +4 -1
  25. package/dist/cjs/tools/annotation/VideoRedactionTool.js.map +1 -1
  26. package/dist/cjs/tools/base/AnnotationDisplayTool.js +4 -2
  27. package/dist/cjs/tools/base/AnnotationDisplayTool.js.map +1 -1
  28. package/dist/cjs/tools/base/AnnotationTool.js +2 -7
  29. package/dist/cjs/tools/base/AnnotationTool.js.map +1 -1
  30. package/dist/cjs/tools/base/BaseTool.js +9 -1
  31. package/dist/cjs/tools/base/BaseTool.js.map +1 -1
  32. package/dist/cjs/tools/index.d.ts +5 -4
  33. package/dist/cjs/tools/index.js +9 -7
  34. package/dist/cjs/tools/index.js.map +1 -1
  35. package/dist/cjs/types/CalculatorTypes.d.ts +1 -1
  36. package/dist/cjs/utilities/annotationFrameRange.d.ts +13 -0
  37. package/dist/cjs/utilities/annotationFrameRange.js +46 -0
  38. package/dist/cjs/utilities/annotationFrameRange.js.map +1 -0
  39. package/dist/cjs/utilities/index.d.ts +2 -1
  40. package/dist/cjs/utilities/index.js +3 -1
  41. package/dist/cjs/utilities/index.js.map +1 -1
  42. package/dist/cjs/utilities/math/basic/BasicStatsCalculator.d.ts +0 -1
  43. package/dist/cjs/utilities/math/basic/BasicStatsCalculator.js +35 -22
  44. package/dist/cjs/utilities/math/basic/BasicStatsCalculator.js.map +1 -1
  45. package/dist/cjs/utilities/math/ellipse/pointInEllipse.d.ts +2 -1
  46. package/dist/cjs/utilities/math/ellipse/pointInEllipse.js.map +1 -1
  47. package/dist/cjs/utilities/math/sphere/pointInSphere.d.ts +1 -1
  48. package/dist/cjs/utilities/math/sphere/pointInSphere.js +3 -3
  49. package/dist/cjs/utilities/math/sphere/pointInSphere.js.map +1 -1
  50. package/dist/cjs/utilities/planar/filterAnnotationsForDisplay.js +19 -2
  51. package/dist/cjs/utilities/planar/filterAnnotationsForDisplay.js.map +1 -1
  52. package/dist/cjs/utilities/pointInShapeCallback.d.ts +6 -5
  53. package/dist/cjs/utilities/pointInShapeCallback.js +27 -26
  54. package/dist/cjs/utilities/pointInShapeCallback.js.map +1 -1
  55. package/dist/cjs/utilities/roundNumber.d.ts +1 -1
  56. package/dist/cjs/utilities/roundNumber.js +3 -0
  57. package/dist/cjs/utilities/roundNumber.js.map +1 -1
  58. package/dist/cjs/utilities/viewport/isViewportPreScaled.js +1 -1
  59. package/dist/cjs/utilities/viewport/isViewportPreScaled.js.map +1 -1
  60. package/dist/esm/index.js +2 -2
  61. package/dist/esm/index.js.map +1 -1
  62. package/dist/esm/stateManagement/annotation/AnnotationGroup.js +70 -0
  63. package/dist/esm/stateManagement/annotation/AnnotationGroup.js.map +1 -0
  64. package/dist/esm/stateManagement/annotation/annotationState.js +1 -1
  65. package/dist/esm/stateManagement/annotation/annotationState.js.map +1 -1
  66. package/dist/esm/stateManagement/annotation/index.js +2 -1
  67. package/dist/esm/stateManagement/annotation/index.js.map +1 -1
  68. package/dist/esm/store/ToolGroupManager/ToolGroup.js +3 -1
  69. package/dist/esm/store/ToolGroupManager/ToolGroup.js.map +1 -1
  70. package/dist/esm/synchronizers/callbacks/stackImageSyncCallback.js +1 -1
  71. package/dist/esm/synchronizers/callbacks/stackImageSyncCallback.js.map +1 -1
  72. package/dist/esm/tools/annotation/KeyImageTool.js +207 -0
  73. package/dist/esm/tools/annotation/KeyImageTool.js.map +1 -0
  74. package/dist/esm/tools/annotation/PlanarFreehandROITool.js +3 -6
  75. package/dist/esm/tools/annotation/PlanarFreehandROITool.js.map +1 -1
  76. package/dist/esm/tools/annotation/ProbeTool.js +17 -6
  77. package/dist/esm/tools/annotation/ProbeTool.js.map +1 -1
  78. package/dist/esm/tools/annotation/VideoRedactionTool.js +4 -1
  79. package/dist/esm/tools/annotation/VideoRedactionTool.js.map +1 -1
  80. package/dist/esm/tools/base/AnnotationDisplayTool.js +4 -2
  81. package/dist/esm/tools/base/AnnotationDisplayTool.js.map +1 -1
  82. package/dist/esm/tools/base/AnnotationTool.js +3 -8
  83. package/dist/esm/tools/base/AnnotationTool.js.map +1 -1
  84. package/dist/esm/tools/base/BaseTool.js +9 -1
  85. package/dist/esm/tools/base/BaseTool.js.map +1 -1
  86. package/dist/esm/tools/index.js +5 -4
  87. package/dist/esm/tools/index.js.map +1 -1
  88. package/dist/esm/utilities/annotationFrameRange.js +43 -0
  89. package/dist/esm/utilities/annotationFrameRange.js.map +1 -0
  90. package/dist/esm/utilities/index.js +2 -1
  91. package/dist/esm/utilities/index.js.map +1 -1
  92. package/dist/esm/utilities/math/basic/BasicStatsCalculator.js +35 -22
  93. package/dist/esm/utilities/math/basic/BasicStatsCalculator.js.map +1 -1
  94. package/dist/esm/utilities/math/ellipse/pointInEllipse.js.map +1 -1
  95. package/dist/esm/utilities/math/sphere/pointInSphere.js +3 -3
  96. package/dist/esm/utilities/math/sphere/pointInSphere.js.map +1 -1
  97. package/dist/esm/utilities/planar/filterAnnotationsForDisplay.js +19 -2
  98. package/dist/esm/utilities/planar/filterAnnotationsForDisplay.js.map +1 -1
  99. package/dist/esm/utilities/pointInShapeCallback.js +27 -26
  100. package/dist/esm/utilities/pointInShapeCallback.js.map +1 -1
  101. package/dist/esm/utilities/roundNumber.js +3 -0
  102. package/dist/esm/utilities/roundNumber.js.map +1 -1
  103. package/dist/esm/utilities/viewport/isViewportPreScaled.js +1 -1
  104. package/dist/esm/utilities/viewport/isViewportPreScaled.js.map +1 -1
  105. package/dist/types/index.d.ts +2 -2
  106. package/dist/types/index.d.ts.map +1 -1
  107. package/dist/types/stateManagement/annotation/AnnotationGroup.d.ts +19 -0
  108. package/dist/types/stateManagement/annotation/AnnotationGroup.d.ts.map +1 -0
  109. package/dist/types/stateManagement/annotation/index.d.ts +2 -1
  110. package/dist/types/stateManagement/annotation/index.d.ts.map +1 -1
  111. package/dist/types/store/ToolGroupManager/ToolGroup.d.ts +1 -0
  112. package/dist/types/store/ToolGroupManager/ToolGroup.d.ts.map +1 -1
  113. package/dist/types/synchronizers/callbacks/stackImageSyncCallback.d.ts.map +1 -1
  114. package/dist/types/tools/annotation/KeyImageTool.d.ts +63 -0
  115. package/dist/types/tools/annotation/KeyImageTool.d.ts.map +1 -0
  116. package/dist/types/tools/annotation/PlanarFreehandROITool.d.ts.map +1 -1
  117. package/dist/types/tools/annotation/ProbeTool.d.ts.map +1 -1
  118. package/dist/types/tools/annotation/VideoRedactionTool.d.ts.map +1 -1
  119. package/dist/types/tools/base/AnnotationDisplayTool.d.ts.map +1 -1
  120. package/dist/types/tools/base/AnnotationTool.d.ts.map +1 -1
  121. package/dist/types/tools/base/BaseTool.d.ts.map +1 -1
  122. package/dist/types/tools/index.d.ts +5 -4
  123. package/dist/types/tools/index.d.ts.map +1 -1
  124. package/dist/types/types/CalculatorTypes.d.ts +1 -1
  125. package/dist/types/types/CalculatorTypes.d.ts.map +1 -1
  126. package/dist/types/utilities/annotationFrameRange.d.ts +14 -0
  127. package/dist/types/utilities/annotationFrameRange.d.ts.map +1 -0
  128. package/dist/types/utilities/index.d.ts +2 -1
  129. package/dist/types/utilities/index.d.ts.map +1 -1
  130. package/dist/types/utilities/math/basic/BasicStatsCalculator.d.ts +0 -1
  131. package/dist/types/utilities/math/basic/BasicStatsCalculator.d.ts.map +1 -1
  132. package/dist/types/utilities/math/ellipse/pointInEllipse.d.ts +2 -1
  133. package/dist/types/utilities/math/ellipse/pointInEllipse.d.ts.map +1 -1
  134. package/dist/types/utilities/math/sphere/pointInSphere.d.ts +1 -1
  135. package/dist/types/utilities/math/sphere/pointInSphere.d.ts.map +1 -1
  136. package/dist/types/utilities/planar/filterAnnotationsForDisplay.d.ts.map +1 -1
  137. package/dist/types/utilities/pointInShapeCallback.d.ts +6 -5
  138. package/dist/types/utilities/pointInShapeCallback.d.ts.map +1 -1
  139. package/dist/types/utilities/roundNumber.d.ts +1 -1
  140. package/dist/types/utilities/roundNumber.d.ts.map +1 -1
  141. package/dist/umd/index.js +1 -1
  142. package/dist/umd/index.js.map +1 -1
  143. package/package.json +3 -3
  144. package/src/index.ts +2 -0
  145. package/src/stateManagement/annotation/AnnotationGroup.ts +120 -0
  146. package/src/stateManagement/annotation/annotationState.ts +1 -1
  147. package/src/stateManagement/annotation/index.ts +2 -0
  148. package/src/store/ToolGroupManager/ToolGroup.ts +10 -1
  149. package/src/synchronizers/callbacks/stackImageSyncCallback.ts +2 -1
  150. package/src/tools/annotation/KeyImageTool.ts +435 -0
  151. package/src/tools/annotation/PlanarFreehandROITool.ts +4 -6
  152. package/src/tools/annotation/ProbeTool.ts +19 -6
  153. package/src/tools/annotation/VideoRedactionTool.ts +10 -1
  154. package/src/tools/base/AnnotationDisplayTool.ts +3 -4
  155. package/src/tools/base/AnnotationTool.ts +3 -6
  156. package/src/tools/base/BaseTool.ts +18 -2
  157. package/src/tools/index.ts +8 -5
  158. package/src/types/CalculatorTypes.ts +1 -1
  159. package/src/utilities/annotationFrameRange.ts +78 -0
  160. package/src/utilities/index.ts +2 -0
  161. package/src/utilities/math/basic/BasicStatsCalculator.ts +51 -23
  162. package/src/utilities/math/ellipse/pointInEllipse.ts +2 -1
  163. package/src/utilities/math/sphere/pointInSphere.ts +4 -7
  164. package/src/utilities/planar/filterAnnotationsForDisplay.ts +29 -3
  165. package/src/utilities/pointInShapeCallback.ts +46 -38
  166. package/src/utilities/roundNumber.ts +7 -1
  167. package/src/utilities/viewport/isViewportPreScaled.ts +1 -1
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cornerstonejs/tools",
3
- "version": "1.31.0",
3
+ "version": "1.32.1",
4
4
  "description": "Cornerstone3D Tools",
5
5
  "main": "src/index.ts",
6
6
  "types": "dist/types/index.d.ts",
@@ -29,7 +29,7 @@
29
29
  "webpack:watch": "webpack --mode development --progress --watch --config ./.webpack/webpack.dev.js"
30
30
  },
31
31
  "dependencies": {
32
- "@cornerstonejs/core": "^1.31.0",
32
+ "@cornerstonejs/core": "^1.32.1",
33
33
  "comlink": "^4.4.1",
34
34
  "lodash.clonedeep": "4.5.0",
35
35
  "lodash.get": "^4.4.2"
@@ -53,5 +53,5 @@
53
53
  "type": "individual",
54
54
  "url": "https://ohif.org/donate"
55
55
  },
56
- "gitHead": "280c27226cb94a0b422f28656e69dbc059f95323"
56
+ "gitHead": "bb586320e1b8c8d07ae7f695cc838ed529631050"
57
57
  }
package/src/index.ts CHANGED
@@ -42,6 +42,7 @@ import {
42
42
  BidirectionalTool,
43
43
  PlanarFreehandROITool,
44
44
  ArrowAnnotateTool,
45
+ KeyImageTool,
45
46
  CrosshairsTool,
46
47
  ReferenceLinesTool,
47
48
  RectangleScissorsTool,
@@ -106,6 +107,7 @@ export {
106
107
  ArrowAnnotateTool,
107
108
  AngleTool,
108
109
  CobbAngleTool,
110
+ KeyImageTool,
109
111
  MagnifyTool,
110
112
  AdvancedMagnifyTool,
111
113
  ReferenceCursors,
@@ -0,0 +1,120 @@
1
+ import { eventTarget, triggerEvent } from '@cornerstonejs/core';
2
+ import Events from '../../enums/Events';
3
+ import { getAnnotation } from './annotationState';
4
+
5
+ export type BaseEventDetail = {
6
+ viewportId: string;
7
+ renderingEngineId: string;
8
+ };
9
+
10
+ /**
11
+ * An annotation group
12
+ */
13
+
14
+ export default class AnnotationGroup {
15
+ private annotationUIDs = new Set<string>();
16
+ private _isVisible = true;
17
+
18
+ public visibleFilter: (uid: string) => boolean;
19
+
20
+ constructor() {
21
+ this.visibleFilter = this.unboundVisibleFilter.bind(this);
22
+ }
23
+
24
+ /**
25
+ * Returns true if other groups are free to hide this annotation.
26
+ * That is, if the annotation is not a member or is hidden.
27
+ */
28
+ protected unboundVisibleFilter(uid: string): boolean {
29
+ return !this._isVisible || !this.annotationUIDs.has(uid);
30
+ }
31
+
32
+ public has(uid: string): boolean {
33
+ return this.annotationUIDs.has(uid);
34
+ }
35
+ /**
36
+ * Sets whether annotations belonging to this group are visible or not.
37
+ * If there are multiple groups, then the set visible false should be called
38
+ * before before re-enabling the other groups with setVisible true.
39
+ */
40
+ public setVisible(
41
+ isVisible = true,
42
+ baseEvent: BaseEventDetail,
43
+ filter?: (annotationUID: string) => boolean
44
+ ) {
45
+ if (this._isVisible === isVisible) {
46
+ return;
47
+ }
48
+ this._isVisible = isVisible;
49
+ this.annotationUIDs.forEach((uid) => {
50
+ const annotation = getAnnotation(uid);
51
+ if (!annotation) {
52
+ this.annotationUIDs.delete(uid);
53
+ return;
54
+ }
55
+ if (annotation.isVisible === isVisible) {
56
+ return;
57
+ }
58
+ if (!isVisible && filter?.(uid) === false) {
59
+ return;
60
+ }
61
+ annotation.isVisible = isVisible;
62
+ const eventDetail = {
63
+ ...baseEvent,
64
+ annotation,
65
+ };
66
+ triggerEvent(eventTarget, Events.ANNOTATION_MODIFIED, eventDetail);
67
+ });
68
+ }
69
+
70
+ public get isVisible() {
71
+ return this._isVisible;
72
+ }
73
+
74
+ /** Finds the nearby/next annotation in the given direction */
75
+ public findNearby(uid: string, direction: 1) {
76
+ const uids = [...this.annotationUIDs];
77
+ if (uids.length === 0) {
78
+ return null;
79
+ }
80
+ if (!uid) {
81
+ return uids[direction === 1 ? 0 : uids.length - 1];
82
+ }
83
+ const index = uids.indexOf(uid);
84
+ if (
85
+ index === -1 ||
86
+ index + direction < 0 ||
87
+ index + direction >= uids.length
88
+ ) {
89
+ return null;
90
+ }
91
+ return uids[index + direction];
92
+ }
93
+
94
+ /**
95
+ * Adds the annotation to the group
96
+ * Does NOT change the visibility status of the annotation.
97
+ */
98
+ public add(...annotationUIDs: string[]) {
99
+ annotationUIDs.forEach((annotationUID) =>
100
+ this.annotationUIDs.add(annotationUID)
101
+ );
102
+ }
103
+
104
+ /**
105
+ * Removes the annotation from the group.
106
+ * Does not affect the visibility status of the annotation.
107
+ */
108
+ public remove(...annotationUIDs: string[]) {
109
+ annotationUIDs.forEach((annotationUID) =>
110
+ this.annotationUIDs.delete(annotationUID)
111
+ );
112
+ }
113
+
114
+ /**
115
+ * Removes everything from the group.
116
+ */
117
+ public clear() {
118
+ this.annotationUIDs.clear();
119
+ }
120
+ }
@@ -75,7 +75,7 @@ function addAnnotation(
75
75
  annotation: Annotation,
76
76
  annotationGroupSelector: AnnotationGroupSelector
77
77
  ): string {
78
- if (annotation.annotationUID === undefined) {
78
+ if (!annotation.annotationUID) {
79
79
  annotation.annotationUID = csUtils.uuidv4() as string;
80
80
  }
81
81
 
@@ -4,6 +4,7 @@ import * as selection from './annotationSelection';
4
4
  import * as state from './annotationState';
5
5
  import * as visibility from './annotationVisibility';
6
6
  import FrameOfReferenceSpecificAnnotationManager from './FrameOfReferenceSpecificAnnotationManager';
7
+ import AnnotationGroup from './AnnotationGroup';
7
8
 
8
9
  export {
9
10
  config,
@@ -12,4 +13,5 @@ export {
12
13
  state,
13
14
  visibility,
14
15
  FrameOfReferenceSpecificAnnotationManager,
16
+ AnnotationGroup,
15
17
  };
@@ -47,6 +47,10 @@ export default class ToolGroup implements IToolGroup {
47
47
  id: string;
48
48
  viewportsInfo = [];
49
49
  toolOptions = {};
50
+ /**
51
+ * Options used for restoring a tool
52
+ */
53
+ restoreToolOptions = {};
50
54
  _toolInstances = {};
51
55
 
52
56
  constructor(id: string) {
@@ -270,7 +274,10 @@ export default class ToolGroup implements IToolGroup {
270
274
  }
271
275
 
272
276
  if (mode === ToolModes.Active) {
273
- this.setToolActive(toolName, options);
277
+ this.setToolActive(
278
+ toolName,
279
+ options || this.restoreToolOptions[toolName]
280
+ );
274
281
  return;
275
282
  }
276
283
 
@@ -510,6 +517,8 @@ export default class ToolGroup implements IToolGroup {
510
517
  mode: Disabled,
511
518
  };
512
519
 
520
+ this.restoreToolOptions[toolName] = this.toolOptions[toolName];
521
+
513
522
  this.toolOptions[toolName] = toolOptions;
514
523
  toolInstance.mode = Disabled;
515
524
 
@@ -12,7 +12,8 @@ import areViewportsCoplanar from './areViewportsCoplanar ';
12
12
  const getSpatialRegistration = (targetId, sourceId) =>
13
13
  utilities.spatialRegistrationMetadataProvider.get(
14
14
  'spatialRegistrationModule',
15
- [targetId, sourceId]
15
+ targetId,
16
+ sourceId
16
17
  );
17
18
 
18
19
  /**
@@ -0,0 +1,435 @@
1
+ import { Events } from '../../enums';
2
+ import {
3
+ getEnabledElement,
4
+ triggerEvent,
5
+ eventTarget,
6
+ utilities as csUtils,
7
+ } from '@cornerstonejs/core';
8
+ import type { Types } from '@cornerstonejs/core';
9
+
10
+ import { AnnotationTool } from '../base';
11
+ import {
12
+ addAnnotation,
13
+ getAnnotations,
14
+ removeAnnotation,
15
+ } from '../../stateManagement/annotation/annotationState';
16
+
17
+ import { drawArrow as drawArrowSvg } from '../../drawingSvg';
18
+ import { state } from '../../store';
19
+ import { getViewportIdsWithToolToRender } from '../../utilities/viewportFilters';
20
+ import triggerAnnotationRenderForViewportIds from '../../utilities/triggerAnnotationRenderForViewportIds';
21
+ import { AnnotationCompletedEventDetail } from '../../types/EventTypes';
22
+
23
+ import { resetElementCursor } from '../../cursors/elementCursor';
24
+
25
+ import {
26
+ EventTypes,
27
+ ToolHandle,
28
+ PublicToolProps,
29
+ ToolProps,
30
+ SVGDrawingHelper,
31
+ } from '../../types';
32
+ import { StyleSpecifier } from '../../types/AnnotationStyle';
33
+ import { Annotation } from '../../types';
34
+
35
+ type Point2 = Types.Point2;
36
+
37
+ class KeyImageTool extends AnnotationTool {
38
+ static toolName;
39
+
40
+ public touchDragCallback: any;
41
+ public mouseDragCallback: any;
42
+ _throttledCalculateCachedStats: any;
43
+ editData: {
44
+ annotation: any;
45
+ viewportIdsToRender: string[];
46
+ handleIndex?: number;
47
+ movingTextBox?: boolean;
48
+ newAnnotation?: boolean;
49
+ hasMoved?: boolean;
50
+ } | null;
51
+ isDrawing: boolean;
52
+ isHandleOutsideImage: boolean;
53
+
54
+ constructor(
55
+ toolProps: PublicToolProps = {},
56
+ defaultToolProps: ToolProps = {
57
+ supportedInteractionTypes: ['Mouse', 'Touch'],
58
+ configuration: {
59
+ getTextCallback,
60
+ changeTextCallback,
61
+ canvasPosition: [10, 10],
62
+ canvasSize: 10,
63
+ },
64
+ }
65
+ ) {
66
+ super(toolProps, defaultToolProps);
67
+ }
68
+
69
+ /**
70
+ * Based on the current position of the mouse and the current imageId to create
71
+ * a Length Annotation and stores it in the annotationManager
72
+ *
73
+ * @param evt - EventTypes.NormalizedMouseEventType
74
+ * @returns The annotation object.
75
+ *
76
+ */
77
+ addNewAnnotation = (evt: EventTypes.InteractionEventType) => {
78
+ const eventDetail = evt.detail;
79
+ const { currentPoints, element } = eventDetail;
80
+ const worldPos = currentPoints.world;
81
+ const enabledElement = getEnabledElement(element);
82
+ const { viewport, renderingEngine } = enabledElement;
83
+
84
+ const camera = viewport.getCamera();
85
+ const { viewPlaneNormal, viewUp } = camera;
86
+
87
+ const referencedImageId = this.getReferencedImageId(
88
+ viewport,
89
+ worldPos,
90
+ viewPlaneNormal,
91
+ viewUp
92
+ );
93
+
94
+ const FrameOfReferenceUID = viewport.getFrameOfReferenceUID();
95
+
96
+ const annotation = {
97
+ annotationUID: null as string,
98
+ highlighted: true,
99
+ invalidated: true,
100
+ metadata: {
101
+ toolName: this.getToolName(),
102
+ viewPlaneNormal: <Types.Point3>[...viewPlaneNormal],
103
+ viewUp: <Types.Point3>[...viewUp],
104
+ FrameOfReferenceUID,
105
+ referencedImageId,
106
+ },
107
+ data: {
108
+ text: '',
109
+ handles: {
110
+ points: new Array<Types.Point3>(),
111
+ textBox: {
112
+ hasMoved: false,
113
+ worldPosition: <Types.Point3>[0, 0, 0],
114
+ worldBoundingBox: {
115
+ topLeft: <Types.Point3>[0, 0, 0],
116
+ topRight: <Types.Point3>[0, 0, 0],
117
+ bottomLeft: <Types.Point3>[0, 0, 0],
118
+ bottomRight: <Types.Point3>[0, 0, 0],
119
+ },
120
+ },
121
+ },
122
+ label: '',
123
+ },
124
+ };
125
+
126
+ addAnnotation(annotation, element);
127
+
128
+ const viewportIdsToRender = getViewportIdsWithToolToRender(
129
+ element,
130
+ this.getToolName()
131
+ );
132
+
133
+ evt.preventDefault();
134
+
135
+ triggerAnnotationRenderForViewportIds(renderingEngine, viewportIdsToRender);
136
+
137
+ this.configuration.getTextCallback((text) => {
138
+ if (!text) {
139
+ removeAnnotation(annotation.annotationUID);
140
+ triggerAnnotationRenderForViewportIds(
141
+ renderingEngine,
142
+ viewportIdsToRender
143
+ );
144
+ this.isDrawing = false;
145
+ return;
146
+ }
147
+ annotation.data.text = text;
148
+
149
+ const eventType = Events.ANNOTATION_COMPLETED;
150
+
151
+ const eventDetail: AnnotationCompletedEventDetail = {
152
+ annotation,
153
+ };
154
+
155
+ triggerEvent(eventTarget, eventType, eventDetail);
156
+
157
+ triggerAnnotationRenderForViewportIds(
158
+ renderingEngine,
159
+ viewportIdsToRender
160
+ );
161
+ });
162
+
163
+ return annotation;
164
+ };
165
+
166
+ public cancel() {
167
+ // No op - the annotation can't be in a partial state
168
+ }
169
+
170
+ /**
171
+ * It returns if the canvas point is near the provided length annotation in the provided
172
+ * element or not. A proximity is passed to the function to determine the
173
+ * proximity of the point to the annotation in number of pixels.
174
+ *
175
+ * @param element - HTML Element
176
+ * @param annotation - Annotation
177
+ * @param canvasCoords - Canvas coordinates
178
+ * @param proximity - Proximity to tool to consider
179
+ * @returns Boolean, whether the canvas point is near tool
180
+ */
181
+ isPointNearTool = (
182
+ element: HTMLDivElement,
183
+ annotation: Annotation,
184
+ canvasCoords: Types.Point2,
185
+ proximity: number
186
+ ): boolean => {
187
+ const enabledElement = getEnabledElement(element);
188
+ const { viewport } = enabledElement;
189
+ const { data } = annotation;
190
+
191
+ const { canvasPosition, canvasSize } = this.configuration;
192
+ if (!canvasPosition?.length) {
193
+ return false;
194
+ }
195
+ if (
196
+ Math.abs(canvasCoords[0] - canvasPosition[0] + canvasSize / 2) <=
197
+ canvasSize / 2 &&
198
+ Math.abs(canvasCoords[1] - canvasPosition[1] + canvasSize / 2) <=
199
+ canvasSize / 2
200
+ ) {
201
+ return true;
202
+ }
203
+ return false;
204
+ };
205
+
206
+ toolSelectedCallback = (
207
+ evt: EventTypes.InteractionEventType,
208
+ annotation: Annotation
209
+ ): void => {
210
+ annotation.highlighted = true;
211
+
212
+ evt.preventDefault();
213
+ };
214
+
215
+ handleSelectedCallback(
216
+ evt: EventTypes.InteractionEventType,
217
+ annotation: Annotation,
218
+ handle: ToolHandle
219
+ ): void {
220
+ // Nothing special to do here.
221
+ }
222
+
223
+ _endCallback = (evt: EventTypes.InteractionEventType): void => {
224
+ const eventDetail = evt.detail;
225
+ const { element } = eventDetail;
226
+
227
+ this._deactivateModify(element);
228
+ resetElementCursor(element);
229
+ };
230
+
231
+ doubleClickCallback = (evt: EventTypes.TouchTapEventType): void => {
232
+ const eventDetail = evt.detail;
233
+ const { element } = eventDetail;
234
+ let annotations = getAnnotations(this.getToolName(), element);
235
+
236
+ annotations = this.filterInteractableAnnotationsForElement(
237
+ element,
238
+ annotations
239
+ );
240
+
241
+ if (!annotations?.length) {
242
+ return;
243
+ }
244
+
245
+ const clickedAnnotation = annotations.find((annotation) =>
246
+ this.isPointNearTool(
247
+ element,
248
+ annotation as Annotation,
249
+ eventDetail.currentPoints.canvas,
250
+ 6 // Todo: get from configuration
251
+ )
252
+ );
253
+
254
+ if (!clickedAnnotation) {
255
+ return;
256
+ }
257
+
258
+ const annotation = clickedAnnotation as Annotation;
259
+
260
+ this.configuration.changeTextCallback(
261
+ clickedAnnotation,
262
+ evt.detail,
263
+ this._doneChangingTextCallback.bind(this, element, annotation)
264
+ );
265
+
266
+ this.isDrawing = false;
267
+
268
+ // This double click was handled and the dialogue was displayed.
269
+ // No need for any other listener to handle it too - stopImmediatePropagation
270
+ // helps ensure this primarily so that no other listeners on the target element
271
+ // get called.
272
+ evt.stopImmediatePropagation();
273
+ evt.preventDefault();
274
+ };
275
+
276
+ _doneChangingTextCallback(element, annotation, updatedText): void {
277
+ annotation.data.text = updatedText;
278
+
279
+ const { renderingEngine, viewportId, renderingEngineId } =
280
+ getEnabledElement(element);
281
+
282
+ const viewportIdsToRender = getViewportIdsWithToolToRender(
283
+ element,
284
+ this.getToolName()
285
+ );
286
+ triggerAnnotationRenderForViewportIds(renderingEngine, viewportIdsToRender);
287
+
288
+ // Dispatching annotation modified
289
+ const eventType = Events.ANNOTATION_MODIFIED;
290
+
291
+ triggerEvent(eventTarget, eventType, {
292
+ annotation,
293
+ viewportId,
294
+ renderingEngineId,
295
+ });
296
+ }
297
+
298
+ _activateModify = (element: HTMLDivElement) => {
299
+ state.isInteractingWithTool = true;
300
+
301
+ element.addEventListener(
302
+ Events.MOUSE_UP,
303
+ this._endCallback as EventListener
304
+ );
305
+ element.addEventListener(
306
+ Events.MOUSE_CLICK,
307
+ this._endCallback as EventListener
308
+ );
309
+
310
+ element.addEventListener(
311
+ Events.TOUCH_TAP,
312
+ this._endCallback as EventListener
313
+ );
314
+ element.addEventListener(
315
+ Events.TOUCH_END,
316
+ this._endCallback as EventListener
317
+ );
318
+ };
319
+
320
+ _deactivateModify = (element: HTMLDivElement) => {
321
+ state.isInteractingWithTool = false;
322
+
323
+ element.removeEventListener(
324
+ Events.MOUSE_UP,
325
+ this._endCallback as EventListener
326
+ );
327
+ element.removeEventListener(
328
+ Events.MOUSE_CLICK,
329
+ this._endCallback as EventListener
330
+ );
331
+
332
+ element.removeEventListener(
333
+ Events.TOUCH_TAP,
334
+ this._endCallback as EventListener
335
+ );
336
+ element.removeEventListener(
337
+ Events.TOUCH_END,
338
+ this._endCallback as EventListener
339
+ );
340
+ };
341
+
342
+ /**
343
+ * it is used to draw the length annotation in each
344
+ * request animation frame. It calculates the updated cached statistics if
345
+ * data is invalidated and cache it.
346
+ *
347
+ * @param enabledElement - The Cornerstone's enabledElement.
348
+ * @param svgDrawingHelper - The svgDrawingHelper providing the context for drawing.
349
+ */
350
+ renderAnnotation = (
351
+ enabledElement: Types.IEnabledElement,
352
+ svgDrawingHelper: SVGDrawingHelper
353
+ ): boolean => {
354
+ let renderStatus = false;
355
+ const { viewport } = enabledElement;
356
+ const { element } = viewport;
357
+
358
+ let annotations = getAnnotations(this.getToolName(), element);
359
+
360
+ // Todo: We don't need this anymore, filtering happens in triggerAnnotationRender
361
+ if (!annotations?.length) {
362
+ return renderStatus;
363
+ }
364
+
365
+ annotations = this.filterInteractableAnnotationsForElement(
366
+ element,
367
+ annotations
368
+ );
369
+
370
+ if (!annotations?.length) {
371
+ return renderStatus;
372
+ }
373
+
374
+ const styleSpecifier: StyleSpecifier = {
375
+ toolGroupId: this.toolGroupId,
376
+ toolName: this.getToolName(),
377
+ viewportId: enabledElement.viewport.id,
378
+ };
379
+
380
+ // Draw SVG
381
+ for (let i = 0; i < annotations.length; i++) {
382
+ const annotation = annotations[i];
383
+ const { annotationUID } = annotation;
384
+
385
+ styleSpecifier.annotationUID = annotationUID;
386
+
387
+ const color = this.getStyle('color', styleSpecifier, annotation);
388
+
389
+ const { canvasPosition, canvasSize } = this.configuration;
390
+ if (canvasPosition?.length) {
391
+ const arrowUID = '1';
392
+ drawArrowSvg(
393
+ svgDrawingHelper,
394
+ annotationUID,
395
+ arrowUID,
396
+ canvasPosition.map((it) => it + canvasSize) as Point2,
397
+ canvasPosition as Point2,
398
+ {
399
+ color,
400
+ width: 1,
401
+ }
402
+ );
403
+ }
404
+
405
+ renderStatus = true;
406
+
407
+ // If rendering engine has been destroyed while rendering
408
+ if (!viewport.getRenderingEngine()) {
409
+ console.warn('Rendering Engine has been destroyed');
410
+ return renderStatus;
411
+ }
412
+ }
413
+
414
+ return renderStatus;
415
+ };
416
+
417
+ _isInsideVolume(index1, index2, dimensions) {
418
+ return (
419
+ csUtils.indexWithinDimensions(index1, dimensions) &&
420
+ csUtils.indexWithinDimensions(index2, dimensions)
421
+ );
422
+ }
423
+ }
424
+
425
+ function getTextCallback(doneChangingTextCallback) {
426
+ return doneChangingTextCallback(prompt('Enter your annotation:'));
427
+ }
428
+
429
+ function changeTextCallback(data, eventData, doneChangingTextCallback) {
430
+ return doneChangingTextCallback(prompt('Enter your annotation:'));
431
+ }
432
+
433
+ KeyImageTool.toolName = 'KeyImage';
434
+
435
+ export default KeyImageTool;
@@ -492,11 +492,7 @@ class PlanarFreehandROITool extends AnnotationTool {
492
492
 
493
493
  let annotationsToDisplay;
494
494
 
495
- if (viewport instanceof StackViewport) {
496
- // Use the default `filterAnnotationsForDisplay` utility, as the stack
497
- // path doesn't require handles.
498
- annotationsToDisplay = filterAnnotationsForDisplay(viewport, annotations);
499
- } else if (viewport instanceof VolumeViewport) {
495
+ if (viewport instanceof VolumeViewport) {
500
496
  const camera = viewport.getCamera();
501
497
 
502
498
  const { spacingInNormalDirection } =
@@ -509,7 +505,9 @@ class PlanarFreehandROITool extends AnnotationTool {
509
505
  spacingInNormalDirection
510
506
  );
511
507
  } else {
512
- throw new Error(`Viewport Type ${viewport.type} not supported`);
508
+ // Use the default `filterAnnotationsForDisplay` utility, as the stack
509
+ // path doesn't require handles.
510
+ annotationsToDisplay = filterAnnotationsForDisplay(viewport, annotations);
513
511
  }
514
512
 
515
513
  return annotationsToDisplay;