@jax-data-science/sci-image-visualizer 0.10.0 → 0.12.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 (58) hide show
  1. package/esm2022/index.mjs +7 -1
  2. package/esm2022/lib/contracts/image.contract.mjs +1 -1
  3. package/esm2022/lib/contracts/ports/region-io.port.mjs +1 -1
  4. package/esm2022/lib/contracts/region-editor-api.contract.mjs +1 -1
  5. package/esm2022/lib/implementations/napari-js/napari-spatial-3d-scene.mjs +70 -2
  6. package/esm2022/lib/implementations/napari-js/napari-visualizer.service.mjs +2 -2
  7. package/esm2022/lib/implementations/napari-js/napari-volume-region-meshes.mjs +11 -1
  8. package/esm2022/lib/implementations/osd/openseadragon-viewer-options.mjs +18 -2
  9. package/esm2022/lib/implementations/osd/openseadragon-visualizer.service.mjs +9 -1
  10. package/esm2022/lib/implementations/osd/osd-tile-loading.mjs +71 -0
  11. package/esm2022/lib/implementations/osd/osd-viewer-like.mjs +1 -1
  12. package/esm2022/lib/implementations/osd/slice-cache.mjs +35 -6
  13. package/esm2022/lib/region-editor/region-editor.component.mjs +152 -4
  14. package/esm2022/lib/region-editor/region-persistence.service.mjs +9 -1
  15. package/esm2022/lib/region-import/label-classes.mjs +149 -0
  16. package/esm2022/lib/region-import/label-volume.mjs +225 -0
  17. package/esm2022/lib/region-import/ome-zarr-labels.mjs +253 -0
  18. package/esm2022/lib/region-import/open-annotations.mjs +289 -0
  19. package/esm2022/lib/region-import/region-import.mjs +71 -0
  20. package/esm2022/lib/region-import/zarr-codecs.mjs +167 -0
  21. package/esm2022/lib/region-import/zip.mjs +157 -0
  22. package/esm2022/lib/routing-visualizer.service.mjs +112 -7
  23. package/esm2022/lib/store/region-source-scope.mjs +19 -4
  24. package/esm2022/lib/store/region-store.service.mjs +64 -14
  25. package/esm2022/lib/visualizer/region-load.mjs +16 -1
  26. package/esm2022/lib/visualizer.component.mjs +28 -2
  27. package/fesm2022/{jax-data-science-sci-image-visualizer-jax-data-science-sci-image-visualizer-BKQhpbHv.mjs → jax-data-science-sci-image-visualizer-jax-data-science-sci-image-visualizer-a68Hw5rw.mjs} +2057 -196
  28. package/fesm2022/jax-data-science-sci-image-visualizer-jax-data-science-sci-image-visualizer-a68Hw5rw.mjs.map +1 -0
  29. package/fesm2022/{jax-data-science-sci-image-visualizer-onnx-sam-session-z1IN-F7w.mjs → jax-data-science-sci-image-visualizer-onnx-sam-session-CvadfzjS.mjs} +4 -2
  30. package/fesm2022/{jax-data-science-sci-image-visualizer-onnx-sam-session-z1IN-F7w.mjs.map → jax-data-science-sci-image-visualizer-onnx-sam-session-CvadfzjS.mjs.map} +1 -1
  31. package/fesm2022/jax-data-science-sci-image-visualizer.mjs +3 -1
  32. package/fesm2022/jax-data-science-sci-image-visualizer.mjs.map +1 -1
  33. package/index.d.ts +12 -0
  34. package/lib/contracts/image.contract.d.ts +7 -0
  35. package/lib/contracts/ports/region-io.port.d.ts +24 -0
  36. package/lib/contracts/region-editor-api.contract.d.ts +19 -1
  37. package/lib/implementations/napari-js/napari-spatial-3d-scene.d.ts +40 -1
  38. package/lib/implementations/napari-js/napari-volume-region-meshes.d.ts +5 -0
  39. package/lib/implementations/osd/openseadragon-viewer-options.d.ts +2 -0
  40. package/lib/implementations/osd/openseadragon-visualizer.service.d.ts +2 -0
  41. package/lib/implementations/osd/osd-tile-loading.d.ts +43 -0
  42. package/lib/implementations/osd/osd-viewer-like.d.ts +14 -0
  43. package/lib/implementations/osd/slice-cache.d.ts +13 -3
  44. package/lib/region-editor/region-editor.component.d.ts +27 -0
  45. package/lib/region-editor/region-persistence.service.d.ts +5 -1
  46. package/lib/region-import/label-classes.d.ts +39 -0
  47. package/lib/region-import/label-volume.d.ts +35 -0
  48. package/lib/region-import/ome-zarr-labels.d.ts +36 -0
  49. package/lib/region-import/open-annotations.d.ts +73 -0
  50. package/lib/region-import/region-import.d.ts +46 -0
  51. package/lib/region-import/zarr-codecs.d.ts +14 -0
  52. package/lib/region-import/zip.d.ts +31 -0
  53. package/lib/routing-visualizer.service.d.ts +39 -1
  54. package/lib/store/region-source-scope.d.ts +8 -2
  55. package/lib/store/region-store.service.d.ts +15 -5
  56. package/lib/visualizer.component.d.ts +9 -0
  57. package/package.json +2 -1
  58. package/fesm2022/jax-data-science-sci-image-visualizer-jax-data-science-sci-image-visualizer-BKQhpbHv.mjs.map +0 -1
