larvitar 2.0.4 → 2.0.6
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/README.md +2 -2
- package/dist/larvitar.js +5 -3
- package/dist/larvitar.js.map +1 -1
- package/package.json +6 -2
- package/.github/workflows/build-docs.yml +0 -59
- package/.github/workflows/codeql-analysis.yml +0 -71
- package/.github/workflows/deploy.yml +0 -37
- package/.vscode/settings.json +0 -4
- package/CODE_OF_CONDUCT.md +0 -76
- package/MIGRATION.md +0 -25
- package/bundler/webpack.common.js +0 -27
- package/bundler/webpack.dev.js +0 -23
- package/bundler/webpack.prod.js +0 -19
- package/decs.d.ts +0 -12
- package/imaging/MetaDataReadable.ts +0 -42
- package/imaging/MetaDataTypes.ts +0 -3491
- package/imaging/dataDictionary.json +0 -21866
- package/imaging/imageAnonymization.ts +0 -135
- package/imaging/imageColormaps.ts +0 -217
- package/imaging/imageContours.ts +0 -196
- package/imaging/imageIo.ts +0 -251
- package/imaging/imageLayers.ts +0 -121
- package/imaging/imageLoading.ts +0 -299
- package/imaging/imageParsing.ts +0 -444
- package/imaging/imagePresets.ts +0 -156
- package/imaging/imageRendering.ts +0 -1091
- package/imaging/imageReslice.ts +0 -87
- package/imaging/imageStore.ts +0 -487
- package/imaging/imageTags.ts +0 -609
- package/imaging/imageTools.js +0 -708
- package/imaging/imageUtils.ts +0 -1079
- package/imaging/loaders/commonLoader.ts +0 -275
- package/imaging/loaders/dicomLoader.ts +0 -66
- package/imaging/loaders/fileLoader.ts +0 -71
- package/imaging/loaders/multiframeLoader.ts +0 -435
- package/imaging/loaders/nrrdLoader.ts +0 -630
- package/imaging/loaders/resliceLoader.ts +0 -205
- package/imaging/monitors/memory.ts +0 -151
- package/imaging/monitors/performance.ts +0 -34
- package/imaging/parsers/ecg.ts +0 -54
- package/imaging/parsers/nrrd.js +0 -485
- package/imaging/tools/README.md +0 -27
- package/imaging/tools/custom/4dSliceScrollTool.js +0 -146
- package/imaging/tools/custom/BorderMagnifyTool.js +0 -99
- package/imaging/tools/custom/contourTool.js +0 -1884
- package/imaging/tools/custom/diameterTool.js +0 -141
- package/imaging/tools/custom/editMaskTool.js +0 -141
- package/imaging/tools/custom/ellipticalRoiOverlayTool.js +0 -534
- package/imaging/tools/custom/polygonSegmentationMixin.js +0 -245
- package/imaging/tools/custom/polylineScissorsTool.js +0 -59
- package/imaging/tools/custom/rectangleRoiOverlayTool.js +0 -564
- package/imaging/tools/custom/seedTool.js +0 -342
- package/imaging/tools/custom/setLabelMap3D.ts +0 -242
- package/imaging/tools/custom/thresholdsBrushTool.js +0 -161
- package/imaging/tools/default.ts +0 -594
- package/imaging/tools/interaction.ts +0 -266
- package/imaging/tools/io.ts +0 -229
- package/imaging/tools/main.ts +0 -424
- package/imaging/tools/segmentation.ts +0 -532
- package/imaging/tools/segmentations.md +0 -38
- package/imaging/tools/state.ts +0 -74
- package/imaging/tools/strategies/eraseFreehand.js +0 -76
- package/imaging/tools/strategies/fillFreehand.js +0 -79
- package/imaging/tools/strategies/index.js +0 -2
- package/imaging/tools/types.d.ts +0 -243
- package/imaging/types.d.ts +0 -200
- package/imaging/waveforms/ecg.ts +0 -191
- package/index.ts +0 -431
- package/jsdoc.json +0 -52
- package/rollup.config.js +0 -51
- package/template/.gitkeep +0 -0
- package/tsconfig.json +0 -102
package/imaging/imageReslice.ts
DELETED
|
@@ -1,87 +0,0 @@
|
|
|
1
|
-
/** @module imaging/imageReslice
|
|
2
|
-
* @desc This file provides functionalities for
|
|
3
|
-
* image reslice in orthogonal directions
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
// external libraries
|
|
7
|
-
import { v4 as uuidv4 } from "uuid";
|
|
8
|
-
import { each } from "lodash";
|
|
9
|
-
|
|
10
|
-
// internal libraries
|
|
11
|
-
import { getReslicedMetadata, getReslicedPixeldata } from "./imageUtils";
|
|
12
|
-
import {
|
|
13
|
-
getLarvitarImageTracker,
|
|
14
|
-
getLarvitarManager
|
|
15
|
-
} from "./loaders/commonLoader";
|
|
16
|
-
import store from "./imageStore";
|
|
17
|
-
import { Series } from "./types";
|
|
18
|
-
|
|
19
|
-
/*
|
|
20
|
-
* This module provides the following functions to be exported:
|
|
21
|
-
* resliceSeries(seriesId, seriesData, orientation)
|
|
22
|
-
*/
|
|
23
|
-
|
|
24
|
-
/**
|
|
25
|
-
* Reslice a serie from native orientation to coronal or sagittal orientation
|
|
26
|
-
* @instance
|
|
27
|
-
* @function resliceSeries
|
|
28
|
-
* @param {Object} seriesData the original series data
|
|
29
|
-
* @param {String} orientation the reslice orientation [coronal or sagittal]
|
|
30
|
-
* @returns {Promise} - Return a promise which will resolve when data is available
|
|
31
|
-
*/
|
|
32
|
-
export function resliceSeries(
|
|
33
|
-
seriesData: Series,
|
|
34
|
-
orientation: "axial" | "coronal" | "sagittal"
|
|
35
|
-
) {
|
|
36
|
-
let reslicePromise = new Promise(resolve => {
|
|
37
|
-
let reslicedSeries: Partial<Series> = {};
|
|
38
|
-
let reslicedSeriesId = uuidv4();
|
|
39
|
-
let reslicedMetaData = getReslicedMetadata(
|
|
40
|
-
reslicedSeriesId,
|
|
41
|
-
"axial",
|
|
42
|
-
orientation,
|
|
43
|
-
seriesData,
|
|
44
|
-
"resliceLoader"
|
|
45
|
-
);
|
|
46
|
-
|
|
47
|
-
reslicedSeries.imageIds = reslicedMetaData.imageIds;
|
|
48
|
-
// @ts-ignore fix incompatibilities between these types
|
|
49
|
-
reslicedSeries.instances = reslicedMetaData.instances;
|
|
50
|
-
|
|
51
|
-
reslicedSeries.currentImageIdIndex = Math.floor(
|
|
52
|
-
reslicedSeries.imageIds.length / 2
|
|
53
|
-
);
|
|
54
|
-
|
|
55
|
-
function computeReslice(
|
|
56
|
-
seriesData: Series,
|
|
57
|
-
reslicedSeriesId: string,
|
|
58
|
-
reslicedSeries: Series
|
|
59
|
-
) {
|
|
60
|
-
let t0 = performance.now();
|
|
61
|
-
let imageTracker = getLarvitarImageTracker();
|
|
62
|
-
let manager = getLarvitarManager();
|
|
63
|
-
each(reslicedSeries.imageIds, function (imageId: string) {
|
|
64
|
-
reslicedSeries.instances[imageId].pixelData = getReslicedPixeldata(
|
|
65
|
-
imageId,
|
|
66
|
-
seriesData,
|
|
67
|
-
reslicedSeries
|
|
68
|
-
) as Uint16Array;
|
|
69
|
-
imageTracker[imageId] = reslicedSeriesId;
|
|
70
|
-
});
|
|
71
|
-
store.addSeriesId(reslicedSeriesId, reslicedSeries.imageIds);
|
|
72
|
-
reslicedSeries.numberOfImages = reslicedSeries.imageIds.length;
|
|
73
|
-
reslicedSeries.seriesUID = reslicedSeriesId;
|
|
74
|
-
reslicedSeries.seriesDescription = seriesData.seriesDescription;
|
|
75
|
-
reslicedSeries.orientation = orientation;
|
|
76
|
-
manager[reslicedSeriesId] = reslicedSeries;
|
|
77
|
-
//@ts-ignore deprecated
|
|
78
|
-
manager[seriesData.seriesUID][orientation] = reslicedSeriesId;
|
|
79
|
-
let t1 = performance.now();
|
|
80
|
-
console.log(`Call to resliceSeries took ${t1 - t0} milliseconds.`);
|
|
81
|
-
resolve(reslicedSeries);
|
|
82
|
-
}
|
|
83
|
-
// reslice the data
|
|
84
|
-
computeReslice(seriesData, reslicedSeriesId, reslicedSeries as Series);
|
|
85
|
-
});
|
|
86
|
-
return reslicePromise;
|
|
87
|
-
}
|
package/imaging/imageStore.ts
DELETED
|
@@ -1,487 +0,0 @@
|
|
|
1
|
-
/** @module imaging/imageStore
|
|
2
|
-
* @desc This file provides functionalities
|
|
3
|
-
* for data config store.
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
// external libraries
|
|
7
|
-
import { get as _get, cloneDeep as _cloneDeep } from "lodash";
|
|
8
|
-
|
|
9
|
-
type StoreSeries = { imageIds: string[]; progress: number };
|
|
10
|
-
|
|
11
|
-
type Store = {
|
|
12
|
-
colormapId: string;
|
|
13
|
-
errorLog: string; // TODO review this, should be an array?
|
|
14
|
-
leftActiveTool?: string;
|
|
15
|
-
rightActiveTool?: string;
|
|
16
|
-
series: { [seriesUID: string]: StoreSeries };
|
|
17
|
-
viewports: { [key: string]: typeof DEFAULT_VIEWPORT };
|
|
18
|
-
// fallback for any other field
|
|
19
|
-
[key: string]: any;
|
|
20
|
-
};
|
|
21
|
-
|
|
22
|
-
type SetPayload =
|
|
23
|
-
| ["errorLog" | "leftActiveTool" | "rightActiveTool", string]
|
|
24
|
-
| [
|
|
25
|
-
"isColor" | "isMultiframe" | "isPDF" | "isTimeserie" | "ready",
|
|
26
|
-
string,
|
|
27
|
-
boolean
|
|
28
|
-
]
|
|
29
|
-
| [
|
|
30
|
-
(
|
|
31
|
-
| "progress"
|
|
32
|
-
| "loading"
|
|
33
|
-
| "minPixelValue"
|
|
34
|
-
| "maxPixelValue"
|
|
35
|
-
| "minSliceId"
|
|
36
|
-
| "maxSliceId"
|
|
37
|
-
| "minTimeId"
|
|
38
|
-
| "maxTimeId"
|
|
39
|
-
| "rotation"
|
|
40
|
-
| "scale"
|
|
41
|
-
| "sliceId"
|
|
42
|
-
| "timeId"
|
|
43
|
-
| "thickness"
|
|
44
|
-
),
|
|
45
|
-
string,
|
|
46
|
-
number
|
|
47
|
-
]
|
|
48
|
-
| ["timestamp", string, number | undefined]
|
|
49
|
-
| ["pendingSliceId", string, number | undefined]
|
|
50
|
-
| ["timestamps" | "timeIds", string, number[]]
|
|
51
|
-
| [
|
|
52
|
-
"contrast" | "dimensions" | "spacing" | "translation",
|
|
53
|
-
string,
|
|
54
|
-
number,
|
|
55
|
-
number
|
|
56
|
-
]
|
|
57
|
-
| [
|
|
58
|
-
"defaultViewport",
|
|
59
|
-
string,
|
|
60
|
-
number,
|
|
61
|
-
number,
|
|
62
|
-
number,
|
|
63
|
-
number,
|
|
64
|
-
number,
|
|
65
|
-
number,
|
|
66
|
-
boolean
|
|
67
|
-
];
|
|
68
|
-
|
|
69
|
-
// Larvitar store object
|
|
70
|
-
let STORE: Store;
|
|
71
|
-
|
|
72
|
-
// Data listeners
|
|
73
|
-
let storeListener: ((data: Store) => {}) | undefined = undefined;
|
|
74
|
-
const seriesListeners = {} as {
|
|
75
|
-
[seriesId: string]: (data: StoreSeries) => {};
|
|
76
|
-
};
|
|
77
|
-
const viewportsListeners = {} as {
|
|
78
|
-
[elementId: string]: (data: typeof DEFAULT_VIEWPORT) => {};
|
|
79
|
-
};
|
|
80
|
-
|
|
81
|
-
// default initial store object
|
|
82
|
-
const INITIAL_STORE_DATA: Store = {
|
|
83
|
-
colormapId: "gray",
|
|
84
|
-
errorLog: "",
|
|
85
|
-
leftActiveTool: undefined,
|
|
86
|
-
rightActiveTool: undefined,
|
|
87
|
-
series: {},
|
|
88
|
-
viewports: {}
|
|
89
|
-
};
|
|
90
|
-
|
|
91
|
-
// default viewport object
|
|
92
|
-
export const DEFAULT_VIEWPORT: {
|
|
93
|
-
loading: number;
|
|
94
|
-
ready: boolean;
|
|
95
|
-
minSliceId: number;
|
|
96
|
-
maxSliceId: number;
|
|
97
|
-
sliceId: number;
|
|
98
|
-
pendingSliceId?: number;
|
|
99
|
-
minTimeId: number;
|
|
100
|
-
maxTimeId: number;
|
|
101
|
-
timeId: number;
|
|
102
|
-
timestamp: number;
|
|
103
|
-
timestamps: number[];
|
|
104
|
-
timeIds: number[];
|
|
105
|
-
rows: number;
|
|
106
|
-
cols: number;
|
|
107
|
-
spacing_x: number;
|
|
108
|
-
spacing_y: number;
|
|
109
|
-
thickness: number;
|
|
110
|
-
minPixelValue: number;
|
|
111
|
-
maxPixelValue: number;
|
|
112
|
-
isColor: boolean;
|
|
113
|
-
isMultiframe: boolean;
|
|
114
|
-
isTimeserie: boolean;
|
|
115
|
-
isPDF: boolean;
|
|
116
|
-
viewport: {
|
|
117
|
-
scale: number;
|
|
118
|
-
rotation: number;
|
|
119
|
-
translation: {
|
|
120
|
-
x: number;
|
|
121
|
-
y: number;
|
|
122
|
-
};
|
|
123
|
-
voi: {
|
|
124
|
-
windowCenter: number;
|
|
125
|
-
windowWidth: number;
|
|
126
|
-
};
|
|
127
|
-
// redundant fields ?
|
|
128
|
-
rows: number;
|
|
129
|
-
cols: number;
|
|
130
|
-
spacing_x: number;
|
|
131
|
-
spacing_y: number;
|
|
132
|
-
thickness: number;
|
|
133
|
-
};
|
|
134
|
-
default: {
|
|
135
|
-
scale: number;
|
|
136
|
-
rotation: number;
|
|
137
|
-
translation: {
|
|
138
|
-
x: number;
|
|
139
|
-
y: number;
|
|
140
|
-
};
|
|
141
|
-
voi: {
|
|
142
|
-
windowCenter: number;
|
|
143
|
-
windowWidth: number;
|
|
144
|
-
invert: boolean;
|
|
145
|
-
};
|
|
146
|
-
};
|
|
147
|
-
} = {
|
|
148
|
-
loading: 0, // from 0 to 100 (%)
|
|
149
|
-
ready: false, // true when currentImageId is rendered
|
|
150
|
-
minSliceId: 0,
|
|
151
|
-
maxSliceId: 0,
|
|
152
|
-
sliceId: 0,
|
|
153
|
-
pendingSliceId: undefined,
|
|
154
|
-
minTimeId: 0,
|
|
155
|
-
maxTimeId: 0,
|
|
156
|
-
timeId: 0,
|
|
157
|
-
timestamp: 0,
|
|
158
|
-
timestamps: [],
|
|
159
|
-
timeIds: [],
|
|
160
|
-
rows: 0,
|
|
161
|
-
cols: 0,
|
|
162
|
-
spacing_x: 0.0,
|
|
163
|
-
spacing_y: 0.0,
|
|
164
|
-
thickness: 0.0,
|
|
165
|
-
minPixelValue: 0,
|
|
166
|
-
maxPixelValue: 0,
|
|
167
|
-
isColor: false,
|
|
168
|
-
isMultiframe: false,
|
|
169
|
-
isTimeserie: false,
|
|
170
|
-
isPDF: false,
|
|
171
|
-
viewport: {
|
|
172
|
-
scale: 0.0,
|
|
173
|
-
rotation: 0.0,
|
|
174
|
-
translation: {
|
|
175
|
-
x: 0.0,
|
|
176
|
-
y: 0.0
|
|
177
|
-
},
|
|
178
|
-
voi: {
|
|
179
|
-
windowCenter: 0.0,
|
|
180
|
-
windowWidth: 0.0
|
|
181
|
-
},
|
|
182
|
-
// redundant fields ?
|
|
183
|
-
rows: 0,
|
|
184
|
-
cols: 0,
|
|
185
|
-
spacing_x: 0.0,
|
|
186
|
-
spacing_y: 0.0,
|
|
187
|
-
thickness: 0.0
|
|
188
|
-
},
|
|
189
|
-
default: {
|
|
190
|
-
scale: 0.0,
|
|
191
|
-
rotation: 0.0,
|
|
192
|
-
translation: {
|
|
193
|
-
x: 0.0,
|
|
194
|
-
y: 0.0
|
|
195
|
-
},
|
|
196
|
-
voi: {
|
|
197
|
-
windowCenter: 0.0,
|
|
198
|
-
windowWidth: 0.0,
|
|
199
|
-
invert: false
|
|
200
|
-
}
|
|
201
|
-
}
|
|
202
|
-
};
|
|
203
|
-
|
|
204
|
-
export type Viewport = typeof DEFAULT_VIEWPORT;
|
|
205
|
-
|
|
206
|
-
// Trigger store listeners
|
|
207
|
-
const triggerStoreListener = (data: Store) =>
|
|
208
|
-
storeListener ? storeListener(data) : undefined;
|
|
209
|
-
|
|
210
|
-
const triggerViewportListener = (elementId: string) => {
|
|
211
|
-
if (viewportsListeners[elementId] && STORE?.viewports[elementId]) {
|
|
212
|
-
viewportsListeners[elementId](STORE.viewports[elementId]);
|
|
213
|
-
}
|
|
214
|
-
};
|
|
215
|
-
|
|
216
|
-
const triggerSeriesListener = (seriesId: string) => {
|
|
217
|
-
if (seriesListeners[seriesId] && STORE?.series[seriesId]) {
|
|
218
|
-
seriesListeners[seriesId](STORE.series[seriesId]);
|
|
219
|
-
}
|
|
220
|
-
};
|
|
221
|
-
|
|
222
|
-
/**
|
|
223
|
-
* Set a value into store
|
|
224
|
-
* @function setValue
|
|
225
|
-
* @param {Object} data - The data object
|
|
226
|
-
*/
|
|
227
|
-
const setValue = (store: Store, data: SetPayload) => {
|
|
228
|
-
let field = data[0];
|
|
229
|
-
const k = data[1];
|
|
230
|
-
let [_1, _2, ...v] = data;
|
|
231
|
-
|
|
232
|
-
const viewport = store.viewports[k];
|
|
233
|
-
|
|
234
|
-
// assign values
|
|
235
|
-
switch (field) {
|
|
236
|
-
case "progress":
|
|
237
|
-
if (!store.series[k]) {
|
|
238
|
-
return;
|
|
239
|
-
}
|
|
240
|
-
store.series[k][field] = (v as [number])[0];
|
|
241
|
-
triggerSeriesListener(k);
|
|
242
|
-
break;
|
|
243
|
-
|
|
244
|
-
case "isColor":
|
|
245
|
-
case "isMultiframe":
|
|
246
|
-
case "isPDF":
|
|
247
|
-
case "isTimeserie":
|
|
248
|
-
case "ready":
|
|
249
|
-
if (!viewport) {
|
|
250
|
-
return;
|
|
251
|
-
}
|
|
252
|
-
viewport[field] = (v as [boolean])[0];
|
|
253
|
-
triggerViewportListener(k);
|
|
254
|
-
break;
|
|
255
|
-
|
|
256
|
-
case "loading":
|
|
257
|
-
case "minPixelValue":
|
|
258
|
-
case "maxPixelValue":
|
|
259
|
-
case "minSliceId":
|
|
260
|
-
case "maxSliceId":
|
|
261
|
-
case "minTimeId":
|
|
262
|
-
case "maxTimeId":
|
|
263
|
-
case "sliceId":
|
|
264
|
-
case "pendingSliceId":
|
|
265
|
-
case "timeId":
|
|
266
|
-
case "timestamp":
|
|
267
|
-
if (!viewport) {
|
|
268
|
-
return;
|
|
269
|
-
}
|
|
270
|
-
viewport[field] = (v as [number])[0];
|
|
271
|
-
triggerViewportListener(k);
|
|
272
|
-
break;
|
|
273
|
-
|
|
274
|
-
case "timestamps":
|
|
275
|
-
case "timeIds":
|
|
276
|
-
if (!viewport) {
|
|
277
|
-
return;
|
|
278
|
-
}
|
|
279
|
-
viewport[field] = (v as [[number]])[0];
|
|
280
|
-
triggerViewportListener(k);
|
|
281
|
-
break;
|
|
282
|
-
|
|
283
|
-
case "rotation":
|
|
284
|
-
case "scale":
|
|
285
|
-
if (!viewport) {
|
|
286
|
-
return;
|
|
287
|
-
}
|
|
288
|
-
viewport.viewport[field] = (v as [number])[0];
|
|
289
|
-
triggerViewportListener(k);
|
|
290
|
-
break;
|
|
291
|
-
|
|
292
|
-
case "thickness":
|
|
293
|
-
if (!viewport) {
|
|
294
|
-
return;
|
|
295
|
-
}
|
|
296
|
-
viewport[field] = (v as [number])[0];
|
|
297
|
-
viewport.viewport[field] = (v as [number])[0];
|
|
298
|
-
triggerViewportListener(k);
|
|
299
|
-
break;
|
|
300
|
-
|
|
301
|
-
case "translation":
|
|
302
|
-
if (!viewport) {
|
|
303
|
-
return;
|
|
304
|
-
}
|
|
305
|
-
v = v as [number, number];
|
|
306
|
-
viewport.viewport[field] = { x: v[0], y: v[1] };
|
|
307
|
-
triggerViewportListener(k);
|
|
308
|
-
break;
|
|
309
|
-
|
|
310
|
-
case "contrast":
|
|
311
|
-
if (!viewport) {
|
|
312
|
-
return;
|
|
313
|
-
}
|
|
314
|
-
v = v as [number, number];
|
|
315
|
-
viewport.viewport.voi.windowWidth = v[0];
|
|
316
|
-
viewport.viewport.voi.windowCenter = v[1];
|
|
317
|
-
triggerViewportListener(k);
|
|
318
|
-
break;
|
|
319
|
-
|
|
320
|
-
case "dimensions":
|
|
321
|
-
if (!viewport) {
|
|
322
|
-
return;
|
|
323
|
-
}
|
|
324
|
-
v = v as [number, number];
|
|
325
|
-
viewport.rows = v[0];
|
|
326
|
-
viewport.cols = v[1];
|
|
327
|
-
viewport.viewport.rows = v[0];
|
|
328
|
-
viewport.viewport.cols = v[1];
|
|
329
|
-
triggerViewportListener(k);
|
|
330
|
-
break;
|
|
331
|
-
|
|
332
|
-
case "spacing":
|
|
333
|
-
if (!viewport) {
|
|
334
|
-
return;
|
|
335
|
-
}
|
|
336
|
-
v = v as [number, number];
|
|
337
|
-
viewport.spacing_x = v[0];
|
|
338
|
-
viewport.spacing_y = v[1];
|
|
339
|
-
viewport.viewport.spacing_x = v[0];
|
|
340
|
-
viewport.viewport.spacing_y = v[1];
|
|
341
|
-
triggerViewportListener(k);
|
|
342
|
-
break;
|
|
343
|
-
|
|
344
|
-
case "defaultViewport":
|
|
345
|
-
if (!viewport) {
|
|
346
|
-
return;
|
|
347
|
-
}
|
|
348
|
-
v = v as [number, number, number, number, number, number, boolean];
|
|
349
|
-
viewport.default.scale = v[0];
|
|
350
|
-
viewport.default.rotation = v[1];
|
|
351
|
-
viewport.default.translation.x = v[2];
|
|
352
|
-
viewport.default.translation.y = v[3];
|
|
353
|
-
viewport.default.voi.windowWidth = v[4];
|
|
354
|
-
viewport.default.voi.windowCenter = v[5];
|
|
355
|
-
viewport.default.voi.invert = v[6];
|
|
356
|
-
triggerViewportListener(k);
|
|
357
|
-
break;
|
|
358
|
-
|
|
359
|
-
default:
|
|
360
|
-
store[field] = k;
|
|
361
|
-
break;
|
|
362
|
-
}
|
|
363
|
-
};
|
|
364
|
-
|
|
365
|
-
/**
|
|
366
|
-
* Instancing the store
|
|
367
|
-
*/
|
|
368
|
-
const setup = (data = _cloneDeep(INITIAL_STORE_DATA)) => {
|
|
369
|
-
/**
|
|
370
|
-
* Create the Proxy handler object
|
|
371
|
-
* @param {String} name The namespace
|
|
372
|
-
* @param {Object} data The data object
|
|
373
|
-
* @return {Object} The Proxy handler
|
|
374
|
-
*/
|
|
375
|
-
const handler: ProxyHandler<Store> = {
|
|
376
|
-
get: (obj, prop: string) => {
|
|
377
|
-
if (prop === "_isProxy") return true;
|
|
378
|
-
if (
|
|
379
|
-
["object", "array"].includes(
|
|
380
|
-
Object.prototype.toString.call(obj[prop]).slice(8, -1).toLowerCase()
|
|
381
|
-
) &&
|
|
382
|
-
!obj[prop]._isProxy
|
|
383
|
-
) {
|
|
384
|
-
obj[prop] = new Proxy<Store>(obj[prop], handler);
|
|
385
|
-
}
|
|
386
|
-
return obj[prop];
|
|
387
|
-
},
|
|
388
|
-
set: (obj, prop: string, value) => {
|
|
389
|
-
// console.warn("SET", obj, prop, value);
|
|
390
|
-
if (obj[prop] === value) return true;
|
|
391
|
-
obj[prop] = value;
|
|
392
|
-
triggerStoreListener(data);
|
|
393
|
-
return true;
|
|
394
|
-
},
|
|
395
|
-
deleteProperty: (obj, prop: string) => {
|
|
396
|
-
delete obj[prop];
|
|
397
|
-
triggerStoreListener(data);
|
|
398
|
-
return true;
|
|
399
|
-
}
|
|
400
|
-
};
|
|
401
|
-
|
|
402
|
-
return new Proxy<Store>(data, handler);
|
|
403
|
-
};
|
|
404
|
-
|
|
405
|
-
const initializeStore = () => {
|
|
406
|
-
STORE = setup();
|
|
407
|
-
};
|
|
408
|
-
|
|
409
|
-
const validateStore = () => {
|
|
410
|
-
if (!STORE) {
|
|
411
|
-
throw "Larvitar store does not exists. Initialize it with the 'initializeStore' function.";
|
|
412
|
-
}
|
|
413
|
-
};
|
|
414
|
-
|
|
415
|
-
export const set = (payload: SetPayload) => {
|
|
416
|
-
validateStore();
|
|
417
|
-
setValue(STORE!, payload);
|
|
418
|
-
};
|
|
419
|
-
|
|
420
|
-
export default {
|
|
421
|
-
initialize: initializeStore,
|
|
422
|
-
// add/remove viewports
|
|
423
|
-
addViewport: (name: string) => {
|
|
424
|
-
validateStore();
|
|
425
|
-
STORE!.viewports[name] = _cloneDeep(DEFAULT_VIEWPORT);
|
|
426
|
-
},
|
|
427
|
-
deleteViewport: (name: string) => {
|
|
428
|
-
validateStore();
|
|
429
|
-
delete STORE!.viewports[name];
|
|
430
|
-
},
|
|
431
|
-
// add/remove series instances ids
|
|
432
|
-
addSeriesId: (seriesId: string, imageIds: string[]) => {
|
|
433
|
-
validateStore();
|
|
434
|
-
if (!STORE!.series[seriesId]) {
|
|
435
|
-
STORE!.series[seriesId] = {} as StoreSeries;
|
|
436
|
-
}
|
|
437
|
-
STORE!.series[seriesId].imageIds = imageIds;
|
|
438
|
-
triggerSeriesListener(seriesId);
|
|
439
|
-
},
|
|
440
|
-
removeSeriesId: (seriesId: string) => {
|
|
441
|
-
validateStore();
|
|
442
|
-
delete STORE!.series[seriesId];
|
|
443
|
-
},
|
|
444
|
-
resetSeriesIds: () => {
|
|
445
|
-
validateStore();
|
|
446
|
-
STORE!.series = {};
|
|
447
|
-
},
|
|
448
|
-
// expose useful sets
|
|
449
|
-
setSliceId: (elementId: string, imageIndex: number) => {
|
|
450
|
-
set(["sliceId", elementId, imageIndex]);
|
|
451
|
-
},
|
|
452
|
-
setPendingSliceId: (elementId: string, imageIndex: number) => {
|
|
453
|
-
set(["pendingSliceId", elementId, imageIndex]);
|
|
454
|
-
},
|
|
455
|
-
setMaxSliceId: (elementId: string, imageIndex: number) => {
|
|
456
|
-
set(["maxSliceId", elementId, imageIndex]);
|
|
457
|
-
},
|
|
458
|
-
// get
|
|
459
|
-
get: (props: string | string[]) => {
|
|
460
|
-
validateStore();
|
|
461
|
-
return _get(STORE, props);
|
|
462
|
-
},
|
|
463
|
-
// watch store
|
|
464
|
-
addStoreListener: (listener: (data: Store) => {}) =>
|
|
465
|
-
(storeListener = listener),
|
|
466
|
-
removeStoreListener: () => (storeListener = undefined),
|
|
467
|
-
// watch single viewport
|
|
468
|
-
addViewportListener: (
|
|
469
|
-
elementId: string,
|
|
470
|
-
listener: (data: typeof DEFAULT_VIEWPORT) => {}
|
|
471
|
-
) => {
|
|
472
|
-
viewportsListeners[elementId] = listener;
|
|
473
|
-
},
|
|
474
|
-
removeViewportListener: (elementId: string) => {
|
|
475
|
-
delete viewportsListeners[elementId];
|
|
476
|
-
},
|
|
477
|
-
// watch single series
|
|
478
|
-
addSeriesListener: (
|
|
479
|
-
seriesId: string,
|
|
480
|
-
listener: (data: StoreSeries) => {}
|
|
481
|
-
) => {
|
|
482
|
-
seriesListeners[seriesId] = listener;
|
|
483
|
-
},
|
|
484
|
-
removeSeriesListener: (seriesId: string) => {
|
|
485
|
-
delete seriesListeners[seriesId];
|
|
486
|
-
}
|
|
487
|
-
};
|