copper3d 3.4.6 → 3.4.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (31) hide show
  1. package/dist/Utils/segmentation/DrawToolCore.d.ts +19 -2
  2. package/dist/Utils/segmentation/DrawToolCore.js +58 -13
  3. package/dist/Utils/segmentation/DrawToolCore.js.map +1 -1
  4. package/dist/Utils/segmentation/NrrdTools.d.ts +0 -1
  5. package/dist/Utils/segmentation/NrrdTools.js +2 -7
  6. package/dist/Utils/segmentation/NrrdTools.js.map +1 -1
  7. package/dist/Utils/segmentation/core/types.d.ts +0 -1
  8. package/dist/Utils/segmentation/core/types.js.map +1 -1
  9. package/dist/Utils/segmentation/coreTools/gui.d.ts +0 -1
  10. package/dist/Utils/segmentation/coreTools/gui.js +21 -29
  11. package/dist/Utils/segmentation/coreTools/gui.js.map +1 -1
  12. package/dist/Utils/segmentation/tools/DrawingTool.d.ts +9 -2
  13. package/dist/Utils/segmentation/tools/DrawingTool.js +28 -19
  14. package/dist/Utils/segmentation/tools/DrawingTool.js.map +1 -1
  15. package/dist/Utils/segmentation/tools/ToolHost.d.ts +2 -3
  16. package/dist/Utils/utils.d.ts +0 -1
  17. package/dist/Utils/utils.js +0 -80
  18. package/dist/Utils/utils.js.map +1 -1
  19. package/dist/bundle.esm.js +109 -147
  20. package/dist/bundle.umd.js +109 -147
  21. package/dist/index.d.ts +1 -1
  22. package/dist/index.js +1 -1
  23. package/dist/types/Utils/segmentation/DrawToolCore.d.ts +19 -2
  24. package/dist/types/Utils/segmentation/NrrdTools.d.ts +0 -1
  25. package/dist/types/Utils/segmentation/core/types.d.ts +0 -1
  26. package/dist/types/Utils/segmentation/coreTools/gui.d.ts +0 -1
  27. package/dist/types/Utils/segmentation/tools/DrawingTool.d.ts +9 -2
  28. package/dist/types/Utils/segmentation/tools/ToolHost.d.ts +2 -3
  29. package/dist/types/Utils/utils.d.ts +0 -1
  30. package/dist/types/index.d.ts +1 -1
  31. package/package.json +1 -1
@@ -40614,86 +40614,6 @@ void main() {
40614
40614
  }
40615
40615
  return url;
40616
40616
  }