@@ -0,0 +1,73 @@
1
+ import type { IImageInfo } from '../contracts/image.contract';
2
+ import type { RegionSource } from '../region-source/region-source';
3
+ import { LabelClasses } from './label-classes';
4
+ import { Gunzip } from './label-volume';
5
+ import { LabelStack } from './ome-zarr-labels';
6
+ import { RegionImportFile } from './region-import';
7
+ import { Inflate } from './zarr-codecs';
8
+ import { InflateRaw } from './zip';
9
+ /** The longest side an image built for annotations may have: OpenSeadragon's non-tiled limit. */
10
+ export declare const ANNOTATION_IMAGE_MAX_DIM = 8192;
11
+ /** Opens a slice's region source (again, after the store closed it). */
12
+ type Opener = () => Promise<RegionSource>;
13
+ /** Decoders, injectable for tests and workers (defaults: the platform's streams). */
14
+ export interface AnnotationDecoders {
15
+ inflateRaw?: InflateRaw;
16
+ inflate?: Inflate;
17
+ gunzip?: Gunzip;
18
+ /** Open a GeoJSON text as a region source (default: in the shared region worker). */
19
+ openGeoJson?: (text: string) => Promise<RegionSource>;
20
+ /**
21
+ * Give a label image's regions the atlas look (dark outlines, labels) when its ontology names
22
+ * no style: drawn over the label image itself, outlines in their classes' own colours would not
23
+ * show. (Imported over a real image, the default look reads.)
24
+ */
25
+ outlineLabels?: boolean;
26
+ }
27
+ /** The annotations among some files, as one region source per slice. */
28
+ export interface AnnotationSlices {
29
+ kind: 'labels' | 'folder' | 'single';
30
+ /** A name for what was opened (the label image's, the folder's, the file's). */
31
+ name: string;
32
+ slices: number;
33
+ /** One opener per slice index. */
34
+ openers: Map<number, Opener>;
35
+ /** A label image's slices and classes (to draw them, see openAnnotations). */
36
+ labels?: {
37
+ stack: LabelStack;
38
+ classes: LabelClasses;
39
+ };
40
+ /** Slice width and height, when known without opening the sources (a label image's). */
41
+ size?: [number, number];
42
+ /** Voxel size x, y, z in micrometres, when the source says. */
43
+ spacing?: [number, number, number];
44
+ /** What was read, for a message ("12 slices of 456 × 320"). */
45
+ summary: string;
46
+ }
47
+ /**
48
+ * The annotations among `files` (zips expanded), as one region source per slice; null when there
49
+ * are none to read. A label image's slices are traced, and a GeoJSON parsed, when the slice is
50
+ * first shown.
51
+ */
52
+ export declare function readAnnotationSlices(chosen: readonly RegionImportFile[], decoders?: AnnotationDecoders): Promise<AnnotationSlices | null>;
53
+ /** What {@link openAnnotations} built: the image to publish, and how to release it. */
54
+ export interface OpenedAnnotations {
55
+ info: IImageInfo;
56
+ summary: string;
57
+ /** Revoke the image's blob URLs, and release the slices' sources the region store never took
58
+ * (once another image replaced it). */
59
+ dispose(): void;
60
+ }
61
+ /**
62
+ * The image `files`' annotations are shown on by themselves (see the module comment). Throws when
63
+ * there are none, or when their regions span more than {@link ANNOTATION_IMAGE_MAX_DIM} pixels
64
+ * (they are then imported onto the image they were drawn on).
65
+ */
66
+ export declare function openAnnotations(files: readonly RegionImportFile[], decoders?: AnnotationDecoders): Promise<OpenedAnnotations>;
67
+ /**
68
+ * One GeoJSON's slices: a collection whose features name planes (`geometry.plane.z`) split into
69
+ * one collection per plane, each keeping the set's class tree and style, its features moved to
70
+ * plane 0 (a slice's source shows plane 0); any other GeoJSON is one slice as it is.
71
+ */
72
+ export declare function splitByPlane(text: string): string[];
73
+ export {};
@@ -0,0 +1,46 @@
1
+ /** A file to import regions from: one the user chose, or one the host's server sent. */
2
+ export interface RegionImportFile {
3
+ name: string;
4
+ text(): Promise<string>;
5
+ bytes(): Promise<Uint8Array>;
6
+ }
7
+ /** A file's contents as the host may hand them over (see `ServerRegionPick`). */
8
+ export type RegionImportData = Blob | ArrayBuffer | Uint8Array | string;
9
+ /** `data`, named `name`, as an import file. A `File`'s own name is used when `name` is omitted. */
10
+ export declare function importFile(data: RegionImportData, name?: string): RegionImportFile;
11
+ /** What a set of chosen files imports as. */
12
+ export type RegionImportPlan =
13
+ /** A label volume, its classes named by an ontology (or a region set description) beside it. */
14
+ {
15
+ kind: 'volume';
16
+ volume: RegionImportFile;
17
+ ontology: RegionImportFile | null;
18
+ }
19
+ /** A folder of per-slice region files, in slice order, with the set's `regionset.json`. */
20
+ | {
21
+ kind: 'folder';
22
+ slices: RegionImportFile[];
23
+ regionSet: RegionImportFile | null;
24
+ }
25
+ /** One region file. */
26
+ | {
27
+ kind: 'single';
28
+ file: RegionImportFile;
29
+ };
30
+ /**
31
+ * What `files` import as: a label volume (`.nii`, `.nii.gz`, `.nrrd`) with the ontology JSON chosen
32
+ * with it (a `regionset.json`, else an Allen `structure_graph*.json`, else any `.json`); several
33
+ * region files (a folder of per-slice `.geojson`, in natural name order, its `regionset.json`
34
+ * apart); or one region file (`.geojson` or `.json`). Null when none of them is one.
35
+ */
36
+ export declare function planRegionImport(files: readonly RegionImportFile[]): RegionImportPlan | null;
37
+ /** "slice_2" before "slice_10": runs of digits compared as numbers. */
38
+ export declare function naturalCompare(a: string, b: string): number;
39
+ /**
40
+ * A folder slice's GeoJSON with the set's class tree and style (its `regionset.json`) as the
41
+ * collection's own members, unless the file has its own: what a served folder's slice carries.
42
+ */
43
+ export declare function folderSliceGeoJson(file: RegionImportFile, regionSet: {
44
+ classHierarchy?: unknown;
45
+ style?: unknown;
46
+ } | null): Promise<string>;
@@ -0,0 +1,14 @@
1
+ /** Inflate gzip or zlib data (default: the platform's `DecompressionStream`). */
2
+ export type Inflate = (bytes: Uint8Array, format: 'gzip' | 'deflate') => Promise<Uint8Array>;
3
+ /** Decode a Blosc frame. */
4
+ export declare function bloscDecompress(frame: Uint8Array, inflate?: Inflate): Promise<Uint8Array>;
5
+ /** Decode one LZ4 block (no frame) of `size` bytes. */
6
+ export declare function lz4BlockDecompress(src: Uint8Array, size: number): Uint8Array;
7
+ /**
8
+ * Decode a zarr chunk through `codecs`, outermost last as zarr lists them (v2: the one
9
+ * `compressor`; v3: the bytes-to-bytes codecs after `bytes`).
10
+ */
11
+ export declare function decodeChunk(bytes: Uint8Array, codecs: readonly {
12
+ id: string;
13
+ [k: string]: unknown;
14
+ }[], inflate?: Inflate): Promise<Uint8Array>;
@@ -0,0 +1,31 @@
1
+ /**
2
+ * The members of a `.zip`, read in the browser: annotations handed over as one archive (a folder
3
+ * of per-slice GeoJSON, a label volume with its ontology, an OME-Zarr store's labels).
4
+ *
5
+ * Only what such archives use: stored or deflated members, ZIP64 sizes and offsets, UTF-8 or
6
+ * legacy names. An encrypted or otherwise compressed member throws when it is read, rather than be
7
+ * read wrongly; a member's CRC-32 is checked. Members are read on demand, so an archive of many
8
+ * chunks (a zarr store) is not inflated whole. Pure: usable from workers.
9
+ */
10
+ import type { RegionImportFile } from './region-import';
11
+ /** One member of an archive. */
12
+ export interface ZipEntry {
13
+ /** Its path in the archive, '/'-separated. */
14
+ name: string;
15
+ /** Its uncompressed size, in bytes. */
16
+ size: number;
17
+ bytes(): Promise<Uint8Array>;
18
+ }
19
+ /** Inflate raw DEFLATE data (default: the platform's `DecompressionStream('deflate-raw')`). */
20
+ export type InflateRaw = (bytes: Uint8Array) => Promise<Uint8Array>;
21
+ /** Whether a file name is a zip archive. */
22
+ export declare function isZipName(name: string): boolean;
23
+ /** The members of the archive in `bytes` (directories and macOS metadata left out). */
24
+ export declare function readZip(bytes: Uint8Array, inflateRaw?: InflateRaw): ZipEntry[];
25
+ /**
26
+ * `files` with every `.zip` among them replaced by its members, named by their paths in it (a
27
+ * single top folder the archive wraps everything in is kept, as a folder pick would keep it).
28
+ */
29
+ export declare function expandZips(files: readonly RegionImportFile[], inflateRaw?: InflateRaw): Promise<RegionImportFile[]>;
30
+ /** CRC-32 (IEEE), as zip records it. */
31
+ export declare function crc32(data: Uint8Array): number;
@@ -75,8 +75,14 @@ export declare class RoutingVisualizerService implements IVisualizer, IRegionEdi
75
75
  private plottedFileName;
