@fideus-labs/fidnii 0.1.0 → 0.2.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.
Files changed (45) hide show
  1. package/dist/BufferManager.d.ts.map +1 -1
  2. package/dist/BufferManager.js +2 -5
  3. package/dist/BufferManager.js.map +1 -1
  4. package/dist/ClipPlanes.d.ts.map +1 -1
  5. package/dist/ClipPlanes.js +11 -15
  6. package/dist/ClipPlanes.js.map +1 -1
  7. package/dist/OMEZarrNVImage.d.ts +33 -3
  8. package/dist/OMEZarrNVImage.d.ts.map +1 -1
  9. package/dist/OMEZarrNVImage.js +129 -50
  10. package/dist/OMEZarrNVImage.js.map +1 -1
  11. package/dist/RegionCoalescer.d.ts.map +1 -1
  12. package/dist/RegionCoalescer.js +1 -1
  13. package/dist/RegionCoalescer.js.map +1 -1
  14. package/dist/ResolutionSelector.d.ts.map +1 -1
  15. package/dist/ResolutionSelector.js +2 -4
  16. package/dist/ResolutionSelector.js.map +1 -1
  17. package/dist/ViewportBounds.d.ts.map +1 -1
  18. package/dist/ViewportBounds.js +7 -5
  19. package/dist/ViewportBounds.js.map +1 -1
  20. package/dist/events.d.ts.map +1 -1
  21. package/dist/events.js.map +1 -1
  22. package/dist/index.d.ts +11 -11
  23. package/dist/index.d.ts.map +1 -1
  24. package/dist/index.js +17 -16
  25. package/dist/index.js.map +1 -1
  26. package/dist/types.d.ts.map +1 -1
  27. package/dist/types.js.map +1 -1
  28. package/dist/utils/affine.d.ts +1 -1
  29. package/dist/utils/affine.d.ts.map +1 -1
  30. package/dist/utils/affine.js.map +1 -1
  31. package/dist/utils/coordinates.d.ts +1 -1
  32. package/dist/utils/coordinates.d.ts.map +1 -1
  33. package/dist/utils/coordinates.js.map +1 -1
  34. package/package.json +1 -1
  35. package/src/BufferManager.ts +45 -45
  36. package/src/ClipPlanes.ts +131 -130
  37. package/src/OMEZarrNVImage.ts +685 -606
  38. package/src/RegionCoalescer.ts +48 -47
  39. package/src/ResolutionSelector.ts +66 -67
  40. package/src/ViewportBounds.ts +120 -118
  41. package/src/events.ts +36 -35
  42. package/src/index.ts +59 -69
  43. package/src/types.ts +95 -94
  44. package/src/utils/affine.ts +65 -65
  45. package/src/utils/coordinates.ts +70 -70
@@ -1,9 +1,10 @@
1
1
  // SPDX-FileCopyrightText: Copyright (c) Fideus Labs LLC
2
2
  // SPDX-License-Identifier: MIT
3
3
 
4
- import type { Niivue } from "@niivue/niivue";
5
- import { SLICE_TYPE } from "@niivue/niivue";
6
- import type { VolumeBounds } from "./types.js";
4
+ import type { Niivue } from "@niivue/niivue"
5
+ import { SLICE_TYPE } from "@niivue/niivue"
6
+
7
+ import type { VolumeBounds } from "./types.js"
7
8
 
