@niivue/niivue 0.67.1-dev.1 → 0.67.1-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/build/drawing/index.d.ts +1 -1
- package/build/drawing/index.js.map +1 -1
- package/build/index.min.js +1 -1
- package/build/metafile-esm.json +1 -1
- package/build/niivue/index.d.ts +2 -2
- package/build/niivue/index.js +89 -20
- package/build/niivue/index.js.map +1 -1
- package/build/{nvdocument-B64_4nuJ.d.ts → nvdocument-DrX6RoEG.d.ts} +14 -1
- package/build/utils/index.d.ts +1 -1
- package/dist/index.d.ts +14 -1
- package/dist/index.js +89 -20
- package/dist/index.js.map +1 -1
- package/dist/index.min.js +1 -1
- package/dist/metafile-esm.json +1 -1
- package/dist/niivue.umd.js +20 -20
- package/package.json +109 -109
- package/src/niivue/index.ts +18 -1
- package/src/nvimage/index.ts +10 -2
- package/src/nvimage/utils.ts +2 -0
- package/src/nvimage/zarr/NVZarrHelper.ts +77 -19
package/build/niivue/index.js
CHANGED
|
@@ -19,7 +19,7 @@ import { mat4 as mat418, vec2, vec3 as vec324, vec4 as vec417 } from "gl-matrix"
|
|
|
19
19
|
// package.json
|
|
20
20
|
var package_default = {
|
|
21
21
|
name: "@niivue/niivue",
|
|
22
|
-
version: "0.67.1-dev.
|
|
22
|
+
version: "0.67.1-dev.2",
|
|
23
23
|
description: "minimal webgl2 nifti image viewer",
|
|
24
24
|
types: "./build/niivue/index.d.ts",
|
|
25
25
|
main: "./build/niivue/index.js",
|
|
@@ -22591,6 +22591,7 @@ var NVZarrHelper = class _NVZarrHelper {
|
|
|
22591
22591
|
__publicField(this, "voxelTranslations");
|
|
22592
22592
|
__publicField(this, "hasTranslations");
|
|
22593
22593
|
__publicField(this, "convertUnitsToMm");
|
|
22594
|
+
__publicField(this, "worldOffsetMM", [0, 0, 0]);
|
|
22594
22595
|
__publicField(this, "centerX");
|
|
22595
22596
|
__publicField(this, "centerY");
|
|
22596
22597
|
__publicField(this, "centerZ");
|
|
@@ -22601,6 +22602,7 @@ var NVZarrHelper = class _NVZarrHelper {
|
|
|
22601
22602
|
__publicField(this, "currentAbortController", null);
|
|
22602
22603
|
__publicField(this, "runningMin", Infinity);
|
|
22603
22604
|
__publicField(this, "runningMax", -Infinity);
|
|
22605
|
+
__publicField(this, "calibrationDone", false);
|
|
22604
22606
|
// Debounce state for batching chunk updates
|
|
22605
22607
|
__publicField(this, "updateDebounceTimer", null);
|
|
22606
22608
|
__publicField(this, "UPDATE_DEBOUNCE_MS", 50);
|
|
@@ -22663,9 +22665,9 @@ var NVZarrHelper = class _NVZarrHelper {
|
|
|
22663
22665
|
const level = Math.max(0, Math.min(options.level, helper.pyramidInfo.levels.length - 1));
|
|
22664
22666
|
helper.pyramidLevel = level;
|
|
22665
22667
|
helper.updateLevelInfo();
|
|
22666
|
-
helper.centerX = helper.
|
|
22667
|
-
helper.centerY = helper.
|
|
22668
|
-
helper.centerZ = helper.
|
|
22668
|
+
helper.centerX = helper.levelDims.width / 2;
|
|
22669
|
+
helper.centerY = helper.levelDims.height / 2;
|
|
22670
|
+
helper.centerZ = helper.levelDims.depth / 2;
|
|
22669
22671
|
helper.configureHostImage();
|
|
22670
22672
|
return helper;
|
|
22671
22673
|
}
|
|
@@ -22828,6 +22830,9 @@ var NVZarrHelper = class _NVZarrHelper {
|
|
|
22828
22830
|
affine[row][col] = niftiCols[col].scale;
|
|
22829
22831
|
affine[row][3] = niftiCols[col].trans;
|
|
22830
22832
|
}
|
|
22833
|
+
affine[0][3] += this.worldOffsetMM[0];
|
|
22834
|
+
affine[1][3] += this.worldOffsetMM[1];
|
|
22835
|
+
affine[2][3] += this.worldOffsetMM[2];
|
|
22831
22836
|
hdr.affine = affine;
|
|
22832
22837
|
} else {
|
|
22833
22838
|
const { scaleW, scaleH, scaleD } = this.getConvertedScales();
|
|
@@ -22851,12 +22856,15 @@ var NVZarrHelper = class _NVZarrHelper {
|
|
|
22851
22856
|
affine[row][col] = niftiCols[col].scale;
|
|
22852
22857
|
affine[row][3] = niftiCols[col].trans;
|
|
22853
22858
|
}
|
|
22859
|
+
affine[0][3] += this.worldOffsetMM[0];
|
|
22860
|
+
affine[1][3] += this.worldOffsetMM[1];
|
|
22861
|
+
affine[2][3] += this.worldOffsetMM[2];
|
|
22854
22862
|
hdr.affine = affine;
|
|
22855
22863
|
} else {
|
|
22856
22864
|
hdr.affine = [
|
|
22857
|
-
[scaleW, 0, 0, volStartW * scaleW],
|
|
22858
|
-
[0, -scaleH, 0, volStartH * scaleH],
|
|
22859
|
-
[0, 0, -scaleD, volStartD * scaleD],
|
|
22865
|
+
[scaleW, 0, 0, volStartW * scaleW + this.worldOffsetMM[0]],
|
|
22866
|
+
[0, -scaleH, 0, volStartH * scaleH + this.worldOffsetMM[1]],
|
|
22867
|
+
[0, 0, -scaleD, volStartD * scaleD + this.worldOffsetMM[2]],
|
|
22860
22868
|
[0, 0, 0, 1]
|
|
22861
22869
|
];
|
|
22862
22870
|
}
|
|
@@ -22930,11 +22938,46 @@ var NVZarrHelper = class _NVZarrHelper {
|
|
|
22930
22938
|
getVolumeDims() {
|
|
22931
22939
|
return { ...this.volumeDims };
|
|
22932
22940
|
}
|
|
22941
|
+
getWorldOffset() {
|
|
22942
|
+
return [...this.worldOffsetMM];
|
|
22943
|
+
}
|
|
22944
|
+
/**
|
|
22945
|
+
* Set the world-space offset so the full level's center maps to targetMM in world space.
|
|
22946
|
+
* Computes the native physical center of the zarr level, then sets worldOffsetMM
|
|
22947
|
+
* so that center aligns with targetMM. Also centers the viewport on the level center.
|
|
22948
|
+
*/
|
|
22949
|
+
setWorldCenter(targetMM) {
|
|
22950
|
+
const { scaleW, scaleH, scaleD } = this.getConvertedScales();
|
|
22951
|
+
const { transW, transH, transD } = this.getConvertedTranslations();
|
|
22952
|
+
const axisNames = this.pyramidInfo.axisMapping.spatialAxisNames;
|
|
22953
|
+
const physW = this.levelDims.width / 2 * scaleW + transW;
|
|
22954
|
+
const physH = this.levelDims.height / 2 * scaleH + transH;
|
|
22955
|
+
const physD = this.levelDims.depth / 2 * scaleD + transD;
|
|
22956
|
+
const nativeCenter = [0, 0, 0];
|
|
22957
|
+
const dims = [
|
|
22958
|
+
{ name: axisNames[axisNames.length - 1], phys: physW },
|
|
22959
|
+
{ name: axisNames[axisNames.length - 2], phys: physH },
|
|
22960
|
+
{ name: axisNames.length >= 3 ? axisNames[axisNames.length - 3] : "z", phys: physD }
|
|
22961
|
+
];
|
|
22962
|
+
for (const d of dims) {
|
|
22963
|
+
const row = d.name === "x" ? 0 : d.name === "y" ? 1 : 2;
|
|
22964
|
+
nativeCenter[row] = d.phys;
|
|
22965
|
+
}
|
|
22966
|
+
this.worldOffsetMM = [targetMM[0] - nativeCenter[0], targetMM[1] - nativeCenter[1], targetMM[2] - nativeCenter[2]];
|
|
22967
|
+
this.centerX = this.levelDims.width / 2;
|
|
22968
|
+
this.centerY = this.levelDims.height / 2;
|
|
22969
|
+
this.centerZ = this.levelDims.depth / 2;
|
|
22970
|
+
this.clampCenter();
|
|
22971
|
+
this.updateAffine();
|
|
22972
|
+
}
|
|
22933
22973
|
/**
|
|
22934
22974
|
* Convert physical (mm) coordinates back to real zarr level pixel coordinates.
|
|
22935
22975
|
* Inverts the affine: levelPixel = (mm - OME_translation) / scale
|
|
22936
22976
|
*/
|
|
22937
22977
|
mmToLevelCoords(mmX, mmY, mmZ) {
|
|
22978
|
+
mmX -= this.worldOffsetMM[0];
|
|
22979
|
+
mmY -= this.worldOffsetMM[1];
|
|
22980
|
+
mmZ -= this.worldOffsetMM[2];
|
|
22938
22981
|
const { scaleW, scaleH, scaleD } = this.getConvertedScales();
|
|
22939
22982
|
const axisNames = this.pyramidInfo.axisMapping.spatialAxisNames;
|
|
22940
22983
|
const mmByAxis = { x: mmX, y: mmY, z: mmZ };
|
|
@@ -23046,8 +23089,6 @@ var NVZarrHelper = class _NVZarrHelper {
|
|
|
23046
23089
|
this.currentAbortController?.abort();
|
|
23047
23090
|
const abortController = new AbortController();
|
|
23048
23091
|
this.currentAbortController = abortController;
|
|
23049
|
-
this.runningMin = Infinity;
|
|
23050
|
-
this.runningMax = -Infinity;
|
|
23051
23092
|
await new Promise((resolve) => {
|
|
23052
23093
|
requestAnimationFrame(() => resolve());
|
|
23053
23094
|
});
|
|
@@ -23160,14 +23201,16 @@ var NVZarrHelper = class _NVZarrHelper {
|
|
|
23160
23201
|
if (actualChunkW <= 0 || actualChunkH <= 0 || actualChunkD <= 0) {
|
|
23161
23202
|
return;
|
|
23162
23203
|
}
|
|
23163
|
-
|
|
23164
|
-
|
|
23165
|
-
|
|
23166
|
-
|
|
23167
|
-
this.runningMin
|
|
23168
|
-
|
|
23169
|
-
|
|
23170
|
-
this.runningMax
|
|
23204
|
+
if (!this.calibrationDone) {
|
|
23205
|
+
const step = Math.max(1, Math.floor(data.length / 2e3));
|
|
23206
|
+
for (let i = 0; i < data.length; i += step) {
|
|
23207
|
+
const val = data[i];
|
|
23208
|
+
if (val < this.runningMin) {
|
|
23209
|
+
this.runningMin = val;
|
|
23210
|
+
}
|
|
23211
|
+
if (val > this.runningMax) {
|
|
23212
|
+
this.runningMax = val;
|
|
23213
|
+
}
|
|
23171
23214
|
}
|
|
23172
23215
|
}
|
|
23173
23216
|
const fullChunkVol = this.chunkSize.width * this.chunkSize.height * this.chunkSize.depth;
|
|
@@ -23198,6 +23241,9 @@ var NVZarrHelper = class _NVZarrHelper {
|
|
|
23198
23241
|
}
|
|
23199
23242
|
}
|
|
23200
23243
|
updateCalibration() {
|
|
23244
|
+
if (this.calibrationDone) {
|
|
23245
|
+
return;
|
|
23246
|
+
}
|
|
23201
23247
|
if (this.runningMin < Infinity && this.runningMax > -Infinity) {
|
|
23202
23248
|
this.hostImage.cal_min = this.runningMin;
|
|
23203
23249
|
this.hostImage.cal_max = this.runningMax;
|
|
@@ -23205,6 +23251,7 @@ var NVZarrHelper = class _NVZarrHelper {
|
|
|
23205
23251
|
this.hostImage.robust_max = this.runningMax;
|
|
23206
23252
|
this.hostImage.global_min = this.runningMin;
|
|
23207
23253
|
this.hostImage.global_max = this.runningMax;
|
|
23254
|
+
this.calibrationDone = true;
|
|
23208
23255
|
}
|
|
23209
23256
|
}
|
|
23210
23257
|
/**
|
|
@@ -23298,6 +23345,7 @@ var NVImage = class _NVImage {
|
|
|
23298
23345
|
__publicField(this, "onOpacityChange", () => {
|
|
23299
23346
|
});
|
|
23300
23347
|
__publicField(this, "zarrHelper", null);
|
|
23348
|
+
__publicField(this, "_hasExplicitZarrCenter", false);
|
|
23301
23349
|
__publicField(this, "mm000");
|
|
23302
23350
|
__publicField(this, "mm100");
|
|
23303
23351
|
__publicField(this, "mm010");
|
|
@@ -23934,7 +23982,8 @@ var NVImage = class _NVImage {
|
|
|
23934
23982
|
zarrLevel,
|
|
23935
23983
|
zarrMaxVolumeSize,
|
|
23936
23984
|
zarrChannel,
|
|
23937
|
-
zarrConvertUnits
|
|
23985
|
+
zarrConvertUnits,
|
|
23986
|
+
zarrCenterMM
|
|
23938
23987
|
} = {}) {
|
|
23939
23988
|
if (url === "") {
|
|
23940
23989
|
throw Error("url must not be empty");
|
|
@@ -23987,7 +24036,8 @@ var NVImage = class _NVImage {
|
|
|
23987
24036
|
channel: zarrChannel,
|
|
23988
24037
|
convertUnitsToMm: zarrConvertUnits,
|
|
23989
24038
|
colormap,
|
|
23990
|
-
opacity
|
|
24039
|
+
opacity,
|
|
24040
|
+
zarrCenterMM
|
|
23991
24041
|
});
|
|
23992
24042
|
}
|
|
23993
24043
|
const zarrResult = await loadZarrData(url);
|
|
@@ -24066,6 +24116,10 @@ var NVImage = class _NVImage {
|
|
|
24066
24116
|
cacheSize: options.cacheSize,
|
|
24067
24117
|
convertUnitsToMm: options.convertUnitsToMm
|
|
24068
24118
|
});
|
|
24119
|
+
if (options.zarrCenterMM) {
|
|
24120
|
+
nvimage.zarrHelper.setWorldCenter(options.zarrCenterMM);
|
|
24121
|
+
nvimage._hasExplicitZarrCenter = true;
|
|
24122
|
+
}
|
|
24069
24123
|
if (options.colormap) {
|
|
24070
24124
|
nvimage._colormap = options.colormap;
|
|
24071
24125
|
}
|
|
@@ -36600,7 +36654,8 @@ var Niivue = class {
|
|
|
36600
36654
|
zarrLevel: imageItem.zarrLevel,
|
|
36601
36655
|
zarrMaxVolumeSize: imageItem.zarrMaxVolumeSize,
|
|
36602
36656
|
zarrChannel: imageItem.zarrChannel,
|
|
36603
|
-
zarrConvertUnits: imageItem.zarrConvertUnits
|
|
36657
|
+
zarrConvertUnits: imageItem.zarrConvertUnits,
|
|
36658
|
+
zarrCenterMM: imageItem.zarrCenterMM
|
|
36604
36659
|
};
|
|
36605
36660
|
const volume = await NVImage.loadFromUrl(imageOptions);
|
|
36606
36661
|
this.document.addImageOptions(volume, imageOptions);
|
|
@@ -37180,6 +37235,20 @@ var Niivue = class {
|
|
|
37180
37235
|
this.setVolume(volume, result.index);
|
|
37181
37236
|
this.onImageLoaded(volume);
|
|
37182
37237
|
if (volume.zarrHelper) {
|
|
37238
|
+
if (!volume._hasExplicitZarrCenter && this.back && this.back !== volume && this.back.hdr?.dims) {
|
|
37239
|
+
const bg = this.back;
|
|
37240
|
+
const dims = bg.hdr.dims;
|
|
37241
|
+
const affine = bg.hdr.affine;
|
|
37242
|
+
const ci = (dims[1] - 1) / 2;
|
|
37243
|
+
const cj = (dims[2] - 1) / 2;
|
|
37244
|
+
const ck = (dims[3] - 1) / 2;
|
|
37245
|
+
const bgCenter = [
|
|
37246
|
+
affine[0][0] * ci + affine[0][1] * cj + affine[0][2] * ck + affine[0][3],
|
|
37247
|
+
affine[1][0] * ci + affine[1][1] * cj + affine[1][2] * ck + affine[1][3],
|
|
37248
|
+
affine[2][0] * ci + affine[2][1] * cj + affine[2][2] * ck + affine[2][3]
|
|
37249
|
+
];
|
|
37250
|
+
volume.zarrHelper.setWorldCenter(bgCenter);
|
|
37251
|
+
}
|
|
37183
37252
|
volume.zarrHelper.onChunksUpdated = () => {
|
|
37184
37253
|
this.updateGLVolume();
|
|
37185
37254
|
this._skipDragInDraw = true;
|