76
76
  /** The div the backends render into (every backend shares it); '' before the first plot. */
77
77
  private plotDiv;
78
- /** Whether a napari volume view is the current plot type. */
78
+ /**
79
+ * Whether regions can be shown in 3D on screen: a napari volume (or isosurface) view, or the 3D
80
+ * spatial cloud over a stack image (its reference volume's, see showVolumeAsImage). Both draw the
81
+ * region reconstructions the same way (VolumeRegionMeshes), in the volume's box.
82
+ */
79
83
  private readonly volumeView$;
84
+ /** Whether a napari volume (or isosurface) view is the current plot type: the slice pane's. */
85
+ private imageVolumeView;
80
86
  /** Whether the volume view's slice pane is wanted (see {@link setSliceEditor}). */
81
87
  private readonly sliceEditor$;
82
88
  /** Whether the volume view draws the region reconstructions through the volume. */
@@ -114,6 +120,8 @@ export declare class RoutingVisualizerService implements IVisualizer, IRegionEdi
114
120
  private readonly sectionSubs;
115
121
  /** The image info and screen height of the last plot (what the slice pane mounts). */
116
122
  private plottedInfo;
123
+ /** The current region import (see regionImportTicket): its id and the image it was taken for. */
124
+ private importTicket;
117
125
  private plottedHeight;
