@niivue/niivue 0.44.2-dev.1 → 0.44.2-dev.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/dist/index.d.ts CHANGED
@@ -678,8 +678,10 @@ type NVConfigOptions = {
678
678
  clickToSegmentIntensityMin: number;
679
679
  clickToSegmentPercent: number;
680
680
  clickToSegmentMaxDistanceMM: number;
681
+ clickToSegmentIs2D: boolean;
681
682
  selectionBoxLineThickness: number;
682
683
  selectionBoxIsOutline: boolean;
684
+ scrollRequiresFocus: boolean;
683
685
  };
684
686
  declare const DEFAULT_OPTIONS: NVConfigOptions;
685
687
  type SceneData = {
@@ -1704,6 +1706,9 @@ declare class Niivue {
1704
1706
  drawUndoBitmaps: Uint8Array[];
1705
1707
  drawLut: LUT;
1706
1708
  drawOpacity: number;
1709
+ clickToSegmentIsGrowing: boolean;
1710
+ clickToSegmentGrowingBitmap: Uint8Array | null;
1711
+ clickToSegmentXY: number[];
1707
1712
  renderDrawAmbientOcclusion: number;
1708
1713
  colorbarHeight: number;
1709
1714
  drawPenLocation: number[];
@@ -2736,7 +2741,7 @@ declare class Niivue {
2736
2741
  neighbors?: 6 | 18 | 26): void;
2737
2742
  drawFloodFillCore(img: Uint8Array, seedVx: number, neighbors?: number): void;
2738
2743
  drawFloodFill(seedXYZ: number[], newColor?: number, growSelectedCluster?: number, // if non-zero, growth based on background intensity POSITIVE_INFINITY for selected or bright, NEGATIVE_INFINITY for selected or darker
2739
- forceMin?: number, forceMax?: number, neighbors?: number, maxDistanceMM?: number): void;
2744
+ forceMin?: number, forceMax?: number, neighbors?: number, maxDistanceMM?: number, is2D?: boolean): void;
2740
2745
  drawPenFilled(): void;
2741
2746
  /**
2742
2747
  * close drawing: make sure you have saved any changes before calling this!
@@ -2750,7 +2755,7 @@ declare class Niivue {
2750
2755
  * @example niivue.refreshDrawing();
2751
2756
  * @see {@link https://niivue.github.io/niivue/features/cactus.html | live demo usage}
2752
2757
  */
2753
- refreshDrawing(isForceRedraw?: boolean): void;
2758
+ refreshDrawing(isForceRedraw?: boolean, useClickToSegmentBitmap?: boolean): void;
2754
2759
  r8Tex(texID: WebGLTexture | null, activeID: number, dims: number[], isInit?: boolean): WebGLTexture | null;
2755
2760
  rgbaTex(texID: WebGLTexture | null, activeID: number, dims: number[], isInit?: boolean): WebGLTexture | null;
2756
2761
  requestCORSIfNotSameOrigin(img: HTMLImageElement, url: string): void;
@@ -3009,6 +3014,8 @@ declare class Niivue {
3009
3014
  sliceScroll3D(posChange?: number): void;
3010
3015
  deleteThumbnail(): void;
3011
3016
  inGraphTile(x: number, y: number): boolean;
3017
+ updateBitmapFromClickToSegment(): void;
3018
+ sumBitmap(img: Uint8Array): number;
3012
3019
  mouseClick(x: number, y: number, posChange?: number, isDelta?: boolean): void;
3013
3020
  drawRuler(): void;
3014
3021
  drawRuler10cm(startXYendXY: number[]): void;
package/dist/index.js CHANGED
@@ -119283,8 +119283,11 @@ var DEFAULT_OPTIONS = {
119283
119283
  clickToSegmentPercent: 0,
119284
119284
  clickToSegmentMaxDistanceMM: Number.POSITIVE_INFINITY,
119285
119285
  // default value is infinity for backwards compatibility with flood fill routine.
119286
+ clickToSegmentIs2D: false,
119286
119287
  selectionBoxLineThickness: 4,
119287
- selectionBoxIsOutline: false
119288
+ selectionBoxIsOutline: false,
119289
+ scrollRequiresFocus: false
119290
+ // determines if the cavas need to be focused to scroll
119288
119291
  };
119289
119292
  var INITIAL_SCENE_DATA = {
119290
119293
  gamma: 1,
@@ -121008,6 +121011,12 @@ var Niivue = class {
121008
121011
  // the color lookup table for drawing
121009
121012
  __publicField(this, "drawOpacity", 0.8);
121010
121013
  // opacity of drawing (default)
121014
+ __publicField(this, "clickToSegmentIsGrowing", false);
121015
+ // flag to indicate if the clickToSegment flood fill growing is in progress with left mouse down + drag
121016
+ __publicField(this, "clickToSegmentGrowingBitmap", null);
121017
+ // the bitmap of the growing flood fill
121018
+ __publicField(this, "clickToSegmentXY", [0, 0]);
121019
+ // the x,y location of the clickToSegment flood fill
121011
121020
  __publicField(this, "renderDrawAmbientOcclusion", 0.4);
121012
121021
  __publicField(this, "colorbarHeight", 0);
121013
121022
  // height in pixels, set when colorbar is drawn
@@ -121780,6 +121789,8 @@ var Niivue = class {
121780
121789
  this.drawPenLocation = [NaN, NaN, NaN];
121781
121790
  this.drawPenAxCorSag = -1;
121782
121791
  this.uiData.mousedown = true;
121792
+ this.setDragStart(0, 0);
121793
+ this.setDragEnd(0, 0);
121783
121794
  log.debug("mouse down");
121784
121795
  log.debug(e);
121785
121796
  const pos = this.getNoPaddingNoBorderCanvasRelativeMousePosition(e, this.gl.canvas);
@@ -121787,6 +121798,9 @@ var Niivue = class {
121787
121798
  return;
121788
121799
  }
121789
121800
  const [x, y] = [pos.x * this.uiData.dpr, pos.y * this.uiData.dpr];
121801
+ if (this.opts.clickToSegment) {
121802
+ this.clickToSegmentXY = [x, y];
121803
+ }
121790
121804
  const label = this.getLabelAtPoint([x, y]);
121791
121805
  if (label) {
121792
121806
  if (label.onClick) {
@@ -121987,8 +122001,15 @@ var Niivue = class {
121987
122001
  if (this.drawPenFillPts.length > 0) {
121988
122002
  this.drawPenFilled();
121989
122003
  } else if (this.drawPenAxCorSag >= 0) {
121990
- this.drawAddUndoBitmap();
122004
+ if (this.opts.clickToSegment) {
122005
+ const sumBitmap = this.sumBitmap(this.drawBitmap);
122006
+ const sumSeg = this.sumBitmap(this.clickToSegmentGrowingBitmap);
122007
+ if (sumSeg > sumBitmap) {
122008
+ this.updateBitmapFromClickToSegment();
122009
+ }
122010
+ }
121991
122011
  }
122012
+ this.drawAddUndoBitmap();
121992
122013
  this.drawPenLocation = [NaN, NaN, NaN];
121993
122014
  this.drawPenAxCorSag = -1;
121994
122015
  if (isFunction(this.onMouseUp)) {
@@ -122307,6 +122328,35 @@ var Niivue = class {
122307
122328
  if (this.thumbnailVisible) {
122308
122329
  return;
122309
122330
  }
122331
+ const dragStartSum = this.uiData.dragStart.reduce((a, b) => a + b, 0);
122332
+ const dragEndSum = this.uiData.dragEnd.reduce((a, b) => a + b, 0);
122333
+ const validDrag = dragStartSum > 0 && dragEndSum > 0;
122334
+ if (this.opts.dragMode === 6 /* roiSelection */ && validDrag) {
122335
+ const delta = e.deltaY > 0 ? 1 : -1;
122336
+ if (this.uiData.dragStart[0] < this.uiData.dragEnd[0]) {
122337
+ this.uiData.dragStart[0] -= delta;
122338
+ this.uiData.dragEnd[0] += delta;
122339
+ } else {
122340
+ this.uiData.dragStart[0] += delta;
122341
+ this.uiData.dragEnd[0] -= delta;
122342
+ }
122343
+ if (this.uiData.dragStart[1] < this.uiData.dragEnd[1]) {
122344
+ this.uiData.dragStart[1] -= delta;
122345
+ this.uiData.dragEnd[1] += delta;
122346
+ } else {
122347
+ this.uiData.dragStart[1] += delta;
122348
+ this.uiData.dragEnd[1] -= delta;
122349
+ }
122350
+ this.uiData.isDragging = true;
122351
+ this.drawScene();
122352
+ this.uiData.isDragging = false;
122353
+ const tileIdx = this.tileIndex(this.uiData.dragStart[0], this.uiData.dragStart[1]);
122354
+ this.generateMouseUpCallback(
122355
+ this.screenXY2TextureFrac(this.uiData.dragStart[0], this.uiData.dragStart[1], tileIdx),
122356
+ this.screenXY2TextureFrac(this.uiData.dragEnd[0], this.uiData.dragEnd[1], tileIdx)
122357
+ );
122358
+ return;
122359
+ }
122310
122360
  const rect = this.canvas.getBoundingClientRect();
122311
122361
  if (e.deltaY < 0) {
122312
122362
  this.sliceScroll2D(-0.01, e.clientX - rect.left, e.clientY - rect.top);
@@ -123739,6 +123789,10 @@ var Niivue = class {
123739
123789
  }
123740
123790
  // not included in public docs
123741
123791
  sliceScroll2D(posChange, x, y, isDelta = true) {
123792
+ if (this.opts.scrollRequiresFocus && this.canvas !== document.activeElement) {
123793
+ log.warn("Canvas element does not have focus. Scroll events will not be processed.");
123794
+ return;
123795
+ }
123742
123796
  if (this.inGraphTile(x, y)) {
123743
123797
  let vol = this.volumes[0].frame4D;
123744
123798
  if (posChange > 0) {
@@ -124403,6 +124457,7 @@ var Niivue = class {
124403
124457
  }
124404
124458
  const vx = this.back.dims[1] * this.back.dims[2] * this.back.dims[3];
124405
124459
  this.drawBitmap = new Uint8Array(vx);
124460
+ this.clickToSegmentGrowingBitmap = new Uint8Array(vx);
124406
124461
  this.drawClearAllUndoBitmaps();
124407
124462
  this.drawAddUndoBitmap();
124408
124463
  this.drawTexture = this.r8Tex(this.drawTexture, TEXTURE7_DRAW, this.back.dims, true);
@@ -124847,7 +124902,7 @@ var Niivue = class {
124847
124902
  }
124848
124903
  // not included in public docs
124849
124904
  // set all connected voxels in drawing to new color
124850
- drawFloodFill(seedXYZ, newColor = 0, growSelectedCluster = 0, forceMin = NaN, forceMax = NaN, neighbors = 6, maxDistanceMM = Number.POSITIVE_INFINITY) {
124905
+ drawFloodFill(seedXYZ, newColor = 0, growSelectedCluster = 0, forceMin = NaN, forceMax = NaN, neighbors = 6, maxDistanceMM = Number.POSITIVE_INFINITY, is2D = false) {
124851
124906
  if (!this.drawBitmap) {
124852
124907
  throw new Error("drawBitmap undefined");
124853
124908
  }
@@ -124865,10 +124920,23 @@ var Niivue = class {
124865
124920
  const nx = dims[0];
124866
124921
  const nxy = nx * dims[1];
124867
124922
  const nxyz = nxy * dims[2];
124868
- const img = this.drawBitmap.slice();
124923
+ let img = this.drawBitmap.slice();
124924
+ let drawBitmap = this.drawBitmap;
124925
+ if (this.clickToSegmentIsGrowing) {
124926
+ img = this.clickToSegmentGrowingBitmap.slice();
124927
+ drawBitmap = this.clickToSegmentGrowingBitmap;
124928
+ }
124869
124929
  if (img.length !== nxy * dims[2]) {
124870
124930
  return;
124871
124931
  }
124932
+ let constrainXYZ = -1;
124933
+ if (is2D && this.drawPenAxCorSag === 0 /* AXIAL */) {
124934
+ constrainXYZ = 2;
124935
+ } else if (is2D && this.drawPenAxCorSag === 1 /* CORONAL */) {
124936
+ constrainXYZ = 1;
124937
+ } else if (is2D && this.drawPenAxCorSag === 2 /* SAGITTAL */) {
124938
+ constrainXYZ = 0;
124939
+ }
124872
124940
  function vx2xyz(vx) {
124873
124941
  const Z = Math.floor(vx / nxy);
124874
124942
  const Y = Math.floor((vx - Z * nxy) / nx);
@@ -124884,7 +124952,11 @@ var Niivue = class {
124884
124952
  const seedMM = vx2mm(seedXYZ);
124885
124953
  const maxDistanceMM2 = maxDistanceMM ** 2;
124886
124954
  function isWithinDistance(vx) {
124887
- const xyzMM = vx2mm(vx2xyz(vx));
124955
+ const xzyVox = vx2xyz(vx);
124956
+ if (constrainXYZ >= 0 && xzyVox[constrainXYZ] !== seedXYZ[constrainXYZ]) {
124957
+ return false;
124958
+ }
124959
+ const xyzMM = vx2mm(xzyVox);
124888
124960
  const dist22 = (xyzMM[0] - seedMM[0]) ** 2 + (xyzMM[1] - seedMM[1]) ** 2 + (xyzMM[2] - seedMM[2]) ** 2;
124889
124961
  return dist22 <= maxDistanceMM2;
124890
124962
  }
@@ -124900,7 +124972,7 @@ var Niivue = class {
124900
124972
  }
124901
124973
  for (let i2 = 1; i2 < nxyz; i2++) {
124902
124974
  img[i2] = 0;
124903
- if (this.drawBitmap[i2] === seedColor) {
124975
+ if (drawBitmap[i2] === seedColor) {
124904
124976
  if (!isWithinDistance(i2)) {
124905
124977
  continue;
124906
124978
  }
@@ -124944,11 +125016,19 @@ var Niivue = class {
124944
125016
  }
124945
125017
  for (let i2 = 1; i2 < nxyz; i2++) {
124946
125018
  if (img[i2] === 2) {
124947
- this.drawBitmap[i2] = newColor;
125019
+ drawBitmap[i2] = newColor;
124948
125020
  }
124949
125021
  }
124950
- this.drawAddUndoBitmap();
124951
- this.refreshDrawing(false);
125022
+ if (!this.clickToSegmentIsGrowing) {
125023
+ this.drawBitmap = drawBitmap.slice();
125024
+ if (!this.opts.clickToSegment) {
125025
+ this.drawAddUndoBitmap();
125026
+ }
125027
+ this.refreshDrawing(true, this.clickToSegmentIsGrowing);
125028
+ } else {
125029
+ this.clickToSegmentGrowingBitmap = drawBitmap;
125030
+ this.refreshDrawing(true, this.clickToSegmentIsGrowing);
125031
+ }
124952
125032
  }
124953
125033
  // not included in public docs
124954
125034
  // given series of line segments, connect first and last
@@ -125108,6 +125188,7 @@ var Niivue = class {
125108
125188
  this.drawClearAllUndoBitmaps();
125109
125189
  this.rgbaTex(this.drawTexture, TEXTURE7_DRAW, [2, 2, 2, 2], true);
125110
125190
  this.drawBitmap = null;
125191
+ this.clickToSegmentGrowingBitmap = null;
125111
125192
  this.drawScene();
125112
125193
  }
125113
125194
  /**
@@ -125116,7 +125197,7 @@ var Niivue = class {
125116
125197
  * @example niivue.refreshDrawing();
125117
125198
  * @see {@link https://niivue.github.io/niivue/features/cactus.html | live demo usage}
125118
125199
  */
125119
- refreshDrawing(isForceRedraw = true) {
125200
+ refreshDrawing(isForceRedraw = true, useClickToSegmentBitmap = false) {
125120
125201
  if (!this.back?.dims) {
125121
125202
  throw new Error("back.dims undefined");
125122
125203
  }
@@ -125145,7 +125226,7 @@ var Niivue = class {
125145
125226
  dims[3],
125146
125227
  this.gl.RED,
125147
125228
  this.gl.UNSIGNED_BYTE,
125148
- this.drawBitmap
125229
+ useClickToSegmentBitmap ? this.clickToSegmentGrowingBitmap : this.drawBitmap
125149
125230
  );
125150
125231
  if (isForceRedraw) {
125151
125232
  this.drawScene();
@@ -125783,33 +125864,61 @@ var Niivue = class {
125783
125864
  mask.fill(0);
125784
125865
  console.log("startVox", startVox);
125785
125866
  console.log("endVox", endVox);
125786
- const xrange = this.calculateMinMaxVoxIdx([startVox[0], endVox[0]]);
125787
- const yrange = this.calculateMinMaxVoxIdx([startVox[1], endVox[1]]);
125788
- const zrange = this.calculateMinMaxVoxIdx([startVox[2], endVox[2]]);
125789
- if (startVox[0] - endVox[0] === 0) {
125790
- xrange[1] = startVox[0] + 1;
125791
- } else if (startVox[1] - endVox[1] === 0) {
125792
- yrange[1] = startVox[1] + 1;
125793
- } else if (startVox[2] - endVox[2] === 0) {
125794
- zrange[1] = startVox[2] + 1;
125867
+ let constantDim = -1;
125868
+ if (startVox[0] === endVox[0]) {
125869
+ constantDim = 0;
125870
+ } else if (startVox[1] === endVox[1]) {
125871
+ constantDim = 1;
125872
+ } else if (startVox[2] === endVox[2]) {
125873
+ constantDim = 2;
125874
+ } else {
125875
+ console.error("Error: No constant dimension found.");
125876
+ return;
125795
125877
  }
125878
+ const dims = [0, 1, 2];
125879
+ const varDims = dims.filter((dim) => dim !== constantDim);
125880
+ const centerVox = [];
125881
+ centerVox[constantDim] = startVox[constantDim];
125882
+ centerVox[varDims[0]] = (startVox[varDims[0]] + endVox[varDims[0]]) / 2;
125883
+ centerVox[varDims[1]] = (startVox[varDims[1]] + endVox[varDims[1]]) / 2;
125884
+ const radiusX = Math.abs(endVox[varDims[0]] - startVox[varDims[0]]) / 2;
125885
+ const radiusY = Math.abs(endVox[varDims[1]] - startVox[varDims[1]]) / 2;
125796
125886
  const xdim = hdr.dims[1];
125797
125887
  const ydim = hdr.dims[2];
125798
- for (let z = zrange[0]; z < zrange[1]; z++) {
125799
- const zi = z * xdim * ydim;
125800
- for (let y = yrange[0]; y < yrange[1]; y++) {
125801
- const yi = y * xdim;
125802
- for (let x = xrange[0]; x < xrange[1]; x++) {
125803
- const index = zi + yi + x;
125888
+ const minVarDim0 = Math.max(0, Math.floor(centerVox[varDims[0]] - radiusX));
125889
+ const maxVarDim0 = Math.min(hdr.dims[varDims[0] + 1] - 1, Math.ceil(centerVox[varDims[0]] + radiusX));
125890
+ const minVarDim1 = Math.max(0, Math.floor(centerVox[varDims[1]] - radiusY));
125891
+ const maxVarDim1 = Math.min(hdr.dims[varDims[1] + 1] - 1, Math.ceil(centerVox[varDims[1]] + radiusY));
125892
+ const constDimVal = centerVox[constantDim];
125893
+ if (constDimVal < 0 || constDimVal >= hdr.dims[constantDim + 1]) {
125894
+ console.error("Error: Constant dimension value is out of bounds.");
125895
+ return;
125896
+ }
125897
+ for (let i2 = minVarDim0; i2 <= maxVarDim0; i2++) {
125898
+ for (let j = minVarDim1; j <= maxVarDim1; j++) {
125899
+ const voxel = [];
125900
+ voxel[constantDim] = constDimVal;
125901
+ voxel[varDims[0]] = i2;
125902
+ voxel[varDims[1]] = j;
125903
+ const di = (voxel[varDims[0]] - centerVox[varDims[0]]) / radiusX;
125904
+ const dj = (voxel[varDims[1]] - centerVox[varDims[1]]) / radiusY;
125905
+ const distSq = di * di + dj * dj;
125906
+ if (distSq <= 1) {
125907
+ const x = voxel[0];
125908
+ const y = voxel[1];
125909
+ const z = voxel[2];
125910
+ const index = z * xdim * ydim + y * xdim + x;
125804
125911
  mask[index] = 1;
125805
125912
  }
125806
125913
  }
125807
125914
  }
125808
- const xmm = Math.abs(pixDimsRAS[1] * (endVox[0] - startVox[0]));
125809
- const ymm = Math.abs(pixDimsRAS[2] * (endVox[1] - startVox[1]));
125810
- const zmm = Math.abs(pixDimsRAS[3] * (endVox[2] - startVox[2]));
125811
- const mms = [xmm, ymm, zmm];
125812
- area = mms.filter((m) => m !== 0).reduce((a, b) => a * b, 1);
125915
+ const voxelArea = pixDimsRAS[varDims[0] + 1] * pixDimsRAS[varDims[1] + 1];
125916
+ const numMaskedVoxels = mask.reduce((count, value) => count + (value === 1 ? 1 : 0), 0);
125917
+ area = numMaskedVoxels * voxelArea;
125918
+ const radiusX_mm = radiusX * pixDimsRAS[varDims[0] + 1];
125919
+ const radiusY_mm = radiusY * pixDimsRAS[varDims[1] + 1];
125920
+ const areaEllipse = Math.PI * radiusX_mm * radiusY_mm;
125921
+ area = areaEllipse;
125813
125922
  }
125814
125923
  let k = 0;
125815
125924
  let M = 0;
@@ -127342,6 +127451,29 @@ var Niivue = class {
127342
127451
  const pos = [(x - this.graph.LTWH[0]) / this.graph.LTWH[2], (y - this.graph.LTWH[1]) / this.graph.LTWH[3]];
127343
127452
  return pos[0] > 0 && pos[1] > 0 && pos[0] <= 1 && pos[1] <= 1;
127344
127453
  }
127454
+ // update drawBitmap if it differs from clickTosegmentBitmap
127455
+ updateBitmapFromClickToSegment() {
127456
+ if (this.clickToSegmentGrowingBitmap === null) {
127457
+ return;
127458
+ }
127459
+ if (this.drawBitmap === null) {
127460
+ return;
127461
+ }
127462
+ if (this.clickToSegmentGrowingBitmap.length !== this.drawBitmap.length) {
127463
+ return;
127464
+ }
127465
+ const nvx = this.drawBitmap.length;
127466
+ for (let i2 = 0; i2 < nvx; i2++) {
127467
+ this.drawBitmap[i2] = this.clickToSegmentGrowingBitmap[i2];
127468
+ }
127469
+ }
127470
+ sumBitmap(img) {
127471
+ let sum = 0;
127472
+ for (let i2 = 0; i2 < img.length; i2++) {
127473
+ sum += img[i2];
127474
+ }
127475
+ return sum;
127476
+ }
127345
127477
  // not included in public docs
127346
127478
  // handle mouse click event on canvas
127347
127479
  mouseClick(x, y, posChange = 0, isDelta = true) {
@@ -127391,7 +127523,7 @@ var Niivue = class {
127391
127523
  if (axCorSag > 2 /* SAGITTAL */) {
127392
127524
  continue;
127393
127525
  }
127394
- const texFrac = this.screenXY2TextureFrac(x, y, i2, false);
127526
+ let texFrac = this.screenXY2TextureFrac(x, y, i2, false);
127395
127527
  if (texFrac[0] < 0) {
127396
127528
  continue;
127397
127529
  }
@@ -127418,14 +127550,28 @@ var Niivue = class {
127418
127550
  this.scene.crosshairPos = vec3_exports.clone(texFrac);
127419
127551
  }
127420
127552
  if (this.opts.drawingEnabled) {
127421
- const pt = this.frac2vox(this.scene.crosshairPos);
127553
+ let pt = this.frac2vox(this.scene.crosshairPos);
127422
127554
  if (this.opts.clickToSegment) {
127423
- const voxelIntensity = this.back.getValue(pt[0], pt[1], pt[2]);
127424
- if (this.opts.clickToSegmentPercent > 0 && this.opts.clickToSegmentPercent <= 1) {
127425
- this.opts.clickToSegmentIntensityMax = voxelIntensity * (1 + this.opts.clickToSegmentPercent);
127426
- this.opts.clickToSegmentIntensityMin = voxelIntensity * (1 - this.opts.clickToSegmentPercent);
127427
- }
127555
+ texFrac = this.screenXY2TextureFrac(this.clickToSegmentXY[0], this.clickToSegmentXY[1], i2, false);
127556
+ pt = this.frac2vox(texFrac);
127557
+ let diff = 0;
127558
+ let threshold = this.opts.clickToSegmentPercent + diff;
127559
+ if (this.uiData.mousedown) {
127560
+ const xDiff = (this.clickToSegmentXY[0] - x) / this.gl.canvas.width;
127561
+ const yDiff = (this.clickToSegmentXY[1] - y) / this.gl.canvas.height;
127562
+ diff = Math.max(Math.abs(xDiff), Math.abs(yDiff));
127563
+ diff *= Math.sign(Math.abs(xDiff) > Math.abs(yDiff) ? xDiff : yDiff);
127564
+ threshold = this.opts.clickToSegmentPercent + diff;
127565
+ }
127566
+ let voxelIntensity = this.back.getValue(pt[0], pt[1], pt[2]);
127428
127567
  if (this.opts.clickToSegmentAutoIntensity) {
127568
+ if (threshold !== 0) {
127569
+ if (voxelIntensity === 0) {
127570
+ voxelIntensity = 0.01;
127571
+ }
127572
+ this.opts.clickToSegmentIntensityMax = voxelIntensity * (1 + threshold);
127573
+ this.opts.clickToSegmentIntensityMin = voxelIntensity * (1 - threshold);
127574
+ }
127429
127575
  if (voxelIntensity > (this.back.cal_min + this.back.cal_max) * 0.5) {
127430
127576
  this.opts.clickToSegmentBright = true;
127431
127577
  } else {
@@ -127448,6 +127594,12 @@ var Niivue = class {
127448
127594
  this.opts.penSize = Math.ceil(this.opts.clickToSegmentRadius / minPixDim);
127449
127595
  }
127450
127596
  this.drawPt(pt[0], pt[1], pt[2], this.opts.penValue);
127597
+ if (diff !== 0) {
127598
+ this.clickToSegmentIsGrowing = true;
127599
+ this.clickToSegmentGrowingBitmap = this.drawBitmap.slice();
127600
+ } else {
127601
+ this.clickToSegmentIsGrowing = false;
127602
+ }
127451
127603
  this.drawFloodFill(
127452
127604
  [pt[0], pt[1], pt[2]],
127453
127605
  0,
@@ -127455,10 +127607,14 @@ var Niivue = class {
127455
127607
  this.opts.clickToSegmentIntensityMin,
127456
127608
  this.opts.clickToSegmentIntensityMax,
127457
127609
  this.opts.floodFillNeighbors,
127458
- this.opts.clickToSegmentMaxDistanceMM
127610
+ this.opts.clickToSegmentMaxDistanceMM,
127611
+ this.opts.clickToSegmentIs2D
127459
127612
  );
127460
127613
  this.drawScene();
127461
127614
  this.createOnLocationChange(axCorSag);
127615
+ if (this.clickToSegmentIsGrowing) {
127616
+ return;
127617
+ }
127462
127618
  const info = this.getDescriptives({
127463
127619
  layer: 0,
127464
127620
  masks: [],
@@ -127697,6 +127853,7 @@ var Niivue = class {
127697
127853
  this.gl.drawArrays(this.gl.TRIANGLE_STRIP, 0, 4);
127698
127854
  this.gl.bindVertexArray(this.unusedVAO);
127699
127855
  } else {
127856
+ this.drawCircle(leftTopWidthHeight, lineColor, 0.1);
127700
127857
  this.rectOutlineShader.use(this.gl);
127701
127858
  this.gl.enable(this.gl.BLEND);
127702
127859
  this.gl.uniform1f(this.rectOutlineShader.uniforms.thickness, this.opts.selectionBoxLineThickness);
@@ -127741,6 +127898,10 @@ var Niivue = class {
127741
127898
  // not included in public docs
127742
127899
  // draw a rectangle at desired location
127743
127900
  drawSelectionBox(leftTopWidthHeight) {
127901
+ if (this.opts.dragMode === 6 /* roiSelection */) {
127902
+ this.drawCircle(leftTopWidthHeight, this.opts.selectionBoxColor, 0.1);
127903
+ return;
127904
+ }
127744
127905
  this.drawRect(leftTopWidthHeight, this.opts.selectionBoxColor);
127745
127906
  }
127746
127907
  // not included in public docs