larvitar 1.5.14 → 2.0.2

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 (107) hide show
  1. package/.vscode/settings.json +4 -0
  2. package/README.md +78 -48
  3. package/bundler/webpack.common.js +27 -0
  4. package/bundler/webpack.dev.js +23 -0
  5. package/bundler/webpack.prod.js +19 -0
  6. package/decs.d.ts +12 -0
  7. package/dist/imaging/MetaDataReadable.d.ts +40 -0
  8. package/dist/imaging/MetaDataTypes.d.ts +3489 -0
  9. package/dist/imaging/imageAnonymization.d.ts +12 -0
  10. package/dist/imaging/imageColormaps.d.ts +47 -0
  11. package/dist/imaging/imageContours.d.ts +18 -0
  12. package/dist/imaging/imageIo.d.ts +42 -0
  13. package/dist/imaging/imageLayers.d.ts +56 -0
  14. package/dist/imaging/imageLoading.d.ts +65 -0
  15. package/dist/imaging/imageParsing.d.ts +46 -0
  16. package/dist/imaging/imagePresets.d.ts +43 -0
  17. package/dist/imaging/imageRendering.d.ts +238 -0
  18. package/dist/imaging/imageReslice.d.ts +14 -0
  19. package/dist/imaging/imageStore.d.ts +121 -0
  20. package/dist/imaging/imageTags.d.ts +22 -0
  21. package/dist/imaging/imageTools.d.ts +20 -0
  22. package/dist/imaging/imageUtils.d.ts +165 -0
  23. package/dist/imaging/loaders/commonLoader.d.ts +103 -0
  24. package/dist/imaging/loaders/dicomLoader.d.ts +29 -0
  25. package/dist/imaging/loaders/fileLoader.d.ts +33 -0
  26. package/dist/imaging/loaders/multiframeLoader.d.ts +37 -0
  27. package/dist/imaging/loaders/nrrdLoader.d.ts +113 -0
  28. package/dist/imaging/loaders/resliceLoader.d.ts +15 -0
  29. package/dist/imaging/monitors/memory.d.ts +41 -0
  30. package/dist/imaging/monitors/performance.d.ts +23 -0
  31. package/dist/imaging/parsers/ecg.d.ts +15 -0
  32. package/dist/imaging/parsers/nrrd.d.ts +3 -0
  33. package/dist/imaging/tools/custom/4dSliceScrollTool.d.ts +12 -0
  34. package/dist/imaging/tools/custom/BorderMagnifyTool.d.ts +18 -0
  35. package/dist/imaging/tools/custom/contourTool.d.ts +409 -0
  36. package/dist/imaging/tools/custom/diameterTool.d.ts +18 -0
  37. package/dist/imaging/tools/custom/editMaskTool.d.ts +22 -0
  38. package/dist/imaging/tools/custom/ellipticalRoiOverlayTool.d.ts +45 -0
  39. package/dist/imaging/tools/custom/polygonSegmentationMixin.d.ts +54 -0
  40. package/dist/imaging/tools/custom/polylineScissorsTool.d.ts +11 -0
  41. package/dist/imaging/tools/custom/rectangleRoiOverlayTool.d.ts +45 -0
  42. package/dist/imaging/tools/custom/seedTool.d.ts +0 -0
  43. package/dist/imaging/tools/custom/setLabelMap3D.d.ts +39 -0
  44. package/dist/imaging/tools/custom/thresholdsBrushTool.d.ts +19 -0
  45. package/dist/imaging/tools/default.d.ts +53 -0
  46. package/dist/imaging/tools/interaction.d.ts +30 -0
  47. package/dist/imaging/tools/io.d.ts +38 -0
  48. package/dist/imaging/tools/main.d.ts +81 -0
  49. package/dist/imaging/tools/segmentation.d.ts +125 -0
  50. package/dist/imaging/tools/state.d.ts +17 -0
  51. package/dist/imaging/tools/strategies/eraseFreehand.d.ts +16 -0
  52. package/dist/imaging/tools/strategies/fillFreehand.d.ts +16 -0
  53. package/dist/imaging/tools/strategies/index.d.ts +2 -0
  54. package/dist/imaging/waveforms/ecg.d.ts +39 -0
  55. package/dist/index.d.ts +35 -0
  56. package/dist/larvitar.js +90104 -0
  57. package/dist/larvitar.js.map +1 -0
  58. package/imaging/MetaDataReadable.ts +41 -0
  59. package/imaging/MetaDataTypes.ts +3491 -0
  60. package/imaging/dataDictionary.json +5328 -5328
  61. package/imaging/{imageAnonymization.js → imageAnonymization.ts} +41 -13
  62. package/imaging/{imageColormaps.js → imageColormaps.ts} +48 -30
  63. package/imaging/{imageContours.js → imageContours.ts} +24 -22
  64. package/imaging/{imageIo.js → imageIo.ts} +89 -52
  65. package/imaging/{imageLayers.js → imageLayers.ts} +31 -14
  66. package/imaging/{imageLoading.js → imageLoading.ts} +107 -43
  67. package/imaging/{imageParsing.js → imageParsing.ts} +160 -80
  68. package/imaging/{imagePresets.js → imagePresets.ts} +44 -11
  69. package/imaging/imageRendering.ts +1091 -0
  70. package/imaging/{imageReslice.js → imageReslice.ts} +18 -9
  71. package/imaging/imageStore.ts +487 -0
  72. package/imaging/imageTags.ts +609 -0
  73. package/imaging/imageTools.js +2 -1
  74. package/imaging/{imageUtils.js → imageUtils.ts} +211 -701
  75. package/imaging/loaders/{commonLoader.js → commonLoader.ts} +73 -24
  76. package/imaging/loaders/{dicomLoader.js → dicomLoader.ts} +25 -5
  77. package/imaging/loaders/{fileLoader.js → fileLoader.ts} +5 -5
  78. package/imaging/loaders/{multiframeLoader.js → multiframeLoader.ts} +145 -90
  79. package/imaging/loaders/{nrrdLoader.js → nrrdLoader.ts} +231 -64
  80. package/imaging/loaders/{resliceLoader.js → resliceLoader.ts} +51 -20
  81. package/imaging/monitors/{memory.js → memory.ts} +54 -8
  82. package/imaging/monitors/performance.ts +34 -0
  83. package/imaging/parsers/ecg.ts +54 -0
  84. package/imaging/tools/README.md +27 -0
  85. package/imaging/tools/custom/4dSliceScrollTool.js +47 -46
  86. package/imaging/tools/custom/BorderMagnifyTool.js +99 -0
  87. package/imaging/tools/custom/ellipticalRoiOverlayTool.js +534 -0
  88. package/imaging/tools/custom/polylineScissorsTool.js +1 -1
  89. package/imaging/tools/custom/rectangleRoiOverlayTool.js +564 -0
  90. package/imaging/tools/{setLabelMap3D.js → custom/setLabelMap3D.ts} +19 -25
  91. package/imaging/tools/{default.js → default.ts} +119 -33
  92. package/imaging/tools/{interaction.js → interaction.ts} +42 -23
  93. package/imaging/tools/{io.js → io.ts} +47 -31
  94. package/imaging/tools/{main.js → main.ts} +105 -40
  95. package/imaging/tools/{segmentation.js → segmentation.ts} +95 -68
  96. package/imaging/tools/{state.js → state.ts} +7 -12
  97. package/imaging/tools/types.d.ts +243 -0
  98. package/imaging/types.d.ts +200 -0
  99. package/imaging/waveforms/ecg.ts +191 -0
  100. package/{index.js → index.ts} +53 -14
  101. package/jsdoc.json +1 -1
  102. package/package.json +35 -14
  103. package/tsconfig.json +102 -0
  104. package/imaging/imageRendering.js +0 -860
  105. package/imaging/imageStore.js +0 -322
  106. package/modules/vuex/larvitar.js +0 -187
  107. /package/imaging/tools/{polygonSegmentationMixin.js → custom/polygonSegmentationMixin.js} +0 -0
