@niivue/niivue 0.43.5 → 0.43.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.
package/build/index.d.ts CHANGED
@@ -645,6 +645,11 @@ type NVConfigOptions = {
645
645
  multiplanarLayout: MULTIPLANAR_TYPE;
646
646
  renderOverlayBlend: number;
647
647
  sliceMosaicString: string;
648
+ centerMosaic: boolean;
649
+ clickToSegment: boolean;
650
+ clickToSegmentRadius: number;
651
+ clickToSegmentSteps: number;
652
+ clickToSegmentBright: boolean;
648
653
  };
649
654
  declare const DEFAULT_OPTIONS: NVConfigOptions;
650
655
  type SceneData = {
@@ -1687,7 +1692,6 @@ declare class Niivue {
1687
1692
  private resizeObserver;
1688
1693
  syncOpts: Record<string, unknown>;
1689
1694
  readyForSync: boolean;
1690
- centerMosaic: boolean;
1691
1695
  uiData: UIData;
1692
1696
  back: NVImage | null;
1693
1697
  overlays: NVImage[];
@@ -1773,6 +1777,19 @@ declare class Niivue {
1773
1777
  * }
1774
1778
  */
1775
1779
  onIntensityChange: (volume: NVImage) => void;
1780
+ /**
1781
+ * callback function when clickToSegment is enabled and the user clicks on the image. data contains the volume of the segmented region in mm3 and mL
1782
+ * @example
1783
+ * niivue.onClickToSegment = (data) => {
1784
+ * console.log('clicked to segment')
1785
+ * console.log('volume mm3: ', data.mm3)
1786
+ * console.log('volume mL: ', data.mL)
1787
+ * }
1788
+ */
1789
+ onClickToSegment: (data: {
1790
+ mm3: number;
1791
+ mL: number;
1792
+ }) => void;
1776
1793
  /**
1777
1794
  * callback function to run when a new volume is loaded
1778
1795
  * @example
package/build/index.js CHANGED
@@ -13,7 +13,7 @@ var __publicField = (obj, key, value) => {
13
13
  import { mat4 as mat46, vec2, vec3 as vec311, vec4 as vec48 } from "gl-matrix";
14
14
 
15
15
  // package.json
16
- var version = "0.43.5";
16
+ var version = "0.43.7";
17
17
 
18
18
  // src/logger.ts
19
19
  var _Log = class _Log {
@@ -22006,16 +22006,21 @@ var DEFAULT_OPTIONS = {
22006
22006
  legendTextColor: [1, 1, 1, 1],
22007
22007
  multiplanarLayout: 0 /* AUTO */,
22008
22008
  renderOverlayBlend: 1,
22009
- sliceMosaicString: ""
22009
+ sliceMosaicString: "",
22010
+ centerMosaic: false,
22011
+ clickToSegment: false,
22012
+ clickToSegmentRadius: 2,
22013
+ clickToSegmentSteps: 10,
22014
+ clickToSegmentBright: true
22010
22015
  };
22011
22016
  var INITIAL_SCENE_DATA = {
22012
22017
  azimuth: 110,
22013
22018
  elevation: 10,
22014
- crosshairPos: vec38.fromValues(0.5, 0.5, 0.5),
22019
+ crosshairPos: vec38.create(),
22015
22020
  clipPlane: [0, 0, 0, 0],
22016
22021
  clipPlaneDepthAziElev: [2, 0, 0],
22017
22022
  volScaleMultiplier: 1,
22018
- pan2Dxyzmm: vec46.fromValues(0, 0, 0, 1),
22023
+ pan2Dxyzmm: vec46.create(),
22019
22024
  clipThick: 2,
22020
22025
  clipVolumeLow: [0, 0, 0],
22021
22026
  clipVolumeHigh: [1, 1, 1]
@@ -22044,7 +22049,11 @@ var NVDocument = class _NVDocument {
22044
22049
  },
22045
22050
  onZoom3DChange: () => {
22046
22051
  },
22047
- sceneData: { ...INITIAL_SCENE_DATA },
22052
+ sceneData: {
22053
+ ...INITIAL_SCENE_DATA,
22054
+ pan2Dxyzmm: vec46.fromValues(0, 0, 0, 1),
22055
+ crosshairPos: vec38.fromValues(0.5, 0.5, 0.5)
22056
+ },
22048
22057
  get renderAzimuth() {
22049
22058
  return this.sceneData.azimuth;
22050
22059
  },
@@ -23779,7 +23788,6 @@ var Niivue = class _Niivue {
23779
23788
  __publicField(this, "resizeObserver", null);
23780
23789
  __publicField(this, "syncOpts", {});
23781
23790
  __publicField(this, "readyForSync", false);
23782
- __publicField(this, "centerMosaic", false);
23783
23791
  // UI Data
23784
23792
  __publicField(this, "uiData", {
23785
23793
  mousedown: false,
@@ -23943,6 +23951,17 @@ var Niivue = class _Niivue {
23943
23951
  */
23944
23952
  __publicField(this, "onIntensityChange", () => {
23945
23953
  });
23954
+ /**
23955
+ * callback function when clickToSegment is enabled and the user clicks on the image. data contains the volume of the segmented region in mm3 and mL
23956
+ * @example
23957
+ * niivue.onClickToSegment = (data) => {
23958
+ * console.log('clicked to segment')
23959
+ * console.log('volume mm3: ', data.mm3)
23960
+ * console.log('volume mL: ', data.mL)
23961
+ * }
23962
+ */
23963
+ __publicField(this, "onClickToSegment", () => {
23964
+ });
23946
23965
  /**
23947
23966
  * callback function to run when a new volume is loaded
23948
23967
  * @example
@@ -24243,7 +24262,7 @@ var Niivue = class _Niivue {
24243
24262
  */
24244
24263
  syncWith(otherNV, syncOpts = { "2d": true, "3d": true }) {
24245
24264
  this.otherNV = otherNV;
24246
- this.syncOpts = syncOpts;
24265
+ this.syncOpts = { ...syncOpts };
24247
24266
  }
24248
24267
  /**
24249
24268
  * Sync the scene controls (orientation, crosshair location, etc.) from one Niivue instance to others. useful for using one canvas to drive another.
@@ -24280,10 +24299,12 @@ var Niivue = class _Niivue {
24280
24299
  if (this.otherNV instanceof _Niivue) {
24281
24300
  if (this.syncOpts["2d"]) {
24282
24301
  this.otherNV.scene.crosshairPos = this.otherNV.mm2frac(thisMM);
24302
+ this.otherNV.scene.pan2Dxyzmm = vec48.clone(this.scene.pan2Dxyzmm);
24283
24303
  }
24284
24304
  if (this.syncOpts["3d"]) {
24285
24305
  this.otherNV.scene.renderAzimuth = this.scene.renderAzimuth;
24286
24306
  this.otherNV.scene.renderElevation = this.scene.renderElevation;
24307
+ this.otherNV.scene.volScaleMultiplier = this.scene.volScaleMultiplier;
24287
24308
  }
24288
24309
  this.otherNV.drawScene();
24289
24310
  this.otherNV.createOnLocationChange();
@@ -24294,10 +24315,12 @@ var Niivue = class _Niivue {
24294
24315
  }
24295
24316
  if (this.syncOpts["2d"]) {
24296
24317
  this.otherNV[i].scene.crosshairPos = this.otherNV[i].mm2frac(thisMM);
24318
+ this.otherNV[i].scene.pan2Dxyzmm = vec48.clone(this.scene.pan2Dxyzmm);
24297
24319
  }
24298
24320
  if (this.syncOpts["3d"]) {
24299
24321
  this.otherNV[i].scene.renderAzimuth = this.scene.renderAzimuth;
24300
24322
  this.otherNV[i].scene.renderElevation = this.scene.renderElevation;
24323
+ this.otherNV[i].scene.volScaleMultiplier = this.scene.volScaleMultiplier;
24301
24324
  }
24302
24325
  this.otherNV[i].drawScene();
24303
24326
  this.otherNV[i].createOnLocationChange();
@@ -25021,7 +25044,10 @@ var Niivue = class _Niivue {
25021
25044
  // nothing
25022
25045
  imageType: NVIMAGE_TYPE.DCM_FOLDER
25023
25046
  // signify that this is a dicom directory
25024
- }).then((volume) => this.addVolume(volume)).catch((e) => {
25047
+ }).then((volume) => {
25048
+ this.addVolume(volume);
25049
+ this.setDrawingEnabled(true);
25050
+ }).catch((e) => {
25025
25051
  throw e;
25026
25052
  });
25027
25053
  }).catch((e) => {
@@ -25207,6 +25233,7 @@ var Niivue = class _Niivue {
25207
25233
  this.loadDrawing(volume);
25208
25234
  } else {
25209
25235
  this.addVolume(volume);
25236
+ this.setDrawingEnabled(true);
25210
25237
  }
25211
25238
  }).catch((e2) => {
25212
25239
  throw e2;
@@ -25755,7 +25782,10 @@ var Niivue = class _Niivue {
25755
25782
  * @see {@link https://niivue.github.io/niivue/features/draw.ui.html | live demo usage}
25756
25783
  */
25757
25784
  saveImage(options = defaultSaveImageOptions) {
25758
- const saveOptions = { ...defaultSaveImageOptions, ...options };
25785
+ const saveOptions = {
25786
+ ...defaultSaveImageOptions,
25787
+ ...options
25788
+ };
25759
25789
  const { filename, isSaveDrawing, volumeByIndex } = saveOptions;
25760
25790
  log.debug("saveImage", filename, isSaveDrawing, volumeByIndex);
25761
25791
  if (this.back?.dims === void 0) {
@@ -26572,7 +26602,7 @@ var Niivue = class _Niivue {
26572
26602
  * @param esm - bundled version of NiiVue
26573
26603
  * @example
26574
26604
  * const javascript = this.generateLoadDocumentJavaScript("gl1");
26575
- * const html = `<html><body><canvas id="gl1"></canvas><script type="module" async>
26605
+ * const html = `<html><body><canvas id="gl1"></canvas><script type="module" async>
26576
26606
  ${javascript}</script></body></html>`;
26577
26607
  */
26578
26608
  async generateLoadDocumentJavaScript(canvasId, esm) {
@@ -26580,26 +26610,26 @@ var Niivue = class _Niivue {
26580
26610
  const base64 = await NVUtilities.compressToBase64String(JSON.stringify(json));
26581
26611
  const javascript = `
26582
26612
  ${esm}
26583
-
26584
- async function saveNiivueAsHtml(pageName) {
26613
+
26614
+ async function saveNiivueAsHtml(pageName) {
26585
26615
  //get new docstring
26586
26616
  const docString = nv1.json();
26587
- const html =
26617
+ const html =
26588
26618
  document.getElementsByTagName("html")[0]
26589
26619
  .innerHTML.replace(base64, await NVUtilities.compressToBase64String(JSON.stringify(docString)));
26590
26620
  NVUtilities.download(html, pageName, "application/html");
26591
26621
  }
26592
-
26622
+
26593
26623
  var nv1 = new Niivue();
26594
- nv1.attachTo("${canvasId}");
26624
+ nv1.attachTo("${canvasId}");
26595
26625
  var base64 = "${base64}";
26596
26626
  NVUtilities.decompressBase64String(base64).then((jsonText) => {
26597
26627
  var json = JSON.parse(jsonText); // string -> JSON
26598
- var doc = NVDocument.loadFromJSON(json);
26628
+ var doc = NVDocument.loadFromJSON(json);
26599
26629
  nv1.loadDocument(doc);
26600
26630
  nv1.updateGLVolume();
26601
26631
  });
26602
-
26632
+
26603
26633
  `;
26604
26634
  return javascript;
26605
26635
  }
@@ -26673,14 +26703,14 @@ var Niivue = class _Niivue {
26673
26703
  <main>
26674
26704
  <canvas id="gl1"></canvas>
26675
26705
  </main>
26676
- <script type="module" async>
26706
+ <script type="module" async>
26677
26707
  ${javascript}
26678
26708
  function saveAsHtml() {
26679
26709
  saveNiivueAsHtml("page.html");
26680
- }
26710
+ }
26681
26711
  // assign our event handler
26682
26712
  var button = document.getElementById("save");
26683
- button.onclick = saveAsHtml;
26713
+ button.onclick = saveAsHtml;
26684
26714
  </script>
26685
26715
  </body>
26686
26716
  </html>`;
@@ -29739,11 +29769,43 @@ var Niivue = class _Niivue {
29739
29769
  }
29740
29770
  if (this.opts.drawingEnabled) {
29741
29771
  const pt = this.frac2vox(this.scene.crosshairPos);
29772
+ if (this.opts.clickToSegment) {
29773
+ const radius = this.opts.clickToSegmentRadius;
29774
+ const steps = this.opts.clickToSegmentSteps;
29775
+ const brightOrDark = this.opts.clickToSegmentBright ? Number.POSITIVE_INFINITY : Number.NEGATIVE_INFINITY;
29776
+ this.drawPenFillPts = [];
29777
+ this.drawPenAxCorSag = axCorSag;
29778
+ for (let i2 = 1; i2 <= steps; i2++) {
29779
+ const angle = i2 / steps * 2 * Math.PI;
29780
+ let xVox = pt[0] + radius * Math.cos(angle);
29781
+ let yVox = pt[1] + radius * Math.sin(angle);
29782
+ const zVox = pt[2];
29783
+ xVox = Math.round(xVox);
29784
+ yVox = Math.round(yVox);
29785
+ this.drawPt(xVox, yVox, zVox, this.opts.penValue);
29786
+ this.drawPenFillPts.push([xVox, yVox, pt[2]]);
29787
+ if (i2 === steps) {
29788
+ this.drawFloodFill([xVox, yVox, pt[2]], 0, brightOrDark, NaN, NaN, this.opts.floodFillNeighbors);
29789
+ }
29790
+ }
29791
+ this.drawScene();
29792
+ this.createOnLocationChange(axCorSag);
29793
+ const info = this.getDescriptives(0, [], true);
29794
+ this.onClickToSegment({ mL: info.volumeML, mm3: info.volumeMM3 });
29795
+ return;
29796
+ }
29742
29797
  if (!isFinite(this.opts.penValue) || this.opts.penValue < 0 || Object.is(this.opts.penValue, -0)) {
29743
29798
  if (!isFinite(this.opts.penValue)) {
29744
- this.drawFloodFill(pt, 0, this.opts.penValue, this.opts.floodFillNeighbors);
29799
+ this.drawFloodFill(pt, 0, this.opts.penValue, NaN, NaN, this.opts.floodFillNeighbors);
29745
29800
  } else {
29746
- this.drawFloodFill(pt, Math.abs(this.opts.penValue), this.opts.floodFillNeighbors);
29801
+ this.drawFloodFill(
29802
+ pt,
29803
+ Math.abs(this.opts.penValue),
29804
+ this.opts.penValue,
29805
+ NaN,
29806
+ NaN,
29807
+ this.opts.floodFillNeighbors
29808
+ );
29747
29809
  }
29748
29810
  return;
29749
29811
  }
@@ -31311,7 +31373,13 @@ var Niivue = class _Niivue {
31311
31373
  const mm2 = this.frac2mm(this.scene.crosshairPos, 0, true);
31312
31374
  const vox = v.mm2vox(mm2);
31313
31375
  const val = v.getValue(vox[0], vox[1], vox[2], v.frame4D);
31314
- return { name: v.name, value: val, id: v.id, mm: mm2, vox };
31376
+ return {
31377
+ name: v.name,
31378
+ value: val,
31379
+ id: v.id,
31380
+ mm: mm2,
31381
+ vox
31382
+ };
31315
31383
  }),
31316
31384
  string: str
31317
31385
  };
@@ -32246,7 +32314,7 @@ var Niivue = class _Niivue {
32246
32314
  const scaleW = this.gl.canvas.width / mxRowWid;
32247
32315
  const scaleH = this.effectiveCanvasHeight() / top;
32248
32316
  scale = Math.min(scaleW, scaleH);
32249
- if (this.centerMosaic) {
32317
+ if (this.opts.centerMosaic) {
32250
32318
  marginLeft = Math.floor(0.5 * (this.gl.canvas.width - mxRowWid * scale));
32251
32319
  marginTop = Math.floor(0.5 * (this.effectiveCanvasHeight() - top * scale));
32252
32320
  }