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.
- package/.vscode/settings.json +4 -0
- package/README.md +78 -48
- package/bundler/webpack.common.js +27 -0
- package/bundler/webpack.dev.js +23 -0
- package/bundler/webpack.prod.js +19 -0
- package/decs.d.ts +12 -0
- package/dist/imaging/MetaDataReadable.d.ts +40 -0
- package/dist/imaging/MetaDataTypes.d.ts +3489 -0
- package/dist/imaging/imageAnonymization.d.ts +12 -0
- package/dist/imaging/imageColormaps.d.ts +47 -0
- package/dist/imaging/imageContours.d.ts +18 -0
- package/dist/imaging/imageIo.d.ts +42 -0
- package/dist/imaging/imageLayers.d.ts +56 -0
- package/dist/imaging/imageLoading.d.ts +65 -0
- package/dist/imaging/imageParsing.d.ts +46 -0
- package/dist/imaging/imagePresets.d.ts +43 -0
- package/dist/imaging/imageRendering.d.ts +238 -0
- package/dist/imaging/imageReslice.d.ts +14 -0
- package/dist/imaging/imageStore.d.ts +121 -0
- package/dist/imaging/imageTags.d.ts +22 -0
- package/dist/imaging/imageTools.d.ts +20 -0
- package/dist/imaging/imageUtils.d.ts +165 -0
- package/dist/imaging/loaders/commonLoader.d.ts +103 -0
- package/dist/imaging/loaders/dicomLoader.d.ts +29 -0
- package/dist/imaging/loaders/fileLoader.d.ts +33 -0
- package/dist/imaging/loaders/multiframeLoader.d.ts +37 -0
- package/dist/imaging/loaders/nrrdLoader.d.ts +113 -0
- package/dist/imaging/loaders/resliceLoader.d.ts +15 -0
- package/dist/imaging/monitors/memory.d.ts +41 -0
- package/dist/imaging/monitors/performance.d.ts +23 -0
- package/dist/imaging/parsers/ecg.d.ts +15 -0
- package/dist/imaging/parsers/nrrd.d.ts +3 -0
- package/dist/imaging/tools/custom/4dSliceScrollTool.d.ts +12 -0
- package/dist/imaging/tools/custom/BorderMagnifyTool.d.ts +18 -0
- package/dist/imaging/tools/custom/contourTool.d.ts +409 -0
- package/dist/imaging/tools/custom/diameterTool.d.ts +18 -0
- package/dist/imaging/tools/custom/editMaskTool.d.ts +22 -0
- package/dist/imaging/tools/custom/ellipticalRoiOverlayTool.d.ts +45 -0
- package/dist/imaging/tools/custom/polygonSegmentationMixin.d.ts +54 -0
- package/dist/imaging/tools/custom/polylineScissorsTool.d.ts +11 -0
- package/dist/imaging/tools/custom/rectangleRoiOverlayTool.d.ts +45 -0
- package/dist/imaging/tools/custom/seedTool.d.ts +0 -0
- package/dist/imaging/tools/custom/setLabelMap3D.d.ts +39 -0
- package/dist/imaging/tools/custom/thresholdsBrushTool.d.ts +19 -0
- package/dist/imaging/tools/default.d.ts +53 -0
- package/dist/imaging/tools/interaction.d.ts +30 -0
- package/dist/imaging/tools/io.d.ts +38 -0
- package/dist/imaging/tools/main.d.ts +81 -0
- package/dist/imaging/tools/segmentation.d.ts +125 -0
- package/dist/imaging/tools/state.d.ts +17 -0
- package/dist/imaging/tools/strategies/eraseFreehand.d.ts +16 -0
- package/dist/imaging/tools/strategies/fillFreehand.d.ts +16 -0
- package/dist/imaging/tools/strategies/index.d.ts +2 -0
- package/dist/imaging/waveforms/ecg.d.ts +39 -0
- package/dist/index.d.ts +35 -0
- package/dist/larvitar.js +90104 -0
- package/dist/larvitar.js.map +1 -0
- package/imaging/MetaDataReadable.ts +41 -0
- package/imaging/MetaDataTypes.ts +3491 -0
- package/imaging/dataDictionary.json +5328 -5328
- package/imaging/{imageAnonymization.js → imageAnonymization.ts} +41 -13
- package/imaging/{imageColormaps.js → imageColormaps.ts} +48 -30
- package/imaging/{imageContours.js → imageContours.ts} +24 -22
- package/imaging/{imageIo.js → imageIo.ts} +89 -52
- package/imaging/{imageLayers.js → imageLayers.ts} +31 -14
- package/imaging/{imageLoading.js → imageLoading.ts} +107 -43
- package/imaging/{imageParsing.js → imageParsing.ts} +160 -80
- package/imaging/{imagePresets.js → imagePresets.ts} +44 -11
- package/imaging/imageRendering.ts +1091 -0
- package/imaging/{imageReslice.js → imageReslice.ts} +18 -9
- package/imaging/imageStore.ts +487 -0
- package/imaging/imageTags.ts +609 -0
- package/imaging/imageTools.js +2 -1
- package/imaging/{imageUtils.js → imageUtils.ts} +211 -701
- package/imaging/loaders/{commonLoader.js → commonLoader.ts} +73 -24
- package/imaging/loaders/{dicomLoader.js → dicomLoader.ts} +25 -5
- package/imaging/loaders/{fileLoader.js → fileLoader.ts} +5 -5
- package/imaging/loaders/{multiframeLoader.js → multiframeLoader.ts} +145 -90
- package/imaging/loaders/{nrrdLoader.js → nrrdLoader.ts} +231 -64
- package/imaging/loaders/{resliceLoader.js → resliceLoader.ts} +51 -20
- package/imaging/monitors/{memory.js → memory.ts} +54 -8
- package/imaging/monitors/performance.ts +34 -0
- package/imaging/parsers/ecg.ts +54 -0
- package/imaging/tools/README.md +27 -0
- package/imaging/tools/custom/4dSliceScrollTool.js +47 -46
- package/imaging/tools/custom/BorderMagnifyTool.js +99 -0
- package/imaging/tools/custom/ellipticalRoiOverlayTool.js +534 -0
- package/imaging/tools/custom/polylineScissorsTool.js +1 -1
- package/imaging/tools/custom/rectangleRoiOverlayTool.js +564 -0
- package/imaging/tools/{setLabelMap3D.js → custom/setLabelMap3D.ts} +19 -25
- package/imaging/tools/{default.js → default.ts} +119 -33
- package/imaging/tools/{interaction.js → interaction.ts} +42 -23
- package/imaging/tools/{io.js → io.ts} +47 -31
- package/imaging/tools/{main.js → main.ts} +105 -40
- package/imaging/tools/{segmentation.js → segmentation.ts} +95 -68
- package/imaging/tools/{state.js → state.ts} +7 -12
- package/imaging/tools/types.d.ts +243 -0
- package/imaging/types.d.ts +200 -0
- package/imaging/waveforms/ecg.ts +191 -0
- package/{index.js → index.ts} +53 -14
- package/jsdoc.json +1 -1
- package/package.json +35 -14
- package/tsconfig.json +102 -0
- package/imaging/imageRendering.js +0 -860
- package/imaging/imageStore.js +0 -322
- package/modules/vuex/larvitar.js +0 -187
- /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
|
|
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
|
|
16
|
+
import store from "../imageStore";
|
|
17
17
|
import { updateStackToolState } from "../imageTools";
|
|
18
18
|
|
|
19
19
|
// custom code
|
|
20
|
-
import { setLabelmap3DForElement } from "./setLabelMap3D";
|
|
21
|
-
import {
|
|
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
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
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}
|
|
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
|
-
|
|
183
|
-
|
|
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 =
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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
|
-
|
|
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
|
|
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
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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:
|
|
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
|
+
};
|