@fideus-labs/fidnii 0.5.0 → 0.7.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/dist/OMEZarrNVImage.d.ts +147 -14
- package/dist/OMEZarrNVImage.d.ts.map +1 -1
- package/dist/OMEZarrNVImage.js +517 -123
- package/dist/OMEZarrNVImage.js.map +1 -1
- package/dist/RegionCoalescer.d.ts +12 -7
- package/dist/RegionCoalescer.d.ts.map +1 -1
- package/dist/RegionCoalescer.js +30 -20
- package/dist/RegionCoalescer.js.map +1 -1
- package/dist/events.d.ts +17 -0
- package/dist/events.d.ts.map +1 -1
- package/dist/events.js.map +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -2
- package/dist/index.js.map +1 -1
- package/dist/types.d.ts +62 -8
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js.map +1 -1
- package/package.json +5 -5
- package/src/OMEZarrNVImage.ts +633 -139
- package/src/RegionCoalescer.ts +33 -14
- package/src/events.ts +18 -0
- package/src/index.ts +6 -1
- package/src/types.ts +88 -12
package/src/RegionCoalescer.ts
CHANGED
|
@@ -44,15 +44,17 @@ const SPATIAL_DIM_MAP: Record<string, 0 | 1 | 2> = {
|
|
|
44
44
|
* each zarr dimension to the correct slice:
|
|
45
45
|
* - `"z"`, `"y"`, `"x"` → sliced by the corresponding PixelRegion axis
|
|
46
46
|
* - `"c"` (channel) → `null` (select all components)
|
|
47
|
-
* - `"t"` (time) → `
|
|
47
|
+
* - `"t"` (time) → `timeIndex` (selects a single time point)
|
|
48
48
|
*
|
|
49
49
|
* @param dims - Dimension names from NgffImage (e.g. `["y", "x", "c"]`)
|
|
50
50
|
* @param region - The pixel region in `[z, y, x]` order
|
|
51
|
+
* @param timeIndex - Time point index to select (default: 0)
|
|
51
52
|
* @returns Selection array matching the zarr dim order
|
|
52
53
|
*/
|
|
53
54
|
export function buildSelection(
|
|
54
55
|
dims: string[],
|
|
55
56
|
region: PixelRegion,
|
|
57
|
+
timeIndex: number = 0,
|
|
56
58
|
): (zarr.Slice | number | null)[] {
|
|
57
59
|
return dims.map((dim) => {
|
|
58
60
|
const spatialIdx = SPATIAL_DIM_MAP[dim]
|
|
@@ -60,7 +62,7 @@ export function buildSelection(
|
|
|
60
62
|
return zarr.slice(region.start[spatialIdx], region.end[spatialIdx])
|
|
61
63
|
}
|
|
62
64
|
if (dim === "c") return null // select all channels
|
|
63
|
-
if (dim === "t") return
|
|
65
|
+
if (dim === "t") return timeIndex // select specified time point
|
|
64
66
|
// Unknown dimension — select all to avoid data loss
|
|
65
67
|
return null
|
|
66
68
|
})
|
|
@@ -96,16 +98,18 @@ export class RegionCoalescer {
|
|
|
96
98
|
}
|
|
97
99
|
|
|
98
100
|
/**
|
|
99
|
-
* Generate a unique key for a request based on image path, level index,
|
|
101
|
+
* Generate a unique key for a request based on image path, level index,
|
|
102
|
+
* region, and time index.
|
|
100
103
|
*/
|
|
101
104
|
private makeKey(
|
|
102
105
|
imagePath: string,
|
|
103
106
|
levelIndex: number,
|
|
104
107
|
region: PixelRegion,
|
|
108
|
+
timeIndex: number,
|
|
105
109
|
): string {
|
|
106
110
|
const start = region.start.join(",")
|
|
107
111
|
const end = region.end.join(",")
|
|
108
|
-
return `${imagePath}:${levelIndex}:${start}:${end}`
|
|
112
|
+
return `${imagePath}:${levelIndex}:${start}:${end}:t${timeIndex}`
|
|
109
113
|
}
|
|
110
114
|
|
|
111
115
|
/**
|
|
@@ -115,6 +119,8 @@ export class RegionCoalescer {
|
|
|
115
119
|
* @param levelIndex - The resolution level index
|
|
116
120
|
* @param region - The pixel region to fetch
|
|
117
121
|
* @param requesterId - ID of the requester (e.g., 'zoom', 'crop-change', 'progressive-load')
|
|
122
|
+
* @param timeIndex - Time point index to fetch (default: 0)
|
|
123
|
+
* @param signal - Optional AbortSignal to cancel the fetch
|
|
118
124
|
* @returns The fetched region data
|
|
119
125
|
*/
|
|
120
126
|
async fetchRegion(
|
|
@@ -122,8 +128,10 @@ export class RegionCoalescer {
|
|
|
122
128
|
levelIndex: number,
|
|
123
129
|
region: PixelRegion,
|
|
124
130
|
requesterId: string = "default",
|
|
131
|
+
timeIndex: number = 0,
|
|
132
|
+
signal?: AbortSignal,
|
|
125
133
|
): Promise<RegionFetchResult> {
|
|
126
|
-
const key = this.makeKey(ngffImage.data.path, levelIndex, region)
|
|
134
|
+
const key = this.makeKey(ngffImage.data.path, levelIndex, region, timeIndex)
|
|
127
135
|
|
|
128
136
|
// Check if there's already a pending request for this data
|
|
129
137
|
const existing = this.pending.get(key)
|
|
@@ -156,14 +164,21 @@ export class RegionCoalescer {
|
|
|
156
164
|
// Build a dim-aware selection that maps the [z, y, x] PixelRegion
|
|
157
165
|
// to the actual zarr dimension order. Non-spatial dims are handled:
|
|
158
166
|
// "c" (channel) → null (fetch all components)
|
|
159
|
-
// "t" (time) →
|
|
160
|
-
const selection = buildSelection(ngffImage.dims, region)
|
|
167
|
+
// "t" (time) → timeIndex (selects single time point)
|
|
168
|
+
const selection = buildSelection(ngffImage.dims, region, timeIndex)
|
|
161
169
|
// Pass the chunk cache to fizarrita's getWorker via zarrGet.
|
|
162
170
|
// The `cache` option is available in @fideus-labs/fizarrita >=1.2.0.
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
const
|
|
171
|
+
// When an AbortSignal is provided, forward it through `opts` so
|
|
172
|
+
// that the underlying FetchStore passes it as `RequestInit.signal`,
|
|
173
|
+
// allowing in-flight HTTP requests to be cancelled.
|
|
174
|
+
const zarrOpts: Record<string, unknown> = {}
|
|
175
|
+
if (this._cache) zarrOpts.cache = this._cache
|
|
176
|
+
if (signal) zarrOpts.opts = { signal }
|
|
177
|
+
const result = await zarrGet(
|
|
178
|
+
ngffImage.data,
|
|
179
|
+
selection,
|
|
180
|
+
Object.keys(zarrOpts).length > 0 ? zarrOpts : undefined,
|
|
181
|
+
)
|
|
167
182
|
|
|
168
183
|
const fetchResult: RegionFetchResult = {
|
|
169
184
|
data: result.data as TypedArray,
|
|
@@ -190,6 +205,7 @@ export class RegionCoalescer {
|
|
|
190
205
|
* @param levelIndex - The resolution level index
|
|
191
206
|
* @param regions - Array of pixel regions to fetch
|
|
192
207
|
* @param requesterId - ID of the requester
|
|
208
|
+
* @param timeIndex - Time point index to fetch (default: 0)
|
|
193
209
|
* @returns Array of fetched region data
|
|
194
210
|
*/
|
|
195
211
|
async fetchRegions(
|
|
@@ -197,10 +213,11 @@ export class RegionCoalescer {
|
|
|
197
213
|
levelIndex: number,
|
|
198
214
|
regions: PixelRegion[],
|
|
199
215
|
requesterId: string = "default",
|
|
216
|
+
timeIndex: number = 0,
|
|
200
217
|
): Promise<RegionFetchResult[]> {
|
|
201
218
|
return Promise.all(
|
|
202
219
|
regions.map((region) =>
|
|
203
|
-
this.fetchRegion(ngffImage, levelIndex, region, requesterId),
|
|
220
|
+
this.fetchRegion(ngffImage, levelIndex, region, requesterId, timeIndex),
|
|
204
221
|
),
|
|
205
222
|
)
|
|
206
223
|
}
|
|
@@ -212,8 +229,9 @@ export class RegionCoalescer {
|
|
|
212
229
|
ngffImage: NgffImage,
|
|
213
230
|
levelIndex: number,
|
|
214
231
|
region: PixelRegion,
|
|
232
|
+
timeIndex: number = 0,
|
|
215
233
|
): boolean {
|
|
216
|
-
const key = this.makeKey(ngffImage.data.path, levelIndex, region)
|
|
234
|
+
const key = this.makeKey(ngffImage.data.path, levelIndex, region, timeIndex)
|
|
217
235
|
return this.pending.has(key)
|
|
218
236
|
}
|
|
219
237
|
|
|
@@ -225,8 +243,9 @@ export class RegionCoalescer {
|
|
|
225
243
|
ngffImage: NgffImage,
|
|
226
244
|
levelIndex: number,
|
|
227
245
|
region: PixelRegion,
|
|
246
|
+
timeIndex: number = 0,
|
|
228
247
|
): Set<string> | undefined {
|
|
229
|
-
const key = this.makeKey(ngffImage.data.path, levelIndex, region)
|
|
248
|
+
const key = this.makeKey(ngffImage.data.path, levelIndex, region, timeIndex)
|
|
230
249
|
return this.pending.get(key)?.requesters
|
|
231
250
|
}
|
|
232
251
|
|
package/src/events.ts
CHANGED
|
@@ -112,6 +112,24 @@ export interface OMEZarrNVImageEventMap {
|
|
|
112
112
|
levelIndex: number
|
|
113
113
|
trigger: PopulateTrigger
|
|
114
114
|
}
|
|
115
|
+
|
|
116
|
+
/**
|
|
117
|
+
* Fired when the active time index changes.
|
|
118
|
+
*
|
|
119
|
+
* The `cached` flag indicates whether the frame was served instantly
|
|
120
|
+
* from the pre-fetch cache (`true`) or required a fresh zarr fetch
|
|
121
|
+
* (`false`).
|
|
122
|
+
*/
|
|
123
|
+
timeChange: {
|
|
124
|
+
/** New time index (0-based) */
|
|
125
|
+
index: number
|
|
126
|
+
/** Physical time value at the new index */
|
|
127
|
+
timeValue: number
|
|
128
|
+
/** Previous time index */
|
|
129
|
+
previousIndex: number
|
|
130
|
+
/** `true` if the frame was served from the pre-fetch cache */
|
|
131
|
+
cached: boolean
|
|
132
|
+
}
|
|
115
133
|
}
|
|
116
134
|
|
|
117
135
|
/**
|
package/src/index.ts
CHANGED
|
@@ -38,8 +38,10 @@ export type { DeflatePool, TiffStoreOptions } from "@fideus-labs/fiff"
|
|
|
38
38
|
export { TiffStore } from "@fideus-labs/fiff"
|
|
39
39
|
// Re-export Methods enum so consumers can check isLabelImage or compare method values
|
|
40
40
|
export { Methods } from "@fideus-labs/ngff-zarr"
|
|
41
|
-
// Worker pool lifecycle (re-exported from ngff-zarr)
|
|
41
|
+
// Worker pool lifecycle & configuration (re-exported from ngff-zarr)
|
|
42
42
|
export {
|
|
43
|
+
config as ngffZarrConfig,
|
|
44
|
+
setWorkerPoolSize,
|
|
43
45
|
terminateOmeroWorkerPool,
|
|
44
46
|
terminateWorkerPool,
|
|
45
47
|
} from "@fideus-labs/ngff-zarr/browser"
|
|
@@ -99,6 +101,7 @@ export {
|
|
|
99
101
|
// Types
|
|
100
102
|
export type {
|
|
101
103
|
AttachedNiivueState,
|
|
104
|
+
CachedTimeFrame,
|
|
102
105
|
ChannelInfo,
|
|
103
106
|
ChunkAlignedRegion,
|
|
104
107
|
ChunkCache,
|
|
@@ -110,6 +113,8 @@ export type {
|
|
|
110
113
|
ResolutionSelection,
|
|
111
114
|
SlabBufferState,
|
|
112
115
|
SlabSliceType,
|
|
116
|
+
TimeAxisInfo,
|
|
117
|
+
TimeUnit,
|
|
113
118
|
TypedArray,
|
|
114
119
|
VolumeBounds,
|
|
115
120
|
ZarrDtype,
|
package/src/types.ts
CHANGED
|
@@ -165,6 +165,24 @@ export interface OMEZarrNVImageOptions {
|
|
|
165
165
|
* This option has no effect on 3D volumes (images with a `"z"` axis).
|
|
166
166
|
*/
|
|
167
167
|
flipY2D?: boolean
|
|
168
|
+
/**
|
|
169
|
+
* Initial time index to display (default: 0, or `omero.defaultT` if available).
|
|
170
|
+
*
|
|
171
|
+
* Only relevant for datasets with a `"t"` (time) dimension. Ignored
|
|
172
|
+
* when the dataset has no time axis.
|
|
173
|
+
*/
|
|
174
|
+
timeIndex?: number
|
|
175
|
+
/**
|
|
176
|
+
* Number of adjacent time frames to pre-fetch in each direction (default: 2).
|
|
177
|
+
*
|
|
178
|
+
* When the user navigates to time index `t`, frames
|
|
179
|
+
* `[t - timePrefetchCount, t + timePrefetchCount]` are fetched in the
|
|
180
|
+
* background so that subsequent scrubbing can swap frames instantly from
|
|
181
|
+
* the cache. Set to `0` to disable pre-fetching.
|
|
182
|
+
*
|
|
183
|
+
* Only relevant for datasets with a `"t"` (time) dimension.
|
|
184
|
+
*/
|
|
185
|
+
timePrefetchCount?: number
|
|
168
186
|
}
|
|
169
187
|
|
|
170
188
|
/**
|
|
@@ -278,18 +296,8 @@ export interface AttachedNiivueState {
|
|
|
278
296
|
nv: Niivue
|
|
279
297
|
/** The current slice type of this NV instance */
|
|
280
298
|
currentSliceType: SLICE_TYPE
|
|
281
|
-
/**
|
|
282
|
-
|
|
283
|
-
/** Previous onOptsChange callback (to chain) */
|
|
284
|
-
previousOnOptsChange?: (
|
|
285
|
-
propertyName: string,
|
|
286
|
-
newValue: unknown,
|
|
287
|
-
oldValue: unknown,
|
|
288
|
-
) => void
|
|
289
|
-
/** Previous onMouseUp callback (to chain, for viewport-aware mode) */
|
|
290
|
-
previousOnMouseUp?: (data: unknown) => void
|
|
291
|
-
/** Previous onZoom3DChange callback (to chain, for viewport-aware mode) */
|
|
292
|
-
previousOnZoom3DChange?: (zoom: number) => void
|
|
299
|
+
/** AbortController for niivue addEventListener listeners (sliceTypeChange, locationChange) */
|
|
300
|
+
eventAbortController: AbortController
|
|
293
301
|
/** AbortController for viewport-aware event listeners (wheel, etc.) */
|
|
294
302
|
viewportAbortController?: AbortController
|
|
295
303
|
/** AbortController for the 3D zoom override wheel listener */
|
|
@@ -328,6 +336,74 @@ export const NiftiDataType = {
|
|
|
328
336
|
export type NiftiDataTypeCode =
|
|
329
337
|
(typeof NiftiDataType)[keyof typeof NiftiDataType]
|
|
330
338
|
|
|
339
|
+
/**
|
|
340
|
+
* Time units supported by OME-Zarr NGFF.
|
|
341
|
+
*
|
|
342
|
+
* Matches the UDUNITS-2 time units recognized by the OME-Zarr
|
|
343
|
+
* specification for the `"time"` axis type.
|
|
344
|
+
*/
|
|
345
|
+
export type TimeUnit =
|
|
346
|
+
| "attosecond"
|
|
347
|
+
| "centisecond"
|
|
348
|
+
| "day"
|
|
349
|
+
| "decisecond"
|
|
350
|
+
| "exasecond"
|
|
351
|
+
| "femtosecond"
|
|
352
|
+
| "gigasecond"
|
|
353
|
+
| "hectosecond"
|
|
354
|
+
| "hour"
|
|
355
|
+
| "kilosecond"
|
|
356
|
+
| "megasecond"
|
|
357
|
+
| "microsecond"
|
|
358
|
+
| "millisecond"
|
|
359
|
+
| "minute"
|
|
360
|
+
| "nanosecond"
|
|
361
|
+
| "petasecond"
|
|
362
|
+
| "picosecond"
|
|
363
|
+
| "second"
|
|
364
|
+
| "terasecond"
|
|
365
|
+
| "yoctosecond"
|
|
366
|
+
| "yottasecond"
|
|
367
|
+
| "zeptosecond"
|
|
368
|
+
| "zettasecond"
|
|
369
|
+
|
|
370
|
+
/**
|
|
371
|
+
* Time axis metadata extracted from OME-Zarr multiscales.
|
|
372
|
+
*
|
|
373
|
+
* Present only when the dataset has a `"t"` dimension. Contains
|
|
374
|
+
* the number of time points, physical time step, and unit
|
|
375
|
+
* information needed for time navigation.
|
|
376
|
+
*/
|
|
377
|
+
export interface TimeAxisInfo {
|
|
378
|
+
/** Number of time points (from the zarr array shape along `"t"`) */
|
|
379
|
+
readonly count: number
|
|
380
|
+
/** Index of the `"t"` dimension in `NgffImage.dims` */
|
|
381
|
+
readonly dimIndex: number
|
|
382
|
+
/** Physical time step between adjacent indices (from `scale.t`) */
|
|
383
|
+
readonly step: number
|
|
384
|
+
/** Time origin offset (from `translation.t`) */
|
|
385
|
+
readonly origin: number
|
|
386
|
+
/** Time unit (e.g., `"second"`, `"millisecond"`), or `undefined` if not specified */
|
|
387
|
+
readonly unit: TimeUnit | undefined
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
/**
|
|
391
|
+
* A pre-fetched 3D frame ready for instant buffer swap.
|
|
392
|
+
*
|
|
393
|
+
* Used by the time frame cache to avoid re-fetching when scrubbing
|
|
394
|
+
* through adjacent time points.
|
|
395
|
+
*/
|
|
396
|
+
export interface CachedTimeFrame {
|
|
397
|
+
/** The typed array pixel data for this frame */
|
|
398
|
+
data: TypedArray
|
|
399
|
+
/** Spatial shape in `[z, y, x]` order */
|
|
400
|
+
shape: [number, number, number]
|
|
401
|
+
/** The resolution level this was fetched at */
|
|
402
|
+
levelIndex: number
|
|
403
|
+
/** The chunk-aligned pixel region this was fetched for */
|
|
404
|
+
region: ChunkAlignedRegion
|
|
405
|
+
}
|
|
406
|
+
|
|
331
407
|
/**
|
|
332
408
|
* Information about a channel (component) dimension in the image.
|
|
333
409
|
*/
|