118
126
  constructor(plotly: PlotlyService, osd: OpenSeadragonVisualizerService, napari: NapariVisualizerService, store: VisualizerStore, config: VizConfig, regionStore: RegionStore, selectionStore: SpatialSelectionStore, intensity: IntensityProfileService, spatialData?: SpatialDataPort | null);
119
127
  /** A class's colour: its classification colour, else its region source's, else a default. */
@@ -265,12 +273,42 @@ export declare class RoutingVisualizerService implements IVisualizer, IRegionEdi
265
273
  attachRegionSource(source: RegionSource | RegionSourceOpener, slices?: RegionSourceSlices): void;
266
274
  importRegionSource(geoJsonStr: string): Promise<boolean>;
267
275
  dropRegionSource(): Promise<void>;
276
+ /**
277
+ * A ticket for a region import that is about to read or decode its files: the import methods
278
+ * given it change nothing once it is stale — another import took a ticket since, another image
279
+ * was plotted, or the service was destroyed — so an import that finishes late never lands on an
280
+ * image it was not started for.
281
+ */
282
+ regionImportTicket(): number;
283
+ /** Whether `ticket` is still the current import's, on the image it was taken for. */
284
+ private importTicketValid;
285
+ private importImageKey;
286
+ /**
287
+ * Replace the image's regions and region sources with one source per slice, as an imported label
288
+ * volume or folder of per-slice region files gives them: `openers` by slice index, each opened
289
+ * the first time its slice is shown. A single image takes slice 0's. Returns how many slices
290
+ * have a source, or null (changing nothing) when `ticket` is stale (see
291
+ * {@link regionImportTicket}). The sources are marked imported, so a save writes every slice.
292
+ */
293
+ importSliceRegionSources(openers: ReadonlyMap<number, RegionSourceOpener>, ticket?: number): number | null;
294
+ /**
295
+ * Replace the image's regions and region sources with one imported source (a region set the
296
+ * host's server serves): over every slice of a stack when it is z-indexed, else on the slice
297
+ * shown, as {@link applyImageRois} lays out an image's own. Resolves false, changing nothing
298
+ * (and disposing the source), when the import went stale while it opened: another import, or
299
+ * another image (see {@link regionImportTicket}; one is taken here when `ticket` is not given).
300
+ */
301
+ importRegionSourceOpener(open: RegionSourceOpener, ticket?: number): Promise<boolean>;
302
+ /** Empty every slice of a stack (its regions and undo history) for regions imported over it. */
303
+ private enterImportedStack;
268
304
  getRegionSourceView$(): Observable<RegionSourceView | null>;
