@cornerstonejs/tools 1.12.0 → 1.13.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.
Files changed (141) hide show
  1. package/dist/cjs/eventListeners/keyboard/keyDownListener.js +8 -0
  2. package/dist/cjs/eventListeners/keyboard/keyDownListener.js.map +1 -1
  3. package/dist/cjs/store/ToolGroupManager/ToolGroup.d.ts +3 -3
  4. package/dist/cjs/store/ToolGroupManager/ToolGroup.js.map +1 -1
  5. package/dist/cjs/tools/annotation/AngleTool.d.ts +0 -1
  6. package/dist/cjs/tools/annotation/AngleTool.js +11 -10
  7. package/dist/cjs/tools/annotation/AngleTool.js.map +1 -1
  8. package/dist/cjs/tools/annotation/BidirectionalTool.d.ts +0 -1
  9. package/dist/cjs/tools/annotation/BidirectionalTool.js +14 -13
  10. package/dist/cjs/tools/annotation/BidirectionalTool.js.map +1 -1
  11. package/dist/cjs/tools/annotation/CircleROITool.d.ts +0 -1
  12. package/dist/cjs/tools/annotation/CircleROITool.js +39 -51
  13. package/dist/cjs/tools/annotation/CircleROITool.js.map +1 -1
  14. package/dist/cjs/tools/annotation/CobbAngleTool.d.ts +0 -1
  15. package/dist/cjs/tools/annotation/CobbAngleTool.js +11 -10
  16. package/dist/cjs/tools/annotation/CobbAngleTool.js.map +1 -1
  17. package/dist/cjs/tools/annotation/DragProbeTool.js +13 -1
  18. package/dist/cjs/tools/annotation/DragProbeTool.js.map +1 -1
  19. package/dist/cjs/tools/annotation/EllipticalROITool.d.ts +0 -1
  20. package/dist/cjs/tools/annotation/EllipticalROITool.js +33 -45
  21. package/dist/cjs/tools/annotation/EllipticalROITool.js.map +1 -1
  22. package/dist/cjs/tools/annotation/LengthTool.d.ts +0 -1
  23. package/dist/cjs/tools/annotation/LengthTool.js +11 -10
  24. package/dist/cjs/tools/annotation/LengthTool.js.map +1 -1
  25. package/dist/cjs/tools/annotation/PlanarFreehandROITool.d.ts +0 -1
  26. package/dist/cjs/tools/annotation/PlanarFreehandROITool.js +34 -42
  27. package/dist/cjs/tools/annotation/PlanarFreehandROITool.js.map +1 -1
  28. package/dist/cjs/tools/annotation/ProbeTool.d.ts +0 -1
  29. package/dist/cjs/tools/annotation/ProbeTool.js +13 -12
  30. package/dist/cjs/tools/annotation/ProbeTool.js.map +1 -1
  31. package/dist/cjs/tools/annotation/RectangleROITool.d.ts +0 -1
  32. package/dist/cjs/tools/annotation/RectangleROITool.js +31 -47
  33. package/dist/cjs/tools/annotation/RectangleROITool.js.map +1 -1
  34. package/dist/cjs/tools/base/AnnotationTool.d.ts +2 -1
  35. package/dist/cjs/tools/base/AnnotationTool.js +10 -2
  36. package/dist/cjs/tools/base/AnnotationTool.js.map +1 -1
  37. package/dist/cjs/types/CalculatorTypes.d.ts +6 -0
  38. package/dist/cjs/types/CalculatorTypes.js +3 -0
  39. package/dist/cjs/types/CalculatorTypes.js.map +1 -0
  40. package/dist/cjs/types/IToolGroup.d.ts +3 -2
  41. package/dist/cjs/types/ToolProps.d.ts +5 -1
  42. package/dist/cjs/types/index.d.ts +3 -2
  43. package/dist/cjs/utilities/math/basic/BasicStatsCalculator.d.ts +14 -0
  44. package/dist/cjs/utilities/math/basic/BasicStatsCalculator.js +44 -0
  45. package/dist/cjs/utilities/math/basic/BasicStatsCalculator.js.map +1 -0
  46. package/dist/cjs/utilities/math/basic/Calculator.d.ts +8 -0
  47. package/dist/cjs/utilities/math/basic/Calculator.js +6 -0
  48. package/dist/cjs/utilities/math/basic/Calculator.js.map +1 -0
  49. package/dist/cjs/utilities/math/basic/index.d.ts +3 -0
  50. package/dist/cjs/utilities/math/basic/index.js +11 -0
  51. package/dist/cjs/utilities/math/basic/index.js.map +1 -0
  52. package/dist/cjs/utilities/math/index.d.ts +2 -1
  53. package/dist/cjs/utilities/math/index.js +3 -1
  54. package/dist/cjs/utilities/math/index.js.map +1 -1
  55. package/dist/cjs/utilities/math/vec2/liangBarksyClip.d.ts +1 -1
  56. package/dist/cjs/utilities/pointInShapeCallback.d.ts +7 -1
  57. package/dist/cjs/utilities/pointInShapeCallback.js +6 -1
  58. package/dist/cjs/utilities/pointInShapeCallback.js.map +1 -1
  59. package/dist/esm/eventListeners/keyboard/keyDownListener.js +8 -0
  60. package/dist/esm/eventListeners/keyboard/keyDownListener.js.map +1 -1
  61. package/dist/esm/store/ToolGroupManager/ToolGroup.d.ts +3 -3
  62. package/dist/esm/store/ToolGroupManager/ToolGroup.js.map +1 -1
  63. package/dist/esm/tools/annotation/AngleTool.d.ts +0 -1
  64. package/dist/esm/tools/annotation/AngleTool.js +11 -10
  65. package/dist/esm/tools/annotation/AngleTool.js.map +1 -1
  66. package/dist/esm/tools/annotation/BidirectionalTool.d.ts +0 -1
  67. package/dist/esm/tools/annotation/BidirectionalTool.js +14 -13
  68. package/dist/esm/tools/annotation/BidirectionalTool.js.map +1 -1
  69. package/dist/esm/tools/annotation/CircleROITool.d.ts +0 -1
  70. package/dist/esm/tools/annotation/CircleROITool.js +38 -51
  71. package/dist/esm/tools/annotation/CircleROITool.js.map +1 -1
  72. package/dist/esm/tools/annotation/CobbAngleTool.d.ts +0 -1
  73. package/dist/esm/tools/annotation/CobbAngleTool.js +11 -10
  74. package/dist/esm/tools/annotation/CobbAngleTool.js.map +1 -1
  75. package/dist/esm/tools/annotation/DragProbeTool.js +13 -1
  76. package/dist/esm/tools/annotation/DragProbeTool.js.map +1 -1
  77. package/dist/esm/tools/annotation/EllipticalROITool.d.ts +0 -1
  78. package/dist/esm/tools/annotation/EllipticalROITool.js +32 -45
  79. package/dist/esm/tools/annotation/EllipticalROITool.js.map +1 -1
  80. package/dist/esm/tools/annotation/LengthTool.d.ts +0 -1
  81. package/dist/esm/tools/annotation/LengthTool.js +11 -10
  82. package/dist/esm/tools/annotation/LengthTool.js.map +1 -1
  83. package/dist/esm/tools/annotation/PlanarFreehandROITool.d.ts +0 -1
  84. package/dist/esm/tools/annotation/PlanarFreehandROITool.js +33 -42
  85. package/dist/esm/tools/annotation/PlanarFreehandROITool.js.map +1 -1
  86. package/dist/esm/tools/annotation/ProbeTool.d.ts +0 -1
  87. package/dist/esm/tools/annotation/ProbeTool.js +13 -12
  88. package/dist/esm/tools/annotation/ProbeTool.js.map +1 -1
  89. package/dist/esm/tools/annotation/RectangleROITool.d.ts +0 -1
  90. package/dist/esm/tools/annotation/RectangleROITool.js +30 -47
  91. package/dist/esm/tools/annotation/RectangleROITool.js.map +1 -1
  92. package/dist/esm/tools/base/AnnotationTool.d.ts +2 -1
  93. package/dist/esm/tools/base/AnnotationTool.js +9 -2
  94. package/dist/esm/tools/base/AnnotationTool.js.map +1 -1
  95. package/dist/esm/types/CalculatorTypes.d.ts +6 -0
  96. package/dist/esm/types/CalculatorTypes.js +2 -0
  97. package/dist/esm/types/CalculatorTypes.js.map +1 -0
  98. package/dist/esm/types/IToolGroup.d.ts +3 -2
  99. package/dist/esm/types/ToolProps.d.ts +5 -1
  100. package/dist/esm/types/index.d.ts +3 -2
  101. package/dist/esm/utilities/math/basic/BasicStatsCalculator.d.ts +14 -0
  102. package/dist/esm/utilities/math/basic/BasicStatsCalculator.js +36 -0
  103. package/dist/esm/utilities/math/basic/BasicStatsCalculator.js.map +1 -0
  104. package/dist/esm/utilities/math/basic/Calculator.d.ts +8 -0
  105. package/dist/esm/utilities/math/basic/Calculator.js +4 -0
  106. package/dist/esm/utilities/math/basic/Calculator.js.map +1 -0
  107. package/dist/esm/utilities/math/basic/index.d.ts +3 -0
  108. package/dist/esm/utilities/math/basic/index.js +4 -0
  109. package/dist/esm/utilities/math/basic/index.js.map +1 -0
  110. package/dist/esm/utilities/math/index.d.ts +2 -1
  111. package/dist/esm/utilities/math/index.js +2 -1
  112. package/dist/esm/utilities/math/index.js.map +1 -1
  113. package/dist/esm/utilities/math/vec2/liangBarksyClip.d.ts +1 -1
  114. package/dist/esm/utilities/pointInShapeCallback.d.ts +7 -1
  115. package/dist/esm/utilities/pointInShapeCallback.js +6 -1
  116. package/dist/esm/utilities/pointInShapeCallback.js.map +1 -1
  117. package/dist/umd/index.js +1 -1
  118. package/dist/umd/index.js.map +1 -1
  119. package/package.json +3 -3
  120. package/src/eventListeners/keyboard/keyDownListener.ts +13 -0
  121. package/src/store/ToolGroupManager/ToolGroup.ts +4 -3
  122. package/src/tools/annotation/AngleTool.ts +15 -15
  123. package/src/tools/annotation/BidirectionalTool.ts +21 -22
  124. package/src/tools/annotation/CircleROITool.ts +64 -87
  125. package/src/tools/annotation/CobbAngleTool.ts +15 -15
  126. package/src/tools/annotation/DragProbeTool.ts +19 -1
  127. package/src/tools/annotation/EllipticalROITool.ts +47 -70
  128. package/src/tools/annotation/LengthTool.ts +16 -16
  129. package/src/tools/annotation/PlanarFreehandROITool.ts +36 -49
  130. package/src/tools/annotation/ProbeTool.ts +20 -18
  131. package/src/tools/annotation/RectangleROITool.ts +51 -74
  132. package/src/tools/base/AnnotationTool.ts +16 -1
  133. package/src/types/CalculatorTypes.ts +7 -0
  134. package/src/types/IToolGroup.ts +6 -3
  135. package/src/types/ToolProps.ts +7 -1
  136. package/src/types/index.ts +9 -1
  137. package/src/utilities/math/basic/BasicStatsCalculator.ts +60 -0
  138. package/src/utilities/math/basic/Calculator.ts +8 -0
  139. package/src/utilities/math/basic/index.ts +4 -0
  140. package/src/utilities/math/index.ts +10 -1
  141. package/src/utilities/pointInShapeCallback.ts +15 -3
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cornerstonejs/tools",
3
- "version": "1.12.0",
3
+ "version": "1.13.0",
4
4
  "description": "Cornerstone3D Tools",