@@ -4,8 +4,8 @@
4
4
  */
5
5
 
6
6
  // external libraries
7
- import cornerstone from "cornerstone-core";
8
- import cornerstoneTools from "cornerstone-tools/dist/cornerstoneTools.js";
7
+ import cornerstone, { Viewport } from "cornerstone-core";
8
+ import cornerstoneTools from "cornerstone-tools";
9
9
  import { cloneDeep, extend, values, sum } from "lodash";
10
10
  const segModule = cornerstoneTools.getModule("segmentation");
11
11
  const { getters, setters } = segModule;
@@ -13,17 +13,23 @@ const { getters, setters } = segModule;
13
13
  // internal libraries
14
14
  import { setToolActive, setToolDisabled } from "./main";
15
15
  import { isElement } from "../imageUtils";
16
- import { larvitar_store } from "../imageStore";
16
+ import store from "../imageStore";
17
17
  import { updateStackToolState } from "../imageTools";
18
18
 
19
19
  // custom code
20
- import { setLabelmap3DForElement } from "./setLabelMap3D";
21
- import { each } from "hammerjs";
20
+ import { setLabelmap3DForElement } from "./custom/setLabelMap3D";
21
+ import {
22
+ BrushProperties,
23
+ MaskProperties,
24
+ MaskVisualizations,
25
+ SegmentationConfig
26
+ } from "./types.d";
27
+ import type { TypedArray } from "../types";
22
28
  // override function