269
305
  getRegionSourceIndex(query: Omit<RegionIndexQuery, 'exclude'>): Promise<RegionIndexPage>;
270
306
  selectSourceFeatures(ids: readonly string[], additive?: boolean): Promise<number[]>;
271
307
  deleteSourceFeatures(ids: readonly string[]): void;
272
308
  getRegionStyle$(): Observable<RegionStyle>;
273
309
  setRegionStyle(patch: Partial<RegionStyle>): void;
310
+ /** Recompute which 3D view is on screen for `plotType` (see {@link volumeView$}). */
311
+ private updateVolumeView;
274
312
  /** Whether a napari volume (or isosurface) view is on screen: regions can be shown in 3D. */
275
313
  getVolumeView$(): Observable<boolean>;
276
314
  /** Whether the volume view's slice pane is wanted (it shows while a volume view is on screen). */
@@ -31,8 +31,12 @@ export declare class RegionSourceScope {
31
31
  private readonly openOrder;
32
32
  /** The entry of the slice on screen: kept open. */
33
33
  private shown;
34
- /** Attach `open` to `image` for `slices`, replacing (and closing) what was there. */
35
- attach(image: string, open: RegionSourceOpener, slices: RegionSourceSlices): void;
34
+ /**
35
+ * Attach `open` to `image` for `slices`, replacing (and closing) what was there. `imported` names
36
+ * the slices it brings that a save must write (see {@link importedSlices}): for a source of one
37
+ * slice, that slice when non-empty; for a `'planes'` source, the slices its planes cover.
38
+ */
39
+ attach(image: string, open: RegionSourceOpener, slices: RegionSourceSlices, imported?: readonly number[]): void;
36
40
  /** Drop every source of `image` (closing the open ones) and what was taken from them. */
37
41
  detachImage(image: string): void;
38
42
  /** Drop the source of one slice of `image`. */
@@ -56,6 +60,8 @@ export declare class RegionSourceScope {
56
60
  taken(image: string | undefined, slice: number): ReadonlySet<string>;
57
61
  /** Every id taken from any slice of `image` (a `'planes'` source's ids are unique across them). */
58
62
  allTaken(image: string | undefined): string[];
63
+ /** The slices of `image` whose source was imported (see {@link attach}), in order. */
64
+ importedSlices(image: string | undefined): number[];
59
65
  /** The slices of `image` with anything taken from their source. */
60
66
  slicesWithTaken(image: string | undefined): number[];
61
67
  /** Replace the ids taken from `slice`'s source (copy-on-write: `ids` is kept as given). */
@@ -338,8 +338,13 @@ export declare class RegionStore implements IRegionStore, IRegionEditApi, IRegio
338
338
  * source was closed to save memory). `slices` says which slice of the current image it
339
339
  * serves: one (default: the slice shown; plane 0 of the source), or `'planes'`, every slice z
340
340
  * from plane z of a z-indexed source. Replaces the source those slices had.
341
+ *
342
+ * `imported` marks a source brought in over the image (an imported volume, folder or served set)
343
+ * rather than the image's own regions: it is on no file yet, so a save writes its slices though
344
+ * nothing was taken from it — `true` for a source of one slice, the slices its planes cover for a
345
+ * `'planes'` source. The image's own sources are not marked: loading them changes nothing to save.
341
346
  */
342
- attachRegionSource(source: RegionSource | RegionSourceOpener, slices?: RegionSourceSlices): void;
347
+ attachRegionSource(source: RegionSource | RegionSourceOpener, slices?: RegionSourceSlices, imported?: boolean | readonly number[]): void;
343
348
  /** Drop the current image's region sources (closing them) and what was taken from them. */
344
349
  detachRegionSources(): void;
345
350
  /**
@@ -439,10 +444,15 @@ export declare class RegionStore implements IRegionStore, IRegionEditApi, IRegio
439
444
  */
440
445
  getRegionSourceIndex(query: Omit<RegionIndexQuery, 'exclude'>): Promise<RegionIndexPage>;
441
446
  /**
442
- * `regions` as a GeoJSON FeatureCollection string merged with the region source behind them:
443
- * the source's features that were not taken (or deleted), then `regions`. Without a source,
444
- * {@link getGeoJsonString}. `slice` names a folder stack's slice (default the one shown);
445
- * on a z-indexed stack's source (`'planes'`) the export spans every slice.
447
+ * `regions` as a GeoJSON FeatureCollection string merged with the region sources behind them:
448
+ * the sources' features that were not taken (or deleted), then `regions`. Without a source,
449
+ * {@link getGeoJsonString}.
450
+ *
451
+ * `slice` names one slice-file of a folder stack (a per-slice-file save): its source's features,
452
+ * on the file's own plane — of a z-indexed source over every slice, only that slice's plane.
453
+ * Without it, the export is the image's: on a stack saved as one file, every slice's source
454
+ * (each feature on its slice's plane, `geometry.plane.z`) and a z-indexed source's every plane;
455
+ * otherwise the source of the slice shown.
446
456
  */
447
457
  getGeoJsonWithSource(regions: Region[], slice?: number): Promise<string>;
448
458
  /**
@@ -290,6 +290,8 @@ export declare class VisualizerComponent implements OnInit, OnChanges, AfterView
290
290
  protected get hasSpatialDataset(): boolean;
291
291
  /** Keyboard, wheel and context-menu handling; created once the view exists. */
292
292
  private shortcuts?;
293
+ /** Waits for a viewer created outside the document to be attached (see {@link whenInDocument}). */
294
+ private attachObserver;
293
295
  /** Debounced z-slice scrubbing (see SliceScrubber — refactoring plan Step 7). */
294
296
  private readonly scrubber;
295
297
  constructor(state: ImageStatePort, plotService: IVisualizer, messageService: MessageService, ngZone: NgZone, cdr: ChangeDetectorRef, session: VisualizerStore, samTool: SamToolService, cellSegmentTool: CellSegmentToolService, samPointTool: SamPointToolService, regionOps: RegionOpsService, vizConfig?: VizConfig | undefined, toolContributions?: readonly ToolbarContribution[], spatialData?: SpatialDataPort | undefined, plotTypeContributions?: readonly PlotTypeContribution[], injector?: Injector | undefined, hostRef?: ElementRef<HTMLElement> | undefined, destroyRef?: DestroyRef);
@@ -338,6 +340,13 @@ export declare class VisualizerComponent implements OnInit, OnChanges, AfterView
338
340
  ngAfterViewInit(): void;
339
341
  /** The plot div exists now: run an image-less draw that arrived before it did. */
340
342
  private onViewReady;
343
+ /**
344
+ * Run `ready` once this viewer is in the document. A host may create it detached — a closed
345
+ * dialog's projected content, such as jit-ui's pipeline preview — and the backends find the
346
+ * plot div by id, so a draw then found no target and alerted "the renderer could not start"
347
+ * over another viewer. Until then its view is not ready, and an image-less draw waits.
348
+ */
349
+ private whenInDocument;
341
350
  /** What the keyboard, wheel and context-menu shortcuts act on. Their listeners live
342
351
  * outside this view, so every action that changes what it shows marks it for check. */
343
352
  private shortcutHost;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jax-data-science/sci-image-visualizer",
3
- "version": "0.10.0",
3
+ "version": "0.12.0",
4
4
  "engines": {
5
5
  "node": ">=20.9.0"
6
6
  },
@@ -39,6 +39,7 @@
39
39
  "dependencies": {
40
40
  "cellpose-js": "^0.6.0",
41
41
  "fast-png": "^6.4.0",
42
+ "fzstd": "^0.1.1",
42
43
  "napari-js": "^0.18.0",
43
44
  "openseadragon": "^6.0.2",
44
45
  "plotly.js-dist-min": "^3.0.1",