8
9
  /**
9
10
  * Intersect two axis-aligned bounding boxes.
@@ -17,12 +18,12 @@ export function intersectBounds(
17
18
  Math.max(a.min[0], b.min[0]),
18
19
  Math.max(a.min[1], b.min[1]),
19
20
  Math.max(a.min[2], b.min[2]),
20
- ];
21
+ ]
21
22
  const max: [number, number, number] = [
22
23
  Math.min(a.max[0], b.max[0]),
23
24
  Math.min(a.max[1], b.max[1]),
24
25
  Math.min(a.max[2], b.max[2]),
25
- ];
26
+ ]
26
27
  // Ensure valid bounds (max >= min)
27
28
  return {
28
29
  min: [
@@ -35,7 +36,7 @@ export function intersectBounds(
35
36
  Math.max(min[1], max[1]),
36
37
  Math.max(min[2], max[2]),
37
38
  ],
38
- };
39
+ }
39
40
  }
40
41
 
41
42
  /**
@@ -56,40 +57,40 @@ export function computeViewportBounds3D(
56
57
  volumeBounds: VolumeBounds,
57
58
  ): VolumeBounds {
58
59
  // Get scene extents: [min, max, range]
59
- const extents = nv.sceneExtentsMinMax(true);
60
- const mn = extents[0]; // vec3
61
- const mx = extents[1]; // vec3
62
- const range = extents[2]; // vec3
60
+ const extents = nv.sceneExtentsMinMax(true)
61
+ const mn = extents[0] // vec3
62
+ const mx = extents[1] // vec3
63
+ const range = extents[2] // vec3
63
64
 
64
65
  // Pivot = center of scene
65
- const pivotX = (mn[0] + mx[0]) * 0.5;
66
- const pivotY = (mn[1] + mx[1]) * 0.5;
67
- const pivotZ = (mn[2] + mx[2]) * 0.5;
66
+ const pivotX = (mn[0] + mx[0]) * 0.5
67
+ const pivotY = (mn[1] + mx[1]) * 0.5
68
+ const pivotZ = (mn[2] + mx[2]) * 0.5
68
69
 
69
70
  // furthestFromPivot = half-diagonal of bounding box
70
- const furthest = Math.sqrt(
71
- range[0] * range[0] + range[1] * range[1] + range[2] * range[2],
72
- ) * 0.5;
71
+ const furthest =
72
+ Math.sqrt(range[0] * range[0] + range[1] * range[1] + range[2] * range[2]) *
73
+ 0.5
73
74
 
74
75
  // NiiVue's orthographic scale (matches calculateMvpMatrix)
75
- const scale = (0.8 * furthest) / (nv.scene.volScaleMultiplier || 1);
76
+ const scale = (0.8 * furthest) / (nv.scene.volScaleMultiplier || 1)
76
77
 
77
78
  // Canvas aspect ratio
78
- const canvas = nv.canvas;
79
- const canvasW = canvas?.width ?? 1;
80
- const canvasH = canvas?.height ?? 1;
81
- const whratio = canvasW / canvasH;
79
+ const canvas = nv.canvas
80
+ const canvasW = canvas?.width ?? 1
81
+ const canvasH = canvas?.height ?? 1
82
+ const whratio = canvasW / canvasH
82
83
 
83
84
  // Ortho extents in view space (before rotation)
84
- let halfW: number, halfH: number;
85
+ let halfW: number, halfH: number
85
86
  if (whratio < 1) {
86
87
  // Portrait
87
- halfW = scale;
88
- halfH = scale / whratio;
88
+ halfW = scale
89
+ halfH = scale / whratio
89
90
  } else {
90
91
  // Landscape
91
- halfW = scale * whratio;
92
- halfH = scale;
92
+ halfW = scale * whratio
93
+ halfH = scale
93
94
  }
94
95
  // For viewport-aware resolution, we need the world-space extent that is
95
96
  // visible on screen. Rather than rotating a full 3D frustum box (whose depth
@@ -105,15 +106,15 @@ export function computeViewportBounds3D(
105
106
  // NiiVue applies: rotateX(270 - elevation) then rotateZ(azimuth - 180)
106
107
  // Also mirrors X (modelMatrix[0] = -1).
107
108
  // We need the inverse rotation to go from view space back to world space.
108
- const azimuth = nv.scene.renderAzimuth ?? 0;
109
- const elevation = nv.scene.renderElevation ?? 0;
110
- const azRad = ((azimuth - 180) * Math.PI) / 180;
111
- const elRad = ((270 - elevation) * Math.PI) / 180;
109
+ const azimuth = nv.scene.renderAzimuth ?? 0
110
+ const elevation = nv.scene.renderElevation ?? 0
111
+ const azRad = ((azimuth - 180) * Math.PI) / 180
112
+ const elRad = ((270 - elevation) * Math.PI) / 180
112
113
 
113
- const cosAz = Math.cos(azRad);
114
- const sinAz = Math.sin(azRad);
115
- const cosEl = Math.cos(elRad);
116
- const sinEl = Math.sin(elRad);
114
+ const cosAz = Math.cos(azRad)
115
+ const sinAz = Math.sin(azRad)
116
+ const cosEl = Math.cos(elRad)
117
+ const sinEl = Math.sin(elRad)
117
118
 
118
119
  // Compute inverse rotation of unit view-space axes to world space.
119
120
  // Inverse: un-mirror X, then rotateZ(-azRad), then rotateX(-elRad).
@@ -123,28 +124,29 @@ export function computeViewportBounds3D(
123
124
  -cosAz, // wx
124
125
  sinAz * cosEl, // wy
125
126
  -sinAz * sinEl, // wz
126
- ];
127
+ ]
127
128
  // View Y axis (0, 1, 0) — no mirror effect
128
129
  const viewYinWorld: [number, number, number] = [
129
130
  sinAz, // wx
130
131
  cosAz * cosEl, // wy
131
132
  -cosAz * sinEl, // wz
132
- ];
133
+ ]
133
134
  // View Z axis (0, 0, 1) — no mirror effect
134
135
  const viewZinWorld: [number, number, number] = [
135
136
  0, // wx
136
137
  sinEl, // wy
137
138
  cosEl, // wz
138
- ];
139
+ ]
139
140
 
140
141
  // For each world axis, the visible half-extent is:
141
142
  // halfW * |viewXinWorld[axis]| + halfH * |viewYinWorld[axis]|
142
143
  // + furthest * |viewZinWorld[axis]| (full volume depth along view Z)
143
- const worldHalfExtent: [number, number, number] = [0, 0, 0];
144
+ const worldHalfExtent: [number, number, number] = [0, 0, 0]
144
145
  for (let axis = 0; axis < 3; axis++) {
145
- worldHalfExtent[axis] = halfW * Math.abs(viewXinWorld[axis]) +
146
+ worldHalfExtent[axis] =
147
+ halfW * Math.abs(viewXinWorld[axis]) +
146
148
  halfH * Math.abs(viewYinWorld[axis]) +
147
- furthest * Math.abs(viewZinWorld[axis]);
149
+ furthest * Math.abs(viewZinWorld[axis])
148
150
  }
149
151
 
150
152
  const frustumBounds: VolumeBounds = {
@@ -158,9 +160,9 @@ export function computeViewportBounds3D(
158
160
  pivotY + worldHalfExtent[1],
159
161
  pivotZ + worldHalfExtent[2],
160
162
  ],
161
- };
163
+ }
162
164
 
163
- return intersectBounds(frustumBounds, volumeBounds);
165
+ return intersectBounds(frustumBounds, volumeBounds)
164
166
  }
165
167
 
166
168
  /**
@@ -203,97 +205,97 @@ export function computeViewportBounds2D(
203
205
  volumeBounds.min[0] * normalizationScale,
204
206
  volumeBounds.min[1] * normalizationScale,
205
207
  volumeBounds.min[2] * normalizationScale,
206
- ];
208
+ ]
207
209
  const normMax: [number, number, number] = [
208
210
  volumeBounds.max[0] * normalizationScale,
209
211
  volumeBounds.max[1] * normalizationScale,
210
212
  volumeBounds.max[2] * normalizationScale,
211
- ];
213
+ ]
212
214
 
213
215
  // Swizzle to screen axes (same mapping as NiiVue's swizzleVec3MM):
214
216
  // AXIAL: screen X = mm X, screen Y = mm Y
215
217
  // CORONAL: screen X = mm X, screen Y = mm Z
216
218
  // SAGITTAL: screen X = mm Y, screen Y = mm Z
217
- let mnMM0: number, mxMM0: number, mnMM1: number, mxMM1: number;
219
+ let mnMM0: number, mxMM0: number, mnMM1: number, mxMM1: number
218
220
  switch (sliceType) {
219
221
  case SLICE_TYPE.CORONAL:
220
- mnMM0 = normMin[0];
221
- mxMM0 = normMax[0]; // screen X = mm X
222
- mnMM1 = normMin[2];
223
- mxMM1 = normMax[2]; // screen Y = mm Z
224
- break;
222
+ mnMM0 = normMin[0]
223
+ mxMM0 = normMax[0] // screen X = mm X
224
+ mnMM1 = normMin[2]
225
+ mxMM1 = normMax[2] // screen Y = mm Z
226
+ break
225
227
  case SLICE_TYPE.SAGITTAL:
226
- mnMM0 = normMin[1];
227
- mxMM0 = normMax[1]; // screen X = mm Y
228
- mnMM1 = normMin[2];
229
- mxMM1 = normMax[2]; // screen Y = mm Z
230
- break;
228
+ mnMM0 = normMin[1]
229
+ mxMM0 = normMax[1] // screen X = mm Y
230
+ mnMM1 = normMin[2]
231
+ mxMM1 = normMax[2] // screen Y = mm Z
232
+ break
231
233
  default: // AXIAL
232
- mnMM0 = normMin[0];
233
- mxMM0 = normMax[0]; // screen X = mm X
234
- mnMM1 = normMin[1];
235
- mxMM1 = normMax[1]; // screen Y = mm Y
236
- break;
234
+ mnMM0 = normMin[0]
235
+ mxMM0 = normMax[0] // screen X = mm X
236
+ mnMM1 = normMin[1]
237
+ mxMM1 = normMax[1] // screen Y = mm Y
238
+ break
237
239
  }
238
240
 
239
241
  // Account for canvas aspect ratio stretching (matches draw2DMain logic)
240
242
  // NiiVue stretches the FOV to fill the canvas while preserving aspect ratio
241
- const canvas = nv.canvas;
243
+ const canvas = nv.canvas
242
244
  if (canvas) {
243
- const canvasW = canvas.width || 1;
244
- const canvasH = canvas.height || 1;
245
- const fovW = Math.abs(mxMM0 - mnMM0);
246
- const fovH = Math.abs(mxMM1 - mnMM1);
245
+ const canvasW = canvas.width || 1
246
+ const canvasH = canvas.height || 1
247
+ const fovW = Math.abs(mxMM0 - mnMM0)
248
+ const fovH = Math.abs(mxMM1 - mnMM1)
247
249
  if (fovW > 0 && fovH > 0) {
248
- const canvasAspect = canvasW / canvasH;
249
- const fovAspect = fovW / fovH;
250
+ const canvasAspect = canvasW / canvasH
251
+ const fovAspect = fovW / fovH
250
252
  if (canvasAspect > fovAspect) {
251
253
  // Canvas is wider than FOV: expand X
252
- const midX = (mnMM0 + mxMM0) * 0.5;
253
- const newHalfW = (fovH * canvasAspect) * 0.5;
254
- mnMM0 = midX - newHalfW;
255
- mxMM0 = midX + newHalfW;
254
+ const midX = (mnMM0 + mxMM0) * 0.5
255
+ const newHalfW = fovH * canvasAspect * 0.5
256
+ mnMM0 = midX - newHalfW
257
+ mxMM0 = midX + newHalfW
256
258
  } else {
257
259
  // Canvas is taller than FOV: expand Y
258
- const midY = (mnMM1 + mxMM1) * 0.5;
259
- const newHalfH = (fovW / canvasAspect) * 0.5;
260
- mnMM1 = midY - newHalfH;
261
- mxMM1 = midY + newHalfH;
260
+ const midY = (mnMM1 + mxMM1) * 0.5
261
+ const newHalfH = (fovW / canvasAspect) * 0.5
262
+ mnMM1 = midY - newHalfH
263
+ mxMM1 = midY + newHalfH
262
264
  }
263
265
  }
264
266
  }
265
267
 
266
268
  // Apply pan and zoom (matching NiiVue's draw2DMain logic)
267
- const pan = nv.scene.pan2Dxyzmm; // vec4: [panX, panY, panZ, zoom]
269
+ const pan = nv.scene.pan2Dxyzmm // vec4: [panX, panY, panZ, zoom]
268
270
  // Swizzle the pan vector to match the current orientation
269
271
  const panSwizzled = nv.swizzleVec3MM(
270
272
  [pan[0], pan[1], pan[2]] as unknown as import("gl-matrix").vec3,
271
273
  sliceType,
272
- );
273
- const zoom = pan[3] || 1;
274
+ )
275
+ const zoom = pan[3] || 1
274
276
 
275
277
  // Apply pan: shift visible window
276
- mnMM0 -= panSwizzled[0];
277
- mxMM0 -= panSwizzled[0];
278
- mnMM1 -= panSwizzled[1];
279
- mxMM1 -= panSwizzled[1];
278
+ mnMM0 -= panSwizzled[0]
279
+ mxMM0 -= panSwizzled[0]
280
+ mnMM1 -= panSwizzled[1]
281
+ mxMM1 -= panSwizzled[1]
280
282
 
281
283
  // Apply zoom: divide by zoom factor (zoom > 1 = zoomed in = smaller FOV)
282
- mnMM0 /= zoom;
283
- mxMM0 /= zoom;
284
- mnMM1 /= zoom;
285
- mxMM1 /= zoom;
284
+ mnMM0 /= zoom
285
+ mxMM0 /= zoom
286
+ mnMM1 /= zoom
287
+ mxMM1 /= zoom
286
288
 
287
289
  // Convert from NiiVue's mm space back to physical world coordinates.
288
290
  // If the slab affine was normalized (multiplied by normalizationScale),
289
291
  // NiiVue's mm values are world * normalizationScale. Dividing by the
290
292
  // normalization scale recovers physical coordinates.
291
293
  if (normalizationScale !== 1.0 && normalizationScale > 0) {
292
- const invNorm = 1.0 / normalizationScale;
293
- mnMM0 *= invNorm;
294
- mxMM0 *= invNorm;
295
- mnMM1 *= invNorm;
296
- mxMM1 *= invNorm;
294
+ const invNorm = 1.0 / normalizationScale
295
+ mnMM0 *= invNorm
296
+ mxMM0 *= invNorm
297
+ mnMM1 *= invNorm
298
+ mxMM1 *= invNorm
297
299
  }
298
300
 
299
301
  // Now un-swizzle back to RAS world coordinates.
@@ -306,42 +308,42 @@ export function computeViewportBounds2D(
306
308
  const result: VolumeBounds = {
307
309
  min: [...volumeBounds.min],
308
310
  max: [...volumeBounds.max],
309
- };
311
+ }
310
312
 
311
313
  // Ensure min < max for each swizzled axis
312
- const visMin0 = Math.min(mnMM0, mxMM0);
313
- const visMax0 = Math.max(mnMM0, mxMM0);
314
- const visMin1 = Math.min(mnMM1, mxMM1);
315
- const visMax1 = Math.max(mnMM1, mxMM1);
314
+ const visMin0 = Math.min(mnMM0, mxMM0)
315
+ const visMax0 = Math.max(mnMM0, mxMM0)
316
+ const visMin1 = Math.min(mnMM1, mxMM1)
317
+ const visMax1 = Math.max(mnMM1, mxMM1)
316
318
 
317
319
  switch (sliceType) {
318
320
  case SLICE_TYPE.AXIAL:
319
321
  // screen X = world X (R/L), screen Y = world Y (A/P)
320
- result.min[0] = visMin0;
321
- result.max[0] = visMax0;
322
- result.min[1] = visMin1;
323
- result.max[1] = visMax1;
322
+ result.min[0] = visMin0
323
+ result.max[0] = visMax0
324
+ result.min[1] = visMin1
325
+ result.max[1] = visMax1
324
326
  // Z (S/I) = full extent (orthogonal axis)
325
- break;
327
+ break
326
328
  case SLICE_TYPE.CORONAL:
327
329
  // screen X = world X (R/L), screen Y = world Z (S/I)
328
- result.min[0] = visMin0;
329
- result.max[0] = visMax0;
330
- result.min[2] = visMin1;
331
- result.max[2] = visMax1;
330
+ result.min[0] = visMin0
331
+ result.max[0] = visMax0
332
+ result.min[2] = visMin1
333
+ result.max[2] = visMax1
332
334
  // Y (A/P) = full extent (orthogonal axis)
333
- break;
335
+ break
334
336
  case SLICE_TYPE.SAGITTAL:
335
337
  // screen X = world Y (A/P), screen Y = world Z (S/I)
336
- result.min[1] = visMin0;
337
- result.max[1] = visMax0;
338
- result.min[2] = visMin1;
339
- result.max[2] = visMax1;
338
+ result.min[1] = visMin0
339
+ result.max[1] = visMax0
340
+ result.min[2] = visMin1
341
+ result.max[2] = visMax1
340
342
  // X (R/L) = full extent (orthogonal axis)
341
- break;
343
+ break
342
344
  }
343
345
 
344
- return intersectBounds(result, volumeBounds);
346
+ return intersectBounds(result, volumeBounds)
345
347
  }
346
348
 
347
349
  /**
@@ -358,12 +360,12 @@ export function boundsApproxEqual(
358
360
  tolerance: number = 0.01,
359
361
  ): boolean {
360
362
  for (let i = 0; i < 3; i++) {
361
- const rangeA = a.max[i] - a.min[i];
362
- const rangeB = b.max[i] - b.min[i];
363
- const maxRange = Math.max(Math.abs(rangeA), Math.abs(rangeB), 1e-10);
363
+ const rangeA = a.max[i] - a.min[i]
364
+ const rangeB = b.max[i] - b.min[i]
365
+ const maxRange = Math.max(Math.abs(rangeA), Math.abs(rangeB), 1e-10)
364
366
 
365
- if (Math.abs(a.min[i] - b.min[i]) / maxRange > tolerance) return false;
366
- if (Math.abs(a.max[i] - b.max[i]) / maxRange > tolerance) return false;
367
+ if (Math.abs(a.min[i] - b.min[i]) / maxRange > tolerance) return false
368
+ if (Math.abs(a.max[i] - b.max[i]) / maxRange > tolerance) return false
367
369
  }
368
- return true;
370
+ return true
369
371
  }
package/src/events.ts CHANGED
@@ -1,8 +1,9 @@
1
1
  // SPDX-FileCopyrightText: Copyright (c) Fideus Labs LLC
2
2
  // SPDX-License-Identifier: MIT
3
3
 
4
- import type { SLICE_TYPE } from "@niivue/niivue";
5
- import type { ClipPlanes } from "./types.js";
4
+ import type { SLICE_TYPE } from "@niivue/niivue"
5
+
6
+ import type { ClipPlanes } from "./types.js"
6
7
 
7
8
  /**
8
9
  * Identifies what triggered a volume population.
@@ -12,7 +13,7 @@ export type PopulateTrigger =
12
13
  | "initial" // First load or reload with new settings
13
14
  | "clipPlanesChanged" // Clip planes were modified
14
15
  | "sliceChanged" // Slice position changed (slab reload)
15
- | "viewportChanged"; // Viewport pan/zoom/rotation changed
16
+ | "viewportChanged" // Viewport pan/zoom/rotation changed
16
17
 
17
18
  /**
18
19
  * Type-safe event map for OMEZarrNVImage events.
@@ -43,15 +44,15 @@ export type PopulateTrigger =
43
44
  export interface OMEZarrNVImageEventMap {
44
45
  /** Fired when loading starts for a resolution level */