23
29
  setters.labelmap3DForElement = setLabelmap3DForElement;
24
30
 
25
31
  // General segmentation cs tools module configuration
26
- const config = {
32
+ const config: SegmentationConfig = {
27
33
  arrayType: 0,
28
34
  renderOutline: false,
29
35
  renderFill: true,
@@ -44,27 +50,31 @@ const config = {
44
50
  // utils to convert from hex to rgb and vice-versa ====
45
51
  // ====================================================
46
52
 
47
- function componentToHex(c) {
53
+ function componentToHex(c: number) {
48
54
  var hex = c.toString(16);
49
55
  return hex.length == 1 ? "0" + hex : hex;
50
56
  }
51
57
 
52
- export function rgbToHex(c) {
58
+ export function rgbToHex(c: number[]) {
53
59
  let r = componentToHex(c[0]);
54
60
  let g = componentToHex(c[1]);
55
61
  let b = componentToHex(c[2]);
56
62
  return "#" + r + g + b;
57
63
  }
58
64
 
59
- export function hexToRgb(hex) {
65
+ export function hexToRgb(hex: string) {
60
66
  var result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex);
61
- return result
62
- ? [
63
- parseInt(result[1], 16),
64
- parseInt(result[2], 16),
65
- parseInt(result[3], 16)
66
- ]
67
- : null;
67
+
68
+ if (!result) {
69
+ console.error("Error parsing hex color");
70
+ return [0, 0, 0];
71
+ }
72
+
73
+ return [
74
+ parseInt(result[1], 16),
75
+ parseInt(result[2], 16),
76
+ parseInt(result[3], 16)
77
+ ];
68
78
  }
69
79
 
70
80
  /**
@@ -72,7 +82,7 @@ export function hexToRgb(hex) {
72
82
  * @param {Array} color as [h,s,v] 0-1
73
83
  * @returns color as [r,g,b] 0-255
74
84
  */
75
- function HSVtoRGB([h, s, v]) {
85
+ function HSVtoRGB([h, s, v]: [number, number, number]) {
76
86
  var r, g, b, i, f, p, q, t;
77
87
  i = Math.floor(h * 6);
78
88
  f = h * 6 - i;
@@ -98,6 +108,9 @@ function HSVtoRGB([h, s, v]) {
98
108
  case 5:
99
109
  (r = v), (g = p), (b = q);
100
110
  break;
111
+ default:
112
+ (r = v), (g = t), (b = p);
113
+ console.error("HSVtoRGB: Input color must be [h,s,v] 0-1");
101
114
  }
102
115
  return [Math.round(r * 255), Math.round(g * 255), Math.round(b * 255)];
103
116
  }
@@ -116,7 +129,7 @@ export function forceRender() {
116
129
  * Generate the custom LUT - single volume version
117
130
  */
118
131
 
119
- function generateLUT(opacity) {
132
+ function generateLUT(opacity: number) {
120
133
  let lut = new Array(segModule.configuration.segmentsPerLabelmap).fill(0);
121
134
  lut = lut.map((e, i) => {
122
135
  return HSVtoRGB([i / lut.length, 1, 1]).concat(Math.round(opacity * 255));
@@ -130,7 +143,7 @@ function generateLUT(opacity) {
130
143
  * @param {String} hex_color - color for LUT in the #RRGGBB form
131
144
  * @param {NUmber} opacity - number between 0 and 1
132
145
  */
133
- function generateUniformLUT(hex_color, opacity) {
146
+ function generateUniformLUT(hex_color: string, opacity: number) {
134
147
  let lut = new Array(segModule.configuration.segmentsPerLabelmap);
135
148
  let rgb_color = hexToRgb(hex_color);
136
149
  let rgba_color = rgb_color.concat(Math.round(opacity * 255));
@@ -143,7 +156,7 @@ function generateUniformLUT(hex_color, opacity) {
143
156
  * @param {Number} labelId
144
157
  * @param {String} color in hex format
145
158
  */
146
- export function setLabelColor(labelId, color) {
159
+ export function setLabelColor(labelId: string, color: string) {
147
160
  let volumeId = 0; // TODO MULTIVOLUME
148
161
  let rgb = hexToRgb(color);
149
162
  let rgba = [...rgb, 128];
@@ -156,7 +169,7 @@ export function setLabelColor(labelId, color) {
156
169
  * @param {Number} labelId
157
170
  * @returns {String} Color in hex format
158
171
  */
159
- export function getLabelColor(labelId) {
172
+ export function getLabelColor(labelId: string) {
160
173
  let volumeId = 0; // TODO MULTIVOLUME
161
174
  let rgba = getters.colorForSegmentIndexColorLUT(volumeId, labelId);
162
175
  return rgbToHex(rgba);
@@ -166,7 +179,7 @@ export function getLabelColor(labelId) {
166
179
  * A function to group all settings to load before masks
167
180
  * @param {Object} customConfig - Object containing override values for segmentation module config
168
181
  */
169
- export function initSegmentationModule(customConfig) {
182
+ export function initSegmentationModule(customConfig: SegmentationConfig) {
170
183
  // set configuration
171
184
  segModule.configuration = cloneDeep(config);
172
185
  extend(segModule.configuration, customConfig);
@@ -174,16 +187,21 @@ export function initSegmentationModule(customConfig) {
174
187
 
175
188
  /**
176
189
  * Add segmentation mask to segmentation module
177
- * @param {Object} maskProps - The mask properties (labelId, color and opacity)
190
+ * @param {Object} props - The mask properties (labelId, color and opacity)
178
191
  * @param {TypedArray} - The mask data array
179
192
  * @param {String} elementId - The target html element Id or its DOM HTMLElement
180
193
  * @returns {Promise} - Return a promise which will resolve when segmentation mask is added
181
194
  */
182
- export function addSegmentationMask(props, data, elementId) {
183
- let promise = new Promise(async resolve => {
195
+
196
+ export function addSegmentationMask(
197
+ props: MaskProperties,
198
+ data: TypedArray,
199
+ elementId: string | HTMLElement
200
+ ) {
201
+ let promise = new Promise<void>(async resolve => {
184
202
  let element = isElement(elementId)
185
- ? elementId
186
- : document.getElementById(elementId);
203
+ ? (elementId as HTMLElement)
204
+ : document.getElementById(elementId as string);
187
205
  if (!element) {
188
206
  console.error("invalid html element: " + elementId);
189
207
  return;
@@ -204,13 +222,9 @@ export function addSegmentationMask(props, data, elementId) {
204
222
  setters.colorLUTIndexForLabelmap3D(labelmap3d, props.labelId);
205
223
 
206
224
  // set current imageIdIndex in tool state
207
- let currentImageIdIndex = larvitar_store.get(
208
- "viewports",
209
- elementId,
210
- "sliceId"
211
- );
225
+ let currentImageIdIndex = store.get(["viewports", element.id, "sliceId"]);
212
226
  if (currentImageIdIndex !== "error" && currentImageIdIndex >= 0) {
213
- updateStackToolState(elementId, currentImageIdIndex);
227
+ updateStackToolState(element.id, currentImageIdIndex);
214
228
  } else {
215
229
  console.error("Cannot get currentImageIdIndex");
216
230
  }
@@ -226,15 +240,19 @@ export function addSegmentationMask(props, data, elementId) {
226
240
  * @param {Number} sliceIndex - the index of the new mask slice
227
241
  * @param {ArrayBuffer} pixelData - the pixelData array
228
242
  */
229
- export function loadMaskSlice(elementId, sliceIndex, pixelData) {
243
+ export function loadMaskSlice(
244
+ elementId: string | HTMLElement,
245
+ sliceIndex: number,
246
+ pixelData: TypedArray
247
+ ) {
230
248
  // optimization: if pixelData contains no labels, return
231
249
  if (sum(pixelData) === 0) {
232
250
  return;
233
251
  }
234
252
 
235
253
  let element = isElement(elementId)
236
- ? elementId
237
- : document.getElementById(elementId);
254
+ ? (elementId as HTMLElement)
255
+ : document.getElementById(elementId as string);
238
256
  if (!element) {
239
257
  console.error("invalid html element: " + elementId);
240
258
  return;
@@ -258,10 +276,13 @@ export function loadMaskSlice(elementId, sliceIndex, pixelData) {
258
276
  * @param {Number} labelId - The labelmap id to activate
259
277
  * @param {String} elementId - The target html element Id or its DOM HTMLElement
260
278
  */
261
- export function setActiveLabelmap(labelId, elementId) {
279
+ export function setActiveLabelmap(
280
+ labelId: number,
281
+ elementId: string | HTMLElement
282
+ ) {
262
283
  let element = isElement(elementId)
263
- ? elementId
264
- : document.getElementById(elementId);
284
+ ? (elementId as HTMLElement)
285
+ : document.getElementById(elementId as string);
265
286
  if (!element) {
266
287
  console.error("invalid html element: " + elementId);
267
288
  return;
@@ -274,10 +295,10 @@ export function setActiveLabelmap(labelId, elementId) {
274
295
  * @param {String} elementId - The target html element Id or its DOM HTMLElement
275
296
  * @returns {Object} The active labelmap object that contains the buffer
276
297
  */
277
- export function getActiveLabelmapBuffer(elementId) {
298
+ export function getActiveLabelmapBuffer(elementId: string | HTMLElement) {
278
299
  let element = isElement(elementId)
279
- ? elementId
280
- : document.getElementById(elementId);
300
+ ? (elementId as HTMLElement)
301
+ : document.getElementById(elementId as string);
281
302
  if (!element) {
282
303
  console.error("invalid html element: " + elementId);
283
304
  return;
@@ -290,10 +311,13 @@ export function getActiveLabelmapBuffer(elementId) {
290
311
  * @param {Number} segmentIndex - The segment index to activate
291
312
  * @param {String} elementId - The target html element Id or its DOM HTMLElement
292
313
  */
293
- export function setActiveSegment(segmentIndex, elementId) {
314
+ export function setActiveSegment(
315
+ segmentIndex: number,
316
+ elementId: string | HTMLElement
317
+ ) {
294
318
  let element = isElement(elementId)
295
- ? elementId
296
- : document.getElementById(elementId);
319
+ ? (elementId as HTMLElement)
320
+ : document.getElementById(elementId as string);
297
321
  if (!element) {
298
322
  console.error("invalid html element: " + elementId);
299
323
  return;
@@ -305,7 +329,7 @@ export function setActiveSegment(segmentIndex, elementId) {
305
329
  * Change opacity for active label
306
330
  * @param {Number} opacity - The desired opacity value
307
331
  */
308
- export function setActiveLabelOpacity(opacity) {
332
+ export function setActiveLabelOpacity(opacity: number) {
309
333
  segModule.configuration.fillAlpha = opacity;
310
334
  forceRender();
311
335
  }
@@ -314,7 +338,7 @@ export function setActiveLabelOpacity(opacity) {
314
338
  * Change opacity for inactive labels
315
339
  * @param {Number} opacity - The desired opacity value
316
340
  */
317
- export function setInactiveLabelOpacity(opacity) {
341
+ export function setInactiveLabelOpacity(opacity: number) {
318
342
  segModule.configuration.fillAlphaInactive = opacity;
319
343
  forceRender();
320
344
  }
@@ -324,10 +348,13 @@ export function setInactiveLabelOpacity(opacity) {
324
348
  * @param {String} elementId - The target html element Id or its DOM HTMLElement
325
349
  * @param {Number} labelId - The id of the mask label
326
350
  */
327
- export function toggleVisibility(elementId, labelId) {
351
+ export function toggleVisibility(
352
+ elementId: string | HTMLElement,
353
+ labelId: number
354
+ ) {
328
355
  let element = isElement(elementId)
329
- ? elementId
330
- : document.getElementById(elementId);
356
+ ? (elementId as HTMLElement)
357
+ : document.getElementById(elementId as string);
331
358
  if (!element) {
332
359
  console.error("invalid html element: " + elementId);
333
360
  return;
@@ -341,7 +368,7 @@ export function toggleVisibility(elementId, labelId) {
341
368
  * Toggle between 'contours mode' and 'filled mode'
342
369
  * @param {Bool} toggle - Contour mode enabled if true
343
370
  */
344
- export function toggleContourMode(toggle) {
371
+ export function toggleContourMode(toggle: boolean) {
345
372
  if (toggle) {
346
373
  segModule.configuration.fillAlpha = 0.0;
347
374
  segModule.configuration.fillAlphaInactive = 0.0;
@@ -362,7 +389,8 @@ export function toggleContourMode(toggle) {
362
389
  * Set mask appearance props
363
390
  * @param {Object} maskProps - The mask appearance props (labelId, visualization [0=filled, 1=contour, 2=hidden], opacity (if mode=0), between 0 and 1)
364
391
  */
365
- export function setMaskProps(props) {
392
+
393
+ export function setMaskProps(props: MaskProperties) {
366
394
  // Lut index and segment values are hardcoded because they will depend on design choices:
367
395
  // eg single/multiple volumes for segmentations
368
396
  let lutIndex = props.labelId;
@@ -378,7 +406,7 @@ export function setMaskProps(props) {
378
406
  let newColor = currentColor;
379
407
  switch (props.visualization) {
380
408
  // full
381
- case 0:
409
+ case MaskVisualizations.FILL:
382
410
  segModule.configuration.renderOutline = true;
383
411
  getters.isSegmentVisible(htmlelement, segmentValue, labelIndex)
384
412
  ? null
@@ -391,7 +419,7 @@ export function setMaskProps(props) {
391
419
  setters.colorForSegmentIndexOfColorLUT(lutIndex, segmentValue, newColor);
392
420
  break;
393
421
  // contours
394
- case 1:
422
+ case MaskVisualizations.CONTOUR:
395
423
  segModule.configuration.renderOutline = true;
396
424
  getters.isSegmentVisible(htmlelement, segmentValue, labelIndex)
397
425
  ? null
@@ -404,7 +432,7 @@ export function setMaskProps(props) {
404
432
  setters.colorForSegmentIndexOfColorLUT(lutIndex, segmentValue, newColor);
405
433
  break;
406
434
  // hidden
407
- case 2:
435
+ case MaskVisualizations.HIDDEN:
408
436
  setters.toggleSegmentVisibility(htmlelement, segmentValue, labelIndex);
409
437
  break;
410
438
  }
@@ -424,11 +452,10 @@ export function clearSegmentationState() {
424
452
  * Anyway, the activated tool name is returned
425
453
  * @param {Object} options - An object containing configuration values (eg radius, thresholds, etc...)
426
454
  */
427
- export function enableBrushTool(viewports, options) {
428
- console.log("enable", options);
455
+ export function enableBrushTool(viewports: string[], options: BrushProperties) {
429
456
  setBrushProps(options);
430
457
  const brushType = "thresholds" in options ? "ThresholdsBrush" : "Brush";
431
- setToolActive(brushType, viewports);
458
+ setToolActive(brushType, undefined, viewports);
432
459
  return brushType;
433
460
  }
434
461
 
@@ -437,8 +464,8 @@ export function enableBrushTool(viewports, options) {
437
464
  * This function disables both brush tools, if found active on `viewports`
438
465
  * @param {String} toolToActivate - The name of the tool to activate after removing the brush @optional
439
466
  */
440
- export function disableBrushTool(viewports, toolToActivate) {
441
- each(viewports, viewport => {
467
+ export function disableBrushTool(viewports: string[], toolToActivate?: string) {
468
+ viewports.forEach((viewport: string) => {
442
469
  const el = document.getElementById(viewport);
443
470
  if (cornerstoneTools.isToolActiveForElement(el, "ThresholdsBrush")) {
444
471
  setToolDisabled("ThresholdsBrush", [viewport]);
@@ -457,7 +484,7 @@ export function disableBrushTool(viewports, toolToActivate) {
457
484
  * Change the brush props
458
485
  * @param {Object} props - The new brush props {radius: number[px], thresholds: array[min,max]}
459
486
  */
460
- export function setBrushProps(props) {
487
+ export function setBrushProps(props: BrushProperties) {
461
488
  extend(segModule.configuration, props);
462
489
  forceRender();
463
490
  }
@@ -466,10 +493,10 @@ export function setBrushProps(props) {
466
493
  * Undo last brush operation (stroke)
467
494
  * @param {String} elementId - The target html element Id or its DOM HTMLElement
468
495
  */
469
- export function undoLastStroke(elementId) {
496
+ export function undoLastStroke(elementId: string | HTMLElement) {
470
497
  let element = isElement(elementId)
471
- ? elementId
472
- : document.getElementById(elementId);
498
+ ? (elementId as HTMLElement)
499
+ : document.getElementById(elementId as string);
473
500
  if (!element) {
474
501
  console.error("invalid html element: " + elementId);
475
502
  return;
@@ -482,10 +509,10 @@ export function undoLastStroke(elementId) {
482
509
  * Redo last brush operation (stroke)
483
510
  * @param {String} elementId - The target html element Id or its DOM HTMLElement
484
511
  */
485
- export function redoLastStroke(elementId) {
512
+ export function redoLastStroke(elementId: string | HTMLElement) {
486
513
  let element = isElement(elementId)
487
- ? elementId
488
- : document.getElementById(elementId);
514
+ ? (elementId as HTMLElement)
515
+ : document.getElementById(elementId as string);
489
516
  if (!element) {
490
517
  console.error("invalid html element: " + elementId);
491
518
  return;
@@ -498,7 +525,7 @@ export function redoLastStroke(elementId) {
498
525
  * Delete mask from state
499
526
  * @param {Number} labelId - The labelmap id to delete
500
527
  */
501
- export function deleteMask(labelId) {
528
+ export function deleteMask(labelId: number) {
502
529
  let masks = values(segModule.state.series)[0].labelmaps3D;
503
530
  delete masks[labelId];
504
531
  forceRender();
@@ -4,18 +4,16 @@
4
4
  */
5
5
 
6
6
  // external libraries
7
- import cornerstone from "cornerstone-core";
8
7
  import cornerstoneTools from "cornerstone-tools";
9
8
  import { each } from "lodash";
10
9
 
11
- // internal libraries
12
- import { state_example } from "./cstools_state_example.js";
10
+ import type { ToolState } from "./types";
13
11
 
14
12
  /**
15
13
  *
16
14
  * @param {*} elementId
17
15
  */
18
- const saveToolState = function (elementId) {
16
+ const saveToolState = function (elementId: string) {
19
17
  const elementToolStateManager = cornerstoneTools.getElementToolStateManager(
20
18
  document.getElementById(elementId)
21
19
  );
@@ -30,7 +28,7 @@ const saveToolState = function (elementId) {
30
28
  * @param {*} elementId
31
29
  * @param {*} allToolState
32
30
  */
33
- const restoreToolState = function (elementId, allToolState) {
31
+ const restoreToolState = function (elementId: string, allToolState: ToolState) {
34
32
  const elementToolStateManager = cornerstoneTools.getElementToolStateManager(
35
33
  document.getElementById(elementId)
36
34
  );
@@ -46,7 +44,7 @@ const restoreToolState = function (elementId, allToolState) {
46
44
 
47
45
  // EXAMPLE OF CORRECT USE OF TOOL STATE MANAGER
48
46
 
49
- export const example = function () {
47
+ /*
50
48
  // Declare state manager
51
49
  const stateManager = cornerstoneTools.newImageIdSpecificToolStateManager();
52
50
 
@@ -62,11 +60,8 @@ export const example = function () {
62
60
 
63
61
  // Setup with some initial data
64
62
  const toolType = "EllipticalRoi";
65
- // stateManager.restoreImageIdToolState(imageId, {
66
- // [toolType]: { data: ["initialData"] }
67
- // });
68
63
  stateManager.restoreImageIdToolState(imageId, {
69
- [toolType]: { data: state_example[imageId] }
64
+ [toolType]: { data: state_to_load[imageId] }
70
65
  });
71
66
 
72
67
  // Add more data
@@ -74,6 +69,6 @@ export const example = function () {
74
69
 
75
70
  // Check the results
76
71
  const allToolState = stateManager.saveToolState();
77
- };
78
-
72
+ }
73
+ */
79
74
  export { saveToolState, restoreToolState };
@@ -0,0 +1,243 @@
1
+ type ToolOptions = {
2
+ mouseButtonMask?: number | number[];
3
+ supportedInteractionTypes?: string[];
4
+ loop?: boolean;
5
+ allowSkipping?: boolean;
6
+ invert?: boolean;
7
+ } & { [key: string]: unknown };
8
+
9
+ export type ToolConfig = {
10
+ name: string;
11
+ viewports: string | string[];
12
+ configuration: Object;
13
+ options: ToolOptions;
14
+ class: string;
15
+ sync?: string;
16
+ cleanable?: boolean;
17
+ defaultActive?: boolean;
18
+ shortcut?: string;
19
+ type?: "utils" | "annotation" | "segmentation" | "overlay";
20
+ description?: string;
21
+ };
22
+
23
+ export type ToolStyle = {
24
+ width: number;
25
+ color: string; // "#00FF00"
26
+ activeColor: string; // "#00FF00"
27
+ fillColor: string; // "#00FF00"
28
+ fontFamily: string; // "Arial"
29
+ fontSize: number;
30
+ backgroundColor: string; // "rgba(1,1,1,0.7)"
31
+ };
32
+
33
+ export type ToolSettings = {
34
+ mouseEnabled: boolean;
35
+ touchEnabled: boolean;
36
+ showSVGCursors: boolean;
37
+ globalToolSyncEnabled: boolean;
38
+ autoResizeViewports: boolean;
39
+ lineDash: [number, number];
40
+ };
41
+
42
+ export type ToolMouseKeys = {
43
+ debug: boolean;
44
+ mouse_button_left: {
45
+ shift: string;
46
+ ctrl: string;
47
+ default: string;
48
+ };
49
+ mouse_button_right: {
50
+ shift: string;
51
+ ctrl: string;
52
+ default: string;
53
+ };
54
+ keyboard_shortcuts: {
55
+ // alt key + letter
56
+ // key in the form "KEY_A"
57
+ [key: string]: string;
58
+ };
59
+ };
60
+
61
+ type HanldePosition = {
62
+ active: boolean;
63
+ allowedOutsideImage?: boolean;
64
+ drawnIndependently?: boolean;
65
+ highlight: boolean;
66
+ index?: number;
67
+ locked?: boolean;
68
+ moving?: boolean;
69
+ x: number;
70
+ y: number;
71
+ };
72
+
73
+ type HandleTextBox = {
74
+ active: boolean;
75
+ allowedOutsideImage: boolean;
76
+ boundingBox: { height: number; left: number; top: number; width: number };
77
+ drawnIndependently: boolean;
78
+ hasBoundingBox: boolean;
79
+ hasMoved: boolean;
80
+ highlight?: boolean;
81
+ index?: number;
82
+ movesIndependently: boolean;
83
+ x: number;
84
+ y: number;
85
+ };
86
+
87
+ type BaseToolStateData = {
88
+ active: boolean;
89
+ color: string;
90
+ invalidated: boolean;
91
+ uuid: string;
92
+ visible: boolean;
93
+ };
94
+
95
+ type AngleStateData = BaseToolStateData & {
96
+ handles: {
97
+ end: HanldePosition;
98
+ middle: HanldePosition;
99
+ start: HanldePosition;
100
+ textBox: HandleTextBox;
101
+ };
102
+ rAngle: number;
103
+ };
104
+
105
+ type ArrowAnnotateStateData = BaseToolStateData & {
106
+ handles: {
107
+ end: HanldePosition;
108
+ start: HanldePosition;
109
+ textBox: HandleTextBox;
110
+ };
111
+ text: string;
112
+ };
113
+
114
+ type BidirectionalStateData = BaseToolStateData & {
115
+ handles: {
116
+ end: HanldePosition;
117
+ perpendicularEnd: HanldePosition;
118
+ perpendicularStart: HanldePosition;
119
+ start: HanldePosition;
120
+ textBox: HandleTextBox;
121
+ };
122
+ isCreating: boolean;
123
+ longestDiameter: number;
124
+ shortestDiameter: number;
125
+ toolName: "Bidirectional";
126
+ toolType: "Bidirectional";
127
+ };
128
+
129
+ type EllipticalRoiStateData = BaseToolStateData & {
130
+ cachedStats: {
131
+ area: number;
132
+ count: number;
133
+ max: number;
134
+ mean: number;
135
+ meanStdDevSUV?: number;
136
+ min: number;
137
+ stdDev: snumber;
138
+ variance: number;
139
+ };
140
+ handles: {
141
+ end: HanldePosition;
142
+ initialRotation: number;
143
+ start: HanldePosition;
144
+ textBox: HandleTextBox;
145
+ };
146
+ unit: string;
147
+ };
148
+
149
+ type FreehandRoiStateData = ToolStateData & {
150
+ area: number;
151
+ canComplete: boolean;
152
+ handles: {
153
+ points: FreehandHandleData[];
154
+ textBox: any;
155
+ invalidHandlePlacement: boolean;
156
+ };
157
+ highlight: boolean;
158
+ meanStdDev: { count: number; mean: number; variance: number; stdDev: number };
159
+ meanStdDevSUV: undefined;
160
+ polyBoundingBox: { left: number; top: number; width: number; height: number };
161
+ unit: string;
162
+ };
163
+
164
+ type LengthStateData = BaseToolStateData & {
165
+ handles: {
166
+ end: HanldePosition;
167
+ start: HanldePosition;
168
+ textBox: HandleTextBox;
169
+ };
170
+ length: number;
171
+ unit: string;
172
+ };
173
+
174
+ type ProbeStateData = BaseToolStateData;
175
+
176
+ type RectangleRoiStateData = BaseToolStateData & {
177
+ cachedStats: {
178
+ area: number;
179
+ count: number;
180
+ max: number;
181
+ mean: number;
182
+ meanStdDevSUV?: number;
183
+ min: number;
184
+ perimeter: number;
185
+ stdDev: number;
186
+ variance: number;
187
+ };
188
+ handles: {
189
+ end: HanldePosition;
190
+ initialRotation: number;
191
+ start: HanldePosition;
192
+ textBox: HandleTextBox;
193
+ };
194
+ unit: string;
195
+ };
196
+
197
+ export type ToolState = {
198
+ [imageId: string]: {
199
+ Angle: AngleStateData;
200
+ ArrowAnnotate: ArrowAnnotateStateData;
201
+ Bidirectional: BidirectionalStateData;
202
+ EllipticalRoi: EllipticalRoiStateData;
203
+ FreehandRoi: FreehandRoiStateData;
204
+ Length: LengthStateData;
205
+ Probe: ProbeStateData;
206
+ RectangleRoi: RectangleRoiStateData;
207
+ };
208
+ };
209
+
210
+ export type SegmentationConfig = {
211
+ arrayType: number;
212
+ renderOutline: boolean;
213
+ renderFill: boolean;
214
+ shouldRenderInactiveLabelmaps: boolean;
215
+ radius: number;
216
+ minRadius: number;
217
+ maxRadius: number;
218
+ segmentsPerLabelmap: number;
219
+ fillAlpha: number;
220
+ fillAlphaInactive: number;
221
+ outlineAlpha: number;
222
+ outlineAlphaInactive: number;
223
+ outlineWidth: number;
224
+ storeHistory: boolean;
225
+ };
226
+
227
+ export const enum MaskVisualizations {
228
+ FILL,
229
+ CONTOUR,
230
+ HIDDEN
231
+ }
232
+
233
+ export type MaskProperties = {
234
+ color: string;
235
+ labelId: number;
236
+ opacity: number;
237
+ visualization: MaskVisualizations;
238
+ };
239
+
240
+ export type BrushProperties = {
241
+ radius: number; // px
242
+ thresholds: [number, number]; // [min, max] in px
243
+ };