40617
- function switchEraserSize(size, urls) {
40618
- let url = "";
40619
- if (!!urls && urls.length > 0) {
40620
- if (size <= 3) {
40621
- url = `url(${urls[0]}) 3 3, crosshair`;
40622
- }
40623
- else if (3 < size && size <= 8) {
40624
- url = `url(${urls[1]}) 8 8, crosshair`;
40625
- }
40626
- else if (8 < size && size <= 13) {
40627
- url = `url(${urls[2]}) 13 13, crosshair`;
40628
- }
40629
- else if (13 < size && size <= 18) {
40630
- url = `url(${urls[3]}) 18 18, crosshair`;
40631
- }
40632
- else if (18 < size && size <= 23) {
40633
- url = `url(${urls[4]}) 23 23, crosshair`;
40634
- }
40635
- else if (23 < size && size <= 28) {
40636
- url = `url(${urls[5]}) 28 28, crosshair`;
40637
- }
40638
- else if (28 < size && size <= 33) {
40639
- url = `url(${urls[6]}) 33 33, crosshair`;
40640
- }
40641
- else if (33 < size && size <= 38) {
40642
- url = `url(${urls[7]}) 38 38, crosshair`;
40643
- }
40644
- else if (38 < size && size <= 43) {
40645
- url = `url(${urls[8]}) 43 43, crosshair`;
40646
- }
40647
- else if (43 < size && size <= 48) {
40648
- url = `url(${urls[9]}) 48 48, crosshair`;
40649
- }
40650
- else if (48 < size && size <= 53) {
40651
- url = `url(${urls[10]}) 52 52, crosshair`;
40652
- }
40653
- else {
40654
- url = `url(${urls[11]}) 52 52, crosshair`;
40655
- }
40656
- }
40657
- else {
40658
- if (size <= 3) {
40659
- url = `url(https://raw.githubusercontent.com/LinkunGao/copper3d-datasets/main/icons/eraser/circular-cursor_3.png) 3 3, crosshair`;
40660
- }
40661
- else if (3 < size && size <= 8) {
40662
- url = `url(https://raw.githubusercontent.com/LinkunGao/copper3d-datasets/main/icons/eraser/circular-cursor_8.png) 8 8, crosshair`;
40663
- }
40664
- else if (8 < size && size <= 13) {
40665
- url = `url(https://raw.githubusercontent.com/LinkunGao/copper3d-datasets/main/icons/eraser/circular-cursor_13.png) 13 13, crosshair`;
40666
- }
40667
- else if (13 < size && size <= 18) {
40668
- url = `url(https://raw.githubusercontent.com/LinkunGao/copper3d-datasets/main/icons/eraser/circular-cursor_18.png) 18 18, crosshair`;
40669
- }
40670
- else if (18 < size && size <= 23) {
40671
- url = `url(https://raw.githubusercontent.com/LinkunGao/copper3d-datasets/main/icons/eraser/circular-cursor_23.png) 23 23, crosshair`;
40672
- }
40673
- else if (23 < size && size <= 28) {
40674
- url = `url(https://raw.githubusercontent.com/LinkunGao/copper3d-datasets/main/icons/eraser/circular-cursor_28.png) 28 28, crosshair`;
40675
- }
40676
- else if (28 < size && size <= 33) {
40677
- url = `url(https://raw.githubusercontent.com/LinkunGao/copper3d-datasets/main/icons/eraser/circular-cursor_33.png) 33 33, crosshair`;
40678
- }
40679
- else if (33 < size && size <= 38) {
40680
- url = `url(https://raw.githubusercontent.com/LinkunGao/copper3d-datasets/main/icons/eraser/circular-cursor_38.png) 38 38, crosshair`;
40681
- }
40682
- else if (38 < size && size <= 43) {
40683
- url = `url(https://raw.githubusercontent.com/LinkunGao/copper3d-datasets/main/icons/eraser/circular-cursor_43.png) 43 43, crosshair`;
40684
- }
40685
- else if (43 < size && size <= 48) {
40686
- url = `url(https://raw.githubusercontent.com/LinkunGao/copper3d-datasets/main/icons/eraser/circular-cursor_48.png) 48 48, crosshair`;
40687
- }
40688
- else if (48 < size && size <= 53) {
40689
- url = `url(https://raw.githubusercontent.com/LinkunGao/copper3d-datasets/main/icons/eraser/circular-cursor_52.png) 52 52, crosshair`;
40690
- }
40691
- else {
40692
- url = `url(https://raw.githubusercontent.com/LinkunGao/copper3d-datasets/main/icons/eraser/circular-cursor_52.png) 52 52, crosshair`;
40693
- }
40694
- }
40695
- return url;
40696
- }
40697
40617
  function throttle(callback, wait) {
40698
40618
  let start = 0;
40699
40619
  return function (event) {
@@ -73010,10 +72930,7 @@ void main() {
73010
72930
  .name("BrushAndEraserSize")
73011
72931
  .min(5)
73012
72932
  .max(50)
73013
- .step(1)
73014
- .onChange(() => {
73015
- updateGuiBrushAndEraserSize();
73016
- });
72933
+ .step(1);
73017
72934
  actionsFolder.add(configs.gui_states.mode, "eraser").onChange((value) => {
73018
72935
  updateGuiEraserState();
73019
72936
  });
@@ -73141,37 +73058,33 @@ void main() {
73141
73058
  configs.gui_states.viewConfig.readyToUpdate = true;
73142
73059
  });
73143
73060
  actionsFolder.open();
73144
- const updateGuiBrushAndEraserSize = () => {
73145
- if (configs.gui_states.mode.eraser) {
73146
- configs.eraserUrls.length > 0
73147
- ? (configs.drawingCanvas.style.cursor = switchEraserSize(configs.gui_states.drawing.brushAndEraserSize, configs.eraserUrls))
73148
- : (configs.drawingCanvas.style.cursor = switchEraserSize(configs.gui_states.drawing.brushAndEraserSize));
73149
- }
73150
- };
73151
- const updatePencilState = () => {
73152
- if (configs.gui_states.mode.pencil) {
73153
- // add canvas brush circle move event listeners
73154
- configs.drawingCanvas.removeEventListener("mouseover", configs.drawingPrameters.handleOnDrawingBrushCricleMove);
73155
- configs.drawingCanvas.removeEventListener("mouseout", configs.drawingPrameters.handleOnDrawingBrushCricleMove);
73061
+ // Add/remove the hover-tracking listeners that feed the brush/eraser preview
73062
+ // ring (mouseOver position). Present for brush & eraser, removed for pencil.
73063
+ const setBrushHoverTracking = (enabled) => {
73064
+ const handler = configs.drawingPrameters.handleOnDrawingBrushCricleMove;
73065
+ if (enabled) {
73066
+ configs.drawingCanvas.addEventListener("mouseover", handler);
73067
+ configs.drawingCanvas.addEventListener("mouseout", handler);
73156
73068
  }
73157
73069
  else {
73158
- // add canvas brush circle move event listeners
73159
- configs.drawingCanvas.addEventListener("mouseover", configs.drawingPrameters.handleOnDrawingBrushCricleMove);
73160
- configs.drawingCanvas.addEventListener("mouseout", configs.drawingPrameters.handleOnDrawingBrushCricleMove);
73070
+ configs.drawingCanvas.removeEventListener("mouseover", handler);
73071
+ configs.drawingCanvas.removeEventListener("mouseout", handler);
73161
73072
  }
73073
+ };
73074
+ const updatePencilState = () => {
73075
+ // Pencil has no preview ring; brush keeps the hover-tracking listeners.
73076
+ setBrushHoverTracking(!configs.gui_states.mode.pencil);
73162
73077
  configs.drawingCanvas.style.cursor = configs.gui_states.viewConfig.defaultPaintCursor;
73163
73078
  };
73164
73079
  const updateGuiEraserState = () => {
73165
- // configs.gui_states.mode.eraser = value;
73080
+ // The eraser shows a dashed preview ring (rendered in DrawToolCore.start),
73081
+ // so it needs the same hover-tracking as the brush. The canvas keeps the
73082
+ // default paint cursor; the ring conveys size (resize via Shift+wheel).
73166
73083
  if (configs.gui_states.mode.eraser) {
73167
- configs.eraserUrls.length > 0
73168
- ? (configs.drawingCanvas.style.cursor = switchEraserSize(configs.gui_states.drawing.brushAndEraserSize, configs.eraserUrls))
73169
- : (configs.drawingCanvas.style.cursor = switchEraserSize(configs.gui_states.drawing.brushAndEraserSize));
73170
- }
73171
- else {
73172
- configs.drawingCanvas.style.cursor =
73173
- configs.gui_states.viewConfig.defaultPaintCursor;
73084
+ setBrushHoverTracking(true);
73174
73085
  }
73086
+ configs.drawingCanvas.style.cursor =
73087
+ configs.gui_states.viewConfig.defaultPaintCursor;
73175
73088
  };
73176
73089
  const updateGuiSphereState = () => {
73177
73090
  var _a, _b, _c, _d;
@@ -73227,7 +73140,6 @@ void main() {
73227
73140
  min: 5,
73228
73141
  max: 50,
73229
73142
  step: 1,
73230
- onChange: updateGuiBrushAndEraserSize,
73231
73143
  },
73232
73144
  eraser: {
73233
73145
  name: "Eraser",
@@ -74956,18 +74868,11 @@ void main() {
74956
74868
  this.drawingLines = [];
74957
74869
  this.isPainting = true;
74958
74870
  this.ctx.protectedData.isDrawing = true;
74959
- // Set cursor based on mode
74960
- if (this.ctx.gui_states.mode.eraser) {
74961
- const urls = this.callbacks.getEraserUrls();
74962
- this.ctx.protectedData.canvases.drawingCanvas.style.cursor =
74963
- urls.length > 0
74964
- ? switchEraserSize(this.ctx.gui_states.drawing.brushAndEraserSize, urls)
74965
- : switchEraserSize(this.ctx.gui_states.drawing.brushAndEraserSize);
74966
- }
74967
- else {
74968
- this.ctx.protectedData.canvases.drawingCanvas.style.cursor =
74969
- this.ctx.gui_states.viewConfig.defaultPaintCursor;
74970
- }
74871
+ // Brush and eraser both show their size via the dashed/solid preview ring
74872
+ // rendered in DrawToolCore.start(); the canvas keeps the default paint
74873
+ // cursor underneath. (The eraser previously swapped in a sized PNG cursor.)
74874
+ this.ctx.protectedData.canvases.drawingCanvas.style.cursor =
74875
+ this.ctx.gui_states.viewConfig.defaultPaintCursor;
74971
74876
  // Record draw start position
74972
74877
  this.ctx.nrrd_states.interaction.drawStartPos.x = e.offsetX;
74973
74878
  this.ctx.nrrd_states.interaction.drawStartPos.y = e.offsetY;
@@ -75105,20 +75010,37 @@ void main() {
75105
75010
  return handler;
75106
75011
  }
75107
75012
  /**
75108
- * Render brush circle preview on the drawing context.
75013
+ * Render the size-preview ring for the brush / eraser on the drawing context.
75014
+ *
75015
+ * - Brush: solid outline in the current brush colour.
75016
+ * - Eraser: red dashed outline (matches the sphereEraser preview), so the
75017
+ * eraser no longer needs a sized PNG cursor — the ring tracks the live
75018
+ * `brushAndEraserSize` and is what the user resizes with Shift+wheel.
75019
+ *
75020
+ * Only the pencil has no preview ring (its stroke width is fixed).
75109
75021
  */
75110
- renderBrushPreview(ctx, width, height) {
75022
+ renderBrushPreview(ctx, _width, _height) {
75111
75023
  if (this.ctx.gui_states.mode.pencil ||
75112
- this.ctx.gui_states.mode.eraser ||
75113
75024
  !this.ctx.nrrd_states.interaction.mouseOver) {
75114
75025
  return;
75115
75026
  }
75116
- ctx.clearRect(0, 0, width, height);
75117
- ctx.fillStyle = this.ctx.gui_states.drawing.brushColor;
75027
+ const isEraser = this.ctx.gui_states.mode.eraser;
75028
+ // No clearRect here: DrawToolCore.start() clears drawingCtx once per frame
75029
+ // before compositing, and this ring is now drawn on top of the mask so it
75030
+ // stays visible during an active stroke (e.g. while Shift+wheel resizing).
75031
+ ctx.save();
75118
75032
  ctx.beginPath();
75119
75033
  ctx.arc(this.ctx.nrrd_states.interaction.mouseOverX, this.ctx.nrrd_states.interaction.mouseOverY, this.ctx.gui_states.drawing.brushAndEraserSize / 2 + 1, 0, Math.PI * 2);
75120
- ctx.strokeStyle = this.ctx.gui_states.drawing.brushColor;
75034
+ if (isEraser) {
75035
+ ctx.strokeStyle = "#ff4444";
75036
+ ctx.lineWidth = 2;
75037
+ ctx.setLineDash([4, 4]);
75038
+ }
75039
+ else {
75040
+ ctx.strokeStyle = this.ctx.gui_states.drawing.brushColor;
75041
+ }
75121
75042
  ctx.stroke();
75043
+ ctx.restore();
75122
75044
  }
75123
75045
  // ── Brush mode: direct voxel write ────────────────────────────
75124
75046
  /**
@@ -76259,7 +76181,6 @@ void main() {
76259
76181
  handleOnContrastMouseUp: (ev) => { },
76260
76182
  handleOnContrastMouseLeave: (ev) => { },
76261
76183
  };
76262
- this.eraserUrls = [];
76263
76184
  this.pencilUrls = [];
76264
76185
  this.undoManager = new UndoManager();
76265
76186
  /** Slice index recorded when paintOnCanvas() starts, guards stale-click */
@@ -76334,7 +76255,6 @@ void main() {
76334
76255
  filterDrawedImage: (axis, index) => this.renderer.filterDrawedImage(axis, index),
76335
76256
  getVolumeForLayer: (layer) => this.renderer.getVolumeForLayer(layer),
76336
76257
  pushUndoDelta: (delta) => this.undoManager.push(delta),
76337
- getEraserUrls: () => this.eraserUrls,
76338
76258
  renderSliceToCanvas: (layer, axis, sliceIndex, buffer, ctx, w, h) => this.renderer.renderSliceToCanvas(layer, axis, sliceIndex, buffer, ctx, w, h),
76339
76259
  getOrCreateSliceBuffer: (axis) => this.renderer.getOrCreateSliceBuffer(axis),
76340
76260
  });
@@ -76346,7 +76266,6 @@ void main() {
76346
76266
  getOrCreateSliceBuffer: (axis) => this.renderer.getOrCreateSliceBuffer(axis),
76347
76267
  setEmptyCanvasSize: (axis) => this.setEmptyCanvasSize(axis),
76348
76268
  reloadMasksFromVolume: () => this.reloadMasksFromVolume(),
76349
- getEraserUrls: () => this.eraserUrls,
76350
76269
  });
76351
76270
  }
76352
76271
  initDrawToolCore() {
@@ -76501,6 +76420,12 @@ void main() {
76501
76420
  });
76502
76421
  // Register wheel handler with EventRouter
76503
76422
  this.eventRouter.setWheelHandler((e) => {
76423
+ // Shift + wheel resizes the brush/eraser (like sphereBrush/sphereEraser
76424
+ // radius), independent of whether the left button is held. Consumes the
76425
+ // event so it never falls through to zoom/slice. Pencil is excluded even
76426
+ // though it also uses Shift — see tryBrushEraserResizeWheel.
76427
+ if (this.tryBrushEraserResizeWheel(e))
76428
+ return;
76504
76429
  if (this.activeWheelMode === 'zoom') {
76505
76430
  this.drawingPrameters.handleMouseZoomSliceWheel(e);
76506
76431
  }
@@ -76514,8 +76439,47 @@ void main() {
76514
76439
  // Bind all event listeners
76515
76440
  this.eventRouter.bindAll();
76516
76441
  }
76517
- setEraserUrls(urls) {
76518
- this.eraserUrls = urls;
76442
+ /**
76443
+ * Shift + mouse-wheel resize for the brush and eraser tools.
76444
+ *
76445
+ * Mirrors the sphereBrush/sphereEraser "scroll to change radius" UX so the
76446
+ * user no longer has to reach for the B&E Size slider mid-annotation. Active
76447
+ * whenever the EventRouter is in `draw` mode (i.e. Shift is held — with or
76448
+ * without the left button down) and the current tool is brush or eraser.
76449
+ *
76450
+ * Pencil is deliberately excluded: it also draws with Shift, but its stroke
76451
+ * width is fixed and unrelated to `brushAndEraserSize`. Sphere-family tools
76452
+ * keep their own wheel-radius handler (`activeWheelMode === 'sphereBrush'`).
76453
+ *
76454
+ * `gui_states.mode` is the source of truth for the active tool here, not
76455
+ * `eventRouter.getGuiTool()` — the latter is only updated for sphere tools.
76456
+ *
76457
+ * @returns true if the event was handled (and should not fall through to
76458
+ * the zoom/slice/sphere wheel handlers).
76459
+ */
76460
+ tryBrushEraserResizeWheel(e) {
76461
+ // `draw` mode means Shift is held and neither crosshair nor contrast is
76462
+ // active (EventRouter only enters it for drawing tools under those rules),
76463
+ // so it doubles as the "Shift held, not blocked" gate.
76464
+ if (this.eventRouter.getMode() !== 'draw')
76465
+ return false;
76466
+ const mode = this.state.gui_states.mode;
76467
+ // Brush = no flag set; eraser = mode.eraser. Exclude pencil and all
76468
+ // sphere-family tools.
76469
+ if (mode.pencil || mode.sphere || mode.sphereBrush || mode.sphereEraser) {
76470
+ return false;
76471
+ }
76472
+ e.preventDefault();
76473
+ const drawing = this.state.gui_states.drawing;
76474
+ // Step/bounds match the B&E Size slider config (min 5, max 50, step 1).
76475
+ const next = Math.max(5, Math.min(50, drawing.brushAndEraserSize + (e.deltaY < 0 ? 1 : -1)));
76476
+ if (next === drawing.brushAndEraserSize)
76477
+ return true;
76478
+ drawing.brushAndEraserSize = next;
76479
+ // Both brush and eraser draw a size-preview ring in start() that reads
76480
+ // brushAndEraserSize live, so the new size shows up on the next frame with
76481
+ // no extra work here.
76482
+ return true;
76519
76483
  }
76520
76484
  setPencilIconUrls(urls) {
76521
76485
  this.pencilUrls = urls;
@@ -76684,6 +76648,7 @@ void main() {
76684
76648
  this.state.protectedData.ctxes.drawingCtx.clearRect(0, 0, this.state.nrrd_states.view.changedWidth, this.state.nrrd_states.view.changedHeight);
76685
76649
  this.state.protectedData.ctxes.drawingCtx.globalAlpha =
76686
76650
  this.state.gui_states.drawing.globalAlpha;
76651
+ const currentMode = this.eventRouter.getMode();
76687
76652
  if (this.state.protectedData.isDrawing) {
76688
76653
  this.state.protectedData.ctxes.drawingLayerMasterCtx.lineCap = "round";
76689
76654
  this.state.protectedData.ctxes.drawingLayerMasterCtx.globalAlpha = 1;
@@ -76692,16 +76657,18 @@ void main() {
76692
76657
  target.ctx.globalAlpha = 1;
76693
76658
  }
76694
76659
  }
76695
- else {
76696
- const currentMode = this.eventRouter.getMode();
76697
- if (currentMode === 'draw') {
76698
- this.drawingTool.renderBrushPreview(this.state.protectedData.ctxes.drawingCtx, this.state.nrrd_states.view.changedWidth, this.state.nrrd_states.view.changedHeight);
76699
- }
76700
- else if (currentMode === 'crosshair' || this.eventRouter.isCrosshairEnabled()) {
76701
- this.crosshairTool.renderCrosshair(this.state.protectedData.ctxes.drawingCtx, this.state.nrrd_states.view.changedWidth, this.state.nrrd_states.view.changedHeight);
76702
- }
76660
+ else if (currentMode === 'crosshair' || this.eventRouter.isCrosshairEnabled()) {
76661
+ this.crosshairTool.renderCrosshair(this.state.protectedData.ctxes.drawingCtx, this.state.nrrd_states.view.changedWidth, this.state.nrrd_states.view.changedHeight);
76703
76662
  }
76704
76663
  this.state.protectedData.ctxes.drawingCtx.drawImage(this.state.protectedData.canvases.drawingCanvasLayerMaster, 0, 0);
76664
+ // Brush/eraser size ring is drawn AFTER the mask composite so it stays
76665
+ // visible during an active stroke (not just on hover) — e.g. while the
76666
+ // user resizes with Shift+wheel mid-paint. Gated on draw mode so it only
76667
+ // shows for brush/eraser with Shift held (renderBrushPreview itself
76668
+ // skips pencil and the no-hover case).
76669
+ if (currentMode === 'draw') {
76670
+ this.drawingTool.renderBrushPreview(this.state.protectedData.ctxes.drawingCtx);
76671
+ }
76705
76672
  if (this.state.gui_states.mode.sphere
76706
76673
  || this.state.gui_states.mode.sphereBrush
76707
76674
  || this.state.gui_states.mode.sphereEraser) {
@@ -78413,7 +78380,6 @@ void main() {
78413
78380
  nrrd_states: this.state.nrrd_states,
78414
78381
  drawingCanvas: this.state.protectedData.canvases.drawingCanvas,
78415
78382
  drawingPrameters: this.drawCore.drawingPrameters,
78416
- eraserUrls: this.drawCore.eraserUrls,
78417
78383
  pencilUrls: this.drawCore.pencilUrls,
78418
78384
  mainPreSlices: this.state.protectedData.mainPreSlices,
78419
78385
  protectedData: this.state.protectedData,
@@ -78446,7 +78412,6 @@ void main() {
78446
78412
  this.guiCallbacks = {
78447
78413
  updatePencilState: this.guiParameterSettings.pencil.onChange,
78448
78414
  updateEraserState: this.guiParameterSettings.eraser.onChange,
78449
- updateBrushAndEraserSize: this.guiParameterSettings.brushAndEraserSize.onChange,
78450
78415
  updateSphereState: this.guiParameterSettings.sphere.onChange,
78451
78416
  updateCalDistance: this.guiParameterSettings.activeSphereType.onChange,
78452
78417
  updateWindowHigh: this.guiParameterSettings.windowHigh.onChange,
@@ -78559,9 +78524,9 @@ void main() {
78559
78524
  return this.state.gui_states.drawing.globalAlpha;
78560
78525
  }
78561
78526
  setBrushSize(size) {
78562
- var _a;
78527
+ // No cursor side-effect needed: the brush/eraser preview ring reads this
78528
+ // value live each frame (see DrawingTool.renderBrushPreview).
78563
78529
  this.state.gui_states.drawing.brushAndEraserSize = Math.max(5, Math.min(50, size));
78564
- (_a = this.guiCallbacks) === null || _a === void 0 ? void 0 : _a.updateBrushAndEraserSize();
78565
78530
  }
78566
78531
  getBrushSize() {
78567
78532
  return this.state.gui_states.drawing.brushAndEraserSize;
@@ -78796,9 +78761,6 @@ void main() {
78796
78761
  enableContrastDragEvents(callback) {
78797
78762
  this.drawCore.setupConrastEvents(callback);
78798
78763
  }
78799
- setEraserUrls(urls) {
78800
- this.drawCore.setEraserUrls(urls);
78801
- }
78802
78764
  setPencilIconUrls(urls) {
78803
78765
  this.drawCore.setPencilIconUrls(urls);
78804
78766
  }
@@ -79488,7 +79450,7 @@ void main() {
79488
79450
  }
79489
79451
 
79490
79452
  // import * as kiwrious from "copper3d_plugin_heart_k";
79491
- const REVISION = "v3.4.6-beta";
79453
+ const REVISION = "v3.4.7-beta";
79492
79454
  console.log(`%cCopper3D Visualisation %cBeta:${REVISION}`, "padding: 3px;color:white; background:#023047", "padding: 3px;color:white; background:#f50a25");
79493
79455
 
79494
79456
  exports.CHANNEL_COLORS = CHANNEL_COLORS;
package/dist/index.d.ts CHANGED
@@ -25,6 +25,6 @@ import type { ToolMode, IAnnotationCallbacks } from "./Utils/segmentation/core/t
25
25
  import { CHANNEL_COLORS, CHANNEL_HEX_COLORS, rgbaToHex, rgbaToCss } from "./Utils/segmentation/core/index";
26
26
  import type { LayerId, ChannelValue } from "./Utils/segmentation/core/index";
27
27
  import "./css/style.css";
28
- export declare const REVISION = "v3.4.6-beta";
28
+ export declare const REVISION = "v3.4.7-beta";
29
29
  export { copperRenderer, copperRendererOnDemond, copperMSceneRenderer, setHDRFilePath, addLabelToScene, convert3DPostoScreenPos, convertScreenPosto3DPos, addBoxHelper, fullScreenListenner, configKiwriousHeart, copperScene, copperSceneOnDemond, copperMScene, CameraViewPoint, kiwrious, NrrdTools, loading, Copper3dTrackballControls, createTexture2D_NRRD, MeshNodeTool, throttle, removeGuiFolderChilden, CHANNEL_COLORS, CHANNEL_HEX_COLORS, rgbaToHex, rgbaToCss, GaussianSmoother, };
30
30
  export type { positionType, screenPosType, optsType, nrrdMeshesType, nrrdSliceType, SensorDecodedValue_kiwrious, SensorReadResult_kiwrious, HeartRateResult_kiwrious, loadingBarType, IPaintImage, exportPaintImageType, IOptVTKLoader, ICommXYZ, IGUIStates, IGuiParameterSettings, INrrdStates, NrrdState, GuiState, IGuiMeta, ToolMode, IAnnotationCallbacks, LayerId, ChannelValue, };
package/dist/index.js CHANGED
@@ -21,7 +21,7 @@ import { MeshNodeTool } from "./Utils/MeshNodeTool";
21
21
  import { removeGuiFolderChilden } from "./Utils/segmentation/coreTools/gui";
22
22
  import { CHANNEL_COLORS, CHANNEL_HEX_COLORS, rgbaToHex, rgbaToCss } from "./Utils/segmentation/core/index";
23
23
  import "./css/style.css";
24
- export const REVISION = "v3.4.6-beta";
24
+ export const REVISION = "v3.4.7-beta";
25
25
  console.log(`%cCopper3D Visualisation %cBeta:${REVISION}`, "padding: 3px;color:white; background:#023047", "padding: 3px;color:white; background:#f50a25");
26
26
  export { copperRenderer, copperRendererOnDemond, copperMSceneRenderer, setHDRFilePath, addLabelToScene, convert3DPostoScreenPos, convertScreenPosto3DPos, addBoxHelper, fullScreenListenner, configKiwriousHeart, copperScene, copperSceneOnDemond, copperMScene, CameraViewPoint, kiwrious, NrrdTools, loading, Copper3dTrackballControls, createTexture2D_NRRD, MeshNodeTool, throttle, removeGuiFolderChilden, CHANNEL_COLORS, CHANNEL_HEX_COLORS, rgbaToHex, rgbaToCss, GaussianSmoother, };
27
27
  //# sourceMappingURL=index.js.map
@@ -30,7 +30,6 @@ export declare class DrawToolCore {
30
30
  readonly renderer: RenderingUtils;
31
31
  drawingPrameters: IDrawingEvents;
32
32
  contrastEventPrameters: IContrastEvents;
33
- eraserUrls: string[];
34
33
  pencilUrls: string[];
35
34
  undoManager: UndoManager;
36
35
  eventRouter: EventRouter;
@@ -59,7 +58,25 @@ export declare class DrawToolCore {
59
58
  constructor(container: HTMLElement, state: CanvasState);
60
59
  private initTools;
61
60
  private initDrawToolCore;
62
- setEraserUrls(urls: string[]): void;
61
+ /**
62
+ * Shift + mouse-wheel resize for the brush and eraser tools.
63
+ *
64
+ * Mirrors the sphereBrush/sphereEraser "scroll to change radius" UX so the
65
+ * user no longer has to reach for the B&E Size slider mid-annotation. Active
66
+ * whenever the EventRouter is in `draw` mode (i.e. Shift is held — with or
67
+ * without the left button down) and the current tool is brush or eraser.
68
+ *
69
+ * Pencil is deliberately excluded: it also draws with Shift, but its stroke
70
+ * width is fixed and unrelated to `brushAndEraserSize`. Sphere-family tools
71
+ * keep their own wheel-radius handler (`activeWheelMode === 'sphereBrush'`).
72
+ *
73
+ * `gui_states.mode` is the source of truth for the active tool here, not
74
+ * `eventRouter.getGuiTool()` — the latter is only updated for sphere tools.
75
+ *
76
+ * @returns true if the event was handled (and should not fall through to
77
+ * the zoom/slice/sphere wheel handlers).
78
+ */
79
+ private tryBrushEraserResizeWheel;
63
80
  setPencilIconUrls(urls: string[]): void;
64
81
  private setCurrentLayer;
65
82
  draw(opts?: IDrawOpts): void;
@@ -110,7 +110,6 @@ export declare class NrrdTools {
110
110
  setBaseDrawDisplayCanvasesSize(size: number): void;
111
111
  setDisplaySliceIndexPanel(panel: HTMLDivElement): void;
112
112
  enableContrastDragEvents(callback: (step: number, towards: "horizental" | "vertical") => void): void;
113
- setEraserUrls(urls: string[]): void;
114
113
  setPencilIconUrls(urls: string[]): void;
115
114
  /**
116
115
  * Switch all contrast slices' orientation
@@ -287,7 +287,6 @@ export interface IGuiParameterSettings {
287
287
  min: number;
288
288
  max: number;
289
289
  step: number;
290
- onChange: () => void;
291
290
  };
292
291
  eraser: {
293
292
  name: "Eraser";
@@ -11,7 +11,6 @@ interface IConfigGUI {
11
11
  drawingCanvas: HTMLCanvasElement;
12
12
  drawingPrameters: IDrawingEvents;
13
13
  protectedData: IProtected;
14
- eraserUrls: string[];
15
14
  pencilUrls: string[];
16
15
  getVolumeForLayer: (layer: string) => any;
17
16
  mainPreSlices: any;
@@ -65,9 +65,16 @@ export declare class DrawingTool extends BaseTool {
65
65
  */
66
66
  createBrushTrackingHandler(): (e: MouseEvent) => void;
67
67
  /**
68
- * Render brush circle preview on the drawing context.
68
+ * Render the size-preview ring for the brush / eraser on the drawing context.
69
+ *
70
+ * - Brush: solid outline in the current brush colour.
71
+ * - Eraser: red dashed outline (matches the sphereEraser preview), so the
72
+ * eraser no longer needs a sized PNG cursor — the ring tracks the live
73
+ * `brushAndEraserSize` and is what the user resizes with Shift+wheel.
74
+ *
75
+ * Only the pencil has no preview ring (its stroke width is fixed).
69
76
  */
70
- renderBrushPreview(ctx: CanvasRenderingContext2D, width: number, height: number): void;
77
+ renderBrushPreview(ctx: CanvasRenderingContext2D, _width?: number, _height?: number): void;
71
78
  /**
72
79
  * Convert display (zoomed) coordinates to 3D voxel coordinates.
73
80
  * Same logic as SphereBrushTool.canvasToVoxelCenter.
@@ -41,7 +41,6 @@ export interface ToolHost {
41
41
  } | undefined;
42
42
  pushUndoDelta(delta: MaskDelta): void;
43
43
  pushUndoGroup(deltas: MaskDelta[]): void;
44
- getEraserUrls(): string[];
45
44
  enableCrosshair(): void;
46
45
  setUpSphereOrigins(mouseX: number, mouseY: number, sliceIndex: number): void;
47
46
  zoomActionAfterDrawSphere(): void;
@@ -64,7 +63,7 @@ export type ZoomHostDeps = Pick<ToolHost, 'resetPaintAreaUIPosition' | 'resizePa
64
63
  /** SphereTool host dependencies */
65
64
  export type SphereHostDeps = Pick<ToolHost, 'setEmptyCanvasSize' | 'drawImageOnEmptyImage' | 'enableCrosshair' | 'setUpSphereOrigins'>;
66
65
  /** DrawingTool host dependencies */
67
- export type DrawingHostDeps = Pick<ToolHost, 'setCurrentLayer' | 'compositeAllLayers' | 'syncLayerSliceData' | 'filterDrawedImage' | 'getVolumeForLayer' | 'pushUndoDelta' | 'getEraserUrls' | 'renderSliceToCanvas' | 'getOrCreateSliceBuffer'>;
66
+ export type DrawingHostDeps = Pick<ToolHost, 'setCurrentLayer' | 'compositeAllLayers' | 'syncLayerSliceData' | 'filterDrawedImage' | 'getVolumeForLayer' | 'pushUndoDelta' | 'renderSliceToCanvas' | 'getOrCreateSliceBuffer'>;
68
67
  /** DragSliceTool host dependencies */
69
68
  export type DragSliceHostDeps = Pick<ToolHost, 'setSyncsliceNum' | 'setIsDrawFalse' | 'flipDisplayImageByAxis' | 'setEmptyCanvasSize' | 'getOrCreateSliceBuffer' | 'renderSliceToCanvas' | 'refreshSphereOverlay' | 'compositeAllLayers'>;
70
69
  /** LayerChannelManager host dependencies */
@@ -74,4 +73,4 @@ export type SliceRenderHostDeps = Pick<ToolHost, 'compositeAllLayers' | 'getOrCr
74
73
  /** DataLoader host dependencies */
75
74
  export type DataLoaderHostDeps = Pick<ToolHost, 'invalidateSliceBuffer' | 'setDisplaySlicesBaseOnAxis' | 'afterLoadSlice' | 'setEmptyCanvasSize' | 'syncLayerSliceData' | 'reloadMasksFromVolume' | 'resetZoom'>;
76
75
  /** SphereBrushTool host dependencies */
77
- export type SphereBrushHostDeps = Pick<ToolHost, 'getVolumeForLayer' | 'compositeAllLayers' | 'pushUndoGroup' | 'renderSliceToCanvas' | 'getOrCreateSliceBuffer' | 'setEmptyCanvasSize' | 'reloadMasksFromVolume' | 'getEraserUrls'>;
76
+ export type SphereBrushHostDeps = Pick<ToolHost, 'getVolumeForLayer' | 'compositeAllLayers' | 'pushUndoGroup' | 'renderSliceToCanvas' | 'getOrCreateSliceBuffer' | 'setEmptyCanvasSize' | 'reloadMasksFromVolume'>;
@@ -7,7 +7,6 @@ export declare function loading(loadingGif?: string): {
7
7
  progress: HTMLDivElement;
8
8
  };
9
9
  export declare function switchPencilIcon(icon: string, urls?: string[]): string;
10
- export declare function switchEraserSize(size: number, urls?: string[]): string;
11
10
  export declare function throttle(callback: (event: MouseEvent) => void, wait: number): (event: MouseEvent) => void;
12
11
  /**
13
12
  * Cubic-Lagrange basis function
@@ -25,6 +25,6 @@ import type { ToolMode, IAnnotationCallbacks } from "./Utils/segmentation/core/t
25
25
  import { CHANNEL_COLORS, CHANNEL_HEX_COLORS, rgbaToHex, rgbaToCss } from "./Utils/segmentation/core/index";
26
26
  import type { LayerId, ChannelValue } from "./Utils/segmentation/core/index";
27
27
  import "./css/style.css";
28
- export declare const REVISION = "v3.4.6-beta";
28
+ export declare const REVISION = "v3.4.7-beta";
29
29
  export { copperRenderer, copperRendererOnDemond, copperMSceneRenderer, setHDRFilePath, addLabelToScene, convert3DPostoScreenPos, convertScreenPosto3DPos, addBoxHelper, fullScreenListenner, configKiwriousHeart, copperScene, copperSceneOnDemond, copperMScene, CameraViewPoint, kiwrious, NrrdTools, loading, Copper3dTrackballControls, createTexture2D_NRRD, MeshNodeTool, throttle, removeGuiFolderChilden, CHANNEL_COLORS, CHANNEL_HEX_COLORS, rgbaToHex, rgbaToCss, GaussianSmoother, };
30
30
  export type { positionType, screenPosType, optsType, nrrdMeshesType, nrrdSliceType, SensorDecodedValue_kiwrious, SensorReadResult_kiwrious, HeartRateResult_kiwrious, loadingBarType, IPaintImage, exportPaintImageType, IOptVTKLoader, ICommXYZ, IGUIStates, IGuiParameterSettings, INrrdStates, NrrdState, GuiState, IGuiMeta, ToolMode, IAnnotationCallbacks, LayerId, ChannelValue, };
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "copper3d",
3
3
  "description": "A 3d visualisation package base on threejs provides multiple scenes and Nrrd image load funtion.",
4
- "version": "3.4.6",
4
+ "version": "3.4.7",
5
5
  "main": "dist/bundle.umd.js",
6
6
  "moudle": "dist/bundle.esm.js",
7
7
  "types": "dist/types/index.d.ts",