45
46
  loadingStart: {
46
- levelIndex: number;
47
- trigger: PopulateTrigger;
48
- };
47
+ levelIndex: number
48
+ trigger: PopulateTrigger
49
+ }
49
50
 
50
51
  /** Fired when loading completes for a resolution level */
51
52
  loadingComplete: {
52
- levelIndex: number;
53
- trigger: PopulateTrigger;
54
- };
53
+ levelIndex: number
54
+ trigger: PopulateTrigger
55
+ }
55
56
 
56
57
  /**
57
58
  * Fired when resolution level changes.
@@ -59,27 +60,27 @@ export interface OMEZarrNVImageEventMap {
59
60
  * cause a resolution change.
60
61
  */
61
62
  resolutionChange: {
62
- currentLevel: number;
63
- targetLevel: number;
64
- previousLevel: number;
65
- trigger: PopulateTrigger;
66
- };
63
+ currentLevel: number
64
+ targetLevel: number
65
+ previousLevel: number
66
+ trigger: PopulateTrigger
67
+ }
67
68
 
68
69
  /**
69
70
  * Fired when clip planes are updated (after debounce).
70
71
  * This is emitted after the debounce delay, not on every slider movement.
71
72
  */
72
- clipPlanesChange: { clipPlanes: ClipPlanes };
73
+ clipPlanesChange: { clipPlanes: ClipPlanes }
73
74
 
