@idetik/core 0.40.3 → 0.42.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/README.md CHANGED
@@ -16,7 +16,7 @@ Idetik is a high-performance library for exploring multi-dimensional OME-Zarr da
16
16
 
17
17
  #### Documentation
18
18
 
19
- - Guide: https://chanzuckerberg.github.io/idetik/guide/getting-started
19
+ - User guide: https://chanzuckerberg.github.io/idetik/guide/getting-started
20
20
  - API reference: https://chanzuckerberg.github.io/idetik/api/
21
21
 
22
22
  ## Installation
package/dist/index.d.ts CHANGED
@@ -160,8 +160,13 @@ type ChunkLoader = {
160
160
  loadChunkData(chunk: Chunk, signal: AbortSignal): Promise<void>;
161
161
  };
162
162
 
163
- declare const ALL_CATEGORIES: readonly ["fallbackVisible", "prefetchTime", "visibleCurrent", "fallbackBackground", "prefetchSpace"];
164
- type PriorityCategory = (typeof ALL_CATEGORIES)[number];
163
+ /**
164
+ * A category of chunk request ordered by a loading policy.
165
+ */
166
+ type PriorityCategory = "fallbackVisible" | "prefetchTime" | "visibleCurrent" | "fallbackBackground" | "prefetchSpace";
167
+ /**
168
+ * @hidden
169
+ */
165
170
  type ImageSourcePolicyProps = {
166
171
  profile?: string;
167
172
  prefetch: {
@@ -177,6 +182,13 @@ type ImageSourcePolicyProps = {
177
182
  bias?: number;
178
183
  };
179
184
  };
185
+ /**
186
+ * A resolved and frozen loading policy consumed by layers.
187
+ *
188
+ * Create instances with {@link createExplorationPolicy},
189
+ * {@link createPlaybackPolicy}, {@link createNoPrefetchPolicy}, or
190
+ * {@link createImageSourcePolicy} rather than by hand.
191
+ */
180
192
  type ImageSourcePolicy = Readonly<{
181
193
  profile: string;
182
194
  prefetch: {
@@ -193,14 +205,42 @@ type ImageSourcePolicy = Readonly<{
193
205
  bias: number;
194
206
  };
195
207
  }>;
196
- /** @hidden */
197
- declare function createImageSourcePolicy(config: ImageSourcePolicyProps): ImageSourcePolicy;
198
- /** @hidden */
208
+ /**
209
+ * Creates a loading policy tuned for interactively browsing a scene.
210
+ *
211
+ * Prefetches one chunk beyond the view along each spatial axis and
212
+ * fills the visible region before prefetching. This is the default
213
+ * policy for layers constructed without one.
214
+ *
215
+ * @param overrides - Properties merged over.
216
+ */
199
217
  declare function createExplorationPolicy(overrides?: Partial<ImageSourcePolicyProps>): ImageSourcePolicy;
200
- /** @hidden */
218
+ /**
219
+ * Creates a loading policy tuned for playing through timepoints.
220
+ *
221
+ * Prefetches twenty timepoints ahead, buffering at the current LOD
222
+ * for smooth playback without reduced quality.
223
+ *
224
+ * @param overrides - Properties merged over.
225
+ */
201
226
  declare function createPlaybackPolicy(overrides?: Partial<ImageSourcePolicyProps>): ImageSourcePolicy;
202
- /** @hidden */
227
+ /**
228
+ * Creates a loading policy with spatial and temporal prefetching disabled.
229
+ *
230
+ * No spatial or temporal prefetching happens, which minimizes memory
231
+ * use and network traffic for static scenes.
232
+ *
233
+ * @param overrides - Properties merged over.
234
+ */
203
235
  declare function createNoPrefetchPolicy(overrides?: Partial<ImageSourcePolicyProps>): ImageSourcePolicy;
236
+ /**
237
+ * Creates a loading policy from explicit properties, validating and
238
+ * freezing them. Prefer the profile factories for common cases and use
239
+ * this to build a policy from scratch.
240
+ *
241
+ * @param config - Initialization properties.
242
+ */
243
+ declare function createImageSourcePolicy(config: ImageSourcePolicyProps): ImageSourcePolicy;
204
244
 
205
245
  declare class ChunkStore {
206
246
  private readonly chunks_;
@@ -1262,6 +1302,14 @@ interface CameraControls {
1262
1302
  */
1263
1303
  onEvent(event: EventContext): void;
1264
1304
  }
1305
+ type ScrollZoomMode = "always" | "modifier" | "never";
1306
+ /**
1307
+ * Initialization properties for constructing pan and zoom controls.
1308
+ */
1309
+ type PanZoomControlsProps = {
1310
+ /** When the scroll wheel zooms. Defaults to `"always"`. */
1311
+ scrollZoom?: ScrollZoomMode;
1312
+ };
1265
1313
  /**
1266
1314
  * Camera controls for 2D pan and zoom with an orthographic camera.
1267
1315
  *
@@ -1291,14 +1339,16 @@ interface CameraControls {
1291
1339
  */
1292
1340
  declare class PanZoomControls implements CameraControls {
1293
1341
  private readonly camera_;
1342
+ private readonly scrollZoom_;
1294
1343
  private dragActive_;
1295
1344
  private dragStart_;
1296
1345
  /**
1297
1346
  * Creates pan and zoom controls for the given camera.
1298
1347
  *
1299
1348
  * @param camera - The orthographic camera to control.
1349
+ * @param params - Initialization properties.
1300
1350
  */
1301
- constructor(camera: OrthographicCamera);
1351
+ constructor(camera: OrthographicCamera, params?: PanZoomControlsProps);
1302
1352
  /** Whether a pan drag is in progress. */
1303
1353
  get isMoving(): boolean;
1304
1354
  /**
@@ -3328,6 +3378,8 @@ type OrbitControlsProps = {
3328
3378
  target?: vec3;
3329
3379
  /** Velocity decay rate between `0` and `1`. Defaults to `0.5`. */
3330
3380
  dampingFactor?: number;
3381
+ /** When the scroll wheel zooms. Defaults to `"always"`. */
3382
+ scrollZoom?: ScrollZoomMode;
3331
3383
  };
3332
3384
  /**
3333
3385
  * Camera controls for orbiting a perspective camera around a target.
@@ -3361,6 +3413,7 @@ declare class OrbitControls implements CameraControls {
3361
3413
  private readonly currPos_;
3362
3414
  private readonly currCenter_;
3363
3415
  private readonly dampingFactor_;
3416
+ private readonly scrollZoom_;
3364
3417
  private currMouseButton_;
3365
3418
  /**
3366
3419
  * Creates orbit controls and moves the camera to the initial pose.
@@ -3405,4 +3458,4 @@ declare class OrbitControls implements CameraControls {
3405
3458
  }
3406
3459
 
3407
3460
  export { AxesLayer, Box2, Box3, Camera, Color, Frustum, Idetik, ImageLayer, ImageRenderable, LabelImageRenderable, LabelLayer, Layer, OmeZarrImageSource, OrbitControls, OrthographicCamera, PanZoomControls, PerspectiveCamera, PointsRenderable, ProjectedLineRenderable, RenderableObject, TrsTransform, Viewport, VolumeLayer, VolumeRenderable, createExplorationPolicy, createImageSourcePolicy, createNoPrefetchPolicy, createPlaybackPolicy, loadOmeZarrPlate, loadOmeZarrWell, loadOmeroChannels, loadOmeroDefaults };
3408
- export type { AxesLayerProps, BlendMode, CameraControls, CameraType, ChannelProps, ColorLike, FileSystemOmeZarrImageSourceProps, HttpOmeZarrImageSourceProps, IdetikProps, ImageLayerProps, ImageRenderableProps, LabelColorMap, LabelColorMapProps, LabelImageRenderableProps, LabelLayerProps, LayerProps, LayerState, MemoryStats, OrbitControlsProps, OrthographicCameraFrame, OrthographicCameraProps, Overlay, PerspectiveCameraProps, PointPickingResult, PointProps, ProjectedLineRenderableProps, QueueStats, SliceCoordinates, SliceOrientation, SourceDimension, SourceDimensionLod, SourceDimensionMap, StateChangeCallback, ViewportProps, VolumeLayerProps, VolumeRenderableProps };
3461
+ export type { AxesLayerProps, BlendMode, CameraControls, CameraType, ChannelProps, ColorLike, FileSystemOmeZarrImageSourceProps, HttpOmeZarrImageSourceProps, IdetikProps, ImageLayerProps, ImageRenderableProps, ImageSourcePolicy, ImageSourcePolicyProps, LabelColorMap, LabelColorMapProps, LabelImageRenderableProps, LabelLayerProps, LayerProps, LayerState, MemoryStats, OrbitControlsProps, OrthographicCameraFrame, OrthographicCameraProps, Overlay, PanZoomControlsProps, PerspectiveCameraProps, PointPickingResult, PointProps, PriorityCategory, ProjectedLineRenderableProps, QueueStats, SliceCoordinates, SliceOrientation, SourceDimension, SourceDimensionLod, SourceDimensionMap, StateChangeCallback, ViewportProps, VolumeLayerProps, VolumeRenderableProps };
package/dist/index.js CHANGED
@@ -2409,44 +2409,44 @@ class JQ {
2409
2409
  return o === this.currentLOD_ ? !1 : (this.currentLOD_ = o, !0);
2410
2410
  }
2411
2411
  markTimeChunksForPrefetchImage(A, I, B, C) {
2412
- const Q = this.store_.dimensions.t?.lods[0].size ?? 1, E = Math.min(this.policy_.prefetch.t, Q - 1), i = this.fallbackLOD(), o = this.policy_.priorityMap.prefetchTime, a = this.channelsOfInterest(I);
2413
- for (let s = 1; s <= E; ++s) {
2414
- const D = (A + s) % Q;
2412
+ const Q = this.store_.dimensions.t?.lods[0].size ?? 1, E = Math.min(this.policy_.prefetch.t, Q - 1), i = this.policy_.priorityMap.prefetchTime, o = this.channelsOfInterest(I);
2413
+ for (let a = 1; a <= E; ++a) {
2414
+ const s = (A + a) % Q;
2415
2415
  this.iterateChunksInBox(
2416
- D,
2417
- i,
2418
- a,
2416
+ s,
2417
+ this.currentLOD_,
2418
+ o,
2419
2419
  B,
2420
- (h) => {
2421
- const t = this.squareDistance2D(
2422
- h,
2420
+ (D) => {
2421
+ const h = this.squareDistance2D(
2422
+ D,
2423
2423
  C
2424
- ), y = hA(
2425
- t / this.sourceMaxSquareDistance2D_,
2424
+ ), t = hA(
2425
+ h / this.sourceMaxSquareDistance2D_,
2426
2426
  0,
2427
2427
  1 - Number.EPSILON
2428
- ), n = s + y;
2429
- this.chunkViewStates_.set(h, {
2428
+ ), y = a + t;
2429
+ this.chunkViewStates_.set(D, {
2430
2430
  visible: !1,
2431
2431
  prefetch: !0,
2432
- priority: o,
2433
- orderKey: n
2432
+ priority: i,
2433
+ orderKey: y
2434
2434
  });
2435
2435
  }
2436
2436
  );
2437
2437
  }
2438
2438
  }
2439
2439
  markTimeChunksForPrefetchVolume(A, I) {
2440
- const B = this.store_.dimensions.t?.lods[0].size ?? 1, C = Math.min(this.policy_.prefetch.t, B - 1), Q = this.fallbackLOD(), E = this.policy_.priorityMap.prefetchTime, i = this.channelsOfInterest(I);
2441
- for (let o = 1; o <= C; ++o) {
2442
- const a = (A + o) % B;
2443
- this.iterateAllChunksAtLod(a, Q, i, (s) => {
2444
- const D = o;
2445
- this.chunkViewStates_.set(s, {
2440
+ const B = this.store_.dimensions.t?.lods[0].size ?? 1, C = Math.min(this.policy_.prefetch.t, B - 1), Q = this.policy_.priorityMap.prefetchTime, E = this.channelsOfInterest(I);
2441
+ for (let i = 1; i <= C; ++i) {
2442
+ const o = (A + i) % B;
2443
+ this.iterateAllChunksAtLod(o, this.currentLOD_, E, (a) => {
2444
+ const s = i;
2445
+ this.chunkViewStates_.set(a, {
2446
2446
  visible: !1,
2447
2447
  prefetch: !0,
2448
- priority: E,
2449
- orderKey: D
2448
+ priority: Q,
2449
+ orderKey: s
2450
2450
  });
2451
2451
  });
2452
2452
  }
@@ -12828,36 +12828,8 @@ const nC = [
12828
12828
  "fallbackBackground",
12829
12829
  "prefetchSpace"
12830
12830
  ];
12831
- function mg(g) {
12832
- mi(g);
12833
- const A = {
12834
- x: g.prefetch.x,
12835
- y: g.prefetch.y,
12836
- z: g.prefetch.z ?? 0,
12837
- t: g.prefetch.t ?? 0
12838
- }, I = Object.freeze(
12839
- nC.reduce(
12840
- (Q, E) => {
12841
- const i = g.priorityOrder.indexOf(E);
12842
- return Q[E] = i, Q;
12843
- },
12844
- {}
12845
- )
12846
- ), B = {
12847
- min: g.lod?.min ?? 0,
12848
- max: g.lod?.max ?? Number.MAX_SAFE_INTEGER,
12849
- bias: g.lod?.bias ?? 0.5
12850
- }, C = {
12851
- profile: g.profile ?? "custom",
12852
- prefetch: A,
12853
- priorityOrder: Object.freeze([...g.priorityOrder]),
12854
- priorityMap: I,
12855
- lod: B
12856
- };
12857
- return Object.freeze(C);
12858
- }
12859
- function ug(g = {}) {
12860
- return mg(Tg({
12831
+ function mg(g = {}) {
12832
+ return ug(Tg({
12861
12833
  profile: "exploration",
12862
12834
  prefetch: { x: 1, y: 1, z: 1, t: 0 },
12863
12835
  priorityOrder: [
@@ -12870,20 +12842,20 @@ function ug(g = {}) {
12870
12842
  }, g));
12871
12843
  }
12872
12844
  function No(g = {}) {
12873
- return mg(Tg({
12845
+ return ug(Tg({
12874
12846
  profile: "playback",
12875
12847
  prefetch: { x: 0, y: 0, z: 0, t: 20 },
12876
12848
  priorityOrder: [
12877
12849
  "fallbackVisible",
12878
- "prefetchTime",
12879
12850
  "visibleCurrent",
12851
+ "prefetchTime",
12880
12852
  "fallbackBackground",
12881
12853
  "prefetchSpace"
12882
12854
  ]
12883
12855
  }, g));
12884
12856
  }
12885
12857
  function co(g = {}) {
12886
- return mg(Tg({
12858
+ return ug(Tg({
12887
12859
  profile: "no-prefetch",
12888
12860
  prefetch: { x: 0, y: 0, z: 0, t: 0 },
12889
12861
  priorityOrder: [
@@ -12895,6 +12867,34 @@ function co(g = {}) {
12895
12867
  ]
12896
12868
  }, g));
12897
12869
  }
12870
+ function ug(g) {
12871
+ mi(g);
12872
+ const A = {
12873
+ x: g.prefetch.x,
12874
+ y: g.prefetch.y,
12875
+ z: g.prefetch.z ?? 0,
12876
+ t: g.prefetch.t ?? 0
12877
+ }, I = Object.freeze(
12878
+ nC.reduce(
12879
+ (Q, E) => {
12880
+ const i = g.priorityOrder.indexOf(E);
12881
+ return Q[E] = i, Q;
12882
+ },
12883
+ {}
12884
+ )
12885
+ ), B = {
12886
+ min: g.lod?.min ?? 0,
12887
+ max: g.lod?.max ?? Number.MAX_SAFE_INTEGER,
12888
+ bias: g.lod?.bias ?? 0.5
12889
+ }, C = {
12890
+ profile: g.profile ?? "custom",
12891
+ prefetch: A,
12892
+ priorityOrder: Object.freeze([...g.priorityOrder]),
12893
+ priorityMap: I,
12894
+ lod: B
12895
+ };
12896
+ return Object.freeze(C);
12897
+ }
12898
12898
  function mi(g) {
12899
12899
  for (const [B, C] of Object.entries(g.prefetch))
12900
12900
  if (C !== void 0 && C < 0)
@@ -13166,7 +13166,7 @@ class rC extends qI {
13166
13166
  onPickValue: E,
13167
13167
  ...i
13168
13168
  }) {
13169
- super({ blendMode: "additive", occludes: !0, ...i }), this.setState("initialized"), this.source_ = A, this.policy_ = B ?? ug(), this.sliceCoords_ = I, this.orientation_ = C ?? "XY", this.axes_ = MA(this.orientation_), this.planeRotation_ = dA(this.axes_), this.channelProps_ = Q, this.initialChannelProps_ = Q, this.onPickValue_ = E;
13169
+ super({ blendMode: "additive", occludes: !0, ...i }), this.setState("initialized"), this.source_ = A, this.policy_ = B ?? mg(), this.sliceCoords_ = I, this.orientation_ = C ?? "XY", this.axes_ = MA(this.orientation_), this.planeRotation_ = dA(this.axes_), this.channelProps_ = Q, this.initialChannelProps_ = Q, this.onPickValue_ = E;
13170
13170
  }
13171
13171
  /** @hidden */
13172
13172
  attach(A) {
@@ -13748,7 +13748,7 @@ class Uo extends qI {
13748
13748
  * @param props - Initialization properties.
13749
13749
  */
13750
13750
  constructor({ source: A, sliceCoords: I, policy: B, channelProps: C }) {
13751
- super({ blendMode: "premultipliedOver" }), this.source_ = A, this.sliceCoords_ = I, this.policy_ = B ?? ug(), this.initialChannelProps_ = C, this.channelProps_ = C, this.setState("initialized");
13751
+ super({ blendMode: "premultipliedOver" }), this.source_ = A, this.sliceCoords_ = I, this.policy_ = B ?? mg(), this.initialChannelProps_ = C, this.channelProps_ = C, this.setState("initialized");
13752
13752
  }
13753
13753
  getOrCreateVolume(A, I) {
13754
13754
  const B = this.currentVolumes_.get(A);
@@ -14036,7 +14036,7 @@ class RC extends qI {
14036
14036
  outlineSelected: i = !1,
14037
14037
  ...o
14038
14038
  }) {
14039
- super(o), this.setState("initialized"), this.source_ = A, this.policy_ = B ?? ug(), this.sliceCoords_ = I, this.orientation_ = C ?? "XY", this.axes_ = MA(this.orientation_), this.planeRotation_ = dA(this.axes_), this.colorMap_ = JI(Q), this.onPickValue_ = E, this.outlineSelected_ = i;
14039
+ super(o), this.setState("initialized"), this.source_ = A, this.policy_ = B ?? mg(), this.sliceCoords_ = I, this.orientation_ = C ?? "XY", this.axes_ = MA(this.orientation_), this.planeRotation_ = dA(this.axes_), this.colorMap_ = JI(Q), this.onPickValue_ = E, this.outlineSelected_ = i;
14040
14040
  }
14041
14041
  /** @hidden */
14042
14042
  attach(A) {
@@ -14537,6 +14537,7 @@ class Lo {
14537
14537
  currPos_;
14538
14538
  currCenter_ = d();
14539
14539
  dampingFactor_;
14540
+ scrollZoom_;
14540
14541
  currMouseButton_ = vI;
14541
14542
  /**
14542
14543
  * Creates orbit controls and moves the camera to the initial pose.
@@ -14553,7 +14554,7 @@ class Lo {
14553
14554
  I?.dampingFactor ?? so,
14554
14555
  0,
14555
14556
  1
14556
- ), this.updateCamera();
14557
+ ), this.scrollZoom_ = I?.scrollZoom ?? "always", this.updateCamera();
14557
14558
  }
14558
14559
  /** The current distance from the target in world units. */
14559
14560
  get radius() {
@@ -14624,6 +14625,7 @@ class Lo {
14624
14625
  }
14625
14626
  onWheel(A) {
14626
14627
  const I = A.event;
14628
+ if (this.scrollZoom_ === "never" || this.scrollZoom_ === "modifier" && !(I.ctrlKey || I.metaKey)) return;
14627
14629
  I.preventDefault();
14628
14630
  const B = I.deltaY ?? 0;
14629
14631
  this.zoom(B);
@@ -14771,15 +14773,17 @@ class Jo extends cC {
14771
14773
  const PB = 0;
14772
14774
  class Yo {
14773
14775
  camera_;
14776
+ scrollZoom_;
14774
14777
  dragActive_ = !1;
14775
14778
  dragStart_ = d();
14776
14779
  /**
14777
14780
  * Creates pan and zoom controls for the given camera.
14778
14781
  *
14779
14782
  * @param camera - The orthographic camera to control.
14783
+ * @param params - Initialization properties.
14780
14784
  */
14781
- constructor(A) {
14782
- this.camera_ = A;
14785
+ constructor(A, I) {
14786
+ this.camera_ = A, this.scrollZoom_ = I?.scrollZoom ?? "always";
14783
14787
  }
14784
14788
  /** Whether a pan drag is in progress. */
14785
14789
  get isMoving() {
@@ -14818,6 +14822,7 @@ class Yo {
14818
14822
  onWheel(A) {
14819
14823
  if (!A.worldPos || !A.clipPos) return;
14820
14824
  const I = A.event;
14825
+ if (this.scrollZoom_ === "never" || this.scrollZoom_ === "modifier" && !(I.ctrlKey || I.metaKey)) return;
14821
14826
  I.preventDefault();
14822
14827
  const B = EA(A.worldPos), C = I.deltaY < 0 ? 1.05 : 0.95;
14823
14828
  this.camera_.zoom(C);
@@ -14930,8 +14935,8 @@ export {
14930
14935
  uQ as Viewport,
14931
14936
  Uo as VolumeLayer,
14932
14937
  bi as VolumeRenderable,
14933
- ug as createExplorationPolicy,
14934
- mg as createImageSourcePolicy,
14938
+ mg as createExplorationPolicy,
14939
+ ug as createImageSourcePolicy,
14935
14940
  co as createNoPrefetchPolicy,
14936
14941
  No as createPlaybackPolicy,
14937
14942
  wo as loadOmeZarrPlate,