copper3d 3.0.0 → 3.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/README.md +195 -28
- package/dist/Utils/segmentation/CommToolsData.d.ts +32 -18
- package/dist/Utils/segmentation/CommToolsData.js +69 -152
- package/dist/Utils/segmentation/CommToolsData.js.map +1 -1
- package/dist/Utils/segmentation/DragOperator.d.ts +10 -2
- package/dist/Utils/segmentation/DragOperator.js +18 -8
- package/dist/Utils/segmentation/DragOperator.js.map +1 -1
- package/dist/Utils/segmentation/DrawToolCore.d.ts +24 -18
- package/dist/Utils/segmentation/DrawToolCore.js +255 -436
- package/dist/Utils/segmentation/DrawToolCore.js.map +1 -1
- package/dist/Utils/segmentation/NrrdTools.d.ts +152 -10
- package/dist/Utils/segmentation/NrrdTools.js +604 -203
- package/dist/Utils/segmentation/NrrdTools.js.map +1 -1
- package/dist/Utils/segmentation/core/MaskVolume.d.ts +1 -34
- package/dist/Utils/segmentation/core/MaskVolume.js +24 -124
- package/dist/Utils/segmentation/core/MaskVolume.js.map +1 -1
- package/dist/Utils/segmentation/core/UndoManager.d.ts +1 -1
- package/dist/Utils/segmentation/core/UndoManager.js +1 -1
- package/dist/Utils/segmentation/core/index.d.ts +0 -2
- package/dist/Utils/segmentation/core/index.js +0 -1
- package/dist/Utils/segmentation/core/index.js.map +1 -1
- package/dist/Utils/segmentation/core/types.js +24 -24
- package/dist/Utils/segmentation/core/types.js.map +1 -1
- package/dist/Utils/segmentation/coreTools/GuiState.d.ts +22 -0
- package/dist/Utils/segmentation/coreTools/GuiState.js +48 -0
- package/dist/Utils/segmentation/coreTools/GuiState.js.map +1 -0
- package/dist/Utils/segmentation/coreTools/NrrdState.d.ts +25 -0
- package/dist/Utils/segmentation/coreTools/NrrdState.js +85 -0
- package/dist/Utils/segmentation/coreTools/NrrdState.js.map +1 -0
- package/dist/Utils/segmentation/coreTools/coreType.d.ts +88 -65
- package/dist/Utils/segmentation/coreTools/coreType.js.map +1 -1
- package/dist/Utils/segmentation/coreTools/divControlTools.js +1 -1
- package/dist/Utils/segmentation/coreTools/divControlTools.js.map +1 -1
- package/dist/Utils/segmentation/coreTools/gui.d.ts +12 -9
- package/dist/Utils/segmentation/coreTools/gui.js +81 -107
- package/dist/Utils/segmentation/coreTools/gui.js.map +1 -1
- package/dist/Utils/segmentation/eventRouter/EventRouter.d.ts +2 -0
- package/dist/Utils/segmentation/eventRouter/EventRouter.js +19 -8
- package/dist/Utils/segmentation/eventRouter/EventRouter.js.map +1 -1
- package/dist/Utils/segmentation/eventRouter/types.d.ts +3 -3
- package/dist/Utils/segmentation/tools/BaseTool.d.ts +11 -5
- package/dist/Utils/segmentation/tools/BaseTool.js +1 -2
- package/dist/Utils/segmentation/tools/BaseTool.js.map +1 -1
- package/dist/Utils/segmentation/tools/CrosshairTool.js +25 -25
- package/dist/Utils/segmentation/tools/CrosshairTool.js.map +1 -1
- package/dist/Utils/segmentation/tools/DragSliceTool.d.ts +2 -0
- package/dist/Utils/segmentation/tools/DragSliceTool.js +63 -53
- package/dist/Utils/segmentation/tools/DragSliceTool.js.map +1 -1
- package/dist/Utils/segmentation/tools/DrawingTool.d.ts +93 -0
- package/dist/Utils/segmentation/tools/DrawingTool.js +222 -0
- package/dist/Utils/segmentation/tools/DrawingTool.js.map +1 -0
- package/dist/Utils/segmentation/tools/EraserTool.js +8 -8
- package/dist/Utils/segmentation/tools/EraserTool.js.map +1 -1
- package/dist/Utils/segmentation/tools/ImageStoreHelper.d.ts +12 -32
- package/dist/Utils/segmentation/tools/ImageStoreHelper.js +45 -102
- package/dist/Utils/segmentation/tools/ImageStoreHelper.js.map +1 -1
- package/dist/Utils/segmentation/tools/PanTool.d.ts +53 -0
- package/dist/Utils/segmentation/tools/PanTool.js +90 -0
- package/dist/Utils/segmentation/tools/PanTool.js.map +1 -0
- package/dist/Utils/segmentation/tools/SphereTool.d.ts +208 -3
- package/dist/Utils/segmentation/tools/SphereTool.js +456 -45
- package/dist/Utils/segmentation/tools/SphereTool.js.map +1 -1
- package/dist/Utils/segmentation/tools/ZoomTool.js +5 -4
- package/dist/Utils/segmentation/tools/ZoomTool.js.map +1 -1
- package/dist/Utils/segmentation/tools/index.d.ts +6 -2
- package/dist/Utils/segmentation/tools/index.js +4 -1
- package/dist/Utils/segmentation/tools/index.js.map +1 -1
- package/dist/bundle.esm.js +2451 -1622
- package/dist/bundle.umd.js +2451 -1622
- package/dist/index.d.ts +6 -3
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/types/Utils/segmentation/CommToolsData.d.ts +32 -18
- package/dist/types/Utils/segmentation/DragOperator.d.ts +10 -2
- package/dist/types/Utils/segmentation/DrawToolCore.d.ts +24 -18
- package/dist/types/Utils/segmentation/NrrdTools.d.ts +152 -10
- package/dist/types/Utils/segmentation/core/MaskVolume.d.ts +1 -34
- package/dist/types/Utils/segmentation/core/UndoManager.d.ts +1 -1
- package/dist/types/Utils/segmentation/core/index.d.ts +0 -2
- package/dist/types/Utils/segmentation/coreTools/GuiState.d.ts +22 -0
- package/dist/types/Utils/segmentation/coreTools/NrrdState.d.ts +25 -0
- package/dist/types/Utils/segmentation/coreTools/coreType.d.ts +88 -65
- package/dist/types/Utils/segmentation/coreTools/gui.d.ts +12 -9
- package/dist/types/Utils/segmentation/eventRouter/EventRouter.d.ts +2 -0
- package/dist/types/Utils/segmentation/eventRouter/types.d.ts +3 -3
- package/dist/types/Utils/segmentation/tools/BaseTool.d.ts +11 -5
- package/dist/types/Utils/segmentation/tools/DragSliceTool.d.ts +2 -0
- package/dist/types/Utils/segmentation/tools/DrawingTool.d.ts +93 -0
- package/dist/types/Utils/segmentation/tools/ImageStoreHelper.d.ts +12 -32
- package/dist/types/Utils/segmentation/tools/PanTool.d.ts +53 -0
- package/dist/types/Utils/segmentation/tools/SphereTool.d.ts +208 -3
- package/dist/types/Utils/segmentation/tools/index.d.ts +6 -2
- package/dist/types/index.d.ts +6 -3
- package/package.json +1 -1
- package/dist/Utils/segmentation/core/MigrationUtils.d.ts +0 -97
- package/dist/Utils/segmentation/core/MigrationUtils.js +0 -163
- package/dist/Utils/segmentation/core/MigrationUtils.js.map +0 -1
- package/dist/types/Utils/segmentation/core/MigrationUtils.d.ts +0 -97
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import { setupGui } from "./coreTools/gui";
|
|
2
|
-
import { autoFocusDiv } from "./coreTools/divControlTools";
|
|
2
|
+
import { autoFocusDiv, enableDownload } from "./coreTools/divControlTools";
|
|
3
3
|
import { DragOperator } from "./DragOperator";
|
|
4
4
|
import { DrawToolCore } from "./DrawToolCore";
|
|
5
|
-
import { MaskVolume, CHANNEL_HEX_COLORS, rgbaToHex, rgbaToCss } from "./core";
|
|
5
|
+
import { MaskVolume, CHANNEL_HEX_COLORS, MASK_CHANNEL_COLORS, rgbaToHex, rgbaToCss } from "./core";
|
|
6
|
+
import { SPHERE_CHANNEL_MAP, SPHERE_LABELS } from "./tools/SphereTool";
|
|
6
7
|
/**
|
|
7
8
|
* Core NRRD annotation tool for medical image segmentation.
|
|
8
9
|
*
|
|
@@ -21,15 +22,19 @@ export class NrrdTools extends DrawToolCore {
|
|
|
21
22
|
this.initState = true;
|
|
22
23
|
this._sliceRAFId = null;
|
|
23
24
|
this._pendingSliceStep = 0;
|
|
25
|
+
/** Whether calculator mode is active (not part of gui_states interface) */
|
|
26
|
+
this._calculatorActive = false;
|
|
27
|
+
/** Stored closure callbacks from gui.ts setupGui() */
|
|
28
|
+
this.guiCallbacks = null;
|
|
24
29
|
this.container = container;
|
|
25
|
-
this.protectedData.previousDrawingImage =
|
|
26
|
-
this.protectedData.ctxes.emptyCtx.createImageData(1, 1);
|
|
27
30
|
this.init();
|
|
28
31
|
this.dragOperator = new DragOperator(this.container, this.nrrd_states, this.gui_states, this.protectedData, this.drawingPrameters, this.setSyncsliceNum.bind(this), this.setIsDrawFalse.bind(this), this.flipDisplayImageByAxis.bind(this), this.setEmptyCanvasSize.bind(this), this.getOrCreateSliceBuffer.bind(this), this.renderSliceToCanvas.bind(this));
|
|
29
32
|
// Inject EventRouter into DragOperator for centralized event handling
|
|
30
33
|
if (this.eventRouter) {
|
|
31
34
|
this.dragOperator.setEventRouter(this.eventRouter);
|
|
32
35
|
}
|
|
36
|
+
// Wire sphere overlay refresh callback into DragOperator → DragSliceTool
|
|
37
|
+
this.dragOperator.setRefreshSphereOverlay(() => this.refreshSphereOverlay());
|
|
33
38
|
}
|
|
34
39
|
/**
|
|
35
40
|
* core function for drag slices
|
|
@@ -83,8 +88,8 @@ export class NrrdTools extends DrawToolCore {
|
|
|
83
88
|
protectedData: this.protectedData,
|
|
84
89
|
removeDragMode: this.dragOperator.removeDragMode,
|
|
85
90
|
configDragMode: this.dragOperator.configDragMode,
|
|
86
|
-
|
|
87
|
-
|
|
91
|
+
clearActiveLayer: this.clearActiveLayer,
|
|
92
|
+
clearActiveSlice: this.clearActiveSlice,
|
|
88
93
|
updateSlicesContrast: this.updateSlicesContrast,
|
|
89
94
|
setMainAreaSize: this.setMainAreaSize,
|
|
90
95
|
resetPaintAreaUIPosition: this.resetPaintAreaUIPosition,
|
|
@@ -94,81 +99,361 @@ export class NrrdTools extends DrawToolCore {
|
|
|
94
99
|
resetLayerCanvas: this.resetLayerCanvas,
|
|
95
100
|
redrawDisplayCanvas: this.redrawDisplayCanvas,
|
|
96
101
|
flipDisplayImageByAxis: this.flipDisplayImageByAxis,
|
|
97
|
-
filterDrawedImage: this.filterDrawedImage,
|
|
98
102
|
setEmptyCanvasSize: this.setEmptyCanvasSize,
|
|
99
|
-
|
|
103
|
+
syncLayerSliceData: this.syncLayerSliceData,
|
|
100
104
|
drawImageOnEmptyImage: this.drawImageOnEmptyImage,
|
|
101
|
-
storeEachLayerImage: this.storeEachLayerImage,
|
|
102
|
-
storeImageToLayer: this.storeImageToLayer,
|
|
103
105
|
getRestLayer: this.getRestLayer,
|
|
104
106
|
setIsDrawFalse: this.setIsDrawFalse,
|
|
105
107
|
getVolumeForLayer: this.getVolumeForLayer.bind(this),
|
|
108
|
+
undoLastPainting: this.undoLastPainting.bind(this),
|
|
109
|
+
redoLastPainting: this.redoLastPainting.bind(this),
|
|
110
|
+
resetZoom: () => this.executeAction("resetZoom"),
|
|
111
|
+
downloadCurrentMask: () => this.executeAction("downloadCurrentMask"),
|
|
106
112
|
};
|
|
107
113
|
this.guiParameterSettings = setupGui(guiOptions);
|
|
114
|
+
// Store closure callbacks for programmatic access (Phase 1 Task 1.2)
|
|
115
|
+
this.guiCallbacks = {
|
|
116
|
+
updatePencilState: this.guiParameterSettings.pencil.onChange,
|
|
117
|
+
updateEraserState: this.guiParameterSettings.eraser.onChange,
|
|
118
|
+
updateBrushAndEraserSize: this.guiParameterSettings.brushAndEraserSize.onChange,
|
|
119
|
+
updateSphereState: this.guiParameterSettings.sphere.onChange,
|
|
120
|
+
updateCalDistance: this.guiParameterSettings.activeSphereType.onChange,
|
|
121
|
+
updateWindowHigh: this.guiParameterSettings.windowHigh.onChange,
|
|
122
|
+
updateWindowLow: this.guiParameterSettings.windowLow.onChange,
|
|
123
|
+
finishContrastAdjustment: this.guiParameterSettings.windowHigh.onFinished,
|
|
124
|
+
};
|
|
108
125
|
}
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
126
|
+
/**
|
|
127
|
+
* Sync guiParameterSettings with current volume metadata.
|
|
128
|
+
* Called internally when slices are loaded or switched.
|
|
129
|
+
*/
|
|
130
|
+
syncGuiParameterSettings() {
|
|
131
|
+
if (this.guiParameterSettings && this.protectedData.mainPreSlices) {
|
|
112
132
|
this.guiParameterSettings.windowHigh.value = this.guiParameterSettings.windowLow.value = this.protectedData.mainPreSlices.volume;
|
|
113
133
|
this.guiParameterSettings.windowHigh.max = this.guiParameterSettings.windowLow.max = this.protectedData.mainPreSlices.volume.max;
|
|
114
134
|
this.guiParameterSettings.windowHigh.min = this.guiParameterSettings.windowLow.min = this.protectedData.mainPreSlices.volume.min;
|
|
115
135
|
}
|
|
116
|
-
return {
|
|
117
|
-
guiState: this.gui_states,
|
|
118
|
-
guiSetting: this.guiParameterSettings,
|
|
119
|
-
};
|
|
120
136
|
}
|
|
121
137
|
// ── Layer & Channel Management API ─────────────────────────────────────
|
|
122
138
|
/**
|
|
123
139
|
* Set the active layer and update fillColor/brushColor to match the active channel.
|
|
124
140
|
*/
|
|
125
141
|
setActiveLayer(layerId) {
|
|
126
|
-
this.gui_states.layer = layerId;
|
|
142
|
+
this.gui_states.layerChannel.layer = layerId;
|
|
127
143
|
this.syncBrushColor();
|
|
128
144
|
}
|
|
129
145
|
/**
|
|
130
146
|
* Set the active channel (1-8) and update fillColor/brushColor.
|
|
131
147
|
*/
|
|
132
148
|
setActiveChannel(channel) {
|
|
133
|
-
this.gui_states.activeChannel = channel;
|
|
149
|
+
this.gui_states.layerChannel.activeChannel = channel;
|
|
134
150
|
this.syncBrushColor();
|
|
135
151
|
}
|
|
152
|
+
/**
|
|
153
|
+
* Set the active sphere type for the SphereTool.
|
|
154
|
+
* Replaces direct mutation of `gui_states.activeSphereType`.
|
|
155
|
+
*
|
|
156
|
+
* @example
|
|
157
|
+
* ```ts
|
|
158
|
+
* nrrdTools.setActiveSphereType('nipple');
|
|
159
|
+
* ```
|
|
160
|
+
*/
|
|
161
|
+
setActiveSphereType(type) {
|
|
162
|
+
this.gui_states.mode.activeSphereType = type;
|
|
163
|
+
// Apply color side-effect: update fillColor/brushColor from sphere channel map
|
|
164
|
+
const mapping = SPHERE_CHANNEL_MAP[type];
|
|
165
|
+
if (mapping) {
|
|
166
|
+
const volume = this.getVolumeForLayer(mapping.layer);
|
|
167
|
+
const color = volume
|
|
168
|
+
? rgbaToHex(volume.getChannelColor(mapping.channel))
|
|
169
|
+
: (CHANNEL_HEX_COLORS[mapping.channel] || '#00ff00');
|
|
170
|
+
this.gui_states.drawing.fillColor = color;
|
|
171
|
+
this.gui_states.drawing.brushColor = color;
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
/**
|
|
175
|
+
* Get the currently active sphere type.
|
|
176
|
+
*/
|
|
177
|
+
getActiveSphereType() {
|
|
178
|
+
return this.gui_states.mode.activeSphereType;
|
|
179
|
+
}
|
|
180
|
+
// ── Phase 1: GUI API — Mode Management ──────────────────────────────────
|
|
181
|
+
/**
|
|
182
|
+
* Set the current tool mode. Handles deactivation of the previous mode
|
|
183
|
+
* and activation of the new mode, including all gui.ts side-effects.
|
|
184
|
+
*
|
|
185
|
+
* Replaces direct mutation of `guiSettings.value.guiState["pencil"]` etc.
|
|
186
|
+
* from Vue components.
|
|
187
|
+
*/
|
|
188
|
+
setMode(mode) {
|
|
189
|
+
if (!this.guiCallbacks)
|
|
190
|
+
return;
|
|
191
|
+
const prevSphere = this.gui_states.mode.sphere;
|
|
192
|
+
const prevCalculator = this._calculatorActive;
|
|
193
|
+
// Reset all mode flags
|
|
194
|
+
this.gui_states.mode.pencil = false;
|
|
195
|
+
this.gui_states.mode.eraser = false;
|
|
196
|
+
this.gui_states.mode.sphere = false;
|
|
197
|
+
this._calculatorActive = false;
|
|
198
|
+
// Activate new mode
|
|
199
|
+
switch (mode) {
|
|
200
|
+
case "pencil":
|
|
201
|
+
this.gui_states.mode.pencil = true;
|
|
202
|
+
this.guiCallbacks.updatePencilState();
|
|
203
|
+
break;
|
|
204
|
+
case "brush":
|
|
205
|
+
// brush = pencil off + eraser off (default brush mode)
|
|
206
|
+
this.guiCallbacks.updatePencilState();
|
|
207
|
+
break;
|
|
208
|
+
case "eraser":
|
|
209
|
+
this.gui_states.mode.eraser = true;
|
|
210
|
+
this.guiCallbacks.updateEraserState();
|
|
211
|
+
break;
|
|
212
|
+
case "sphere":
|
|
213
|
+
this.gui_states.mode.sphere = true;
|
|
214
|
+
break;
|
|
215
|
+
case "calculator":
|
|
216
|
+
this.gui_states.mode.sphere = true;
|
|
217
|
+
this._calculatorActive = true;
|
|
218
|
+
break;
|
|
219
|
+
}
|
|
220
|
+
// Handle sphere mode transitions
|
|
221
|
+
if (prevSphere && !this.gui_states.mode.sphere) {
|
|
222
|
+
this.guiCallbacks.updateSphereState(); // exits sphere mode
|
|
223
|
+
}
|
|
224
|
+
if (!prevSphere && this.gui_states.mode.sphere) {
|
|
225
|
+
this.guiCallbacks.updateSphereState(); // enters sphere mode
|
|
226
|
+
}
|
|
227
|
+
// Handle calculator exit side-effect
|
|
228
|
+
if (prevCalculator && !this._calculatorActive) {
|
|
229
|
+
// calculator was exited — sphere onChange already handled above
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
/**
|
|
233
|
+
* Get the current tool mode based on gui_states flags.
|
|
234
|
+
*/
|
|
235
|
+
getMode() {
|
|
236
|
+
if (this._calculatorActive)
|
|
237
|
+
return "calculator";
|
|
238
|
+
if (this.gui_states.mode.sphere)
|
|
239
|
+
return "sphere";
|
|
240
|
+
if (this.gui_states.mode.eraser)
|
|
241
|
+
return "eraser";
|
|
242
|
+
if (this.gui_states.mode.pencil)
|
|
243
|
+
return "pencil";
|
|
244
|
+
return "brush";
|
|
245
|
+
}
|
|
246
|
+
/**
|
|
247
|
+
* Check if calculator mode is active.
|
|
248
|
+
*/
|
|
249
|
+
isCalculatorActive() {
|
|
250
|
+
return this._calculatorActive;
|
|
251
|
+
}
|
|
252
|
+
// ── Phase 1: GUI API — Slider Methods ───────────────────────────────────
|
|
253
|
+
/**
|
|
254
|
+
* Set mask overlay opacity.
|
|
255
|
+
* @param value Opacity value [0.1, 1]
|
|
256
|
+
*/
|
|
257
|
+
setOpacity(value) {
|
|
258
|
+
this.gui_states.drawing.globalAlpha = Math.max(0.1, Math.min(1, value));
|
|
259
|
+
}
|
|
260
|
+
/**
|
|
261
|
+
* Get the current mask overlay opacity.
|
|
262
|
+
*/
|
|
263
|
+
getOpacity() {
|
|
264
|
+
return this.gui_states.drawing.globalAlpha;
|
|
265
|
+
}
|
|
266
|
+
/**
|
|
267
|
+
* Set brush and eraser size, and trigger cursor update.
|
|
268
|
+
* @param size Brush size [5, 50]
|
|
269
|
+
*/
|
|
270
|
+
setBrushSize(size) {
|
|
271
|
+
var _a;
|
|
272
|
+
this.gui_states.drawing.brushAndEraserSize = Math.max(5, Math.min(50, size));
|
|
273
|
+
(_a = this.guiCallbacks) === null || _a === void 0 ? void 0 : _a.updateBrushAndEraserSize();
|
|
274
|
+
}
|
|
275
|
+
/**
|
|
276
|
+
* Get the current brush/eraser size.
|
|
277
|
+
*/
|
|
278
|
+
getBrushSize() {
|
|
279
|
+
return this.gui_states.drawing.brushAndEraserSize;
|
|
280
|
+
}
|
|
281
|
+
/**
|
|
282
|
+
* Set window high (image contrast) value.
|
|
283
|
+
* Call finishWindowAdjustment() when the user finishes dragging.
|
|
284
|
+
*/
|
|
285
|
+
setWindowHigh(value) {
|
|
286
|
+
var _a;
|
|
287
|
+
this.gui_states.viewConfig.readyToUpdate = false;
|
|
288
|
+
(_a = this.guiCallbacks) === null || _a === void 0 ? void 0 : _a.updateWindowHigh(value);
|
|
289
|
+
}
|
|
290
|
+
/**
|
|
291
|
+
* Set window low (image center) value.
|
|
292
|
+
* Call finishWindowAdjustment() when the user finishes dragging.
|
|
293
|
+
*/
|
|
294
|
+
setWindowLow(value) {
|
|
295
|
+
var _a;
|
|
296
|
+
this.gui_states.viewConfig.readyToUpdate = false;
|
|
297
|
+
(_a = this.guiCallbacks) === null || _a === void 0 ? void 0 : _a.updateWindowLow(value);
|
|
298
|
+
}
|
|
299
|
+
/**
|
|
300
|
+
* Finish a window/contrast adjustment (repaint all contrast slices).
|
|
301
|
+
*/
|
|
302
|
+
finishWindowAdjustment() {
|
|
303
|
+
var _a;
|
|
304
|
+
(_a = this.guiCallbacks) === null || _a === void 0 ? void 0 : _a.finishContrastAdjustment();
|
|
305
|
+
}
|
|
306
|
+
/**
|
|
307
|
+
* Adjust contrast by delta, used for drag-based contrast adjustment.
|
|
308
|
+
* @param type "windowHigh" or "windowLow"
|
|
309
|
+
* @param delta Delta amount to adjust
|
|
310
|
+
*/
|
|
311
|
+
adjustContrast(type, delta) {
|
|
312
|
+
var _a, _b;
|
|
313
|
+
if (!this.guiParameterSettings)
|
|
314
|
+
return;
|
|
315
|
+
const setting = this.guiParameterSettings[type];
|
|
316
|
+
// setting.value is the volume object at runtime (typed as null in interface)
|
|
317
|
+
const vol = setting.value;
|
|
318
|
+
const currentValue = type === "windowHigh"
|
|
319
|
+
? ((_a = vol === null || vol === void 0 ? void 0 : vol.windowHigh) !== null && _a !== void 0 ? _a : 0)
|
|
320
|
+
: ((_b = vol === null || vol === void 0 ? void 0 : vol.windowLow) !== null && _b !== void 0 ? _b : 0);
|
|
321
|
+
const newValue = currentValue + delta;
|
|
322
|
+
if (newValue >= setting.max || newValue <= 0)
|
|
323
|
+
return;
|
|
324
|
+
if (type === "windowHigh") {
|
|
325
|
+
this.setWindowHigh(newValue);
|
|
326
|
+
}
|
|
327
|
+
else {
|
|
328
|
+
this.setWindowLow(newValue);
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
/**
|
|
332
|
+
* Get slider metadata for UI configuration.
|
|
333
|
+
* @param key Slider key: "globalAlpha", "brushAndEraserSize", "windowHigh", "windowLow"
|
|
334
|
+
* @returns IGuiMeta with min, max, step, and current value
|
|
335
|
+
*/
|
|
336
|
+
getSliderMeta(key) {
|
|
337
|
+
var _a, _b, _c, _d, _e, _f, _g, _h;
|
|
338
|
+
if (!this.guiParameterSettings)
|
|
339
|
+
return null;
|
|
340
|
+
const setting = this.guiParameterSettings[key];
|
|
341
|
+
if (!setting)
|
|
342
|
+
return null;
|
|
343
|
+
let value;
|
|
344
|
+
if (key === "windowHigh") {
|
|
345
|
+
value = (_b = (_a = setting.value) === null || _a === void 0 ? void 0 : _a.windowHigh) !== null && _b !== void 0 ? _b : 0;
|
|
346
|
+
}
|
|
347
|
+
else if (key === "windowLow") {
|
|
348
|
+
value = (_d = (_c = setting.value) === null || _c === void 0 ? void 0 : _c.windowLow) !== null && _d !== void 0 ? _d : 0;
|
|
349
|
+
}
|
|
350
|
+
else {
|
|
351
|
+
value = (_e = this.gui_states.drawing[key]) !== null && _e !== void 0 ? _e : 0;
|
|
352
|
+
}
|
|
353
|
+
return {
|
|
354
|
+
min: (_f = setting.min) !== null && _f !== void 0 ? _f : 0,
|
|
355
|
+
max: (_g = setting.max) !== null && _g !== void 0 ? _g : 100,
|
|
356
|
+
step: (_h = setting.step) !== null && _h !== void 0 ? _h : 1,
|
|
357
|
+
value,
|
|
358
|
+
};
|
|
359
|
+
}
|
|
360
|
+
// ── Phase 1: GUI API — Color & Action Methods ──────────────────────────
|
|
361
|
+
/**
|
|
362
|
+
* Set the pencil stroke color.
|
|
363
|
+
*/
|
|
364
|
+
setPencilColor(hex) {
|
|
365
|
+
this.gui_states.drawing.color = hex;
|
|
366
|
+
}
|
|
367
|
+
/**
|
|
368
|
+
* Get the current pencil stroke color.
|
|
369
|
+
*/
|
|
370
|
+
getPencilColor() {
|
|
371
|
+
return this.gui_states.drawing.color;
|
|
372
|
+
}
|
|
373
|
+
/**
|
|
374
|
+
* Execute a named UI action.
|
|
375
|
+
* @param action Action name
|
|
376
|
+
*
|
|
377
|
+
* Renamed from original gui_states methods:
|
|
378
|
+
* - "clearActiveSliceMask" (was "clear") — clear annotations on current slice
|
|
379
|
+
* - "clearActiveLayerMask" (was "clearAll") — clear annotations on all slices for active layer
|
|
380
|
+
*/
|
|
381
|
+
executeAction(action) {
|
|
382
|
+
switch (action) {
|
|
383
|
+
case "undo":
|
|
384
|
+
this.undo();
|
|
385
|
+
break;
|
|
386
|
+
case "redo":
|
|
387
|
+
this.redo();
|
|
388
|
+
break;
|
|
389
|
+
case "clearActiveSliceMask":
|
|
390
|
+
this.clearActiveSlice();
|
|
391
|
+
break;
|
|
392
|
+
case "clearActiveLayerMask": {
|
|
393
|
+
const text = "Are you sure remove annotations on All slice?";
|
|
394
|
+
if (confirm(text) === true) {
|
|
395
|
+
this.nrrd_states.flags.clearAllFlag = true;
|
|
396
|
+
this.clearActiveSlice();
|
|
397
|
+
this.clearActiveLayer();
|
|
398
|
+
}
|
|
399
|
+
this.nrrd_states.flags.clearAllFlag = false;
|
|
400
|
+
break;
|
|
401
|
+
}
|
|
402
|
+
case "resetZoom":
|
|
403
|
+
this.nrrd_states.view.sizeFactor = this.baseCanvasesSize;
|
|
404
|
+
this.gui_states.viewConfig.mainAreaSize = this.baseCanvasesSize;
|
|
405
|
+
this.resizePaintArea(this.nrrd_states.view.sizeFactor);
|
|
406
|
+
this.resetPaintAreaUIPosition();
|
|
407
|
+
break;
|
|
408
|
+
case "downloadCurrentMask": {
|
|
409
|
+
const config = {
|
|
410
|
+
axis: this.protectedData.axis,
|
|
411
|
+
currentSliceIndex: this.nrrd_states.view.currentSliceIndex,
|
|
412
|
+
drawingCanvas: this.protectedData.canvases.drawingCanvas,
|
|
413
|
+
originWidth: this.nrrd_states.image.originWidth,
|
|
414
|
+
originHeight: this.nrrd_states.image.originHeight,
|
|
415
|
+
};
|
|
416
|
+
enableDownload(config);
|
|
417
|
+
break;
|
|
418
|
+
}
|
|
419
|
+
}
|
|
420
|
+
}
|
|
136
421
|
/**
|
|
137
422
|
* Sync brush/fill color from the active layer's volume color map.
|
|
138
423
|
* Falls back to global CHANNEL_HEX_COLORS if volume not available.
|
|
139
424
|
*/
|
|
140
425
|
syncBrushColor() {
|
|
141
|
-
const channel = this.gui_states.activeChannel || 1;
|
|
142
|
-
const layer = this.gui_states.layer;
|
|
426
|
+
const channel = this.gui_states.layerChannel.activeChannel || 1;
|
|
427
|
+
const layer = this.gui_states.layerChannel.layer;
|
|
143
428
|
const volume = this.protectedData.maskData.volumes[layer];
|
|
144
429
|
if (volume) {
|
|
145
430
|
const hex = rgbaToHex(volume.getChannelColor(channel));
|
|
146
|
-
this.gui_states.fillColor = hex;
|
|
147
|
-
this.gui_states.brushColor = hex;
|
|
431
|
+
this.gui_states.drawing.fillColor = hex;
|
|
432
|
+
this.gui_states.drawing.brushColor = hex;
|
|
148
433
|
}
|
|
149
434
|
else {
|
|
150
435
|
const hex = CHANNEL_HEX_COLORS[channel] || '#00ff00';
|
|
151
|
-
this.gui_states.fillColor = hex;
|
|
152
|
-
this.gui_states.brushColor = hex;
|
|
436
|
+
this.gui_states.drawing.fillColor = hex;
|
|
437
|
+
this.gui_states.drawing.brushColor = hex;
|
|
153
438
|
}
|
|
154
439
|
}
|
|
155
440
|
/**
|
|
156
441
|
* Get the currently active layer id.
|
|
157
442
|
*/
|
|
158
443
|
getActiveLayer() {
|
|
159
|
-
return this.gui_states.layer;
|
|
444
|
+
return this.gui_states.layerChannel.layer;
|
|
160
445
|
}
|
|
161
446
|
/**
|
|
162
447
|
* Get the currently active channel value.
|
|
163
448
|
*/
|
|
164
449
|
getActiveChannel() {
|
|
165
|
-
return this.gui_states.activeChannel;
|
|
450
|
+
return this.gui_states.layerChannel.activeChannel;
|
|
166
451
|
}
|
|
167
452
|
/**
|
|
168
453
|
* Set visibility of a layer and re-render.
|
|
169
454
|
*/
|
|
170
455
|
setLayerVisible(layerId, visible) {
|
|
171
|
-
this.gui_states.layerVisibility[layerId] = visible;
|
|
456
|
+
this.gui_states.layerChannel.layerVisibility[layerId] = visible;
|
|
172
457
|
this.reloadMasksFromVolume();
|
|
173
458
|
}
|
|
174
459
|
/**
|
|
@@ -176,14 +461,14 @@ export class NrrdTools extends DrawToolCore {
|
|
|
176
461
|
*/
|
|
177
462
|
isLayerVisible(layerId) {
|
|
178
463
|
var _a;
|
|
179
|
-
return (_a = this.gui_states.layerVisibility[layerId]) !== null && _a !== void 0 ? _a : true;
|
|
464
|
+
return (_a = this.gui_states.layerChannel.layerVisibility[layerId]) !== null && _a !== void 0 ? _a : true;
|
|
180
465
|
}
|
|
181
466
|
/**
|
|
182
467
|
* Set visibility of a specific channel within a layer and re-render.
|
|
183
468
|
*/
|
|
184
469
|
setChannelVisible(layerId, channel, visible) {
|
|
185
|
-
if (this.gui_states.channelVisibility[layerId]) {
|
|
186
|
-
this.gui_states.channelVisibility[layerId][channel] = visible;
|
|
470
|
+
if (this.gui_states.layerChannel.channelVisibility[layerId]) {
|
|
471
|
+
this.gui_states.layerChannel.channelVisibility[layerId][channel] = visible;
|
|
187
472
|
}
|
|
188
473
|
this.reloadMasksFromVolume();
|
|
189
474
|
}
|
|
@@ -192,21 +477,21 @@ export class NrrdTools extends DrawToolCore {
|
|
|
192
477
|
*/
|
|
193
478
|
isChannelVisible(layerId, channel) {
|
|
194
479
|
var _a, _b;
|
|
195
|
-
return (_b = (_a = this.gui_states.channelVisibility[layerId]) === null || _a === void 0 ? void 0 : _a[channel]) !== null && _b !== void 0 ? _b : true;
|
|
480
|
+
return (_b = (_a = this.gui_states.layerChannel.channelVisibility[layerId]) === null || _a === void 0 ? void 0 : _a[channel]) !== null && _b !== void 0 ? _b : true;
|
|
196
481
|
}
|
|
197
482
|
/**
|
|
198
483
|
* Get the full layer visibility map.
|
|
199
484
|
*/
|
|
200
485
|
getLayerVisibility() {
|
|
201
|
-
return Object.assign({}, this.gui_states.layerVisibility);
|
|
486
|
+
return Object.assign({}, this.gui_states.layerChannel.layerVisibility);
|
|
202
487
|
}
|
|
203
488
|
/**
|
|
204
489
|
* Get the full channel visibility map.
|
|
205
490
|
*/
|
|
206
491
|
getChannelVisibility() {
|
|
207
492
|
const result = {};
|
|
208
|
-
for (const layerId of this.nrrd_states.layers) {
|
|
209
|
-
result[layerId] = Object.assign({}, this.gui_states.channelVisibility[layerId]);
|
|
493
|
+
for (const layerId of this.nrrd_states.image.layers) {
|
|
494
|
+
result[layerId] = Object.assign({}, this.gui_states.layerChannel.channelVisibility[layerId]);
|
|
210
495
|
}
|
|
211
496
|
return result;
|
|
212
497
|
}
|
|
@@ -255,11 +540,11 @@ export class NrrdTools extends DrawToolCore {
|
|
|
255
540
|
return;
|
|
256
541
|
}
|
|
257
542
|
volume.setChannelColor(channel, color);
|
|
258
|
-
if (layerId === this.gui_states.layer && channel === this.gui_states.activeChannel) {
|
|
543
|
+
if (layerId === this.gui_states.layerChannel.layer && channel === this.gui_states.layerChannel.activeChannel) {
|
|
259
544
|
this.syncBrushColor();
|
|
260
545
|
}
|
|
261
546
|
this.reloadMasksFromVolume();
|
|
262
|
-
this.
|
|
547
|
+
this.annotationCallbacks.onChannelColorChanged(layerId, channel, color);
|
|
263
548
|
}
|
|
264
549
|
/**
|
|
265
550
|
* Get the current color for a specific channel in a specific layer.
|
|
@@ -310,7 +595,7 @@ export class NrrdTools extends DrawToolCore {
|
|
|
310
595
|
for (const [ch, color] of Object.entries(colorMap)) {
|
|
311
596
|
volume.setChannelColor(Number(ch), color);
|
|
312
597
|
}
|
|
313
|
-
if (layerId === this.gui_states.layer) {
|
|
598
|
+
if (layerId === this.gui_states.layerChannel.layer) {
|
|
314
599
|
this.syncBrushColor();
|
|
315
600
|
}
|
|
316
601
|
this.reloadMasksFromVolume();
|
|
@@ -322,13 +607,13 @@ export class NrrdTools extends DrawToolCore {
|
|
|
322
607
|
* @param color RGBAColor object
|
|
323
608
|
*/
|
|
324
609
|
setAllLayersChannelColor(channel, color) {
|
|
325
|
-
for (const layerId of this.nrrd_states.layers) {
|
|
610
|
+
for (const layerId of this.nrrd_states.image.layers) {
|
|
326
611
|
const volume = this.protectedData.maskData.volumes[layerId];
|
|
327
612
|
if (volume) {
|
|
328
613
|
volume.setChannelColor(channel, color);
|
|
329
614
|
}
|
|
330
615
|
}
|
|
331
|
-
if (channel === this.gui_states.activeChannel) {
|
|
616
|
+
if (channel === this.gui_states.layerChannel.activeChannel) {
|
|
332
617
|
this.syncBrushColor();
|
|
333
618
|
}
|
|
334
619
|
this.reloadMasksFromVolume();
|
|
@@ -347,7 +632,7 @@ export class NrrdTools extends DrawToolCore {
|
|
|
347
632
|
* ```
|
|
348
633
|
*/
|
|
349
634
|
resetChannelColors(layerId, channel) {
|
|
350
|
-
const layers = layerId ? [layerId] : this.nrrd_states.layers;
|
|
635
|
+
const layers = layerId ? [layerId] : this.nrrd_states.image.layers;
|
|
351
636
|
for (const lid of layers) {
|
|
352
637
|
const volume = this.protectedData.maskData.volumes[lid];
|
|
353
638
|
if (volume) {
|
|
@@ -522,28 +807,39 @@ export class NrrdTools extends DrawToolCore {
|
|
|
522
807
|
setAllSlices(allSlices) {
|
|
523
808
|
this.protectedData.allSlicesArray = [...allSlices];
|
|
524
809
|
const randomSlice = this.protectedData.allSlicesArray[0];
|
|
525
|
-
this.nrrd_states.nrrd_x_mm = randomSlice.z.canvas.width;
|
|
526
|
-
this.nrrd_states.nrrd_y_mm = randomSlice.z.canvas.height;
|
|
527
|
-
this.nrrd_states.nrrd_z_mm = randomSlice.x.canvas.width;
|
|
528
|
-
this.nrrd_states.nrrd_x_pixel = randomSlice.x.volume.dimensions[0];
|
|
529
|
-
this.nrrd_states.nrrd_y_pixel = randomSlice.x.volume.dimensions[1];
|
|
530
|
-
this.nrrd_states.nrrd_z_pixel = randomSlice.x.volume.dimensions[2];
|
|
531
|
-
this.nrrd_states.voxelSpacing = randomSlice.x.volume.spacing;
|
|
532
|
-
this.nrrd_states.ratios.x = randomSlice.x.volume.spacing[0];
|
|
533
|
-
this.nrrd_states.ratios.y = randomSlice.x.volume.spacing[1];
|
|
534
|
-
this.nrrd_states.ratios.z = randomSlice.x.volume.spacing[2];
|
|
535
|
-
this.nrrd_states.dimensions = randomSlice.x.volume.dimensions;
|
|
810
|
+
this.nrrd_states.image.nrrd_x_mm = randomSlice.z.canvas.width;
|
|
811
|
+
this.nrrd_states.image.nrrd_y_mm = randomSlice.z.canvas.height;
|
|
812
|
+
this.nrrd_states.image.nrrd_z_mm = randomSlice.x.canvas.width;
|
|
813
|
+
this.nrrd_states.image.nrrd_x_pixel = randomSlice.x.volume.dimensions[0];
|
|
814
|
+
this.nrrd_states.image.nrrd_y_pixel = randomSlice.x.volume.dimensions[1];
|
|
815
|
+
this.nrrd_states.image.nrrd_z_pixel = randomSlice.x.volume.dimensions[2];
|
|
816
|
+
this.nrrd_states.image.voxelSpacing = randomSlice.x.volume.spacing;
|
|
817
|
+
this.nrrd_states.image.ratios.x = randomSlice.x.volume.spacing[0];
|
|
818
|
+
this.nrrd_states.image.ratios.y = randomSlice.x.volume.spacing[1];
|
|
819
|
+
this.nrrd_states.image.ratios.z = randomSlice.x.volume.spacing[2];
|
|
820
|
+
this.nrrd_states.image.dimensions = randomSlice.x.volume.dimensions;
|
|
536
821
|
// Phase 2 Day 9: Re-initialize MaskVolume with real NRRD dimensions.
|
|
537
822
|
// This replaces the 1×1×1 placeholders from CommToolsData constructor
|
|
538
823
|
// and "turns on" all Day 7/8 volume read/write paths.
|
|
539
824
|
// Invalidate reusable buffer from previous dataset
|
|
540
825
|
this.invalidateSliceBuffer();
|
|
541
|
-
const [vw, vh, vd] = this.nrrd_states.dimensions;
|
|
542
|
-
this.protectedData.maskData.volumes = this.nrrd_states.layers.reduce((acc, id) => {
|
|
826
|
+
const [vw, vh, vd] = this.nrrd_states.image.dimensions;
|
|
827
|
+
this.protectedData.maskData.volumes = this.nrrd_states.image.layers.reduce((acc, id) => {
|
|
543
828
|
acc[id] = new MaskVolume(vw, vh, vd, 1);
|
|
544
829
|
return acc;
|
|
545
830
|
}, {});
|
|
546
|
-
|
|
831
|
+
// Create dedicated SphereMaskVolume for 3D sphere data.
|
|
832
|
+
// Separate from layer volumes to avoid polluting draw mask data.
|
|
833
|
+
// Cleared in reset() when switching cases.
|
|
834
|
+
this.nrrd_states.sphere.sphereMaskVolume = new MaskVolume(vw, vh, vd, 1);
|
|
835
|
+
// Derive sphere label colors from SPHERE_CHANNEL_MAP → MASK_CHANNEL_COLORS
|
|
836
|
+
// so that volume rendering matches the preview circle colors.
|
|
837
|
+
for (const [type, { channel }] of Object.entries(SPHERE_CHANNEL_MAP)) {
|
|
838
|
+
const label = SPHERE_LABELS[type];
|
|
839
|
+
const c = MASK_CHANNEL_COLORS[channel];
|
|
840
|
+
this.nrrd_states.sphere.sphereMaskVolume.setChannelColor(label, { r: c.r, g: c.g, b: c.b, a: c.a });
|
|
841
|
+
}
|
|
842
|
+
this.nrrd_states.image.spaceOrigin = randomSlice.x.volume.header.space_origin.map((item) => {
|
|
547
843
|
return item * 1;
|
|
548
844
|
});
|
|
549
845
|
this.protectedData.allSlicesArray.forEach((item, index) => {
|
|
@@ -552,13 +848,13 @@ export class NrrdTools extends DrawToolCore {
|
|
|
552
848
|
item.z.contrastOrder = index;
|
|
553
849
|
});
|
|
554
850
|
// Phase 3: initPaintImages removed (MaskVolume initialized separately)
|
|
555
|
-
// this.initPaintImages(this.nrrd_states.dimensions);
|
|
851
|
+
// this.initPaintImages(this.nrrd_states.image.dimensions);
|
|
556
852
|
// init displayslices array, the axis default is "z"
|
|
557
853
|
this.setDisplaySlicesBaseOnAxis();
|
|
558
854
|
this.afterLoadSlice();
|
|
559
855
|
}
|
|
560
856
|
loadingMaskByLayer(masks, index, imageData) {
|
|
561
|
-
let imageDataLable = this.protectedData.ctxes.emptyCtx.createImageData(this.nrrd_states.nrrd_x_pixel, this.nrrd_states.nrrd_y_pixel);
|
|
857
|
+
let imageDataLable = this.protectedData.ctxes.emptyCtx.createImageData(this.nrrd_states.image.nrrd_x_pixel, this.nrrd_states.image.nrrd_y_pixel);
|
|
562
858
|
this.setEmptyCanvasSize();
|
|
563
859
|
for (let j = 0; j < masks[index].data.length; j++) {
|
|
564
860
|
imageDataLable.data[j] = masks[index].data[j];
|
|
@@ -569,7 +865,7 @@ export class NrrdTools extends DrawToolCore {
|
|
|
569
865
|
// need to remove
|
|
570
866
|
setMasksData(masksData, loadingBar) {
|
|
571
867
|
if (!!masksData) {
|
|
572
|
-
this.nrrd_states.
|
|
868
|
+
this.nrrd_states.flags.loadingMaskData = true;
|
|
573
869
|
if (loadingBar) {
|
|
574
870
|
let { loadingContainer, progress } = loadingBar;
|
|
575
871
|
loadingContainer.style.display = "flex";
|
|
@@ -578,32 +874,22 @@ export class NrrdTools extends DrawToolCore {
|
|
|
578
874
|
this.setEmptyCanvasSize();
|
|
579
875
|
const len = masksData["layer1"].length;
|
|
580
876
|
for (let i = 0; i < len; i++) {
|
|
581
|
-
let imageData = this.protectedData.ctxes.emptyCtx.createImageData(this.nrrd_states.nrrd_x_pixel, this.nrrd_states.nrrd_y_pixel);
|
|
582
|
-
let imageDataLayer1, imageDataLayer2, imageDataLayer3;
|
|
877
|
+
let imageData = this.protectedData.ctxes.emptyCtx.createImageData(this.nrrd_states.image.nrrd_x_pixel, this.nrrd_states.image.nrrd_y_pixel);
|
|
583
878
|
if (masksData["layer1"][i].data.length > 0) {
|
|
584
|
-
this.
|
|
585
|
-
imageDataLayer1 = this.loadingMaskByLayer(masksData["layer1"], i, imageData);
|
|
586
|
-
this.protectedData.ctxes.emptyCtx.putImageData(imageDataLayer1, 0, 0);
|
|
587
|
-
this.storeEachLayerImage(i, "layer1");
|
|
879
|
+
this.loadingMaskByLayer(masksData["layer1"], i, imageData);
|
|
588
880
|
}
|
|
589
881
|
if (masksData["layer2"][i].data.length > 0) {
|
|
590
|
-
this.
|
|
591
|
-
imageDataLayer2 = this.loadingMaskByLayer(masksData["layer2"], i, imageData);
|
|
592
|
-
this.protectedData.ctxes.emptyCtx.putImageData(imageDataLayer2, 0, 0);
|
|
593
|
-
this.storeEachLayerImage(i, "layer2");
|
|
882
|
+
this.loadingMaskByLayer(masksData["layer2"], i, imageData);
|
|
594
883
|
}
|
|
595
884
|
if (masksData["layer3"][i].data.length > 0) {
|
|
596
|
-
this.
|
|
597
|
-
imageDataLayer3 = this.loadingMaskByLayer(masksData["layer3"], i, imageData);
|
|
598
|
-
this.protectedData.ctxes.emptyCtx.putImageData(imageDataLayer3, 0, 0);
|
|
599
|
-
this.storeEachLayerImage(i, "layer3");
|
|
885
|
+
this.loadingMaskByLayer(masksData["layer3"], i, imageData);
|
|
600
886
|
}
|
|
601
887
|
this.setEmptyCanvasSize();
|
|
602
888
|
this.protectedData.ctxes.emptyCtx.putImageData(imageData, 0, 0);
|
|
603
|
-
this.
|
|
889
|
+
this.syncLayerSliceData(i, "default");
|
|
604
890
|
}
|
|
605
|
-
this.nrrd_states.
|
|
606
|
-
this.
|
|
891
|
+
this.nrrd_states.flags.loadingMaskData = false;
|
|
892
|
+
this.executeAction("resetZoom");
|
|
607
893
|
if (loadingBar) {
|
|
608
894
|
loadingBar.loadingContainer.style.display = "none";
|
|
609
895
|
}
|
|
@@ -645,7 +931,7 @@ export class NrrdTools extends DrawToolCore {
|
|
|
645
931
|
}
|
|
646
932
|
// Reload the current slice from MaskVolume to canvas
|
|
647
933
|
this.reloadMasksFromVolume();
|
|
648
|
-
this.
|
|
934
|
+
this.executeAction("resetZoom");
|
|
649
935
|
}
|
|
650
936
|
catch (error) {
|
|
651
937
|
console.error("Error loading NIfTI masks:", error);
|
|
@@ -657,56 +943,95 @@ export class NrrdTools extends DrawToolCore {
|
|
|
657
943
|
}
|
|
658
944
|
}
|
|
659
945
|
setShowInMainArea() {
|
|
660
|
-
this.nrrd_states.showContrast = true;
|
|
946
|
+
this.nrrd_states.view.showContrast = true;
|
|
661
947
|
}
|
|
662
948
|
getCurrentImageDimension() {
|
|
663
|
-
return this.nrrd_states.dimensions;
|
|
949
|
+
return this.nrrd_states.image.dimensions;
|
|
664
950
|
}
|
|
665
951
|
getVoxelSpacing() {
|
|
666
|
-
return this.nrrd_states.voxelSpacing;
|
|
952
|
+
return this.nrrd_states.image.voxelSpacing;
|
|
667
953
|
}
|
|
668
954
|
getSpaceOrigin() {
|
|
669
|
-
return this.nrrd_states.spaceOrigin;
|
|
955
|
+
return this.nrrd_states.image.spaceOrigin;
|
|
670
956
|
}
|
|
671
957
|
getMaskData() {
|
|
672
958
|
return this.protectedData.maskData;
|
|
673
959
|
}
|
|
674
|
-
|
|
960
|
+
/**
|
|
961
|
+
* Programmatically place a calculator sphere at the given position.
|
|
962
|
+
*
|
|
963
|
+
* Replicates the full mouse-down → mouse-up flow (handleSphereClick + pointerup)
|
|
964
|
+
* so that backend-supplied sphere data is stored identically to a manual click.
|
|
965
|
+
*
|
|
966
|
+
* @param x - X coordinate in unscaled (original) image space
|
|
967
|
+
* @param y - Y coordinate in unscaled (original) image space
|
|
968
|
+
* @param sliceIndex - Target slice index (z-axis)
|
|
969
|
+
* @param cal_position - Sphere type to place
|
|
970
|
+
*/
|
|
675
971
|
setCalculateDistanceSphere(x, y, sliceIndex, cal_position) {
|
|
676
|
-
this.nrrd_states.sphereRadius = 5;
|
|
677
|
-
// move to
|
|
678
|
-
const steps = sliceIndex - this.nrrd_states.
|
|
972
|
+
this.nrrd_states.sphere.sphereRadius = 5;
|
|
973
|
+
// move to target slice
|
|
974
|
+
const steps = sliceIndex - this.nrrd_states.view.currentSliceIndex;
|
|
679
975
|
this.setSliceMoving(steps * this.protectedData.displaySlices.length);
|
|
680
|
-
//
|
|
681
|
-
// if user
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
976
|
+
// --- simulate mouse-down (mirrors DrawToolCore.handleSphereClick) ---
|
|
977
|
+
// if user has zoomed the panel, we need to consider the size factor
|
|
978
|
+
const mouseX = x * this.nrrd_states.view.sizeFactor;
|
|
979
|
+
const mouseY = y * this.nrrd_states.view.sizeFactor;
|
|
980
|
+
// 1. record origin on current axis
|
|
981
|
+
this.nrrd_states.sphere.sphereOrigin[this.protectedData.axis] = [
|
|
982
|
+
mouseX, mouseY, sliceIndex,
|
|
983
|
+
];
|
|
984
|
+
// compute origins for all 3 axes (crosshairTool is protected)
|
|
985
|
+
this.crosshairTool.setUpSphereOrigins(mouseX, mouseY, sliceIndex);
|
|
986
|
+
// 2. store a deep copy of the origin for the specific sphere type
|
|
987
|
+
const originCopy = JSON.parse(JSON.stringify(this.nrrd_states.sphere.sphereOrigin));
|
|
988
|
+
switch (cal_position) {
|
|
989
|
+
case "tumour":
|
|
990
|
+
this.nrrd_states.sphere.tumourSphereOrigin = originCopy;
|
|
991
|
+
break;
|
|
992
|
+
case "skin":
|
|
993
|
+
this.nrrd_states.sphere.skinSphereOrigin = originCopy;
|
|
994
|
+
break;
|
|
995
|
+
case "nipple":
|
|
996
|
+
this.nrrd_states.sphere.nippleSphereOrigin = originCopy;
|
|
997
|
+
break;
|
|
998
|
+
case "ribcage":
|
|
999
|
+
this.nrrd_states.sphere.ribSphereOrigin = originCopy;
|
|
1000
|
+
break;
|
|
1001
|
+
}
|
|
1002
|
+
// 3. draw sphere preview on canvas
|
|
1003
|
+
this.drawCalculatorSphere(this.nrrd_states.sphere.sphereRadius);
|
|
1004
|
+
// --- simulate mouse-up ---
|
|
1005
|
+
// 4. write all placed calculator spheres into sphereMaskVolume
|
|
1006
|
+
this.sphereTool.writeAllCalculatorSpheresToVolume();
|
|
1007
|
+
// 5. re-render sphere overlay from volume
|
|
1008
|
+
this.sphereTool.refreshSphereCanvas();
|
|
685
1009
|
}
|
|
686
1010
|
/**
|
|
687
1011
|
* Switch all contrast slices' orientation
|
|
688
1012
|
* @param {string} aixs:"x" | "y" | "z"
|
|
689
1013
|
* */
|
|
690
1014
|
setSliceOrientation(axisTo) {
|
|
1015
|
+
var _a;
|
|
691
1016
|
let convetObj;
|
|
692
|
-
if (this.
|
|
1017
|
+
if (((_a = this.eventRouter) === null || _a === void 0 ? void 0 : _a.isCrosshairEnabled()) || this.gui_states.mode.sphere) {
|
|
693
1018
|
if (this.protectedData.axis === "z") {
|
|
694
|
-
this.cursorPage.z.index = this.nrrd_states.
|
|
695
|
-
this.cursorPage.z.cursorPageX = this.nrrd_states.cursorPageX;
|
|
696
|
-
this.cursorPage.z.cursorPageY = this.nrrd_states.cursorPageY;
|
|
1019
|
+
this.cursorPage.z.index = this.nrrd_states.view.currentSliceIndex;
|
|
1020
|
+
this.cursorPage.z.cursorPageX = this.nrrd_states.interaction.cursorPageX;
|
|
1021
|
+
this.cursorPage.z.cursorPageY = this.nrrd_states.interaction.cursorPageY;
|
|
697
1022
|
}
|
|
698
1023
|
else if (this.protectedData.axis === "x") {
|
|
699
|
-
this.cursorPage.x.index = this.nrrd_states.
|
|
700
|
-
this.cursorPage.x.cursorPageX = this.nrrd_states.cursorPageX;
|
|
701
|
-
this.cursorPage.x.cursorPageY = this.nrrd_states.cursorPageY;
|
|
1024
|
+
this.cursorPage.x.index = this.nrrd_states.view.currentSliceIndex;
|
|
1025
|
+
this.cursorPage.x.cursorPageX = this.nrrd_states.interaction.cursorPageX;
|
|
1026
|
+
this.cursorPage.x.cursorPageY = this.nrrd_states.interaction.cursorPageY;
|
|
702
1027
|
}
|
|
703
1028
|
else if (this.protectedData.axis === "y") {
|
|
704
|
-
this.cursorPage.y.index = this.nrrd_states.
|
|
705
|
-
this.cursorPage.y.cursorPageX = this.nrrd_states.cursorPageX;
|
|
706
|
-
this.cursorPage.y.cursorPageY = this.nrrd_states.cursorPageY;
|
|
1029
|
+
this.cursorPage.y.index = this.nrrd_states.view.currentSliceIndex;
|
|
1030
|
+
this.cursorPage.y.cursorPageX = this.nrrd_states.interaction.cursorPageX;
|
|
1031
|
+
this.cursorPage.y.cursorPageY = this.nrrd_states.interaction.cursorPageY;
|
|
707
1032
|
}
|
|
708
1033
|
if (axisTo === "z") {
|
|
709
|
-
if (this.nrrd_states.isCursorSelect && !this.cursorPage.z.updated) {
|
|
1034
|
+
if (this.nrrd_states.interaction.isCursorSelect && !this.cursorPage.z.updated) {
|
|
710
1035
|
if (this.protectedData.axis === "x") {
|
|
711
1036
|
// convert x to z
|
|
712
1037
|
convetObj = this.convertCursorPoint("x", "z", this.cursorPage.x.cursorPageX, this.cursorPage.x.cursorPageY, this.cursorPage.x.index);
|
|
@@ -718,15 +1043,15 @@ export class NrrdTools extends DrawToolCore {
|
|
|
718
1043
|
}
|
|
719
1044
|
else {
|
|
720
1045
|
// not cursor select, freedom to switch x -> z or y -> z and z -> x or z -> y
|
|
721
|
-
this.nrrd_states.
|
|
722
|
-
this.nrrd_states.
|
|
723
|
-
this.cursorPage.z.index * this.nrrd_states.ratios.z;
|
|
724
|
-
this.nrrd_states.cursorPageX = this.cursorPage.z.cursorPageX;
|
|
725
|
-
this.nrrd_states.cursorPageY = this.cursorPage.z.cursorPageY;
|
|
1046
|
+
this.nrrd_states.view.currentSliceIndex = this.cursorPage.z.index;
|
|
1047
|
+
this.nrrd_states.view.preSliceIndex =
|
|
1048
|
+
this.cursorPage.z.index * this.nrrd_states.image.ratios.z;
|
|
1049
|
+
this.nrrd_states.interaction.cursorPageX = this.cursorPage.z.cursorPageX;
|
|
1050
|
+
this.nrrd_states.interaction.cursorPageY = this.cursorPage.z.cursorPageY;
|
|
726
1051
|
}
|
|
727
1052
|
}
|
|
728
1053
|
else if (axisTo === "x") {
|
|
729
|
-
if (this.nrrd_states.isCursorSelect && !this.cursorPage.x.updated) {
|
|
1054
|
+
if (this.nrrd_states.interaction.isCursorSelect && !this.cursorPage.x.updated) {
|
|
730
1055
|
if (this.protectedData.axis === "z") {
|
|
731
1056
|
// convert z to x
|
|
732
1057
|
convetObj = this.convertCursorPoint("z", "x", this.cursorPage.z.cursorPageX, this.cursorPage.z.cursorPageY, this.cursorPage.z.index);
|
|
@@ -738,15 +1063,15 @@ export class NrrdTools extends DrawToolCore {
|
|
|
738
1063
|
}
|
|
739
1064
|
else {
|
|
740
1065
|
// not cursor select, freedom to switch z -> x or y -> x and x -> z or x -> y
|
|
741
|
-
this.nrrd_states.
|
|
742
|
-
this.nrrd_states.
|
|
743
|
-
this.cursorPage.x.index * this.nrrd_states.ratios.x;
|
|
744
|
-
this.nrrd_states.cursorPageX = this.cursorPage.x.cursorPageX;
|
|
745
|
-
this.nrrd_states.cursorPageY = this.cursorPage.x.cursorPageY;
|
|
1066
|
+
this.nrrd_states.view.currentSliceIndex = this.cursorPage.x.index;
|
|
1067
|
+
this.nrrd_states.view.preSliceIndex =
|
|
1068
|
+
this.cursorPage.x.index * this.nrrd_states.image.ratios.x;
|
|
1069
|
+
this.nrrd_states.interaction.cursorPageX = this.cursorPage.x.cursorPageX;
|
|
1070
|
+
this.nrrd_states.interaction.cursorPageY = this.cursorPage.x.cursorPageY;
|
|
746
1071
|
}
|
|
747
1072
|
}
|
|
748
1073
|
else if (axisTo === "y") {
|
|
749
|
-
if (this.nrrd_states.isCursorSelect && !this.cursorPage.y.updated) {
|
|
1074
|
+
if (this.nrrd_states.interaction.isCursorSelect && !this.cursorPage.y.updated) {
|
|
750
1075
|
if (this.protectedData.axis === "z") {
|
|
751
1076
|
// convert z to y
|
|
752
1077
|
convetObj = this.convertCursorPoint("z", "y", this.cursorPage.z.cursorPageX, this.cursorPage.z.cursorPageY, this.cursorPage.z.index);
|
|
@@ -758,19 +1083,19 @@ export class NrrdTools extends DrawToolCore {
|
|
|
758
1083
|
}
|
|
759
1084
|
else {
|
|
760
1085
|
// not cursor select, freedom to switch z -> y or x -> y and y -> z or y -> x
|
|
761
|
-
this.nrrd_states.
|
|
762
|
-
this.nrrd_states.
|
|
763
|
-
this.cursorPage.y.index * this.nrrd_states.ratios.y;
|
|
764
|
-
this.nrrd_states.cursorPageX = this.cursorPage.y.cursorPageX;
|
|
765
|
-
this.nrrd_states.cursorPageY = this.cursorPage.y.cursorPageY;
|
|
1086
|
+
this.nrrd_states.view.currentSliceIndex = this.cursorPage.y.index;
|
|
1087
|
+
this.nrrd_states.view.preSliceIndex =
|
|
1088
|
+
this.cursorPage.y.index * this.nrrd_states.image.ratios.y;
|
|
1089
|
+
this.nrrd_states.interaction.cursorPageX = this.cursorPage.y.cursorPageX;
|
|
1090
|
+
this.nrrd_states.interaction.cursorPageY = this.cursorPage.y.cursorPageY;
|
|
766
1091
|
}
|
|
767
1092
|
}
|
|
768
1093
|
if (convetObj) {
|
|
769
1094
|
// update convert cursor point, when cursor select
|
|
770
|
-
this.nrrd_states.
|
|
771
|
-
this.nrrd_states.
|
|
772
|
-
this.nrrd_states.cursorPageX = convetObj.convertCursorNumX;
|
|
773
|
-
this.nrrd_states.cursorPageY = convetObj.convertCursorNumY;
|
|
1095
|
+
this.nrrd_states.view.currentSliceIndex = convetObj.currentNewSliceIndex;
|
|
1096
|
+
this.nrrd_states.view.preSliceIndex = convetObj.preSliceIndex;
|
|
1097
|
+
this.nrrd_states.interaction.cursorPageX = convetObj.convertCursorNumX;
|
|
1098
|
+
this.nrrd_states.interaction.cursorPageY = convetObj.convertCursorNumY;
|
|
774
1099
|
convetObj = undefined;
|
|
775
1100
|
switch (axisTo) {
|
|
776
1101
|
case "x":
|
|
@@ -788,47 +1113,52 @@ export class NrrdTools extends DrawToolCore {
|
|
|
788
1113
|
this.cursorPage.y.updated &&
|
|
789
1114
|
this.cursorPage.z.updated) {
|
|
790
1115
|
// one point convert to all axis, reset all updated status
|
|
791
|
-
this.nrrd_states.isCursorSelect = false;
|
|
1116
|
+
this.nrrd_states.interaction.isCursorSelect = false;
|
|
792
1117
|
}
|
|
793
1118
|
}
|
|
794
1119
|
this.protectedData.axis = axisTo;
|
|
795
1120
|
this.resetDisplaySlicesStatus();
|
|
796
|
-
// for sphere plan a
|
|
797
|
-
if (this.gui_states.sphere && !this.nrrd_states.spherePlanB) {
|
|
798
|
-
this.drawSphere(this.nrrd_states.sphereOrigin[axisTo][0] * this.nrrd_states.sizeFoctor, this.nrrd_states.sphereOrigin[axisTo][1] * this.nrrd_states.sizeFoctor, this.nrrd_states.sphereRadius);
|
|
799
|
-
}
|
|
800
1121
|
}
|
|
801
1122
|
addSkip(index) {
|
|
802
1123
|
this.protectedData.skipSlicesDic[index] =
|
|
803
1124
|
this.protectedData.backUpDisplaySlices[index];
|
|
804
1125
|
if (index >= this.protectedData.displaySlices.length) {
|
|
805
|
-
this.nrrd_states.contrastNum = this.protectedData.displaySlices.length;
|
|
1126
|
+
this.nrrd_states.view.contrastNum = this.protectedData.displaySlices.length;
|
|
806
1127
|
}
|
|
807
1128
|
else {
|
|
808
|
-
this.nrrd_states.contrastNum = index;
|
|
1129
|
+
this.nrrd_states.view.contrastNum = index;
|
|
809
1130
|
}
|
|
810
1131
|
this.resetDisplaySlicesStatus();
|
|
811
1132
|
}
|
|
812
1133
|
removeSkip(index) {
|
|
813
1134
|
this.protectedData.skipSlicesDic[index] = undefined;
|
|
814
|
-
this.nrrd_states.contrastNum = 0;
|
|
1135
|
+
this.nrrd_states.view.contrastNum = 0;
|
|
815
1136
|
this.resetDisplaySlicesStatus();
|
|
816
1137
|
}
|
|
817
|
-
|
|
1138
|
+
/**
|
|
1139
|
+
* Reset the entire NrrdTools instance comprehensively.
|
|
1140
|
+
* This clears ALL data across ALL layers globally, resets the Canvas visuals,
|
|
1141
|
+
* undo/redo history, volume models, index parameters, and sphere overlays.
|
|
1142
|
+
* Primarily used when switching cases/datasets or when a completely fresh state is needed.
|
|
1143
|
+
* It is heavier than `clearActiveLayer` or `clearActiveSlice`.
|
|
1144
|
+
*/
|
|
1145
|
+
reset() {
|
|
818
1146
|
// To effectively reduce the js memory garbage
|
|
819
1147
|
this.protectedData.allSlicesArray.length = 0;
|
|
820
1148
|
this.protectedData.displaySlices.length = 0;
|
|
821
1149
|
// Phase 6: Clear all undo/redo stacks
|
|
822
1150
|
this.undoManager.clearAll();
|
|
823
1151
|
// Phase 3: Reset MaskVolume storage to 1×1×1 placeholders
|
|
824
|
-
this.protectedData.maskData.volumes = this.nrrd_states.layers.reduce((acc, id) => {
|
|
1152
|
+
this.protectedData.maskData.volumes = this.nrrd_states.image.layers.reduce((acc, id) => {
|
|
825
1153
|
acc[id] = new MaskVolume(1, 1, 1, 1);
|
|
826
1154
|
return acc;
|
|
827
1155
|
}, {});
|
|
1156
|
+
// Clear dedicated SphereMaskVolume
|
|
1157
|
+
this.nrrd_states.sphere.sphereMaskVolume = null;
|
|
828
1158
|
// Invalidate reusable slice buffer
|
|
829
1159
|
this.invalidateSliceBuffer();
|
|
830
1160
|
this.clearDictionary(this.protectedData.skipSlicesDic);
|
|
831
|
-
// this.nrrd_states.previousPanelL = this.nrrd_states.previousPanelT = -99999;
|
|
1161
|
+
// this.nrrd_states.view.previousPanelL = this.nrrd_states.view.previousPanelT = -99999;
|
|
832
1162
|
this.protectedData.canvases.displayCanvas.style.left =
|
|
833
1163
|
this.protectedData.canvases.drawingCanvas.style.left = "";
|
|
834
1164
|
this.protectedData.canvases.displayCanvas.style.top =
|
|
@@ -836,21 +1166,19 @@ export class NrrdTools extends DrawToolCore {
|
|
|
836
1166
|
this.protectedData.backUpDisplaySlices.length = 0;
|
|
837
1167
|
this.protectedData.mainPreSlices = undefined;
|
|
838
1168
|
this.protectedData.currentShowingSlice = undefined;
|
|
839
|
-
this.protectedData.previousDrawingImage =
|
|
840
|
-
this.protectedData.ctxes.emptyCtx.createImageData(1, 1);
|
|
841
1169
|
this.initState = true;
|
|
842
1170
|
this.protectedData.axis = "z";
|
|
843
|
-
this.nrrd_states.
|
|
844
|
-
this.gui_states.mainAreaSize = this.baseCanvasesSize;
|
|
1171
|
+
this.nrrd_states.view.sizeFactor = this.baseCanvasesSize;
|
|
1172
|
+
this.gui_states.viewConfig.mainAreaSize = this.baseCanvasesSize;
|
|
845
1173
|
this.resetLayerCanvas();
|
|
846
1174
|
this.protectedData.canvases.drawingCanvas.width =
|
|
847
1175
|
this.protectedData.canvases.drawingCanvas.width;
|
|
848
1176
|
this.protectedData.canvases.displayCanvas.width =
|
|
849
1177
|
this.protectedData.canvases.displayCanvas.width;
|
|
850
|
-
this.nrrd_states.tumourSphereOrigin = null;
|
|
851
|
-
this.nrrd_states.ribSphereOrigin = null;
|
|
852
|
-
this.nrrd_states.skinSphereOrigin = null;
|
|
853
|
-
this.nrrd_states.nippleSphereOrigin = null;
|
|
1178
|
+
this.nrrd_states.sphere.tumourSphereOrigin = null;
|
|
1179
|
+
this.nrrd_states.sphere.ribSphereOrigin = null;
|
|
1180
|
+
this.nrrd_states.sphere.skinSphereOrigin = null;
|
|
1181
|
+
this.nrrd_states.sphere.nippleSphereOrigin = null;
|
|
854
1182
|
}
|
|
855
1183
|
setSliceMoving(step) {
|
|
856
1184
|
if (this.protectedData.mainPreSlices) {
|
|
@@ -863,7 +1191,7 @@ export class NrrdTools extends DrawToolCore {
|
|
|
863
1191
|
this._sliceRAFId = null;
|
|
864
1192
|
const totalStep = this._pendingSliceStep;
|
|
865
1193
|
this._pendingSliceStep = 0;
|
|
866
|
-
this.protectedData.
|
|
1194
|
+
this.protectedData.isDrawing = true;
|
|
867
1195
|
this.setSyncsliceNum();
|
|
868
1196
|
this.dragOperator.updateIndex(totalStep);
|
|
869
1197
|
this.setIsDrawFalse(1000);
|
|
@@ -871,14 +1199,14 @@ export class NrrdTools extends DrawToolCore {
|
|
|
871
1199
|
}
|
|
872
1200
|
}
|
|
873
1201
|
setMainAreaSize(factor) {
|
|
874
|
-
this.nrrd_states.
|
|
875
|
-
if (this.nrrd_states.
|
|
876
|
-
this.nrrd_states.
|
|
1202
|
+
this.nrrd_states.view.sizeFactor = factor;
|
|
1203
|
+
if (this.nrrd_states.view.sizeFactor >= 8) {
|
|
1204
|
+
this.nrrd_states.view.sizeFactor = 8;
|
|
877
1205
|
}
|
|
878
|
-
else if (this.nrrd_states.
|
|
879
|
-
this.nrrd_states.
|
|
1206
|
+
else if (this.nrrd_states.view.sizeFactor <= 1) {
|
|
1207
|
+
this.nrrd_states.view.sizeFactor = 1;
|
|
880
1208
|
}
|
|
881
|
-
this.resizePaintArea(this.nrrd_states.
|
|
1209
|
+
this.resizePaintArea(this.nrrd_states.view.sizeFactor);
|
|
882
1210
|
this.resetPaintAreaUIPosition();
|
|
883
1211
|
// this.setIsDrawFalse(1000);
|
|
884
1212
|
}
|
|
@@ -892,27 +1220,27 @@ export class NrrdTools extends DrawToolCore {
|
|
|
892
1220
|
return this.nrrd_states;
|
|
893
1221
|
}
|
|
894
1222
|
getMaxSliceNum() {
|
|
895
|
-
if (this.nrrd_states.showContrast) {
|
|
1223
|
+
if (this.nrrd_states.view.showContrast) {
|
|
896
1224
|
return [
|
|
897
|
-
this.nrrd_states.maxIndex,
|
|
898
|
-
this.nrrd_states.maxIndex * this.protectedData.displaySlices.length,
|
|
1225
|
+
this.nrrd_states.view.maxIndex,
|
|
1226
|
+
this.nrrd_states.view.maxIndex * this.protectedData.displaySlices.length,
|
|
899
1227
|
];
|
|
900
1228
|
}
|
|
901
1229
|
else {
|
|
902
|
-
return [this.nrrd_states.maxIndex];
|
|
1230
|
+
return [this.nrrd_states.view.maxIndex];
|
|
903
1231
|
}
|
|
904
1232
|
}
|
|
905
1233
|
getCurrentSlicesNumAndContrastNum() {
|
|
906
1234
|
return {
|
|
907
|
-
|
|
908
|
-
contrastIndex: this.nrrd_states.contrastNum,
|
|
1235
|
+
currentSliceIndex: this.nrrd_states.view.currentSliceIndex,
|
|
1236
|
+
contrastIndex: this.nrrd_states.view.contrastNum,
|
|
909
1237
|
};
|
|
910
1238
|
}
|
|
911
1239
|
getCurrentSliceIndex() {
|
|
912
|
-
return Math.ceil(this.protectedData.mainPreSlices.index / this.nrrd_states.RSARatio);
|
|
1240
|
+
return Math.ceil(this.protectedData.mainPreSlices.index / this.nrrd_states.image.RSARatio);
|
|
913
1241
|
}
|
|
914
1242
|
getIsShowContrastState() {
|
|
915
|
-
return this.nrrd_states.showContrast;
|
|
1243
|
+
return this.nrrd_states.view.showContrast;
|
|
916
1244
|
}
|
|
917
1245
|
/**
|
|
918
1246
|
* Give a delay time to finish the last drawing before upcoming interrupt opreations.
|
|
@@ -922,7 +1250,7 @@ export class NrrdTools extends DrawToolCore {
|
|
|
922
1250
|
*/
|
|
923
1251
|
setIsDrawFalse(target) {
|
|
924
1252
|
this.preTimer = setTimeout(() => {
|
|
925
|
-
this.protectedData.
|
|
1253
|
+
this.protectedData.isDrawing = false;
|
|
926
1254
|
if (this.preTimer) {
|
|
927
1255
|
window.clearTimeout(this.preTimer);
|
|
928
1256
|
this.preTimer = undefined;
|
|
@@ -977,35 +1305,37 @@ export class NrrdTools extends DrawToolCore {
|
|
|
977
1305
|
// (also calls resizePaintArea → reloads masks, resizes canvases)
|
|
978
1306
|
this.setOriginCanvasAndPre();
|
|
979
1307
|
// update the show number div on top area
|
|
980
|
-
this.dragOperator.updateShowNumDiv(this.nrrd_states.contrastNum);
|
|
1308
|
+
this.dragOperator.updateShowNumDiv(this.nrrd_states.view.contrastNum);
|
|
981
1309
|
// repaint all contrast images
|
|
982
1310
|
this.repraintCurrentContrastSlice();
|
|
983
1311
|
// Refresh display after contrast repaint (no need for full resizePaintArea
|
|
984
1312
|
// since canvases were already resized in setOriginCanvasAndPre above)
|
|
985
1313
|
this.redrawDisplayCanvas();
|
|
986
1314
|
this.compositeAllLayers();
|
|
1315
|
+
// Sync slider metadata with current volume (replaces old getGuiSettings() side-effect)
|
|
1316
|
+
this.syncGuiParameterSettings();
|
|
987
1317
|
}
|
|
988
1318
|
setMainPreSlice() {
|
|
989
1319
|
this.protectedData.mainPreSlices = this.protectedData.displaySlices[0];
|
|
990
1320
|
if (this.protectedData.mainPreSlices) {
|
|
991
|
-
this.nrrd_states.RSARatio = this.protectedData.mainPreSlices.RSARatio;
|
|
1321
|
+
this.nrrd_states.image.RSARatio = this.protectedData.mainPreSlices.RSARatio;
|
|
992
1322
|
}
|
|
993
1323
|
}
|
|
994
1324
|
setOriginCanvasAndPre() {
|
|
995
1325
|
if (this.protectedData.mainPreSlices) {
|
|
996
|
-
if (this.nrrd_states.
|
|
997
|
-
this.nrrd_states.
|
|
1326
|
+
if (this.nrrd_states.view.preSliceIndex > this.nrrd_states.view.maxIndex)
|
|
1327
|
+
this.nrrd_states.view.preSliceIndex = this.nrrd_states.view.maxIndex;
|
|
998
1328
|
if (this.initState) {
|
|
999
|
-
this.nrrd_states.
|
|
1329
|
+
this.nrrd_states.view.preSliceIndex =
|
|
1000
1330
|
this.protectedData.mainPreSlices.initIndex *
|
|
1001
|
-
this.nrrd_states.RSARatio;
|
|
1002
|
-
this.nrrd_states.
|
|
1331
|
+
this.nrrd_states.image.RSARatio;
|
|
1332
|
+
this.nrrd_states.view.currentSliceIndex =
|
|
1003
1333
|
this.protectedData.mainPreSlices.initIndex;
|
|
1004
1334
|
}
|
|
1005
1335
|
else {
|
|
1006
1336
|
// !need to change
|
|
1007
1337
|
// todo
|
|
1008
|
-
this.protectedData.mainPreSlices.index = this.nrrd_states.
|
|
1338
|
+
this.protectedData.mainPreSlices.index = this.nrrd_states.view.preSliceIndex;
|
|
1009
1339
|
}
|
|
1010
1340
|
this.protectedData.canvases.originCanvas =
|
|
1011
1341
|
this.protectedData.mainPreSlices.canvas;
|
|
@@ -1016,34 +1346,35 @@ export class NrrdTools extends DrawToolCore {
|
|
|
1016
1346
|
this.setMainPreSlice();
|
|
1017
1347
|
this.setOriginCanvasAndPre();
|
|
1018
1348
|
this.protectedData.currentShowingSlice = this.protectedData.mainPreSlices;
|
|
1019
|
-
this.nrrd_states.
|
|
1020
|
-
this.protectedData.mainPreSlices.initIndex * this.nrrd_states.RSARatio;
|
|
1021
|
-
this.nrrd_states.
|
|
1349
|
+
this.nrrd_states.view.preSliceIndex =
|
|
1350
|
+
this.protectedData.mainPreSlices.initIndex * this.nrrd_states.image.RSARatio;
|
|
1351
|
+
this.nrrd_states.view.currentSliceIndex = this.protectedData.mainPreSlices.initIndex;
|
|
1022
1352
|
// Phase 6: Reset undo/redo stacks on new dataset load
|
|
1023
1353
|
this.undoManager.clearAll();
|
|
1024
1354
|
// compute max index
|
|
1025
1355
|
this.updateMaxIndex();
|
|
1026
|
-
this.dragOperator.updateShowNumDiv(this.nrrd_states.contrastNum);
|
|
1356
|
+
this.dragOperator.updateShowNumDiv(this.nrrd_states.view.contrastNum);
|
|
1357
|
+
this.syncGuiParameterSettings();
|
|
1027
1358
|
this.initState = false;
|
|
1028
1359
|
}
|
|
1029
1360
|
updateMaxIndex() {
|
|
1030
1361
|
if (this.protectedData.mainPreSlices) {
|
|
1031
|
-
this.nrrd_states.maxIndex = this.protectedData.mainPreSlices.MaxIndex;
|
|
1362
|
+
this.nrrd_states.view.maxIndex = this.protectedData.mainPreSlices.MaxIndex;
|
|
1032
1363
|
}
|
|
1033
1364
|
}
|
|
1034
1365
|
/**
|
|
1035
1366
|
* Update the original canvas size, allow set to threejs load one (pixel distance not the mm).
|
|
1036
|
-
* Then update the changedWidth and changedHeight based on the
|
|
1367
|
+
* Then update the changedWidth and changedHeight based on the sizeFactor.
|
|
1037
1368
|
*/
|
|
1038
1369
|
updateOriginAndChangedWH() {
|
|
1039
|
-
this.nrrd_states.originWidth =
|
|
1370
|
+
this.nrrd_states.image.originWidth =
|
|
1040
1371
|
this.protectedData.canvases.originCanvas.width;
|
|
1041
|
-
this.nrrd_states.originHeight =
|
|
1372
|
+
this.nrrd_states.image.originHeight =
|
|
1042
1373
|
this.protectedData.canvases.originCanvas.height;
|
|
1043
1374
|
// Let resizePaintArea be the sole setter of changedWidth/changedHeight.
|
|
1044
1375
|
// Setting them here would defeat the sizeChanged detection in resizePaintArea,
|
|
1045
1376
|
// causing canvas elements to keep stale dimensions after axis switches.
|
|
1046
|
-
this.resizePaintArea(this.nrrd_states.
|
|
1377
|
+
this.resizePaintArea(this.nrrd_states.view.sizeFactor);
|
|
1047
1378
|
this.resetPaintAreaUIPosition();
|
|
1048
1379
|
}
|
|
1049
1380
|
/**
|
|
@@ -1060,20 +1391,29 @@ export class NrrdTools extends DrawToolCore {
|
|
|
1060
1391
|
appendLoadingbar(loadingbar) {
|
|
1061
1392
|
this.protectedData.mainAreaContainer.appendChild(loadingbar);
|
|
1062
1393
|
}
|
|
1063
|
-
|
|
1394
|
+
/**
|
|
1395
|
+
* Clear all annotations on the currently active layer across its entire 3D volume.
|
|
1396
|
+
* This resets all voxels globally for the active layer's `MaskVolume` (depth, width, height)
|
|
1397
|
+
* and triggers the `onClearLayerVolume` event to sync the wiped volume to the backend.
|
|
1398
|
+
* It also clears the undo/redo stack for the active layer ONLY.
|
|
1399
|
+
* Other background layers are not impacted by this operation.
|
|
1400
|
+
*/
|
|
1401
|
+
clearActiveLayer() {
|
|
1064
1402
|
// Phase 3 Task 3.1: Only clear the active layer's MaskVolume
|
|
1065
|
-
if (this.nrrd_states.dimensions.length === 3) {
|
|
1066
|
-
const [w, h, d] = this.nrrd_states.dimensions;
|
|
1067
|
-
const activeLayer = this.gui_states.layer;
|
|
1403
|
+
if (this.nrrd_states.image.dimensions.length === 3) {
|
|
1404
|
+
const [w, h, d] = this.nrrd_states.image.dimensions;
|
|
1405
|
+
const activeLayer = this.gui_states.layerChannel.layer;
|
|
1068
1406
|
// Re-init only the active layer's MaskVolume
|
|
1069
1407
|
this.protectedData.maskData.volumes[activeLayer] = new MaskVolume(w, h, d, 1);
|
|
1070
1408
|
// Phase 6 Task 6.6: Clear undo/redo stack for this layer (volume too large to snapshot)
|
|
1071
1409
|
this.undoManager.clearLayer(activeLayer);
|
|
1072
1410
|
// Phase 3 Task 3.2: Notify external that this layer's volume was cleared
|
|
1073
|
-
this.
|
|
1411
|
+
this.annotationCallbacks.onLayerVolumeCleared(activeLayer);
|
|
1074
1412
|
}
|
|
1075
1413
|
// Invalidate reusable slice buffer
|
|
1076
1414
|
this.invalidateSliceBuffer();
|
|
1415
|
+
// Reload all layers to canvas (restores other layers' visuals)
|
|
1416
|
+
this.reloadMasksFromVolume();
|
|
1077
1417
|
}
|
|
1078
1418
|
/**
|
|
1079
1419
|
* Reset the draw and display canvases layout after mouse pan.
|
|
@@ -1107,6 +1447,59 @@ export class NrrdTools extends DrawToolCore {
|
|
|
1107
1447
|
target.canvas.width = target.canvas.width;
|
|
1108
1448
|
}
|
|
1109
1449
|
}
|
|
1450
|
+
/**
|
|
1451
|
+
* Enter sphere mode.
|
|
1452
|
+
*
|
|
1453
|
+
* Clears all layer canvases and the master composite canvas so that
|
|
1454
|
+
* only the sphere overlay is visible. Does NOT touch MaskVolume data.
|
|
1455
|
+
* Also disables drag mode to prevent slice dragging conflicts.
|
|
1456
|
+
*
|
|
1457
|
+
* Called when sphere mode is toggled on (keyboard shortcut or GUI).
|
|
1458
|
+
*/
|
|
1459
|
+
enterSphereMode() {
|
|
1460
|
+
var _a;
|
|
1461
|
+
// Disable left-click drag for slice navigation
|
|
1462
|
+
this.dragOperator.removeDragMode();
|
|
1463
|
+
// Tell EventRouter we're in sphere mode so Shift/draw is blocked
|
|
1464
|
+
(_a = this.eventRouter) === null || _a === void 0 ? void 0 : _a.setGuiTool('sphere');
|
|
1465
|
+
// Clear all layer canvases (NOT MaskVolumes — just visual canvas)
|
|
1466
|
+
const w = this.nrrd_states.view.changedWidth;
|
|
1467
|
+
const h = this.nrrd_states.view.changedHeight;
|
|
1468
|
+
for (const layerId of this.nrrd_states.image.layers) {
|
|
1469
|
+
const target = this.protectedData.layerTargets.get(layerId);
|
|
1470
|
+
if (target) {
|
|
1471
|
+
target.ctx.clearRect(0, 0, target.canvas.width, target.canvas.height);
|
|
1472
|
+
}
|
|
1473
|
+
}
|
|
1474
|
+
// Clear master composite canvas
|
|
1475
|
+
this.protectedData.ctxes.drawingLayerMasterCtx.clearRect(0, 0, w, h);
|
|
1476
|
+
// Refresh sphere overlay from volume (shows existing sphere data on re-entry)
|
|
1477
|
+
this.refreshSphereOverlay();
|
|
1478
|
+
}
|
|
1479
|
+
/**
|
|
1480
|
+
* Exit sphere mode.
|
|
1481
|
+
*
|
|
1482
|
+
* Clears sphere overlay, restores all layer MaskVolume data onto
|
|
1483
|
+
* their canvases by temporarily lifting the sphere guard in
|
|
1484
|
+
* reloadMasksFromVolume and calling it.
|
|
1485
|
+
*
|
|
1486
|
+
* Called when sphere mode is toggled off (keyboard shortcut or GUI).
|
|
1487
|
+
*/
|
|
1488
|
+
exitSphereMode() {
|
|
1489
|
+
var _a;
|
|
1490
|
+
// Restore left-click drag for slice navigation
|
|
1491
|
+
this.dragOperator.configDragMode();
|
|
1492
|
+
// Restore EventRouter guiTool to pencil (default drawing tool)
|
|
1493
|
+
(_a = this.eventRouter) === null || _a === void 0 ? void 0 : _a.setGuiTool('pencil');
|
|
1494
|
+
// Clear sphere canvas overlay
|
|
1495
|
+
this.protectedData.ctxes.drawingSphereCtx.clearRect(0, 0, this.protectedData.canvases.drawingSphereCanvas.width, this.protectedData.canvases.drawingSphereCanvas.height);
|
|
1496
|
+
// resetLayerCanvas clears the layer canvas elements
|
|
1497
|
+
this.resetLayerCanvas();
|
|
1498
|
+
// Temporarily lift sphere guard so reloadMasksFromVolume can run.
|
|
1499
|
+
// gui_states.sphere is already set to false by the caller before
|
|
1500
|
+
// calling this method, so reloadMasksFromVolume will proceed normally.
|
|
1501
|
+
this.reloadMasksFromVolume();
|
|
1502
|
+
}
|
|
1110
1503
|
redrawMianPreOnDisplayCanvas() {
|
|
1111
1504
|
var _a;
|
|
1112
1505
|
this.protectedData.canvases.displayCanvas.width =
|
|
@@ -1118,8 +1511,8 @@ export class NrrdTools extends DrawToolCore {
|
|
|
1118
1511
|
if (this.protectedData.mainPreSlices) {
|
|
1119
1512
|
this.protectedData.mainPreSlices.repaint.call(this.protectedData.mainPreSlices);
|
|
1120
1513
|
this.flipDisplayImageByAxis();
|
|
1121
|
-
(_a = this.protectedData.ctxes.displayCtx) === null || _a === void 0 ? void 0 : _a.drawImage(this.protectedData.canvases.originCanvas, 0, 0, this.nrrd_states.changedWidth, this.nrrd_states.changedHeight);
|
|
1122
|
-
this.resizePaintArea(this.nrrd_states.
|
|
1514
|
+
(_a = this.protectedData.ctxes.displayCtx) === null || _a === void 0 ? void 0 : _a.drawImage(this.protectedData.canvases.originCanvas, 0, 0, this.nrrd_states.view.changedWidth, this.nrrd_states.view.changedHeight);
|
|
1515
|
+
this.resizePaintArea(this.nrrd_states.view.sizeFactor);
|
|
1123
1516
|
}
|
|
1124
1517
|
}
|
|
1125
1518
|
/**
|
|
@@ -1127,10 +1520,10 @@ export class NrrdTools extends DrawToolCore {
|
|
|
1127
1520
|
* @param factor number
|
|
1128
1521
|
*/
|
|
1129
1522
|
resizePaintArea(factor) {
|
|
1130
|
-
const newWidth = Math.floor(this.nrrd_states.originWidth * factor);
|
|
1131
|
-
const newHeight = Math.floor(this.nrrd_states.originHeight * factor);
|
|
1132
|
-
const sizeChanged = newWidth !== this.nrrd_states.changedWidth ||
|
|
1133
|
-
newHeight !== this.nrrd_states.changedHeight;
|
|
1523
|
+
const newWidth = Math.floor(this.nrrd_states.image.originWidth * factor);
|
|
1524
|
+
const newHeight = Math.floor(this.nrrd_states.image.originHeight * factor);
|
|
1525
|
+
const sizeChanged = newWidth !== this.nrrd_states.view.changedWidth ||
|
|
1526
|
+
newHeight !== this.nrrd_states.view.changedHeight;
|
|
1134
1527
|
// Always clear display/drawing/origin canvases (needed for contrast updates)
|
|
1135
1528
|
this.protectedData.canvases.originCanvas.width =
|
|
1136
1529
|
this.protectedData.canvases.originCanvas.width;
|
|
@@ -1143,8 +1536,8 @@ export class NrrdTools extends DrawToolCore {
|
|
|
1143
1536
|
// Skipping this avoids the expensive reloadMasksFromVolume() call
|
|
1144
1537
|
// during contrast toggle (where size stays the same).
|
|
1145
1538
|
this.resetLayerCanvas();
|
|
1146
|
-
this.nrrd_states.changedWidth = newWidth;
|
|
1147
|
-
this.nrrd_states.changedHeight = newHeight;
|
|
1539
|
+
this.nrrd_states.view.changedWidth = newWidth;
|
|
1540
|
+
this.nrrd_states.view.changedHeight = newHeight;
|
|
1148
1541
|
this.protectedData.canvases.displayCanvas.width = newWidth;
|
|
1149
1542
|
this.protectedData.canvases.displayCanvas.height = newHeight;
|
|
1150
1543
|
this.protectedData.canvases.drawingCanvas.width = newWidth;
|
|
@@ -1166,18 +1559,25 @@ export class NrrdTools extends DrawToolCore {
|
|
|
1166
1559
|
// valid data, just recomposite to master for the start() render loop.
|
|
1167
1560
|
this.compositeAllLayers();
|
|
1168
1561
|
}
|
|
1562
|
+
// Refresh sphere overlay from volume after resize/contrast change
|
|
1563
|
+
this.refreshSphereOverlay();
|
|
1169
1564
|
}
|
|
1170
1565
|
/**
|
|
1171
1566
|
* Phase 3: Reload all mask layers from MaskVolume using buffer reuse
|
|
1172
1567
|
* Replaces the old reloadMaskToLayer approach
|
|
1173
1568
|
*/
|
|
1174
1569
|
reloadMasksFromVolume() {
|
|
1570
|
+
// When sphere mode is active, do NOT redraw layer masks.
|
|
1571
|
+
// Layer mask data should remain hidden until the user exits sphere mode.
|
|
1572
|
+
if (this.gui_states.mode.sphere) {
|
|
1573
|
+
return;
|
|
1574
|
+
}
|
|
1175
1575
|
const axis = this.protectedData.axis;
|
|
1176
|
-
let sliceIndex = this.nrrd_states.
|
|
1576
|
+
let sliceIndex = this.nrrd_states.view.currentSliceIndex;
|
|
1177
1577
|
// Clamp sliceIndex to valid range for current axis
|
|
1178
|
-
// (
|
|
1578
|
+
// (currentSliceIndex may not be updated yet when switching axes)
|
|
1179
1579
|
try {
|
|
1180
|
-
const vol = this.getVolumeForLayer(this.nrrd_states.layers[0]);
|
|
1580
|
+
const vol = this.getVolumeForLayer(this.nrrd_states.image.layers[0]);
|
|
1181
1581
|
const dims = vol.getDimensions();
|
|
1182
1582
|
const maxSlice = axis === "x" ? dims.width : axis === "y" ? dims.height : dims.depth;
|
|
1183
1583
|
if (sliceIndex >= maxSlice)
|
|
@@ -1190,10 +1590,10 @@ export class NrrdTools extends DrawToolCore {
|
|
|
1190
1590
|
const buffer = this.getOrCreateSliceBuffer(axis);
|
|
1191
1591
|
if (!buffer)
|
|
1192
1592
|
return;
|
|
1193
|
-
const w = this.nrrd_states.changedWidth;
|
|
1194
|
-
const h = this.nrrd_states.changedHeight;
|
|
1593
|
+
const w = this.nrrd_states.view.changedWidth;
|
|
1594
|
+
const h = this.nrrd_states.view.changedHeight;
|
|
1195
1595
|
// Clear and render each layer using the shared buffer
|
|
1196
|
-
for (const layerId of this.nrrd_states.layers) {
|
|
1596
|
+
for (const layerId of this.nrrd_states.image.layers) {
|
|
1197
1597
|
const target = this.protectedData.layerTargets.get(layerId);
|
|
1198
1598
|
if (!target)
|
|
1199
1599
|
continue;
|
|
@@ -1214,15 +1614,15 @@ export class NrrdTools extends DrawToolCore {
|
|
|
1214
1614
|
var _a, _b, _c, _d, _e, _f;
|
|
1215
1615
|
if (this.protectedData.axis === "x") {
|
|
1216
1616
|
(_a = this.protectedData.ctxes.displayCtx) === null || _a === void 0 ? void 0 : _a.scale(-1, -1);
|
|
1217
|
-
(_b = this.protectedData.ctxes.displayCtx) === null || _b === void 0 ? void 0 : _b.translate(-this.nrrd_states.changedWidth, -this.nrrd_states.changedHeight);
|
|
1617
|
+
(_b = this.protectedData.ctxes.displayCtx) === null || _b === void 0 ? void 0 : _b.translate(-this.nrrd_states.view.changedWidth, -this.nrrd_states.view.changedHeight);
|
|
1218
1618
|
}
|
|
1219
1619
|
else if (this.protectedData.axis === "z") {
|
|
1220
1620
|
(_c = this.protectedData.ctxes.displayCtx) === null || _c === void 0 ? void 0 : _c.scale(1, -1);
|
|
1221
|
-
(_d = this.protectedData.ctxes.displayCtx) === null || _d === void 0 ? void 0 : _d.translate(0, -this.nrrd_states.changedHeight);
|
|
1621
|
+
(_d = this.protectedData.ctxes.displayCtx) === null || _d === void 0 ? void 0 : _d.translate(0, -this.nrrd_states.view.changedHeight);
|
|
1222
1622
|
}
|
|
1223
1623
|
else if (this.protectedData.axis === "y") {
|
|
1224
1624
|
(_e = this.protectedData.ctxes.displayCtx) === null || _e === void 0 ? void 0 : _e.scale(1, -1);
|
|
1225
|
-
(_f = this.protectedData.ctxes.displayCtx) === null || _f === void 0 ? void 0 : _f.translate(0, -this.nrrd_states.changedHeight);
|
|
1625
|
+
(_f = this.protectedData.ctxes.displayCtx) === null || _f === void 0 ? void 0 : _f.translate(0, -this.nrrd_states.view.changedHeight);
|
|
1226
1626
|
}
|
|
1227
1627
|
}
|
|
1228
1628
|
clearDictionary(dic) {
|
|
@@ -1239,21 +1639,21 @@ export class NrrdTools extends DrawToolCore {
|
|
|
1239
1639
|
switch (!!axis ? axis : this.protectedData.axis) {
|
|
1240
1640
|
case "x":
|
|
1241
1641
|
this.protectedData.canvases.emptyCanvas.width =
|
|
1242
|
-
this.nrrd_states.nrrd_z_pixel;
|
|
1642
|
+
this.nrrd_states.image.nrrd_z_pixel;
|
|
1243
1643
|
this.protectedData.canvases.emptyCanvas.height =
|
|
1244
|
-
this.nrrd_states.nrrd_y_pixel;
|
|
1644
|
+
this.nrrd_states.image.nrrd_y_pixel;
|
|
1245
1645
|
break;
|
|
1246
1646
|
case "y":
|
|
1247
1647
|
this.protectedData.canvases.emptyCanvas.width =
|
|
1248
|
-
this.nrrd_states.nrrd_x_pixel;
|
|
1648
|
+
this.nrrd_states.image.nrrd_x_pixel;
|
|
1249
1649
|
this.protectedData.canvases.emptyCanvas.height =
|
|
1250
|
-
this.nrrd_states.nrrd_z_pixel;
|
|
1650
|
+
this.nrrd_states.image.nrrd_z_pixel;
|
|
1251
1651
|
break;
|
|
1252
1652
|
case "z":
|
|
1253
1653
|
this.protectedData.canvases.emptyCanvas.width =
|
|
1254
|
-
this.nrrd_states.nrrd_x_pixel;
|
|
1654
|
+
this.nrrd_states.image.nrrd_x_pixel;
|
|
1255
1655
|
this.protectedData.canvases.emptyCanvas.height =
|
|
1256
|
-
this.nrrd_states.nrrd_y_pixel;
|
|
1656
|
+
this.nrrd_states.image.nrrd_y_pixel;
|
|
1257
1657
|
break;
|
|
1258
1658
|
}
|
|
1259
1659
|
}
|
|
@@ -1275,7 +1675,7 @@ export class NrrdTools extends DrawToolCore {
|
|
|
1275
1675
|
this.protectedData.currentShowingSlice.repaint.call(this.protectedData.currentShowingSlice);
|
|
1276
1676
|
(_a = this.protectedData.ctxes.displayCtx) === null || _a === void 0 ? void 0 : _a.save();
|
|
1277
1677
|
this.flipDisplayImageByAxis();
|
|
1278
|
-
(_b = this.protectedData.ctxes.displayCtx) === null || _b === void 0 ? void 0 : _b.drawImage(this.protectedData.currentShowingSlice.canvas, 0, 0, this.nrrd_states.changedWidth, this.nrrd_states.changedHeight);
|
|
1678
|
+
(_b = this.protectedData.ctxes.displayCtx) === null || _b === void 0 ? void 0 : _b.drawImage(this.protectedData.currentShowingSlice.canvas, 0, 0, this.nrrd_states.view.changedWidth, this.nrrd_states.view.changedHeight);
|
|
1279
1679
|
(_c = this.protectedData.ctxes.displayCtx) === null || _c === void 0 ? void 0 : _c.restore();
|
|
1280
1680
|
}
|
|
1281
1681
|
}
|
|
@@ -1284,7 +1684,8 @@ export class NrrdTools extends DrawToolCore {
|
|
|
1284
1684
|
*/
|
|
1285
1685
|
configMouseSliceWheel() {
|
|
1286
1686
|
const handleMouseZoomSliceWheelMove = (e) => {
|
|
1287
|
-
|
|
1687
|
+
var _a;
|
|
1688
|
+
if ((_a = this.eventRouter) === null || _a === void 0 ? void 0 : _a.isShiftHeld()) {
|
|
1288
1689
|
return;
|
|
1289
1690
|
}
|
|
1290
1691
|
e.preventDefault();
|