74
75
  /**
75
76
  * Fired when populateVolume() completes and no more requests are queued.
76
77
  * This is the final event after all loading is done.
77
78
  */
78
79
  populateComplete: {
79
- currentLevel: number;
80
- targetLevel: number;
81
- trigger: PopulateTrigger;
82
- };
80
+ currentLevel: number
81
+ targetLevel: number
82
+ trigger: PopulateTrigger
83
+ }
83
84
 
84
85
  /**
85
86
  * Fired when a queued load request is replaced by a newer one.
@@ -87,30 +88,30 @@ export interface OMEZarrNVImageEventMap {
87
88
  * the first request is queued.
88
89
  */
89
90
  loadingSkipped: {
90
- reason: "queued-replaced";
91
- trigger: PopulateTrigger;
92
- };
91
+ reason: "queued-replaced"
92
+ trigger: PopulateTrigger
93
+ }
93
94
 
94
95
  /**
95
96
  * Fired when a slab (2D slice buffer) finishes loading.
96
97
  * This event is specific to slab-based loading for 2D slice views.
97
98
  */
98
99
  slabLoadingComplete: {
99
- sliceType: SLICE_TYPE;
100
- levelIndex: number;
101
- slabStart: number;
102
- slabEnd: number;
103
- trigger: PopulateTrigger;
104
- };
100
+ sliceType: SLICE_TYPE
101
+ levelIndex: number
102
+ slabStart: number
103
+ slabEnd: number
104
+ trigger: PopulateTrigger
105
+ }
105
106
 