5
5
  "main": "dist/umd/index.js",
6
6
  "types": "dist/esm/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.12.0",
32
+ "@cornerstonejs/core": "^1.13.0",
33
33
  "lodash.clonedeep": "4.5.0",
34
34
  "lodash.get": "^4.4.2"
35
35
  },
@@ -52,5 +52,5 @@
52
52
  "type": "individual",
53
53
  "url": "https://ohif.org/donate"
54
54
  },
55
- "gitHead": "a97d174f00bc561ade811652f0167f3d783b1927"
55
+ "gitHead": "64173701acdeb7097e6ae4122606138065ebcecc"
56
56
  }
@@ -64,11 +64,23 @@ function keyListener(evt: KeyboardEvent): void {
64
64
  triggerEvent(eventDetail.element, Events.KEY_DOWN, eventDetail);
65
65
 
66
66
  document.addEventListener('keyup', _onKeyUp);
67
+ document.addEventListener('visibilitychange', _onVisibilityChange);
67
68
 
68
69
  // Todo: handle combination of keys
69
70
  state.element.removeEventListener('keydown', keyListener);
70
71
  }
71
72
 
73
+ /**
74
+ * Whenever the visibility (i.e. tab focus) changes such that the tab is NOT the
75
+ * active tab, reset the modifier key.
76
+ */
77
+ function _onVisibilityChange(): void {
78
+ document.removeEventListener('visibilitychange', _onVisibilityChange);
79
+ if (document.visibilityState === 'hidden') {
80
+ resetModifierKey();
81
+ }
82
+ }
83
+
72
84
  function _onKeyUp(evt: KeyboardEvent): void {
73
85
  const eventDetail: KeyUpEventDetail = {
74
86
  renderingEngineId: state.renderingEngineId,
@@ -81,6 +93,7 @@ function _onKeyUp(evt: KeyboardEvent): void {
81
93
 
82
94
  // Remove our temporary handlers
83
95
  document.removeEventListener('keyup', _onKeyUp);
96
+ document.removeEventListener('visibilitychange', _onVisibilityChange);
84
97
  state.element.addEventListener('keydown', keyListener);
85
98
 
86
99
  // Restore `state` to `defaultState`
@@ -20,6 +20,7 @@ import {
20
20
  IToolGroup,
21
21
  SetToolBindingsType,
22
22
  ToolOptionsType,
23
+ ToolConfiguration,
23
24
  } from '../../types';
24
25
 
25
26
  import { MouseCursor, SVGMouseCursor } from '../../cursors';
@@ -87,9 +88,9 @@ export default class ToolGroup implements IToolGroup {
87
88
  * to set the tool to be active or passive or in other states.
88
89
  *
89
90
  * @param toolName - string
90
- * @param configuration - Tool configuration objects
91
+ * @param configuration - Tool configuration objects and a custom statistics calculator if needed
91
92
  */
92
- addTool(toolName: string, configuration = {}): void {
93
+ addTool(toolName: string, configuration: ToolConfiguration = {}): void {
93
94
  const toolDefinition = state.tools[toolName];
94
95
  const hasToolName = typeof toolName !== 'undefined' && toolName !== '';
95
96
  const localToolInstance = this.toolOptions[toolName];
@@ -605,7 +606,7 @@ export default class ToolGroup implements IToolGroup {
605
606
  */
606
607
  public setToolConfiguration(
607
608
  toolName: string,
608
- configuration: Record<any, any>,
609
+ configuration: ToolConfiguration,
609
610
  overwrite?: boolean
610
611
  ): boolean {
611
612
  if (this._toolInstances[toolName] === undefined) {
@@ -74,6 +74,7 @@ class AngleTool extends AnnotationTool {
74
74
  configuration: {
75
75
  shadow: true,
76
76
  preventHandleOutsideImage: false,
77
+ getTextLines: defaultGetTextLines,
77
78
  },
78
79
  }
79
80
  ) {
@@ -744,7 +745,7 @@ class AngleTool extends AnnotationTool {
744
745
  continue;
745
746
  }
746
747
 
747
- const textLines = this._getTextLines(data, targetId);
748
+ const textLines = this.configuration.getTextLines(data, targetId);
748
749
 
749
750
  if (!data.handles.textBox.hasMoved) {
750
751
  // linked to the vertex by default
@@ -783,20 +784,6 @@ class AngleTool extends AnnotationTool {
783
784
  return renderStatus;
784
785
  };
785
786
 
786
- // text line for the current active angle annotation
787
- _getTextLines(data, targetId) {
788
- const cachedVolumeStats = data.cachedStats[targetId];
789
- const { angle } = cachedVolumeStats;
790
-
791
- if (angle === undefined) {
792
- return;
793
- }
794
-
795
- const textLines = [`${roundNumber(angle)} ${String.fromCharCode(176)}`];
796
-
797
- return textLines;
798
- }
799
-
800
787
  _calculateCachedStats(annotation, renderingEngine, enabledElement) {
801
788
  const data = annotation.data;
802
789
  const { viewportId, renderingEngineId } = enabledElement;
@@ -841,5 +828,18 @@ class AngleTool extends AnnotationTool {
841
828
  }
842
829
  }
843
830
 
831
+ function defaultGetTextLines(data, targetId): string[] {
832
+ const cachedVolumeStats = data.cachedStats[targetId];
833
+ const { angle } = cachedVolumeStats;
834
+
835
+ if (angle === undefined) {
836
+ return;
837
+ }
838
+
839
+ const textLines = [`${roundNumber(angle)} ${String.fromCharCode(176)}`];
840
+
841
+ return textLines;
842
+ }
843
+
844
844
  AngleTool.toolName = 'Angle';
845
845
  export default AngleTool;
@@ -91,6 +91,7 @@ const { transformWorldToIndex } = csUtils;
91
91
  *
92
92
  * Read more in the Docs section of the website.
93
93
  */
94
+
94
95
  class BidirectionalTool extends AnnotationTool {
95
96
  static toolName;
96
97
 
@@ -115,6 +116,7 @@ class BidirectionalTool extends AnnotationTool {
115
116
  supportedInteractionTypes: ['Mouse', 'Touch'],
116
117
  configuration: {
117
118
  preventHandleOutsideImage: false,
119
+ getTextLines: defaultGetTextLines,
118
120
  },
119
121
  }
120
122
  ) {
@@ -1160,7 +1162,7 @@ class BidirectionalTool extends AnnotationTool {
1160
1162
 
1161
1163
  renderStatus = true;
1162
1164
 
1163
- const textLines = this._getTextLines(data, targetId);
1165
+ const textLines = this.configuration.getTextLines(data, targetId);
1164
1166
 
1165
1167
  if (!textLines || textLines.length === 0) {
1166
1168
  continue;
@@ -1243,27 +1245,6 @@ class BidirectionalTool extends AnnotationTool {
1243
1245
  return wouldPutThroughShortAxis;
1244
1246
  };
1245
1247
 
1246
- /**
1247
- * get text box content
1248
- */
1249
- _getTextLines = (data, targetId) => {
1250
- const { cachedStats } = data;
1251
- const { length, width, unit } = cachedStats[targetId];
1252
-
1253
- if (length === undefined) {
1254
- return;
1255
- }
1256
-
1257
- // spaceBetweenSlices & pixelSpacing &
1258
- // magnitude in each direction? Otherwise, this is "px"?
1259
- const textLines = [
1260
- `L: ${roundNumber(length)} ${unit}`,
1261
- `W: ${roundNumber(width)} ${unit}`,
1262
- ];
1263
-
1264
- return textLines;
1265
- };
1266
-
1267
1248
  _calculateLength(pos1, pos2) {
1268
1249
  const dx = pos1[0] - pos2[0];
1269
1250
  const dy = pos1[1] - pos2[1];
@@ -1351,5 +1332,23 @@ class BidirectionalTool extends AnnotationTool {
1351
1332
  };
1352
1333
  }
1353
1334
 
1335
+ function defaultGetTextLines(data, targetId): string[] {
1336
+ const { cachedStats } = data;
1337
+ const { length, width, unit } = cachedStats[targetId];
1338
+
1339
+ if (length === undefined) {
1340
+ return;
1341
+ }
1342
+
1343
+ // spaceBetweenSlices & pixelSpacing &
1344
+ // magnitude in each direction? Otherwise, this is "px"?
1345
+ const textLines = [
1346
+ `L: ${roundNumber(length)} ${unit}`,
1347
+ `W: ${roundNumber(width)} ${unit}`,
1348
+ ];
1349
+
1350
+ return textLines;
1351
+ }
1352
+
1354
1353
  BidirectionalTool.toolName = 'Bidirectional';
1355
1354
  export default BidirectionalTool;
@@ -68,6 +68,7 @@ import {
68
68
  getCanvasCircleRadius,
69
69
  } from '../../utilities/math/circle';
70
70
  import { pointInEllipse } from '../../utilities/math/ellipse';
71
+ import { BasicStatsCalculator } from '../../utilities/math/basic';
71
72
 
72
73
  const { transformWorldToIndex } = csUtils;
73
74
 
@@ -117,8 +118,10 @@ const { transformWorldToIndex } = csUtils;
117
118
  *
118
119
  * Read more in the Docs section of the website.
119
120
  */
121
+
120
122
  class CircleROITool extends AnnotationTool {
121
123
  static toolName;
124
+
122
125
  touchDragCallback: any;
123
126
  mouseDragCallback: any;
124
127
  _throttledCalculateCachedStats: any;
@@ -143,6 +146,8 @@ class CircleROITool extends AnnotationTool {
143
146
  // Radius of the circle to draw at the center point of the circle.
144
147
  // Set this zero(0) in order not to draw the circle.
145
148
  centerPointRadius: 0,
149
+ getTextLines: defaultGetTextLines,
150
+ statsCalculator: BasicStatsCalculator,
146
151
  },
147
152
  }
148
153
  ) {
@@ -821,7 +826,7 @@ class CircleROITool extends AnnotationTool {
821
826
 
822
827
  renderStatus = true;
823
828
 
824
- const textLines = this._getTextLines(data, targetId);
829
+ const textLines = this.configuration.getTextLines(data, targetId);
825
830
  if (!textLines || textLines.length === 0) {
826
831
  continue;
827
832
  }
@@ -865,52 +870,6 @@ class CircleROITool extends AnnotationTool {
865
870
  return renderStatus;
866
871
  };
867
872
 
868
- _getTextLines = (data, targetId: string): string[] => {
869
- const cachedVolumeStats = data.cachedStats[targetId];
870
- const {
871
- radius,
872
- radiusUnit,
873
- area,
874
- mean,
875
- stdDev,
876
- max,
877
- isEmptyArea,
878
- Modality,
879
- areaUnit,
880
- modalityUnit,
881
- } = cachedVolumeStats;
882
-
883
- const textLines: string[] = [];
884
-
885
- if (radius) {
886
- const radiusLine = isEmptyArea
887
- ? `Radius: Oblique not supported`
888
- : `Radius: ${roundNumber(radius)} ${radiusUnit}`;
889
- textLines.push(radiusLine);
890
- }
891
-
892
- if (area) {
893
- const areaLine = isEmptyArea
894
- ? `Area: Oblique not supported`
895
- : `Area: ${roundNumber(area)} ${areaUnit}`;
896
- textLines.push(areaLine);
897
- }
898
-
899
- if (mean) {
900
- textLines.push(`Mean: ${roundNumber(mean)} ${modalityUnit}`);
901
- }
902
-
903
- if (max) {
904
- textLines.push(`Max: ${roundNumber(max)} ${modalityUnit}`);
905
- }
906
-
907
- if (stdDev) {
908
- textLines.push(`Std Dev: ${roundNumber(stdDev)} ${modalityUnit}`);
909
- }
910
-
911
- return textLines;
912
- };
913
-
914
873
  _calculateCachedStats = (
915
874
  annotation,
916
875
  viewport,
@@ -1011,57 +970,29 @@ class CircleROITool extends AnnotationTool {
1011
970
  (worldHeight / aspect / scale / 2)
1012
971
  );
1013
972
 
1014
- let count = 0;
1015
- let mean = 0;
1016
- let stdDev = 0;
1017
- let max = -Infinity;
1018
-
1019
- const meanMaxCalculator = ({ value: newValue }) => {
1020
- if (newValue > max) {
1021
- max = newValue;
1022
- }
1023
-
1024
- mean += newValue;
1025
- count += 1;
1026
- };
1027
-
1028
- pointInShapeCallback(
1029
- imageData,
1030
- (pointLPS, pointIJK) => pointInEllipse(ellipseObj, pointLPS),
1031
- meanMaxCalculator,
1032
- boundsIJK
973
+ const modalityUnit = getModalityUnit(
974
+ metadata.Modality,
975
+ annotation.metadata.referencedImageId,
976
+ modalityUnitOptions
1033
977
  );
1034
978
 
1035
- mean /= count;
1036
-
1037
- const stdCalculator = ({ value }) => {
1038
- const valueMinusMean = value - mean;
1039
-
1040
- stdDev += valueMinusMean * valueMinusMean;
1041
- };
1042
-
1043
- pointInShapeCallback(
979
+ const pointsInShape = pointInShapeCallback(
1044
980
  imageData,
1045
981
  (pointLPS, pointIJK) => pointInEllipse(ellipseObj, pointLPS),
1046
- stdCalculator,
982
+ this.configuration.statsCalculator.statsCallback,
1047
983
  boundsIJK
1048
984
  );
1049
985
 
1050
- stdDev /= count;
1051
- stdDev = Math.sqrt(stdDev);
1052
-
1053
- const modalityUnit = getModalityUnit(
1054
- metadata.Modality,
1055
- annotation.metadata.referencedImageId,
1056
- modalityUnitOptions
1057
- );
986
+ const stats = this.configuration.statsCalculator.getStatistics();
1058
987
 
1059
988
  cachedStats[targetId] = {
1060
989
  Modality: metadata.Modality,
1061
990
  area,
1062
- mean,
1063
- max,
1064
- stdDev,
991
+ mean: stats[1]?.value,
992
+ max: stats[0]?.value,
993
+ stdDev: stats[2]?.value,
994
+ statsArray: stats,
995
+ pointsInShape: pointsInShape,
1065
996
  isEmptyArea,
1066
997
  areaUnit: getCalibratedAreaUnits(null, image),
1067
998
  radius: worldWidth / 2 / scale,
@@ -1102,5 +1033,51 @@ class CircleROITool extends AnnotationTool {
1102
1033
  };
1103
1034
  }
1104
1035
 
1036
+ function defaultGetTextLines(data, targetId): string[] {
1037
+ const cachedVolumeStats = data.cachedStats[targetId];
1038
+ const {
1039
+ radius,
1040
+ radiusUnit,
1041
+ area,
1042
+ mean,
1043
+ stdDev,
1044
+ max,
1045
+ isEmptyArea,
1046
+ Modality,
1047
+ areaUnit,
1048
+ modalityUnit,
1049
+ } = cachedVolumeStats;
1050
+
1051
+ const textLines: string[] = [];
1052
+
1053
+ if (radius) {
1054
+ const radiusLine = isEmptyArea
1055
+ ? `Radius: Oblique not supported`
1056
+ : `Radius: ${roundNumber(radius)} ${radiusUnit}`;
1057
+ textLines.push(radiusLine);
1058
+ }
1059
+
1060
+ if (area) {
1061
+ const areaLine = isEmptyArea
1062
+ ? `Area: Oblique not supported`
1063
+ : `Area: ${roundNumber(area)} ${areaUnit}`;
1064
+ textLines.push(areaLine);
1065
+ }
1066
+
1067
+ if (mean) {
1068
+ textLines.push(`Mean: ${roundNumber(mean)} ${modalityUnit}`);
1069
+ }
1070
+
1071
+ if (max) {
1072
+ textLines.push(`Max: ${roundNumber(max)} ${modalityUnit}`);
1073
+ }
1074
+
1075
+ if (stdDev) {
1076
+ textLines.push(`Std Dev: ${roundNumber(stdDev)} ${modalityUnit}`);
1077
+ }
1078
+
1079
+ return textLines;
1080
+ }
1081
+
1105
1082
  CircleROITool.toolName = 'CircleROI';
1106
1083
  export default CircleROITool;
@@ -75,6 +75,7 @@ class CobbAngleTool extends AnnotationTool {
75
75
  configuration: {
76
76
  shadow: true,
77
77
  preventHandleOutsideImage: false,
78
+ getTextLines: defaultGetTextLines,
78
79
  },
79
80
  }
80
81
  ) {
@@ -769,7 +770,7 @@ class CobbAngleTool extends AnnotationTool {
769
770
  continue;
770
771
  }
771
772
 
772
- const textLines = this._getTextLines(data, targetId);
773
+ const textLines = this.configuration.getTextLines(data, targetId);
773
774
 
774
775
  if (!data.handles.textBox.hasMoved) {
775
776
  const canvasTextBoxCoords = getTextBoxCoordsCanvas(canvasCoordinates);
@@ -807,20 +808,6 @@ class CobbAngleTool extends AnnotationTool {
807
808
  return renderStatus;
808
809
  };
809
810
 
810
- // text line for the current active angle annotation
811
- _getTextLines(data, targetId) {
812
- const cachedVolumeStats = data.cachedStats[targetId];
813
- const { angle } = cachedVolumeStats;
814
-
815
- if (angle === undefined) {
816
- return;
817
- }
818
-
819
- const textLines = [`${angle.toFixed(2)} ${String.fromCharCode(176)}`];
820
-
821
- return textLines;
822
- }
823
-
824
811
  _calculateCachedStats(annotation, renderingEngine, enabledElement) {
825
812
  const data = annotation.data;
826
813
  const { viewportId, renderingEngineId } = enabledElement;
@@ -886,5 +873,18 @@ class CobbAngleTool extends AnnotationTool {
886
873
  }
887
874
  }
888
875
 
876
+ function defaultGetTextLines(data, targetId): string[] {
877
+ const cachedVolumeStats = data.cachedStats[targetId];
878
+ const { angle } = cachedVolumeStats;
879
+
880
+ if (angle === undefined) {
881
+ return;
882
+ }
883
+
884
+ const textLines = [`${angle.toFixed(2)} ${String.fromCharCode(176)}`];
885
+
886
+ return textLines;
887
+ }
888
+
889
889
  CobbAngleTool.toolName = 'CobbAngle';
890
890
  export default CobbAngleTool;
@@ -44,6 +44,7 @@ class DragProbeTool extends ProbeTool {
44
44
  configuration: {
45
45
  shadow: true,
46
46
  preventHandleOutsideImage: false,
47
+ getTextLines: defaultGetTextLines,
47
48
  },
48
49
  }
49
50
  ) {
@@ -205,7 +206,7 @@ class DragProbeTool extends ProbeTool {
205
206
 
206
207
  renderStatus = true;
207
208
 
208
- const textLines = this._getTextLines(data, targetId);
209
+ const textLines = this.configuration.getTextLines(data, targetId);
209
210
  if (textLines) {
210
211
  const textCanvasCoordinates = [
211
212
  canvasCoordinates[0] + 6,
@@ -227,5 +228,22 @@ class DragProbeTool extends ProbeTool {
227
228
  };
228
229
  }
229
230
 
231
+ function defaultGetTextLines(data, targetId): string[] {
232
+ const cachedVolumeStats = data.cachedStats[targetId];
233
+ const { index, value, modalityUnit } = cachedVolumeStats;
234
+
235
+ if (value === undefined) {
236
+ return;
237
+ }
238
+
239
+ const textLines = [];
240
+
241
+ textLines.push(`(${index[0]}, ${index[1]}, ${index[2]})`);
242
+
243
+ textLines.push(`${value.toFixed(2)} ${modalityUnit}`);
244
+
245
+ return textLines;
246
+ }
247
+
230
248
  DragProbeTool.toolName = 'DragProbe';
231
249
  export default DragProbeTool;
@@ -66,6 +66,7 @@ import {
66
66
  getModalityUnit,
67
67
  } from '../../utilities/getModalityUnit';
68
68
  import { isViewportPreScaled } from '../../utilities/viewport/isViewportPreScaled';
69
+ import { BasicStatsCalculator } from '../../utilities/math/basic';
69
70
 
70
71
  const { transformWorldToIndex } = csUtils;
71
72
 
@@ -115,8 +116,10 @@ const { transformWorldToIndex } = csUtils;
115
116
  *
116
117
  * Read more in the Docs section of the website.
117
118
  */
119
+
118
120
  class EllipticalROITool extends AnnotationTool {
119
121
  static toolName;
122
+
120
123
  touchDragCallback: any;
121
124
  mouseDragCallback: any;
122
125
  _throttledCalculateCachedStats: any;
@@ -145,6 +148,8 @@ class EllipticalROITool extends AnnotationTool {
145
148
  // Radius of the circle to draw at the center point of the ellipse.
146
149
  // Set this zero(0) in order not to draw the circle.
147
150
  centerPointRadius: 0,
151
+ getTextLines: defaultGetTextLines,
152
+ statsCalculator: BasicStatsCalculator,
148
153
  },
149
154
  }
150
155
  ) {
@@ -945,7 +950,7 @@ class EllipticalROITool extends AnnotationTool {
945
950
 
946
951
  renderStatus = true;
947
952
 
948
- const textLines = this._getTextLines(data, targetId);
953
+ const textLines = this.configuration.getTextLines(data, targetId);
949
954
  if (!textLines || textLines.length === 0) {
950
955
  continue;
951
956
  }
@@ -989,35 +994,6 @@ class EllipticalROITool extends AnnotationTool {
989
994
  return renderStatus;
990
995
  };
991
996
 
992
- _getTextLines = (data, targetId: string): string[] => {
993
- const cachedVolumeStats = data.cachedStats[targetId];
994
- const { area, mean, stdDev, max, isEmptyArea, areaUnit, modalityUnit } =
995
- cachedVolumeStats;
996
-
997
- const textLines: string[] = [];
998
-
999
- if (area) {
1000
- const areaLine = isEmptyArea
1001
- ? `Area: Oblique not supported`
1002
- : `Area: ${roundNumber(area)} ${areaUnit}`;
1003
- textLines.push(areaLine);
1004
- }
1005
-
1006
- if (mean) {
1007
- textLines.push(`Mean: ${roundNumber(mean)} ${modalityUnit}`);
1008
- }
1009
-
1010
- if (max) {
1011
- textLines.push(`Max: ${roundNumber(max)} ${modalityUnit}`);
1012
- }
1013
-
1014
- if (stdDev) {
1015
- textLines.push(`Std Dev: ${roundNumber(stdDev)} ${modalityUnit}`);
1016
- }
1017
-
1018
- return textLines;
1019
- };
1020
-
1021
997
  _calculateCachedStats = (
1022
998
  annotation,
1023
999
  viewport,
@@ -1116,57 +1092,29 @@ class EllipticalROITool extends AnnotationTool {
1116
1092
  scale /
1117
1093
  scale;
1118
1094
 
1119
- let count = 0;
1120
- let mean = 0;
1121
- let stdDev = 0;
1122
- let max = -Infinity;
1123
-
1124
- const meanMaxCalculator = ({ value: newValue }) => {
1125
- if (newValue > max) {
1126
- max = newValue;
1127
- }
1128
-
1129
- mean += newValue;
1130
- count += 1;
1131
- };
1132
-
1133
- pointInShapeCallback(
1134
- imageData,
1135
- (pointLPS, pointIJK) => pointInEllipse(ellipseObj, pointLPS),
1136
- meanMaxCalculator,
1137
- boundsIJK
1095
+ const modalityUnit = getModalityUnit(
1096
+ metadata.Modality,
1097
+ annotation.metadata.referencedImageId,
1098
+ modalityUnitOptions
1138
1099
  );
1139
1100
 
1140
- mean /= count;
1141
-
1142
- const stdCalculator = ({ value }) => {
1143
- const valueMinusMean = value - mean;
1144
-
1145
- stdDev += valueMinusMean * valueMinusMean;
1146
- };
1147
-
1148
- pointInShapeCallback(
1101
+ const pointsInShape = pointInShapeCallback(
1149
1102
  imageData,
1150
1103
  (pointLPS, pointIJK) => pointInEllipse(ellipseObj, pointLPS),
1151
- stdCalculator,
1104
+ this.configuration.statsCalculator.statsCallback,
1152
1105
  boundsIJK
1153
1106
  );
1154
1107
 
1155
- stdDev /= count;
1156
- stdDev = Math.sqrt(stdDev);
1157
-
1158
- const modalityUnit = getModalityUnit(
1159
- metadata.Modality,
1160
- annotation.metadata.referencedImageId,
1161
- modalityUnitOptions
1162
- );
1108
+ const stats = this.configuration.statsCalculator.getStatistics();
1163
1109
 
1164
1110
  cachedStats[targetId] = {
1165
1111
  Modality: metadata.Modality,
1166
1112
  area,
1167
- mean,
1168
- max,
1169
- stdDev,
1113
+ mean: stats[1]?.value,
1114
+ max: stats[0]?.value,
1115
+ stdDev: stats[2]?.value,
1116
+ statsArray: stats,
1117
+ pointsInShape: pointsInShape,
1170
1118
  isEmptyArea,
1171
1119
  areaUnit: getCalibratedAreaUnits(null, image),
1172
1120
  modalityUnit,
@@ -1248,5 +1196,34 @@ class EllipticalROITool extends AnnotationTool {
1248
1196
  }
1249
1197
  }
1250
1198
 
1199
+ function defaultGetTextLines(data, targetId): string[] {
1200
+ const cachedVolumeStats = data.cachedStats[targetId];
1201
+ const { area, mean, stdDev, max, isEmptyArea, areaUnit, modalityUnit } =
1202
+ cachedVolumeStats;
1203
+
1204
+ const textLines: string[] = [];
1205
+
1206
+ if (area) {
1207
+ const areaLine = isEmptyArea
1208
+ ? `Area: Oblique not supported`
1209
+ : `Area: ${roundNumber(area)} ${areaUnit}`;
1210
+ textLines.push(areaLine);
1211
+ }
1212
+
1213
+ if (mean) {
1214
+ textLines.push(`Mean: ${roundNumber(mean)} ${modalityUnit}`);
1215
+ }
1216
+
1217
+ if (max) {
1218
+ textLines.push(`Max: ${roundNumber(max)} ${modalityUnit}`);
1219
+ }
1220
+
1221
+ if (stdDev) {
1222
+ textLines.push(`Std Dev: ${roundNumber(stdDev)} ${modalityUnit}`);
1223
+ }
1224
+
1225
+ return textLines;
1226
+ }
1227
+
1251
1228
  EllipticalROITool.toolName = 'EllipticalROI';
1252
1229
  export default EllipticalROITool;