@niivue/niivue 0.67.1-dev.0 → 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 +3 -2
- package/build/niivue/index.js +171 -26
- package/build/niivue/index.js.map +1 -1
- package/build/{nvdocument-CcP6istx.d.ts → nvdocument-DrX6RoEG.d.ts} +32 -2
- package/build/utils/index.d.ts +1 -1
- package/dist/index.d.ts +33 -2
- package/dist/index.js +171 -26
- 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 +31 -31
- package/package.json +108 -108
- package/src/index_zarr_viewer.html +255 -68
- package/src/niivue/descriptives.ts +1 -1
- package/src/niivue/index.ts +40 -3
- package/src/nvimage/index.ts +11 -3
- package/src/nvimage/utils.ts +2 -0
- package/src/nvimage/zarr/NVZarrHelper.ts +174 -25
- package/src/index_zarr.html +0 -152
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.
|
|
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",
|
|
@@ -22535,9 +22535,11 @@ function createTypedVoxelArray(datatypeCode, size) {
|
|
|
22535
22535
|
case 512 /* DT_UINT16 */:
|
|
22536
22536
|
return new Uint16Array(size);
|
|
22537
22537
|
case 4 /* DT_INT16 */:
|
|
22538
|
-
case 8 /* DT_INT32 */:
|
|
22539
22538
|
return new Int16Array(size);
|
|
22539
|
+
case 8 /* DT_INT32 */:
|
|
22540
|
+
return new Int32Array(size);
|
|
22540
22541
|
case 768 /* DT_UINT32 */:
|
|
22542
|
+
return new Uint32Array(size);
|
|
22541
22543
|
case 16 /* DT_FLOAT32 */:
|
|
22542
22544
|
return new Float32Array(size);
|
|
22543
22545
|
case 64 /* DT_FLOAT64 */:
|
|
@@ -22589,6 +22591,7 @@ var NVZarrHelper = class _NVZarrHelper {
|
|
|
22589
22591
|
__publicField(this, "voxelTranslations");
|
|
22590
22592
|
__publicField(this, "hasTranslations");
|
|
22591
22593
|
__publicField(this, "convertUnitsToMm");
|
|
22594
|
+
__publicField(this, "worldOffsetMM", [0, 0, 0]);
|
|
22592
22595
|
__publicField(this, "centerX");
|
|
22593
22596
|
__publicField(this, "centerY");
|
|
22594
22597
|
__publicField(this, "centerZ");
|
|
@@ -22599,6 +22602,7 @@ var NVZarrHelper = class _NVZarrHelper {
|
|
|
22599
22602
|
__publicField(this, "currentAbortController", null);
|
|
22600
22603
|
__publicField(this, "runningMin", Infinity);
|
|
22601
22604
|
__publicField(this, "runningMax", -Infinity);
|
|
22605
|
+
__publicField(this, "calibrationDone", false);
|
|
22602
22606
|
// Debounce state for batching chunk updates
|
|
22603
22607
|
__publicField(this, "updateDebounceTimer", null);
|
|
22604
22608
|
__publicField(this, "UPDATE_DEBOUNCE_MS", 50);
|
|
@@ -22665,9 +22669,11 @@ var NVZarrHelper = class _NVZarrHelper {
|
|
|
22665
22669
|
helper.centerY = helper.levelDims.height / 2;
|
|
22666
22670
|
helper.centerZ = helper.levelDims.depth / 2;
|
|
22667
22671
|
helper.configureHostImage();
|
|
22668
|
-
await helper.updateVolume();
|
|
22669
22672
|
return helper;
|
|
22670
22673
|
}
|
|
22674
|
+
async loadInitialChunks() {
|
|
22675
|
+
await this.updateVolume();
|
|
22676
|
+
}
|
|
22671
22677
|
updateLevelInfo() {
|
|
22672
22678
|
const levelInfo = this.pyramidInfo.levels[this.pyramidLevel];
|
|
22673
22679
|
const shape = levelInfo.shape;
|
|
@@ -22739,12 +22745,12 @@ var NVZarrHelper = class _NVZarrHelper {
|
|
|
22739
22745
|
img.img = createTypedVoxelArray(this.datatypeCode, width * height * depth);
|
|
22740
22746
|
this.updateAffine();
|
|
22741
22747
|
img.originalAffine = copyAffine(hdr.affine);
|
|
22742
|
-
img.cal_min =
|
|
22743
|
-
img.cal_max =
|
|
22744
|
-
img.robust_min =
|
|
22745
|
-
img.robust_max =
|
|
22746
|
-
img.global_min =
|
|
22747
|
-
img.global_max =
|
|
22748
|
+
img.cal_min = 0;
|
|
22749
|
+
img.cal_max = 0;
|
|
22750
|
+
img.robust_min = 0;
|
|
22751
|
+
img.robust_max = 0;
|
|
22752
|
+
img.global_min = 0;
|
|
22753
|
+
img.global_max = 0;
|
|
22748
22754
|
}
|
|
22749
22755
|
/** Get unit-converted voxel scales */
|
|
22750
22756
|
getConvertedScales() {
|
|
@@ -22824,6 +22830,9 @@ var NVZarrHelper = class _NVZarrHelper {
|
|
|
22824
22830
|
affine[row][col] = niftiCols[col].scale;
|
|
22825
22831
|
affine[row][3] = niftiCols[col].trans;
|
|
22826
22832
|
}
|
|
22833
|
+
affine[0][3] += this.worldOffsetMM[0];
|
|
22834
|
+
affine[1][3] += this.worldOffsetMM[1];
|
|
22835
|
+
affine[2][3] += this.worldOffsetMM[2];
|
|
22827
22836
|
hdr.affine = affine;
|
|
22828
22837
|
} else {
|
|
22829
22838
|
const { scaleW, scaleH, scaleD } = this.getConvertedScales();
|
|
@@ -22847,12 +22856,15 @@ var NVZarrHelper = class _NVZarrHelper {
|
|
|
22847
22856
|
affine[row][col] = niftiCols[col].scale;
|
|
22848
22857
|
affine[row][3] = niftiCols[col].trans;
|
|
22849
22858
|
}
|
|
22859
|
+
affine[0][3] += this.worldOffsetMM[0];
|
|
22860
|
+
affine[1][3] += this.worldOffsetMM[1];
|
|
22861
|
+
affine[2][3] += this.worldOffsetMM[2];
|
|
22850
22862
|
hdr.affine = affine;
|
|
22851
22863
|
} else {
|
|
22852
22864
|
hdr.affine = [
|
|
22853
|
-
[scaleW, 0, 0, volStartW * scaleW],
|
|
22854
|
-
[0, -scaleH, 0, volStartH * scaleH],
|
|
22855
|
-
[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]],
|
|
22856
22868
|
[0, 0, 0, 1]
|
|
22857
22869
|
];
|
|
22858
22870
|
}
|
|
@@ -22863,6 +22875,9 @@ var NVZarrHelper = class _NVZarrHelper {
|
|
|
22863
22875
|
beginDrag() {
|
|
22864
22876
|
this.centerAtDragStart = { x: this.centerX, y: this.centerY, z: this.centerZ };
|
|
22865
22877
|
}
|
|
22878
|
+
endDrag() {
|
|
22879
|
+
this.centerAtDragStart = null;
|
|
22880
|
+
}
|
|
22866
22881
|
async panBy(dx, dy, dz = 0) {
|
|
22867
22882
|
this.centerX -= dx;
|
|
22868
22883
|
this.centerY -= dy;
|
|
@@ -22872,12 +22887,18 @@ var NVZarrHelper = class _NVZarrHelper {
|
|
|
22872
22887
|
await this.updateVolume();
|
|
22873
22888
|
}
|
|
22874
22889
|
async panTo(newCenterX, newCenterY, newCenterZ) {
|
|
22890
|
+
const prevX = this.centerX;
|
|
22891
|
+
const prevY = this.centerY;
|
|
22892
|
+
const prevZ = this.centerZ;
|
|
22875
22893
|
this.centerX = newCenterX;
|
|
22876
22894
|
this.centerY = newCenterY;
|
|
22877
22895
|
if (newCenterZ !== void 0) {
|
|
22878
22896
|
this.centerZ = newCenterZ;
|
|
22879
22897
|
}
|
|
22880
22898
|
this.clampCenter();
|
|
22899
|
+
if (Math.abs(this.centerX - prevX) < 1e-3 && Math.abs(this.centerY - prevY) < 1e-3 && Math.abs(this.centerZ - prevZ) < 1e-3) {
|
|
22900
|
+
return;
|
|
22901
|
+
}
|
|
22881
22902
|
this.updateAffine();
|
|
22882
22903
|
await this.updateVolume();
|
|
22883
22904
|
}
|
|
@@ -22917,6 +22938,89 @@ var NVZarrHelper = class _NVZarrHelper {
|
|
|
22917
22938
|
getVolumeDims() {
|
|
22918
22939
|
return { ...this.volumeDims };
|
|
22919
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
|
+
}
|
|
22973
|
+
/**
|
|
22974
|
+
* Convert physical (mm) coordinates back to real zarr level pixel coordinates.
|
|
22975
|
+
* Inverts the affine: levelPixel = (mm - OME_translation) / scale
|
|
22976
|
+
*/
|
|
22977
|
+
mmToLevelCoords(mmX, mmY, mmZ) {
|
|
22978
|
+
mmX -= this.worldOffsetMM[0];
|
|
22979
|
+
mmY -= this.worldOffsetMM[1];
|
|
22980
|
+
mmZ -= this.worldOffsetMM[2];
|
|
22981
|
+
const { scaleW, scaleH, scaleD } = this.getConvertedScales();
|
|
22982
|
+
const axisNames = this.pyramidInfo.axisMapping.spatialAxisNames;
|
|
22983
|
+
const mmByAxis = { x: mmX, y: mmY, z: mmZ };
|
|
22984
|
+
let levelW = 0;
|
|
22985
|
+
let levelH = 0;
|
|
22986
|
+
let levelD = 0;
|
|
22987
|
+
if (axisNames.length >= 2) {
|
|
22988
|
+
const wAxisName = axisNames[axisNames.length - 1];
|
|
22989
|
+
const hAxisName = axisNames[axisNames.length - 2];
|
|
22990
|
+
const dAxisName = axisNames.length >= 3 ? axisNames[axisNames.length - 3] : "z";
|
|
22991
|
+
const mmW = mmByAxis[wAxisName] ?? mmX;
|
|
22992
|
+
const mmH = mmByAxis[hAxisName] ?? mmY;
|
|
22993
|
+
const mmD = mmByAxis[dAxisName] ?? mmZ;
|
|
22994
|
+
if (this.hasTranslations) {
|
|
22995
|
+
const { transW, transH, transD } = this.getConvertedTranslations();
|
|
22996
|
+
levelW = scaleW !== 0 ? (mmW - transW) / scaleW : 0;
|
|
22997
|
+
levelH = scaleH !== 0 ? (mmH - transH) / scaleH : 0;
|
|
22998
|
+
levelD = scaleD !== 0 ? (mmD - transD) / scaleD : 0;
|
|
22999
|
+
} else {
|
|
23000
|
+
levelW = scaleW !== 0 ? mmW / scaleW : 0;
|
|
23001
|
+
levelH = scaleH !== 0 ? mmH / scaleH : 0;
|
|
23002
|
+
levelD = scaleD !== 0 ? mmD / scaleD : 0;
|
|
23003
|
+
}
|
|
23004
|
+
} else {
|
|
23005
|
+
if (this.hasTranslations) {
|
|
23006
|
+
const { transW, transH, transD } = this.getConvertedTranslations();
|
|
23007
|
+
levelW = scaleW !== 0 ? (mmX - transW) / scaleW : 0;
|
|
23008
|
+
levelH = scaleH !== 0 ? (mmY - transH) / scaleH : 0;
|
|
23009
|
+
levelD = scaleD !== 0 ? (mmZ - transD) / scaleD : 0;
|
|
23010
|
+
} else {
|
|
23011
|
+
levelW = scaleW !== 0 ? mmX / scaleW : 0;
|
|
23012
|
+
levelH = scaleH !== 0 ? mmY / scaleH : 0;
|
|
23013
|
+
levelD = scaleD !== 0 ? mmZ / scaleD : 0;
|
|
23014
|
+
}
|
|
23015
|
+
}
|
|
23016
|
+
return {
|
|
23017
|
+
width: Math.round(levelW),
|
|
23018
|
+
height: Math.round(levelH),
|
|
23019
|
+
depth: Math.round(levelD),
|
|
23020
|
+
level: this.pyramidLevel,
|
|
23021
|
+
levelDims: { ...this.levelDims }
|
|
23022
|
+
};
|
|
23023
|
+
}
|
|
22920
23024
|
clampCenter() {
|
|
22921
23025
|
const halfW = this.volumeDims.width / 2;
|
|
22922
23026
|
const halfH = this.volumeDims.height / 2;
|
|
@@ -22985,8 +23089,6 @@ var NVZarrHelper = class _NVZarrHelper {
|
|
|
22985
23089
|
this.currentAbortController?.abort();
|
|
22986
23090
|
const abortController = new AbortController();
|
|
22987
23091
|
this.currentAbortController = abortController;
|
|
22988
|
-
this.runningMin = Infinity;
|
|
22989
|
-
this.runningMax = -Infinity;
|
|
22990
23092
|
await new Promise((resolve) => {
|
|
22991
23093
|
requestAnimationFrame(() => resolve());
|
|
22992
23094
|
});
|
|
@@ -23099,14 +23201,16 @@ var NVZarrHelper = class _NVZarrHelper {
|
|
|
23099
23201
|
if (actualChunkW <= 0 || actualChunkH <= 0 || actualChunkD <= 0) {
|
|
23100
23202
|
return;
|
|
23101
23203
|
}
|
|
23102
|
-
|
|
23103
|
-
|
|
23104
|
-
|
|
23105
|
-
|
|
23106
|
-
this.runningMin
|
|
23107
|
-
|
|
23108
|
-
|
|
23109
|
-
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
|
+
}
|
|
23110
23214
|
}
|
|
23111
23215
|
}
|
|
23112
23216
|
const fullChunkVol = this.chunkSize.width * this.chunkSize.height * this.chunkSize.depth;
|
|
@@ -23137,6 +23241,9 @@ var NVZarrHelper = class _NVZarrHelper {
|
|
|
23137
23241
|
}
|
|
23138
23242
|
}
|
|
23139
23243
|
updateCalibration() {
|
|
23244
|
+
if (this.calibrationDone) {
|
|
23245
|
+
return;
|
|
23246
|
+
}
|
|
23140
23247
|
if (this.runningMin < Infinity && this.runningMax > -Infinity) {
|
|
23141
23248
|
this.hostImage.cal_min = this.runningMin;
|
|
23142
23249
|
this.hostImage.cal_max = this.runningMax;
|
|
@@ -23144,6 +23251,7 @@ var NVZarrHelper = class _NVZarrHelper {
|
|
|
23144
23251
|
this.hostImage.robust_max = this.runningMax;
|
|
23145
23252
|
this.hostImage.global_min = this.runningMin;
|
|
23146
23253
|
this.hostImage.global_max = this.runningMax;
|
|
23254
|
+
this.calibrationDone = true;
|
|
23147
23255
|
}
|
|
23148
23256
|
}
|
|
23149
23257
|
/**
|
|
@@ -23237,6 +23345,7 @@ var NVImage = class _NVImage {
|
|
|
23237
23345
|
__publicField(this, "onOpacityChange", () => {
|
|
23238
23346
|
});
|
|
23239
23347
|
__publicField(this, "zarrHelper", null);
|
|
23348
|
+
__publicField(this, "_hasExplicitZarrCenter", false);
|
|
23240
23349
|
__publicField(this, "mm000");
|
|
23241
23350
|
__publicField(this, "mm100");
|
|
23242
23351
|
__publicField(this, "mm010");
|
|
@@ -23873,7 +23982,8 @@ var NVImage = class _NVImage {
|
|
|
23873
23982
|
zarrLevel,
|
|
23874
23983
|
zarrMaxVolumeSize,
|
|
23875
23984
|
zarrChannel,
|
|
23876
|
-
zarrConvertUnits
|
|
23985
|
+
zarrConvertUnits,
|
|
23986
|
+
zarrCenterMM
|
|
23877
23987
|
} = {}) {
|
|
23878
23988
|
if (url === "") {
|
|
23879
23989
|
throw Error("url must not be empty");
|
|
@@ -23926,7 +24036,8 @@ var NVImage = class _NVImage {
|
|
|
23926
24036
|
channel: zarrChannel,
|
|
23927
24037
|
convertUnitsToMm: zarrConvertUnits,
|
|
23928
24038
|
colormap,
|
|
23929
|
-
opacity
|
|
24039
|
+
opacity,
|
|
24040
|
+
zarrCenterMM
|
|
23930
24041
|
});
|
|
23931
24042
|
}
|
|
23932
24043
|
const zarrResult = await loadZarrData(url);
|
|
@@ -24005,6 +24116,10 @@ var NVImage = class _NVImage {
|
|
|
24005
24116
|
cacheSize: options.cacheSize,
|
|
24006
24117
|
convertUnitsToMm: options.convertUnitsToMm
|
|
24007
24118
|
});
|
|
24119
|
+
if (options.zarrCenterMM) {
|
|
24120
|
+
nvimage.zarrHelper.setWorldCenter(options.zarrCenterMM);
|
|
24121
|
+
nvimage._hasExplicitZarrCenter = true;
|
|
24122
|
+
}
|
|
24008
24123
|
if (options.colormap) {
|
|
24009
24124
|
nvimage._colormap = options.colormap;
|
|
24010
24125
|
}
|
|
@@ -34659,6 +34774,7 @@ var Niivue = class {
|
|
|
34659
34774
|
crosshair: false
|
|
34660
34775
|
});
|
|
34661
34776
|
__publicField(this, "readyForSync", false);
|
|
34777
|
+
__publicField(this, "_skipDragInDraw", false);
|
|
34662
34778
|
// UI Data
|
|
34663
34779
|
__publicField(this, "uiData", {
|
|
34664
34780
|
mousedown: false,
|
|
@@ -35755,6 +35871,9 @@ var Niivue = class {
|
|
|
35755
35871
|
}
|
|
35756
35872
|
if (this.uiData.isDragging) {
|
|
35757
35873
|
this.uiData.isDragging = false;
|
|
35874
|
+
for (const vol of this.getZarrVolumes()) {
|
|
35875
|
+
vol.zarrHelper?.endDrag();
|
|
35876
|
+
}
|
|
35758
35877
|
if (currentDragMode === 7 /* angle */) {
|
|
35759
35878
|
if (this.uiData.angleState === "drawing_first_line") {
|
|
35760
35879
|
this.uiData.angleFirstLine = [this.uiData.dragStart[0], this.uiData.dragStart[1], this.uiData.dragEnd[0], this.uiData.dragEnd[1]];
|
|
@@ -35900,6 +36019,9 @@ var Niivue = class {
|
|
|
35900
36019
|
}
|
|
35901
36020
|
if (this.uiData.isDragging) {
|
|
35902
36021
|
this.uiData.isDragging = false;
|
|
36022
|
+
for (const vol of this.getZarrVolumes()) {
|
|
36023
|
+
vol.zarrHelper?.endDrag();
|
|
36024
|
+
}
|
|
35903
36025
|
if (this.getCurrentDragMode() === 1 /* contrast */) {
|
|
35904
36026
|
this.calculateNewRange();
|
|
35905
36027
|
this.refreshLayers(this.volumes[0], 0);
|
|
@@ -35959,6 +36081,9 @@ var Niivue = class {
|
|
|
35959
36081
|
if (this.uiData.isDragging || this.uiData.mousedown) {
|
|
35960
36082
|
log.debug("Mouse left canvas during drag, resetting drag state.");
|
|
35961
36083
|
this.uiData.isDragging = false;
|
|
36084
|
+
for (const vol of this.getZarrVolumes()) {
|
|
36085
|
+
vol.zarrHelper?.endDrag();
|
|
36086
|
+
}
|
|
35962
36087
|
const resetState = createResetButtonState();
|
|
35963
36088
|
this.uiData.mouseButtonLeftDown = resetState.mouseButtonLeftDown;
|
|
35964
36089
|
this.uiData.mouseButtonCenterDown = resetState.mouseButtonCenterDown;
|
|
@@ -36529,7 +36654,8 @@ var Niivue = class {
|
|
|
36529
36654
|
zarrLevel: imageItem.zarrLevel,
|
|
36530
36655
|
zarrMaxVolumeSize: imageItem.zarrMaxVolumeSize,
|
|
36531
36656
|
zarrChannel: imageItem.zarrChannel,
|
|
36532
|
-
zarrConvertUnits: imageItem.zarrConvertUnits
|
|
36657
|
+
zarrConvertUnits: imageItem.zarrConvertUnits,
|
|
36658
|
+
zarrCenterMM: imageItem.zarrCenterMM
|
|
36533
36659
|
};
|
|
36534
36660
|
const volume = await NVImage.loadFromUrl(imageOptions);
|
|
36535
36661
|
this.document.addImageOptions(volume, imageOptions);
|
|
@@ -37109,10 +37235,27 @@ var Niivue = class {
|
|
|
37109
37235
|
this.setVolume(volume, result.index);
|
|
37110
37236
|
this.onImageLoaded(volume);
|
|
37111
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
|
+
}
|
|
37112
37252
|
volume.zarrHelper.onChunksUpdated = () => {
|
|
37113
37253
|
this.updateGLVolume();
|
|
37254
|
+
this._skipDragInDraw = true;
|
|
37114
37255
|
this.drawScene();
|
|
37256
|
+
this._skipDragInDraw = false;
|
|
37115
37257
|
};
|
|
37258
|
+
volume.zarrHelper.loadInitialChunks().catch((err) => log.error("Failed to load initial zarr chunks", err));
|
|
37116
37259
|
}
|
|
37117
37260
|
log.debug("loaded volume", volume.name);
|
|
37118
37261
|
log.debug(volume);
|
|
@@ -41239,7 +41382,9 @@ var Niivue = class {
|
|
|
41239
41382
|
}
|
|
41240
41383
|
if (panPromises.length > 0) {
|
|
41241
41384
|
Promise.all(panPromises).then(() => {
|
|
41385
|
+
this._skipDragInDraw = true;
|
|
41242
41386
|
this.drawScene();
|
|
41387
|
+
this._skipDragInDraw = false;
|
|
41243
41388
|
}).catch((err) => {
|
|
41244
41389
|
log.error("Failed to pan Zarr:", err);
|
|
41245
41390
|
});
|
|
@@ -44516,7 +44661,7 @@ var Niivue = class {
|
|
|
44516
44661
|
this.dragForSlicer3D([this.uiData.dragStart[0], this.uiData.dragStart[1], this.uiData.dragEnd[0], this.uiData.dragEnd[1]]);
|
|
44517
44662
|
return;
|
|
44518
44663
|
}
|
|
44519
|
-
if (this.getCurrentDragMode() === 3 /* pan */) {
|
|
44664
|
+
if (this.getCurrentDragMode() === 3 /* pan */ && !this._skipDragInDraw) {
|
|
44520
44665
|
this.dragForPanZoom([this.uiData.dragStart[0], this.uiData.dragStart[1], this.uiData.dragEnd[0], this.uiData.dragEnd[1]]);
|
|
44521
44666
|
return;
|
|
44522
44667
|
}
|