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
|
@@ -20,20 +20,32 @@
|
|
|
20
20
|
* cleanable : if true, this tool will be removed when calling "no tools",
|
|
21
21
|
* defaultActive : if true, this tool will be activated when calling "addDefaultTools",
|
|
22
22
|
* shortcut : keyboard shortcut [not implemented],
|
|
23
|
-
* type : tool category inside Larvitar (one of: "utils", "annotation", "segmentation")
|
|
23
|
+
* type : tool category inside Larvitar (one of: "utils", "annotation", "segmentation", "overlay")
|
|
24
24
|
* }
|
|
25
25
|
*
|
|
26
26
|
*/
|
|
27
27
|
|
|
28
28
|
import { filter, isArray } from "lodash";
|
|
29
29
|
import ThresholdsBrushTool from "./custom/thresholdsBrushTool";
|
|
30
|
-
import Slice4DScrollMouseWheelTool from "./custom/4dSliceScrollTool";
|
|
30
|
+
// import Slice4DScrollMouseWheelTool from "./custom/4dSliceScrollTool";
|
|
31
31
|
import PolylineScissorsTool from "./custom/polylineScissorsTool";
|
|
32
|
+
import RectangleRoiOverlayTool from "./custom/rectangleRoiOverlayTool";
|
|
33
|
+
import EllipticalRoiOverlayTool from "./custom/ellipticalRoiOverlayTool";
|
|
34
|
+
import BorderMagnifyTool from "./custom/BorderMagnifyTool";
|
|
35
|
+
|
|
36
|
+
import type {
|
|
37
|
+
ToolConfig,
|
|
38
|
+
ToolMouseKeys,
|
|
39
|
+
ToolSettings,
|
|
40
|
+
ToolStyle
|
|
41
|
+
} from "./types";
|
|
32
42
|
|
|
33
43
|
/**
|
|
34
44
|
* These tools are added with `addDefaultTools()`
|
|
35
45
|
*/
|
|
36
|
-
const DEFAULT_TOOLS
|
|
46
|
+
const DEFAULT_TOOLS: {
|
|
47
|
+
[key: string]: ToolConfig;
|
|
48
|
+
} = {
|
|
37
49
|
ScaleOverlay: {
|
|
38
50
|
name: "ScaleOverlay",
|
|
39
51
|
viewports: "all",
|
|
@@ -47,7 +59,6 @@ const DEFAULT_TOOLS = {
|
|
|
47
59
|
cleanable: false,
|
|
48
60
|
defaultActive: false,
|
|
49
61
|
class: "ScaleOverlayTool",
|
|
50
|
-
sync: null,
|
|
51
62
|
description: "Add scale overlay",
|
|
52
63
|
shortcut: "ctrl-m",
|
|
53
64
|
type: "overlay"
|
|
@@ -62,7 +73,6 @@ const DEFAULT_TOOLS = {
|
|
|
62
73
|
cleanable: false,
|
|
63
74
|
defaultActive: false,
|
|
64
75
|
class: "OrientationMarkersTool",
|
|
65
|
-
sync: null,
|
|
66
76
|
description: "Add orientation markers",
|
|
67
77
|
shortcut: "ctrl-m",
|
|
68
78
|
type: "overlay"
|
|
@@ -78,7 +88,7 @@ const DEFAULT_TOOLS = {
|
|
|
78
88
|
cleanable: false,
|
|
79
89
|
defaultActive: true,
|
|
80
90
|
class: "WwwcTool",
|
|
81
|
-
sync: "wwwcSynchronizer",
|
|
91
|
+
// sync: "wwwcSynchronizer",
|
|
82
92
|
description: "Change image contrast",
|
|
83
93
|
shortcut: "ctrl-m",
|
|
84
94
|
type: "utils"
|
|
@@ -94,38 +104,53 @@ const DEFAULT_TOOLS = {
|
|
|
94
104
|
cleanable: false,
|
|
95
105
|
defaultActive: false,
|
|
96
106
|
class: "WwwcRegionTool",
|
|
97
|
-
sync: "wwwcSynchronizer",
|
|
107
|
+
// sync: "wwwcSynchronizer",
|
|
98
108
|
description: "Change image contrast based on selected region",
|
|
99
109
|
shortcut: "ctrl-m",
|
|
100
110
|
type: "utils"
|
|
101
111
|
},
|
|
102
|
-
|
|
103
|
-
name: "
|
|
112
|
+
StackScroll: {
|
|
113
|
+
name: "StackScroll",
|
|
104
114
|
viewports: "all",
|
|
105
|
-
configuration: {
|
|
106
|
-
options: {
|
|
115
|
+
configuration: {
|
|
107
116
|
loop: false, // default false
|
|
108
|
-
allowSkipping:
|
|
109
|
-
|
|
117
|
+
allowSkipping: true // default true
|
|
118
|
+
},
|
|
119
|
+
options: {
|
|
120
|
+
mouseButtonMask: 1,
|
|
121
|
+
deltaY: 0 // default 0
|
|
110
122
|
},
|
|
111
123
|
cleanable: false,
|
|
112
124
|
defaultActive: false,
|
|
113
|
-
class: "
|
|
125
|
+
class: "StackScrollTool"
|
|
114
126
|
},
|
|
115
|
-
|
|
116
|
-
name: "
|
|
127
|
+
StackScrollMouseWheel: {
|
|
128
|
+
name: "StackScrollMouseWheel",
|
|
117
129
|
viewports: "all",
|
|
118
130
|
configuration: {
|
|
119
131
|
loop: false, // default false
|
|
120
|
-
allowSkipping:
|
|
121
|
-
invert: false
|
|
122
|
-
framesNumber: 1
|
|
132
|
+
allowSkipping: true, // default true
|
|
133
|
+
invert: false
|
|
123
134
|
},
|
|
124
135
|
options: {},
|
|
125
136
|
cleanable: false,
|
|
126
137
|
defaultActive: true,
|
|
127
|
-
class: "
|
|
138
|
+
class: "StackScrollMouseWheelTool"
|
|
128
139
|
},
|
|
140
|
+
// Slice4DScrollMouseWheel: {
|
|
141
|
+
// name: "Slice4DScrollMouseWheel",
|
|
142
|
+
// viewports: "all",
|
|
143
|
+
// configuration: {
|
|
144
|
+
// loop: false, // default false
|
|
145
|
+
// allowSkipping: false, // default true
|
|
146
|
+
// invert: false,
|
|
147
|
+
// framesNumber: 1
|
|
148
|
+
// },
|
|
149
|
+
// options: {},
|
|
150
|
+
// cleanable: false,
|
|
151
|
+
// defaultActive: true,
|
|
152
|
+
// class: "Slice4DScrollMouseWheelTool"
|
|
153
|
+
// },
|
|
129
154
|
Pan: {
|
|
130
155
|
name: "Pan",
|
|
131
156
|
viewports: "all",
|
|
@@ -161,8 +186,8 @@ const DEFAULT_TOOLS = {
|
|
|
161
186
|
shortcut: "ctrl-z",
|
|
162
187
|
type: "utils"
|
|
163
188
|
},
|
|
164
|
-
|
|
165
|
-
name: "
|
|
189
|
+
BorderMagnify: {
|
|
190
|
+
name: "BorderMagnify",
|
|
166
191
|
viewports: "all",
|
|
167
192
|
configuration: {},
|
|
168
193
|
options: {
|
|
@@ -170,7 +195,7 @@ const DEFAULT_TOOLS = {
|
|
|
170
195
|
supportedInteractionTypes: ["Mouse", "Touch"]
|
|
171
196
|
},
|
|
172
197
|
cleanable: false,
|
|
173
|
-
class: "
|
|
198
|
+
class: "BorderMagnifyTool",
|
|
174
199
|
defaultActive: false,
|
|
175
200
|
description: "Magnify image at mouse position",
|
|
176
201
|
shortcut: "ctrl-m",
|
|
@@ -246,6 +271,7 @@ const DEFAULT_TOOLS = {
|
|
|
246
271
|
RectangleRoi: {
|
|
247
272
|
name: "RectangleRoi",
|
|
248
273
|
viewports: "all",
|
|
274
|
+
configuration: {},
|
|
249
275
|
options: { mouseButtonMask: 1 },
|
|
250
276
|
cleanable: true,
|
|
251
277
|
defaultActive: false,
|
|
@@ -254,6 +280,29 @@ const DEFAULT_TOOLS = {
|
|
|
254
280
|
shortcut: "ctrl-a",
|
|
255
281
|
type: "annotation"
|
|
256
282
|
},
|
|
283
|
+
EllipticalRoiOverlay: {
|
|
284
|
+
name: "EllipticalRoiOverlay",
|
|
285
|
+
viewports: "all",
|
|
286
|
+
configuration: {},
|
|
287
|
+
options: { mouseButtonMask: 1 },
|
|
288
|
+
cleanable: true,
|
|
289
|
+
class: "EllipticalRoiOverlayTool",
|
|
290
|
+
description: "Draw an ellipse",
|
|
291
|
+
shortcut: "ctrl-f",
|
|
292
|
+
type: "annotation"
|
|
293
|
+
},
|
|
294
|
+
RectangleRoiOverlay: {
|
|
295
|
+
name: "RectangleRoiOverlay",
|
|
296
|
+
viewports: "all",
|
|
297
|
+
configuration: {},
|
|
298
|
+
options: { mouseButtonMask: 1 },
|
|
299
|
+
cleanable: true,
|
|
300
|
+
defaultActive: false,
|
|
301
|
+
class: "RectangleRoiOverlayTool",
|
|
302
|
+
description: "Draw a rectangle",
|
|
303
|
+
shortcut: "ctrl-a",
|
|
304
|
+
type: "annotation"
|
|
305
|
+
},
|
|
257
306
|
FreehandRoi: {
|
|
258
307
|
name: "FreehandRoi",
|
|
259
308
|
viewports: "all",
|
|
@@ -268,6 +317,7 @@ const DEFAULT_TOOLS = {
|
|
|
268
317
|
Probe: {
|
|
269
318
|
name: "Probe",
|
|
270
319
|
viewports: "all",
|
|
320
|
+
configuration: {},
|
|
271
321
|
options: { mouseButtonMask: 1 },
|
|
272
322
|
cleanable: true,
|
|
273
323
|
class: "ProbeTool"
|
|
@@ -411,10 +461,15 @@ const DEFAULT_TOOLS = {
|
|
|
411
461
|
/**
|
|
412
462
|
* D/Vision Lab custom tools
|
|
413
463
|
*/
|
|
414
|
-
const dvTools
|
|
464
|
+
const dvTools: {
|
|
465
|
+
[key: string]: any; // TODO-ts tools class type @mronzoni
|
|
466
|
+
} = {
|
|
415
467
|
ThresholdsBrushTool: ThresholdsBrushTool,
|
|
416
468
|
PolylineScissorsTool: PolylineScissorsTool,
|
|
417
|
-
Slice4DScrollMouseWheelTool: Slice4DScrollMouseWheelTool
|
|
469
|
+
// Slice4DScrollMouseWheelTool: Slice4DScrollMouseWheelTool,
|
|
470
|
+
RectangleRoiOverlayTool: RectangleRoiOverlayTool,
|
|
471
|
+
EllipticalRoiOverlayTool: EllipticalRoiOverlayTool,
|
|
472
|
+
BorderMagnifyTool: BorderMagnifyTool
|
|
418
473
|
};
|
|
419
474
|
|
|
420
475
|
/**
|
|
@@ -424,7 +479,7 @@ const dvTools = {
|
|
|
424
479
|
* Helvetica Neue Light, Helvetica Neue, Helvetica,
|
|
425
480
|
* Arial, Lucida Grande, sans-serif;
|
|
426
481
|
*/
|
|
427
|
-
const DEFAULT_STYLE = {
|
|
482
|
+
const DEFAULT_STYLE: ToolStyle = {
|
|
428
483
|
width: 1,
|
|
429
484
|
color: "#02FAE5",
|
|
430
485
|
activeColor: "#00FF00",
|
|
@@ -437,7 +492,7 @@ const DEFAULT_STYLE = {
|
|
|
437
492
|
/**
|
|
438
493
|
* Tools default settings
|
|
439
494
|
*/
|
|
440
|
-
const DEFAULT_SETTINGS = {
|
|
495
|
+
const DEFAULT_SETTINGS: ToolSettings = {
|
|
441
496
|
mouseEnabled: true,
|
|
442
497
|
touchEnabled: true,
|
|
443
498
|
showSVGCursors: true,
|
|
@@ -449,7 +504,7 @@ const DEFAULT_SETTINGS = {
|
|
|
449
504
|
/**
|
|
450
505
|
* Shortcut and mouse bindings defaults
|
|
451
506
|
*/
|
|
452
|
-
const DEFAULT_MOUSE_KEYS = {
|
|
507
|
+
const DEFAULT_MOUSE_KEYS: ToolMouseKeys = {
|
|
453
508
|
debug: true, // log changes
|
|
454
509
|
mouse_button_left: {
|
|
455
510
|
shift: "Zoom",
|
|
@@ -473,7 +528,7 @@ const DEFAULT_MOUSE_KEYS = {
|
|
|
473
528
|
* Get available tools by type (useful to populate menus)
|
|
474
529
|
* @param {String} type
|
|
475
530
|
*/
|
|
476
|
-
const getDefaultToolsByType = function (type) {
|
|
531
|
+
const getDefaultToolsByType = function (type: NonNullable<ToolConfig["type"]>) {
|
|
477
532
|
return filter(DEFAULT_TOOLS, ["type", type]);
|
|
478
533
|
};
|
|
479
534
|
|
|
@@ -482,14 +537,19 @@ const getDefaultToolsByType = function (type) {
|
|
|
482
537
|
* @param {Array} newProps - An array of objects as in the DEFAULT_TOOLS list, but with a subset of props
|
|
483
538
|
* NOTE: prop "name" is mandatory
|
|
484
539
|
*/
|
|
485
|
-
const setDefaultToolsProps = function (newProps) {
|
|
540
|
+
const setDefaultToolsProps = function (newProps: Partial<ToolConfig>[]) {
|
|
486
541
|
if (isArray(newProps)) {
|
|
487
542
|
newProps.forEach(props => {
|
|
543
|
+
if (!props.name) {
|
|
544
|
+
console.error("newProps must have a name property");
|
|
545
|
+
return;
|
|
546
|
+
}
|
|
547
|
+
|
|
488
548
|
let targetTool = DEFAULT_TOOLS[props.name];
|
|
489
549
|
if (targetTool) {
|
|
490
550
|
DEFAULT_TOOLS[props.name] = Object.assign(targetTool, props);
|
|
491
551
|
} else {
|
|
492
|
-
console.error(`${
|
|
552
|
+
console.error(`${props.name} does not exist`);
|
|
493
553
|
}
|
|
494
554
|
});
|
|
495
555
|
} else {
|
|
@@ -497,6 +557,31 @@ const setDefaultToolsProps = function (newProps) {
|
|
|
497
557
|
}
|
|
498
558
|
};
|
|
499
559
|
|
|
560
|
+
/**
|
|
561
|
+
* Register a custom tool
|
|
562
|
+
* @param {String} toolName - The name of the tool
|
|
563
|
+
* @param {Object} toolClass - The tool class
|
|
564
|
+
* NOTE: toolName must be unique
|
|
565
|
+
* NOTE: toolClass must be a valid cornerstone tool
|
|
566
|
+
*/
|
|
567
|
+
|
|
568
|
+
const registerExternalTool = function (toolName: string, toolClass: any) {
|
|
569
|
+
if (dvTools[toolName] || DEFAULT_TOOLS[toolName]) {
|
|
570
|
+
console.error(`${toolName} already exists`);
|
|
571
|
+
return;
|
|
572
|
+
}
|
|
573
|
+
|
|
574
|
+
dvTools[toolClass.name] = toolClass;
|
|
575
|
+
DEFAULT_TOOLS[toolName] = {
|
|
576
|
+
name: toolName,
|
|
577
|
+
class: toolClass.name,
|
|
578
|
+
viewports: "all",
|
|
579
|
+
configuration: {},
|
|
580
|
+
options: { mouseButtonMask: 1 },
|
|
581
|
+
defaultActive: false
|
|
582
|
+
};
|
|
583
|
+
};
|
|
584
|
+
|
|
500
585
|
export {
|
|
501
586
|
DEFAULT_TOOLS,
|
|
502
587
|
DEFAULT_STYLE,
|
|
@@ -504,5 +589,6 @@ export {
|
|
|
504
589
|
DEFAULT_MOUSE_KEYS,
|
|
505
590
|
dvTools,
|
|
506
591
|
getDefaultToolsByType,
|
|
507
|
-
setDefaultToolsProps
|
|
508
|
-
|
|
592
|
+
setDefaultToolsProps,
|
|
593
|
+
registerExternalTool
|
|
594
|
+
};
|
|
@@ -7,14 +7,15 @@
|
|
|
7
7
|
import { throttle } from "lodash";
|
|
8
8
|
import * as keyCodes from "keycode-js";
|
|
9
9
|
import cornerstone from "cornerstone-core";
|
|
10
|
-
import cornerstoneTools from "cornerstone-tools
|
|
10
|
+
import cornerstoneTools from "cornerstone-tools";
|
|
11
11
|
|
|
12
12
|
// internal libraries
|
|
13
13
|
import { DEFAULT_MOUSE_KEYS } from "./default";
|
|
14
14
|
import { setToolActive } from "./main";
|
|
15
15
|
import { isElement } from "../imageUtils";
|
|
16
|
-
import {
|
|
16
|
+
import store, { set as setStore } from "../imageStore";
|
|
17
17
|
import { updateViewportData } from "../imageRendering";
|
|
18
|
+
import type { ToolMouseKeys } from "./types";
|
|
18
19
|
|
|
19
20
|
/**
|
|
20
21
|
* TOOLS INTERACTIONS TODOS:
|
|
@@ -26,8 +27,8 @@ import { updateViewportData } from "../imageRendering";
|
|
|
26
27
|
/**
|
|
27
28
|
* Global event callbacks
|
|
28
29
|
*/
|
|
29
|
-
let onKeyDownFn = null;
|
|
30
|
-
let onKeyUpFn = null;
|
|
30
|
+
let onKeyDownFn: ((evt: KeyboardEvent) => void) | null = null;
|
|
31
|
+
let onKeyUpFn: ((evt: KeyboardEvent) => void) | null = null;
|
|
31
32
|
|
|
32
33
|
/**
|
|
33
34
|
* Setup mouse handler modifiers and keyboard shortcuts:
|
|
@@ -42,7 +43,7 @@ let onKeyUpFn = null;
|
|
|
42
43
|
* @param {Object} config - see tools/default
|
|
43
44
|
*/
|
|
44
45
|
|
|
45
|
-
export function addMouseKeyHandlers(config) {
|
|
46
|
+
export function addMouseKeyHandlers(config: ToolMouseKeys) {
|
|
46
47
|
if (!config) {
|
|
47
48
|
config = DEFAULT_MOUSE_KEYS;
|
|
48
49
|
}
|
|
@@ -64,30 +65,42 @@ export function addMouseKeyHandlers(config) {
|
|
|
64
65
|
let allViewports = cornerstone.getEnabledElements().map(enel => enel.element);
|
|
65
66
|
|
|
66
67
|
// Define behaviour on key down: activate registered tool
|
|
67
|
-
function onKeyDown(evt) {
|
|
68
|
+
function onKeyDown(evt: KeyboardEvent) {
|
|
68
69
|
// keyboard shortcuts (activate on left mouse button)
|
|
69
70
|
let codes = config.keyboard_shortcuts
|
|
70
|
-
? Object.keys(config.keyboard_shortcuts).map(
|
|
71
|
+
? Object.keys(config.keyboard_shortcuts).map(
|
|
72
|
+
// @ts-ignore
|
|
73
|
+
key => keyCodes[key]
|
|
74
|
+
)
|
|
71
75
|
: [];
|
|
72
76
|
|
|
73
77
|
if (codes.includes(evt.keyCode) && evt.altKey) {
|
|
74
78
|
evt.preventDefault(); // avoid browser menu selections
|
|
75
79
|
|
|
76
80
|
let key = Object.keys(config.keyboard_shortcuts)
|
|
77
|
-
|
|
81
|
+
// @ts-ignore
|
|
82
|
+
.filter(key => keyCodes[key] == evt.keyCode) // TODO keyCode is deprecated
|
|
78
83
|
.pop();
|
|
79
|
-
|
|
84
|
+
|
|
85
|
+
if (!key) {
|
|
86
|
+
console.warn("Key not found in config.keyboard_shortcuts");
|
|
87
|
+
return;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
let toolName = config.keyboard_shortcuts[key];
|
|
91
|
+
|
|
92
|
+
if (config.debug) console.log("active", toolName);
|
|
93
|
+
|
|
80
94
|
const viewports = allViewports.filter(viewport =>
|
|
81
|
-
cornerstoneTools.getToolForElement(
|
|
82
|
-
viewport,
|
|
83
|
-
config.keyboard_shortcuts[key]
|
|
84
|
-
)
|
|
95
|
+
cornerstoneTools.getToolForElement(viewport, toolName)
|
|
85
96
|
);
|
|
97
|
+
|
|
86
98
|
setToolActive(
|
|
87
|
-
|
|
99
|
+
toolName,
|
|
88
100
|
{ mouseButtonMask: 1 },
|
|
89
101
|
viewports.map(v => v.id)
|
|
90
102
|
);
|
|
103
|
+
|
|
91
104
|
document.addEventListener("keydown", onKeyDown, { once: true });
|
|
92
105
|
}
|
|
93
106
|
// right drag + shift
|
|
@@ -140,7 +153,7 @@ export function addMouseKeyHandlers(config) {
|
|
|
140
153
|
}
|
|
141
154
|
|
|
142
155
|
// Define behaviour on key up: restore original tool
|
|
143
|
-
function onKeyUp(e) {
|
|
156
|
+
function onKeyUp(e: KeyboardEvent) {
|
|
144
157
|
if (config.debug)
|
|
145
158
|
console.log("active default", config.mouse_button_right.default);
|
|
146
159
|
const viewports = allViewports.filter(viewport =>
|
|
@@ -197,6 +210,7 @@ export function addMouseKeyHandlers(config) {
|
|
|
197
210
|
*
|
|
198
211
|
*/
|
|
199
212
|
export function removeMouseKeyHandlers() {
|
|
213
|
+
if (!onKeyDownFn) return;
|
|
200
214
|
document.removeEventListener("keydown", onKeyDownFn);
|
|
201
215
|
onKeyDownFn = null;
|
|
202
216
|
onKeyUpFn = null;
|
|
@@ -206,13 +220,16 @@ export function removeMouseKeyHandlers() {
|
|
|
206
220
|
* Add event handlers to mouse move
|
|
207
221
|
* @instance
|
|
208
222
|
* @function toggleMouseHandlers
|
|
209
|
-
* @param {String} elementId - The html div id used for rendering or its DOM HTMLElement
|
|
223
|
+
* @param {String | HTMLElement} elementId - The html div id used for rendering or its DOM HTMLElement
|
|
210
224
|
* @param {Boolean} disable - If true disable handlers, default is false
|
|
211
225
|
*/
|
|
212
|
-
export const toggleMouseToolsListeners = function (
|
|
226
|
+
export const toggleMouseToolsListeners = function (
|
|
227
|
+
elementId: string | HTMLElement,
|
|
228
|
+
disable: boolean
|
|
229
|
+
) {
|
|
213
230
|
let element = isElement(elementId)
|
|
214
|
-
? elementId
|
|
215
|
-
: document.getElementById(elementId);
|
|
231
|
+
? (elementId as HTMLElement)
|
|
232
|
+
: document.getElementById(elementId as string);
|
|
216
233
|
if (!element) {
|
|
217
234
|
console.error("invalid html element: " + elementId);
|
|
218
235
|
return;
|
|
@@ -222,14 +239,16 @@ export const toggleMouseToolsListeners = function (elementId, disable) {
|
|
|
222
239
|
let mouseMoveHandler = throttle(function (evt) {
|
|
223
240
|
let activeTool =
|
|
224
241
|
evt.detail.buttons == 1
|
|
225
|
-
?
|
|
226
|
-
:
|
|
242
|
+
? store.get("leftActiveTool")
|
|
243
|
+
: store.get("rightActiveTool");
|
|
227
244
|
updateViewportData(evt.srcElement.id, evt.detail.viewport, activeTool);
|
|
228
245
|
}, 250);
|
|
229
246
|
|
|
230
247
|
// mouse wheel handler
|
|
231
|
-
function mouseWheelHandler(evt) {
|
|
232
|
-
|
|
248
|
+
function mouseWheelHandler(evt: any) {
|
|
249
|
+
// TODO-ts fix type (should be a cornerstoneTools event type)
|
|
250
|
+
// @mronzoni does cornerstoneTools have a type for this event?
|
|
251
|
+
setStore(["sliceId", evt.target.id, evt.detail.newImageIdIndex]);
|
|
233
252
|
updateViewportData(evt.srcElement.id, evt.detail, "mouseWheel");
|
|
234
253
|
}
|
|
235
254
|
|
|
@@ -10,29 +10,31 @@ import { each, map, assign, invert } from "lodash";
|
|
|
10
10
|
import { unparse } from "papaparse";
|
|
11
11
|
|
|
12
12
|
// internal libraries
|
|
13
|
-
import { setToolEnabled } from "
|
|
13
|
+
import { setToolEnabled } from "./main";
|
|
14
|
+
import type { ToolState } from "./types";
|
|
15
|
+
import { fileManager } from "../loaders/fileLoader";
|
|
14
16
|
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
17
|
+
declare global {
|
|
18
|
+
interface Document {
|
|
19
|
+
documentMode?: any;
|
|
20
|
+
}
|
|
21
|
+
interface Navigator {
|
|
22
|
+
msSaveBlob?: (blob: any, defaultName?: string) => boolean;
|
|
23
|
+
}
|
|
24
|
+
}
|
|
18
25
|
|
|
19
26
|
/**
|
|
20
27
|
* Load annotation from json object
|
|
21
28
|
* @param {Object} jsonData - The previously saved tools state
|
|
22
29
|
*/
|
|
23
|
-
export const loadAnnotations = function (jsonData) {
|
|
24
|
-
// DEV
|
|
25
|
-
// if (!jsonData) {
|
|
26
|
-
// jsonData = saved_state_2;
|
|
27
|
-
// }
|
|
28
|
-
|
|
30
|
+
export const loadAnnotations = function (jsonData: ToolState) {
|
|
29
31
|
// restore saved tool state
|
|
30
32
|
cornerstoneTools.globalImageIdSpecificToolStateManager.restoreToolState(
|
|
31
33
|
jsonData
|
|
32
34
|
);
|
|
33
35
|
|
|
34
36
|
// set all found tools to passive
|
|
35
|
-
let toolsInState = new Set();
|
|
37
|
+
let toolsInState: Set<string> = new Set();
|
|
36
38
|
for (let imageId in jsonData) {
|
|
37
39
|
for (let toolName in jsonData[imageId]) {
|
|
38
40
|
toolsInState.add(toolName);
|
|
@@ -40,6 +42,7 @@ export const loadAnnotations = function (jsonData) {
|
|
|
40
42
|
}
|
|
41
43
|
|
|
42
44
|
toolsInState.forEach(toolName => {
|
|
45
|
+
// TODO-ts fix 'null' this after setToolEnabled is typed @mronzoni
|
|
43
46
|
setToolEnabled(toolName);
|
|
44
47
|
});
|
|
45
48
|
|
|
@@ -50,7 +53,12 @@ export const loadAnnotations = function (jsonData) {
|
|
|
50
53
|
|
|
51
54
|
// FIXME error if called when image is not loaded
|
|
52
55
|
for (let elementId of enabledElementIds) {
|
|
53
|
-
|
|
56
|
+
let element = document.getElementById(elementId);
|
|
57
|
+
if (!element) {
|
|
58
|
+
console.warn(`Element ${elementId} not found`);
|
|
59
|
+
continue;
|
|
60
|
+
}
|
|
61
|
+
cornerstone.updateImage(element);
|
|
54
62
|
}
|
|
55
63
|
};
|
|
56
64
|
|
|
@@ -59,13 +67,16 @@ export const loadAnnotations = function (jsonData) {
|
|
|
59
67
|
* @param {bool} download - True to download json
|
|
60
68
|
* @param {string} filename - The json file name, @default state.json
|
|
61
69
|
*/
|
|
62
|
-
export const saveAnnotations = function (
|
|
70
|
+
export const saveAnnotations = function (
|
|
71
|
+
download: boolean,
|
|
72
|
+
filename = "state.json"
|
|
73
|
+
) {
|
|
63
74
|
let currentToolState =
|
|
64
75
|
cornerstoneTools.globalImageIdSpecificToolStateManager.saveToolState();
|
|
65
|
-
if (
|
|
76
|
+
if (download) {
|
|
66
77
|
// Convert JSON Array to string.
|
|
67
78
|
var json_string = JSON.stringify(currentToolState);
|
|
68
|
-
|
|
79
|
+
downloadFile(json_string, filename);
|
|
69
80
|
}
|
|
70
81
|
|
|
71
82
|
return currentToolState;
|
|
@@ -76,14 +87,14 @@ export const saveAnnotations = function (toDownload, filename = "state.json") {
|
|
|
76
87
|
* containing only useful informations for user
|
|
77
88
|
*/
|
|
78
89
|
export const exportAnnotations = function (
|
|
79
|
-
fileManager,
|
|
90
|
+
manager: typeof fileManager,
|
|
80
91
|
filename = "annotations.csv"
|
|
81
92
|
) {
|
|
82
93
|
let currentToolState =
|
|
83
94
|
cornerstoneTools.globalImageIdSpecificToolStateManager.saveToolState();
|
|
84
|
-
let
|
|
85
|
-
let csvstring = unparse(
|
|
86
|
-
|
|
95
|
+
let { fieldsArr: fields, data } = generateCSV(manager, currentToolState);
|
|
96
|
+
let csvstring = unparse({ fields, data });
|
|
97
|
+
downloadFile(csvstring, filename);
|
|
87
98
|
};
|
|
88
99
|
|
|
89
100
|
/**
|
|
@@ -91,13 +102,12 @@ export const exportAnnotations = function (
|
|
|
91
102
|
* @param {*} stringContent
|
|
92
103
|
* @param {*} filename
|
|
93
104
|
*/
|
|
94
|
-
function
|
|
105
|
+
function downloadFile(stringContent: string, filename: string) {
|
|
95
106
|
// Convert string to BLOB.
|
|
96
|
-
|
|
97
|
-
var blob = new Blob(stringContent, { type: "text/plain;charset=utf-8" });
|
|
107
|
+
var blob = new Blob([stringContent], { type: "text/plain;charset=utf-8" });
|
|
98
108
|
//Check the Browser.
|
|
99
109
|
var isIE = false || !!document.documentMode;
|
|
100
|
-
if (isIE) {
|
|
110
|
+
if (isIE && window.navigator.msSaveBlob) {
|
|
101
111
|
window.navigator.msSaveBlob(blob, filename);
|
|
102
112
|
} else {
|
|
103
113
|
var url = window.URL || window.webkitURL;
|
|
@@ -115,14 +125,17 @@ function download(stringContent, filename) {
|
|
|
115
125
|
*
|
|
116
126
|
* @param {*} allToolState
|
|
117
127
|
*/
|
|
118
|
-
export function generateCSV(
|
|
119
|
-
|
|
128
|
+
export function generateCSV(
|
|
129
|
+
manager: typeof fileManager,
|
|
130
|
+
allToolState: ToolState
|
|
131
|
+
) {
|
|
132
|
+
let fields: Set<string> = new Set();
|
|
120
133
|
fields.add("imagePath");
|
|
121
134
|
fields.add("toolName");
|
|
122
|
-
let data = [];
|
|
135
|
+
let data: Object[] = [];
|
|
123
136
|
each(allToolState, (imageToolState, imageId) => {
|
|
124
137
|
// convert imageId to imagePath
|
|
125
|
-
let imagePath = invert(
|
|
138
|
+
let imagePath = invert(manager)[imageId];
|
|
126
139
|
each(imageToolState, (toolState, toolName) => {
|
|
127
140
|
// extract useful information from tool state
|
|
128
141
|
let extractedData = extractToolInfo(toolName, toolState.data);
|
|
@@ -134,10 +147,10 @@ export function generateCSV(fileManager, allToolState) {
|
|
|
134
147
|
});
|
|
135
148
|
});
|
|
136
149
|
|
|
137
|
-
|
|
150
|
+
let fieldsArr: string[] = Array.from(fields);
|
|
138
151
|
|
|
139
152
|
return {
|
|
140
|
-
|
|
153
|
+
fieldsArr,
|
|
141
154
|
data
|
|
142
155
|
};
|
|
143
156
|
}
|
|
@@ -146,8 +159,11 @@ export function generateCSV(fileManager, allToolState) {
|
|
|
146
159
|
*
|
|
147
160
|
* @param {*} toolData
|
|
148
161
|
*/
|
|
149
|
-
function extractToolInfo(
|
|
150
|
-
|
|
162
|
+
function extractToolInfo(
|
|
163
|
+
toolName: string,
|
|
164
|
+
toolData: ToolState["imageId"][keyof ToolState["imageId"]]
|
|
165
|
+
) {
|
|
166
|
+
let dataArray: Object[] = [];
|
|
151
167
|
switch (toolName) {
|
|
152
168
|
case "RectangleRoi":
|
|
153
169
|
case "EllipticalRoi":
|