@niivue/niivue 0.43.6 → 0.44.0

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
@@ -211,6 +211,7 @@ type ImageFromUrlOptions = {
211
211
  useQFormNotSForm?: boolean;
212
212
  alphaThreshold?: boolean;
213
213
  colormapNegative?: string;
214
+ colorMapNegative?: string;
214
215
  cal_minNeg?: number;
215
216
  cal_maxNeg?: number;
216
217
  colorbarVisible?: boolean;
@@ -558,6 +559,11 @@ declare enum SLICE_TYPE {
558
559
  MULTIPLANAR = 3,
559
560
  RENDER = 4
560
561
  }
562
+ declare enum SHOW_RENDER {
563
+ NEVER = 0,
564
+ ALWAYS = 1,
565
+ AUTO = 2
566
+ }
561
567
  /**
562
568
  * Multi-planar layout
563
569
  * @ignore
@@ -613,6 +619,7 @@ type NVConfigOptions = {
613
619
  isOrientCube: boolean;
614
620
  multiplanarPadPixels: number;
615
621
  multiplanarForceRender: boolean;
622
+ multiplanarShowRender: SHOW_RENDER;
616
623
  isRadiologicalConvention: boolean;
617
624
  meshThicknessOn2D: number | string;
618
625
  dragMode: DRAG_MODE;
@@ -645,6 +652,11 @@ type NVConfigOptions = {
645
652
  multiplanarLayout: MULTIPLANAR_TYPE;
646
653
  renderOverlayBlend: number;
647
654
  sliceMosaicString: string;
655
+ centerMosaic: boolean;
656
+ clickToSegment: boolean;
657
+ clickToSegmentRadius: number;
658
+ clickToSegmentSteps: number;
659
+ clickToSegmentBright: boolean;
648
660
  };
649
661
  declare const DEFAULT_OPTIONS: NVConfigOptions;
650
662
  type SceneData = {
@@ -1687,7 +1699,6 @@ declare class Niivue {
1687
1699
  private resizeObserver;
1688
1700
  syncOpts: Record<string, unknown>;
1689
1701
  readyForSync: boolean;
1690
- centerMosaic: boolean;
1691
1702
  uiData: UIData;
1692
1703
  back: NVImage | null;
1693
1704
  overlays: NVImage[];
@@ -1773,6 +1784,19 @@ declare class Niivue {
1773
1784
  * }
1774
1785
  */
1775
1786
  onIntensityChange: (volume: NVImage) => void;
1787
+ /**
1788
+ * 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
1789
+ * @example
1790
+ * niivue.onClickToSegment = (data) => {
1791
+ * console.log('clicked to segment')
1792
+ * console.log('volume mm3: ', data.mm3)
1793
+ * console.log('volume mL: ', data.mL)
1794
+ * }
1795
+ */
1796
+ onClickToSegment: (data: {
1797
+ mm3: number;
1798
+ mL: number;
1799
+ }) => void;
1776
1800
  /**
1777
1801
  * callback function to run when a new volume is loaded
1778
1802
  * @example
@@ -2042,6 +2066,7 @@ declare class Niivue {
2042
2066
  * @see {@link https://niivue.github.io/niivue/features/document.3d.html | live demo usage}
2043
2067
  */
2044
2068
  addVolumeFromUrl(imageOptions: ImageFromUrlOptions): Promise<NVImage>;
2069
+ addVolumesFromUrl(imageOptionsArray: ImageFromUrlOptions[]): Promise<NVImage[]>;
2045
2070
  /**
2046
2071
  * Find media by url
2047
2072
  */
@@ -2555,6 +2580,11 @@ declare class Niivue {
2555
2580
  * @see {@link https://niivue.github.io/niivue/features/multiuser.meshes.html | live demo usage}
2556
2581
  */
2557
2582
  addMeshFromUrl(meshOptions: LoadFromUrlParams): Promise<NVMesh>;
2583
+ /**
2584
+ * Add mesh and notify subscribers
2585
+ * @see {@link https://niivue.github.io/niivue/features/multiuser.meshes.html | live demo usage}
2586
+ */
2587
+ addMeshesFromUrl(meshOptions: LoadFromUrlParams[]): Promise<NVMesh[]>;
2558
2588
  /**
2559
2589
  * load an array of meshes
2560
2590
  * @param meshList - the array of objects to load. each object must have a resolvable "url" property at a minimum
@@ -2979,4 +3009,4 @@ declare class Niivue {
2979
3009
  set gl(gl: WebGL2RenderingContext | null);
2980
3010
  }
2981
3011
 
2982
- export { type Connectome, type ConnectomeOptions, DEFAULT_OPTIONS, DRAG_MODE, type DocumentData, type DragReleaseParams, type ExportDocumentData, INITIAL_SCENE_DATA, LabelLineTerminator, LabelTextAlignment, type LegacyConnectome, type LegacyNodes, MULTIPLANAR_TYPE, type NVConfigOptions, type NVConnectomeEdge, type NVConnectomeNode, NVController, NVDocument, NVImage, NVImageFromUrlOptions, NVLabel3D, NVLabel3DStyle, NVMesh, NVMeshFromUrlOptions, NVMeshLayerDefaults, NVMeshLoaders, NVUtilities, type NiftiHeader, type NiiVueLocation, type NiiVueLocationValue, Niivue, type Point, SLICE_TYPE, type Scene, type Volume, cmapper, ColorTables as colortables };
3012
+ export { type Connectome, type ConnectomeOptions, DEFAULT_OPTIONS, DRAG_MODE, type DocumentData, type DragReleaseParams, type ExportDocumentData, INITIAL_SCENE_DATA, LabelLineTerminator, LabelTextAlignment, type LegacyConnectome, type LegacyNodes, MULTIPLANAR_TYPE, type NVConfigOptions, type NVConnectomeEdge, type NVConnectomeNode, NVController, NVDocument, NVImage, NVImageFromUrlOptions, NVLabel3D, NVLabel3DStyle, NVMesh, NVMeshFromUrlOptions, NVMeshLayerDefaults, NVMeshLoaders, NVUtilities, type NiftiHeader, type NiiVueLocation, type NiiVueLocationValue, Niivue, type Point, SHOW_RENDER, SLICE_TYPE, type Scene, type Volume, cmapper, ColorTables as colortables };
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.6";
16
+ var version = "0.44.0";
17
17
 
18
18
  // src/logger.ts
19
19
  var _Log = class _Log {
@@ -21929,6 +21929,12 @@ var SLICE_TYPE = /* @__PURE__ */ ((SLICE_TYPE2) => {
21929
21929
  SLICE_TYPE2[SLICE_TYPE2["RENDER"] = 4] = "RENDER";
21930
21930
  return SLICE_TYPE2;
21931
21931
  })(SLICE_TYPE || {});
21932
+ var SHOW_RENDER = /* @__PURE__ */ ((SHOW_RENDER2) => {
21933
+ SHOW_RENDER2[SHOW_RENDER2["NEVER"] = 0] = "NEVER";
21934
+ SHOW_RENDER2[SHOW_RENDER2["ALWAYS"] = 1] = "ALWAYS";
21935
+ SHOW_RENDER2[SHOW_RENDER2["AUTO"] = 2] = "AUTO";
21936
+ return SHOW_RENDER2;
21937
+ })(SHOW_RENDER || {});
21932
21938
  var MULTIPLANAR_TYPE = /* @__PURE__ */ ((MULTIPLANAR_TYPE2) => {
21933
21939
  MULTIPLANAR_TYPE2[MULTIPLANAR_TYPE2["AUTO"] = 0] = "AUTO";
21934
21940
  MULTIPLANAR_TYPE2[MULTIPLANAR_TYPE2["COLUMN"] = 1] = "COLUMN";
@@ -21975,7 +21981,10 @@ var DEFAULT_OPTIONS = {
21975
21981
  isColorbar: false,
21976
21982
  isOrientCube: false,
21977
21983
  multiplanarPadPixels: 0,
21984
+ // @deprecated
21978
21985
  multiplanarForceRender: false,
21986
+ multiplanarShowRender: 2 /* AUTO */,
21987
+ // auto is the same behaviour as multiplanarForceRender: false
21979
21988
  isRadiologicalConvention: false,
21980
21989
  meshThicknessOn2D: Infinity,
21981
21990
  dragMode: 1 /* contrast */,
@@ -22006,7 +22015,12 @@ var DEFAULT_OPTIONS = {
22006
22015
  legendTextColor: [1, 1, 1, 1],
22007
22016
  multiplanarLayout: 0 /* AUTO */,
22008
22017
  renderOverlayBlend: 1,
22009
- sliceMosaicString: ""
22018
+ sliceMosaicString: "",
22019
+ centerMosaic: false,
22020
+ clickToSegment: false,
22021
+ clickToSegmentRadius: 2,
22022
+ clickToSegmentSteps: 10,
22023
+ clickToSegmentBright: true
22010
22024
  };
22011
22025
  var INITIAL_SCENE_DATA = {
22012
22026
  azimuth: 110,
@@ -23783,7 +23797,6 @@ var Niivue = class _Niivue {
23783
23797
  __publicField(this, "resizeObserver", null);
23784
23798
  __publicField(this, "syncOpts", {});
23785
23799
  __publicField(this, "readyForSync", false);
23786
- __publicField(this, "centerMosaic", false);
23787
23800
  // UI Data
23788
23801
  __publicField(this, "uiData", {
23789
23802
  mousedown: false,
@@ -23947,6 +23960,17 @@ var Niivue = class _Niivue {
23947
23960
  */
23948
23961
  __publicField(this, "onIntensityChange", () => {
23949
23962
  });
23963
+ /**
23964
+ * 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
23965
+ * @example
23966
+ * niivue.onClickToSegment = (data) => {
23967
+ * console.log('clicked to segment')
23968
+ * console.log('volume mm3: ', data.mm3)
23969
+ * console.log('volume mL: ', data.mL)
23970
+ * }
23971
+ */
23972
+ __publicField(this, "onClickToSegment", () => {
23973
+ });
23950
23974
  /**
23951
23975
  * callback function to run when a new volume is loaded
23952
23976
  * @example
@@ -24982,6 +25006,39 @@ var Niivue = class _Niivue {
24982
25006
  this.addVolume(volume);
24983
25007
  return volume;
24984
25008
  }
25009
+ async addVolumesFromUrl(imageOptionsArray) {
25010
+ const promises = imageOptionsArray.map(async (imageItem) => {
25011
+ const imageOptions = {
25012
+ url: imageItem.url,
25013
+ headers: imageItem.headers,
25014
+ name: imageItem.name,
25015
+ colormap: imageItem.colormap ? imageItem.colormap : imageItem.colorMap,
25016
+ colormapNegative: imageItem.colormapNegative ? imageItem.colormapNegative : imageItem.colorMapNegative,
25017
+ opacity: imageItem.opacity,
25018
+ urlImgData: imageItem.urlImgData,
25019
+ cal_min: imageItem.cal_min,
25020
+ cal_max: imageItem.cal_max,
25021
+ trustCalMinMax: this.opts.trustCalMinMax,
25022
+ isManifest: imageItem.isManifest,
25023
+ frame4D: imageItem.frame4D,
25024
+ limitFrames4D: imageItem.limitFrames4D || this.opts.limitFrames4D,
25025
+ colorbarVisible: imageItem.colorbarVisible
25026
+ };
25027
+ const volume = await NVImage.loadFromUrl(imageOptions);
25028
+ this.document.addImageOptions(volume, imageOptions);
25029
+ volume.onColormapChange = this.onColormapChange;
25030
+ this.mediaUrlMap.set(volume, imageOptions.url);
25031
+ if (this.onVolumeAddedFromUrl) {
25032
+ this.onVolumeAddedFromUrl(imageOptions, volume);
25033
+ }
25034
+ return volume;
25035
+ });
25036
+ const volumes = await Promise.all(promises);
25037
+ for (let i = 0; i < volumes.length; i++) {
25038
+ this.addVolume(volumes[i]);
25039
+ }
25040
+ return volumes;
25041
+ }
24985
25042
  /**
24986
25043
  * Find media by url
24987
25044
  */
@@ -25029,7 +25086,10 @@ var Niivue = class _Niivue {
25029
25086
  // nothing
25030
25087
  imageType: NVIMAGE_TYPE.DCM_FOLDER
25031
25088
  // signify that this is a dicom directory
25032
- }).then((volume) => this.addVolume(volume)).catch((e) => {
25089
+ }).then((volume) => {
25090
+ this.addVolume(volume);
25091
+ this.setDrawingEnabled(true);
25092
+ }).catch((e) => {
25033
25093
  throw e;
25034
25094
  });
25035
25095
  }).catch((e) => {
@@ -25215,6 +25275,7 @@ var Niivue = class _Niivue {
25215
25275
  this.loadDrawing(volume);
25216
25276
  } else {
25217
25277
  this.addVolume(volume);
25278
+ this.setDrawingEnabled(true);
25218
25279
  }
25219
25280
  }).catch((e2) => {
25220
25281
  throw e2;
@@ -25763,7 +25824,10 @@ var Niivue = class _Niivue {
25763
25824
  * @see {@link https://niivue.github.io/niivue/features/draw.ui.html | live demo usage}
25764
25825
  */
25765
25826
  saveImage(options = defaultSaveImageOptions) {
25766
- const saveOptions = { ...defaultSaveImageOptions, ...options };
25827
+ const saveOptions = {
25828
+ ...defaultSaveImageOptions,
25829
+ ...options
25830
+ };
25767
25831
  const { filename, isSaveDrawing, volumeByIndex } = saveOptions;
25768
25832
  log.debug("saveImage", filename, isSaveDrawing, volumeByIndex);
25769
25833
  if (this.back?.dims === void 0) {
@@ -26580,7 +26644,7 @@ var Niivue = class _Niivue {
26580
26644
  * @param esm - bundled version of NiiVue
26581
26645
  * @example
26582
26646
  * const javascript = this.generateLoadDocumentJavaScript("gl1");
26583
- * const html = `<html><body><canvas id="gl1"></canvas><script type="module" async>
26647
+ * const html = `<html><body><canvas id="gl1"></canvas><script type="module" async>
26584
26648
  ${javascript}</script></body></html>`;
26585
26649
  */
26586
26650
  async generateLoadDocumentJavaScript(canvasId, esm) {
@@ -26588,26 +26652,26 @@ var Niivue = class _Niivue {
26588
26652
  const base64 = await NVUtilities.compressToBase64String(JSON.stringify(json));
26589
26653
  const javascript = `
26590
26654
  ${esm}
26591
-
26592
- async function saveNiivueAsHtml(pageName) {
26655
+
26656
+ async function saveNiivueAsHtml(pageName) {
26593
26657
  //get new docstring
26594
26658
  const docString = nv1.json();
26595
- const html =
26659
+ const html =
26596
26660
  document.getElementsByTagName("html")[0]
26597
26661
  .innerHTML.replace(base64, await NVUtilities.compressToBase64String(JSON.stringify(docString)));
26598
26662
  NVUtilities.download(html, pageName, "application/html");
26599
26663
  }
26600
-
26664
+
26601
26665
  var nv1 = new Niivue();
26602
- nv1.attachTo("${canvasId}");
26666
+ nv1.attachTo("${canvasId}");
26603
26667
  var base64 = "${base64}";
26604
26668
  NVUtilities.decompressBase64String(base64).then((jsonText) => {
26605
26669
  var json = JSON.parse(jsonText); // string -> JSON
26606
- var doc = NVDocument.loadFromJSON(json);
26670
+ var doc = NVDocument.loadFromJSON(json);
26607
26671
  nv1.loadDocument(doc);
26608
26672
  nv1.updateGLVolume();
26609
26673
  });
26610
-
26674
+
26611
26675
  `;
26612
26676
  return javascript;
26613
26677
  }
@@ -26681,14 +26745,14 @@ var Niivue = class _Niivue {
26681
26745
  <main>
26682
26746
  <canvas id="gl1"></canvas>
26683
26747
  </main>
26684
- <script type="module" async>
26748
+ <script type="module" async>
26685
26749
  ${javascript}
26686
26750
  function saveAsHtml() {
26687
26751
  saveNiivueAsHtml("page.html");
26688
- }
26752
+ }
26689
26753
  // assign our event handler
26690
26754
  var button = document.getElementById("save");
26691
- button.onclick = saveAsHtml;
26755
+ button.onclick = saveAsHtml;
26692
26756
  </script>
26693
26757
  </body>
26694
26758
  </html>`;
@@ -26753,28 +26817,27 @@ var Niivue = class _Niivue {
26753
26817
  this.volumes = [];
26754
26818
  this.gl.clearColor(0, 0, 0, 1);
26755
26819
  this.gl.clear(this.gl.COLOR_BUFFER_BIT);
26756
- for (let i = 0; i < volumeList.length; i++) {
26757
- if (volumeList[i].colorMap !== void 0) {
26758
- volumeList[i].colormap = volumeList[i].colorMap;
26759
- }
26760
- const imageOptions = {
26761
- url: volumeList[i].url,
26762
- headers: volumeList[i].headers,
26763
- name: volumeList[i].name,
26764
- colormap: volumeList[i].colormap,
26765
- colormapNegative: volumeList[i].colormapNegative,
26766
- opacity: volumeList[i].opacity,
26767
- urlImgData: volumeList[i].urlImgData,
26768
- cal_min: volumeList[i].cal_min,
26769
- cal_max: volumeList[i].cal_max,
26770
- trustCalMinMax: this.opts.trustCalMinMax,
26771
- isManifest: volumeList[i].isManifest,
26772
- frame4D: volumeList[i].frame4D,
26773
- limitFrames4D: volumeList[i].limitFrames4D || this.opts.limitFrames4D,
26774
- colorbarVisible: volumeList[i].colorbarVisible
26775
- };
26776
- await this.addVolumeFromUrl(imageOptions);
26820
+ if (volumeList.length > 1) {
26821
+ await this.addVolumesFromUrl(volumeList);
26822
+ return this;
26777
26823
  }
26824
+ const imageOptions = {
26825
+ url: volumeList[0].url,
26826
+ headers: volumeList[0].headers,
26827
+ name: volumeList[0].name,
26828
+ colormap: volumeList[0].colormap ? volumeList[0].colormap : volumeList[0].colorMap,
26829
+ colormapNegative: volumeList[0].colormapNegative ? volumeList[0].colormapNegative : volumeList[0].colorMapNegative,
26830
+ opacity: volumeList[0].opacity,
26831
+ urlImgData: volumeList[0].urlImgData,
26832
+ cal_min: volumeList[0].cal_min,
26833
+ cal_max: volumeList[0].cal_max,
26834
+ trustCalMinMax: this.opts.trustCalMinMax,
26835
+ isManifest: volumeList[0].isManifest,
26836
+ frame4D: volumeList[0].frame4D,
26837
+ limitFrames4D: volumeList[0].limitFrames4D || this.opts.limitFrames4D,
26838
+ colorbarVisible: volumeList[0].colorbarVisible
26839
+ };
26840
+ await this.addVolumeFromUrl(imageOptions);
26778
26841
  return this;
26779
26842
  }
26780
26843
  /**
@@ -26798,6 +26861,32 @@ var Niivue = class _Niivue {
26798
26861
  this.addMesh(mesh);
26799
26862
  return mesh;
26800
26863
  }
26864
+ /**
26865
+ * Add mesh and notify subscribers
26866
+ * @see {@link https://niivue.github.io/niivue/features/multiuser.meshes.html | live demo usage}
26867
+ */
26868
+ async addMeshesFromUrl(meshOptions) {
26869
+ const promises = meshOptions.map(async (meshItem) => {
26870
+ const ext = this.getFileExt(meshItem.url);
26871
+ if (ext === "JCON" || ext === "JSON") {
26872
+ const response = await fetch(meshItem.url, {});
26873
+ const json = await response.json();
26874
+ const mesh2 = this.loadConnectomeAsMesh(json);
26875
+ this.mediaUrlMap.set(mesh2, meshItem.url);
26876
+ this.onMeshAddedFromUrl(meshItem, mesh2);
26877
+ return mesh2;
26878
+ }
26879
+ const mesh = await NVMesh2.loadFromUrl({ ...meshItem, gl: this.gl });
26880
+ this.mediaUrlMap.set(mesh, meshItem.url);
26881
+ this.onMeshAddedFromUrl(meshItem, mesh);
26882
+ return mesh;
26883
+ });
26884
+ const meshes = await Promise.all(promises);
26885
+ for (let i = 0; i < meshes.length; i++) {
26886
+ this.addMesh(meshes[i]);
26887
+ }
26888
+ return meshes;
26889
+ }
26801
26890
  /**
26802
26891
  * load an array of meshes
26803
26892
  * @param meshList - the array of objects to load. each object must have a resolvable "url" property at a minimum
@@ -26819,9 +26908,13 @@ var Niivue = class _Niivue {
26819
26908
  this.meshes = [];
26820
26909
  this.gl.clearColor(0, 0, 0, 1);
26821
26910
  this.gl.clear(this.gl.COLOR_BUFFER_BIT);
26822
- for (let i = 0; i < meshList.length; i++) {
26823
- await this.addMeshFromUrl(meshList[i]);
26911
+ if (meshList.length > 1) {
26912
+ await this.addMeshesFromUrl(meshList);
26913
+ this.updateGLVolume();
26914
+ this.drawScene();
26915
+ return this;
26824
26916
  }
26917
+ await this.addMeshFromUrl(meshList[0]);
26825
26918
  this.updateGLVolume();
26826
26919
  this.drawScene();
26827
26920
  return this;
@@ -29747,11 +29840,43 @@ var Niivue = class _Niivue {
29747
29840
  }
29748
29841
  if (this.opts.drawingEnabled) {
29749
29842
  const pt = this.frac2vox(this.scene.crosshairPos);
29843
+ if (this.opts.clickToSegment) {
29844
+ const radius = this.opts.clickToSegmentRadius;
29845
+ const steps = this.opts.clickToSegmentSteps;
29846
+ const brightOrDark = this.opts.clickToSegmentBright ? Number.POSITIVE_INFINITY : Number.NEGATIVE_INFINITY;
29847
+ this.drawPenFillPts = [];
29848
+ this.drawPenAxCorSag = axCorSag;
29849
+ for (let i2 = 1; i2 <= steps; i2++) {
29850
+ const angle = i2 / steps * 2 * Math.PI;
29851
+ let xVox = pt[0] + radius * Math.cos(angle);
29852
+ let yVox = pt[1] + radius * Math.sin(angle);
29853
+ const zVox = pt[2];
29854
+ xVox = Math.round(xVox);
29855
+ yVox = Math.round(yVox);
29856
+ this.drawPt(xVox, yVox, zVox, this.opts.penValue);
29857
+ this.drawPenFillPts.push([xVox, yVox, pt[2]]);
29858
+ if (i2 === steps) {
29859
+ this.drawFloodFill([xVox, yVox, pt[2]], 0, brightOrDark, NaN, NaN, this.opts.floodFillNeighbors);
29860
+ }
29861
+ }
29862
+ this.drawScene();
29863
+ this.createOnLocationChange(axCorSag);
29864
+ const info = this.getDescriptives(0, [], true);
29865
+ this.onClickToSegment({ mL: info.volumeML, mm3: info.volumeMM3 });
29866
+ return;
29867
+ }
29750
29868
  if (!isFinite(this.opts.penValue) || this.opts.penValue < 0 || Object.is(this.opts.penValue, -0)) {
29751
29869
  if (!isFinite(this.opts.penValue)) {
29752
- this.drawFloodFill(pt, 0, this.opts.penValue, this.opts.floodFillNeighbors);
29870
+ this.drawFloodFill(pt, 0, this.opts.penValue, NaN, NaN, this.opts.floodFillNeighbors);
29753
29871
  } else {
29754
- this.drawFloodFill(pt, Math.abs(this.opts.penValue), this.opts.floodFillNeighbors);
29872
+ this.drawFloodFill(
29873
+ pt,
29874
+ Math.abs(this.opts.penValue),
29875
+ this.opts.penValue,
29876
+ NaN,
29877
+ NaN,
29878
+ this.opts.floodFillNeighbors
29879
+ );
29755
29880
  }
29756
29881
  return;
29757
29882
  }
@@ -30050,6 +30175,9 @@ var Niivue = class _Niivue {
30050
30175
  width = bulletMargin + longestTextLength;
30051
30176
  width += horizontalMargin * 2;
30052
30177
  }
30178
+ if (width >= this.gl.canvas.width) {
30179
+ return 0;
30180
+ }
30053
30181
  return width;
30054
30182
  }
30055
30183
  getLegendPanelHeight() {
@@ -31319,7 +31447,13 @@ var Niivue = class _Niivue {
31319
31447
  const mm2 = this.frac2mm(this.scene.crosshairPos, 0, true);
31320
31448
  const vox = v.mm2vox(mm2);
31321
31449
  const val = v.getValue(vox[0], vox[1], vox[2], v.frame4D);
31322
- return { name: v.name, value: val, id: v.id, mm: mm2, vox };
31450
+ return {
31451
+ name: v.name,
31452
+ value: val,
31453
+ id: v.id,
31454
+ mm: mm2,
31455
+ vox
31456
+ };
31323
31457
  }),
31324
31458
  string: str
31325
31459
  };
@@ -32254,7 +32388,7 @@ var Niivue = class _Niivue {
32254
32388
  const scaleW = this.gl.canvas.width / mxRowWid;
32255
32389
  const scaleH = this.effectiveCanvasHeight() / top;
32256
32390
  scale = Math.min(scaleW, scaleH);
32257
- if (this.centerMosaic) {
32391
+ if (this.opts.centerMosaic) {
32258
32392
  marginLeft = Math.floor(0.5 * (this.gl.canvas.width - mxRowWid * scale));
32259
32393
  marginTop = Math.floor(0.5 * (this.effectiveCanvasHeight() - top * scale));
32260
32394
  }
@@ -32330,6 +32464,20 @@ var Niivue = class _Niivue {
32330
32464
  } else if (this.opts.sliceType === 2 /* SAGITTAL */) {
32331
32465
  this.draw2D([0, 0, 0, 0], 2);
32332
32466
  } else {
32467
+ let isShowRender = false;
32468
+ if (this.opts.multiplanarForceRender) {
32469
+ isShowRender = true;
32470
+ if (this.opts.multiplanarForceRender) {
32471
+ this.opts.multiplanarShowRender = 1 /* ALWAYS */;
32472
+ } else {
32473
+ this.opts.multiplanarShowRender = 2 /* AUTO */;
32474
+ }
32475
+ delete this.opts.multiplanarForceRender;
32476
+ } else {
32477
+ if (this.opts.multiplanarShowRender === 1 /* ALWAYS */) {
32478
+ isShowRender = true;
32479
+ }
32480
+ }
32333
32481
  const isDrawPenDown = isFinite(this.drawPenLocation[0]) && this.opts.drawingEnabled;
32334
32482
  const { volScale } = this.sliceScale();
32335
32483
  if (typeof this.opts.multiplanarPadPixels !== "number") {
@@ -32371,7 +32519,7 @@ var Niivue = class _Niivue {
32371
32519
  }
32372
32520
  if (isDrawColumn) {
32373
32521
  let ltwh = ltwh1x3;
32374
- if (this.opts.multiplanarForceRender || ltwh1x4[4] >= ltwh1x3[4]) {
32522
+ if (isShowRender || this.opts.multiplanarShowRender === 2 /* AUTO */ && ltwh1x4[4] >= ltwh1x3[4]) {
32375
32523
  ltwh = ltwh1x4;
32376
32524
  } else {
32377
32525
  isDraw3D = false;
@@ -32388,7 +32536,7 @@ var Niivue = class _Niivue {
32388
32536
  }
32389
32537
  } else if (isDrawRow) {
32390
32538
  let ltwh = ltwh3x1;
32391
- if (this.opts.multiplanarForceRender || ltwh4x1[4] >= ltwh3x1[4]) {
32539
+ if (isShowRender || this.opts.multiplanarShowRender === 2 /* AUTO */ && ltwh4x1[4] >= ltwh3x1[4]) {
32392
32540
  ltwh = ltwh4x1;
32393
32541
  } else {
32394
32542
  isDraw3D = false;
@@ -32403,6 +32551,12 @@ var Niivue = class _Niivue {
32403
32551
  this.draw3D([ltwh[0] + sX + sX + sY + pad * 3, ltwh[1], ltwh[3], ltwh[3]]);
32404
32552
  }
32405
32553
  } else if (isDrawGrid) {
32554
+ if (!isShowRender) {
32555
+ isDraw3D = false;
32556
+ }
32557
+ if (this.opts.multiplanarShowRender === 2 /* AUTO */) {
32558
+ isDraw3D = true;
32559
+ }
32406
32560
  const ltwh = ltwh2x2;
32407
32561
  const sX = volScale[0] * ltwh[4];
32408
32562
  const sY = volScale[1] * ltwh[4];
@@ -32527,6 +32681,7 @@ export {
32527
32681
  NVMeshLoaders,
32528
32682
  NVUtilities,
32529
32683
  Niivue,
32684
+ SHOW_RENDER,
32530
32685
  SLICE_TYPE,
32531
32686
  cmapper,
32532
32687
  ColorTables as colortables