106
107
  /**
107
108
  * Fired when a slab starts loading.
108
109
  */
109
110
  slabLoadingStart: {
110
- sliceType: SLICE_TYPE;
111
- levelIndex: number;
112
- trigger: PopulateTrigger;
113
- };
111
+ sliceType: SLICE_TYPE
112
+ levelIndex: number
113
+ trigger: PopulateTrigger
114
+ }
114
115
  }
115
116
 
116
117
  /**
@@ -121,7 +122,7 @@ export class OMEZarrNVImageEvent<
121
122
  K extends keyof OMEZarrNVImageEventMap,
122
123
  > extends CustomEvent<OMEZarrNVImageEventMap[K]> {
123
124
  constructor(type: K, detail: OMEZarrNVImageEventMap[K]) {
124
- super(type, { detail });
125
+ super(type, { detail })
125
126
  }
126
127
  }
127
128
 
@@ -131,7 +132,7 @@ export class OMEZarrNVImageEvent<
131
132
  */
132
133
  export type OMEZarrNVImageEventListener<
133
134
  K extends keyof OMEZarrNVImageEventMap,
134
- > = (event: OMEZarrNVImageEvent<K>) => void | Promise<void>;
135
+ > = (event: OMEZarrNVImageEvent<K>) => void | Promise<void>
135
136
 
136
137
  /**
137
138
  * Options for addEventListener/removeEventListener.
@@ -143,4 +144,4 @@ export type OMEZarrNVImageEventListener<
143
144
  */
144
145
  export type OMEZarrNVImageEventListenerOptions =
145
146
  | boolean
146
- | AddEventListenerOptions;
147
+ | AddEventListenerOptions