@jax-data-science/sci-image-visualizer 0.9.0 → 0.11.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 (149) hide show
  1. package/esm2022/index.mjs +10 -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/contracts/region-store.contract.mjs +1 -1
  6. package/esm2022/lib/contracts/section-view.contract.mjs +2 -0
  7. package/esm2022/lib/contracts/visualizer.contract.mjs +1 -1
  8. package/esm2022/lib/contracts/viz-config.mjs +1 -1
  9. package/esm2022/lib/geometry/loft.mjs +128 -0
  10. package/esm2022/lib/geometry/polylabel.mjs +156 -0
  11. package/esm2022/lib/geometry/reconstruct.mjs +315 -0
  12. package/esm2022/lib/geometry/reslice-image.mjs +57 -0
  13. package/esm2022/lib/geometry/section.mjs +215 -0
  14. package/esm2022/lib/implementations/napari-js/napari-loading-badge.mjs +11 -7
  15. package/esm2022/lib/implementations/napari-js/napari-loading-state.mjs +20 -3
  16. package/esm2022/lib/implementations/napari-js/napari-region-mesh-pointer.mjs +100 -0
  17. package/esm2022/lib/implementations/napari-js/napari-region-overlay.mjs +28 -5
  18. package/esm2022/lib/implementations/napari-js/napari-scene.mjs +1 -1
  19. package/esm2022/lib/implementations/napari-js/napari-spatial-hover.mjs +9 -2
  20. package/esm2022/lib/implementations/napari-js/napari-tool-bridge.mjs +5 -2
  21. package/esm2022/lib/implementations/napari-js/napari-visualizer.service.mjs +81 -1
  22. package/esm2022/lib/implementations/napari-js/napari-volume-region-meshes.mjs +129 -0
  23. package/esm2022/lib/implementations/napari-js/napari-volume-scene.mjs +115 -4
  24. package/esm2022/lib/implementations/napari-js/napari-volume-slice-planes.mjs +103 -0
  25. package/esm2022/lib/implementations/napari-js/region-overlay/region-svg-renderer.mjs +15 -3
  26. package/esm2022/lib/implementations/osd/openseadragon-viewer-options.mjs +18 -2
  27. package/esm2022/lib/implementations/osd/openseadragon-visualizer.service.mjs +9 -1
  28. package/esm2022/lib/implementations/osd/osd-region-overlay-draw.mjs +18 -7
  29. package/esm2022/lib/implementations/osd/osd-region-overlay.mjs +38 -8
  30. package/esm2022/lib/implementations/osd/osd-tile-loading.mjs +71 -0
  31. package/esm2022/lib/implementations/osd/osd-viewer-like.mjs +1 -1
  32. package/esm2022/lib/implementations/osd/slice-cache.mjs +35 -6
  33. package/esm2022/lib/implementations/tile-server/tile-protocol.mjs +1 -1
  34. package/esm2022/lib/models/class-preset.mjs +1 -1
  35. package/esm2022/lib/models/polygon-factory.mjs +17 -1
  36. package/esm2022/lib/models/region-geojson.mjs +44 -6
  37. package/esm2022/lib/models/region.mjs +1 -1
  38. package/esm2022/lib/region-editor/class-tree/class-tree.component.mjs +156 -0
  39. package/esm2022/lib/region-editor/class-tree/class-tree.mjs +108 -0
  40. package/esm2022/lib/region-editor/classes-panel/classes-panel.component.mjs +77 -13
  41. package/esm2022/lib/region-editor/region-editor.component.mjs +670 -42
  42. package/esm2022/lib/region-editor/region-metrics.mjs +20 -2
  43. package/esm2022/lib/region-editor/region-persistence.service.mjs +44 -10
  44. package/esm2022/lib/region-editor/region-table/region-table.component.mjs +24 -8
  45. package/esm2022/lib/region-import/label-classes.mjs +149 -0
  46. package/esm2022/lib/region-import/label-volume.mjs +194 -0
  47. package/esm2022/lib/region-import/region-import.mjs +71 -0
  48. package/esm2022/lib/region-overlay/region-geometry.mjs +3 -3
  49. package/esm2022/lib/region-overlay/region-source-layer.mjs +378 -0
  50. package/esm2022/lib/region-overlay/region-style.mjs +97 -0
  51. package/esm2022/lib/region-source/http-region-source.mjs +104 -0
  52. package/esm2022/lib/region-source/region-source-ops.mjs +53 -0
  53. package/esm2022/lib/region-source/region-source-worker.mjs +10 -0
  54. package/esm2022/lib/region-source/region-source.mjs +67 -0
  55. package/esm2022/lib/region-source/region-tiles.mjs +708 -0
  56. package/esm2022/lib/region-source/worker-region-source.mjs +229 -0
  57. package/esm2022/lib/routing-visualizer.service.mjs +510 -22
  58. package/esm2022/lib/section-pane/section-pane.component.mjs +299 -0
  59. package/esm2022/lib/store/class-color.util.mjs +10 -5
  60. package/esm2022/lib/store/class-signatures.mjs +63 -0
  61. package/esm2022/lib/store/region-scope-cache.mjs +5 -1
  62. package/esm2022/lib/store/region-source-scope.mjs +186 -0
  63. package/esm2022/lib/store/region-store.service.mjs +774 -12
  64. package/esm2022/lib/store/visualizer-store.service.mjs +33 -6
  65. package/esm2022/lib/toolbar/region-tools/region-tools.component.mjs +8 -2
  66. package/esm2022/lib/toolbar/stack-controls/stack-controls.component.mjs +55 -15
  67. package/esm2022/lib/toolbar/toolbar.component.mjs +19 -5
  68. package/esm2022/lib/visualizer/region-load.mjs +67 -4
  69. package/esm2022/lib/visualizer/volume-sections.mjs +175 -0
  70. package/esm2022/lib/visualizer.component.mjs +155 -7
  71. package/fesm2022/{jax-data-science-sci-image-visualizer-jax-data-science-sci-image-visualizer-Csxlnq7I.mjs → jax-data-science-sci-image-visualizer-jax-data-science-sci-image-visualizer-BELcx0jv.mjs} +9851 -2904
  72. package/fesm2022/jax-data-science-sci-image-visualizer-jax-data-science-sci-image-visualizer-BELcx0jv.mjs.map +1 -0
  73. package/fesm2022/{jax-data-science-sci-image-visualizer-onnx-sam-session-Bkujqg7m.mjs → jax-data-science-sci-image-visualizer-onnx-sam-session-DEDSm_NL.mjs} +4 -4
  74. package/fesm2022/{jax-data-science-sci-image-visualizer-onnx-sam-session-Bkujqg7m.mjs.map → jax-data-science-sci-image-visualizer-onnx-sam-session-DEDSm_NL.mjs.map} +1 -1
  75. package/fesm2022/jax-data-science-sci-image-visualizer-region-source-worker-CAqBjM5L.mjs +12 -0
  76. package/fesm2022/jax-data-science-sci-image-visualizer-region-source-worker-CAqBjM5L.mjs.map +1 -0
  77. package/fesm2022/jax-data-science-sci-image-visualizer.mjs +3 -3
  78. package/fesm2022/region-source.worker.js +1067 -0
  79. package/index.d.ts +12 -0
  80. package/lib/contracts/image.contract.d.ts +4 -0
  81. package/lib/contracts/ports/region-io.port.d.ts +24 -0
  82. package/lib/contracts/region-editor-api.contract.d.ts +102 -0
  83. package/lib/contracts/region-store.contract.d.ts +22 -0
  84. package/lib/contracts/section-view.contract.d.ts +44 -0
  85. package/lib/contracts/visualizer.contract.d.ts +10 -0
  86. package/lib/contracts/viz-config.d.ts +8 -0
  87. package/lib/geometry/loft.d.ts +22 -0
  88. package/lib/geometry/polylabel.d.ts +23 -0
  89. package/lib/geometry/reconstruct.d.ts +54 -0
  90. package/lib/geometry/reslice-image.d.ts +33 -0
  91. package/lib/geometry/section.d.ts +52 -0
  92. package/lib/implementations/napari-js/napari-loading-badge.d.ts +4 -2
  93. package/lib/implementations/napari-js/napari-loading-state.d.ts +8 -1
  94. package/lib/implementations/napari-js/napari-region-mesh-pointer.d.ts +32 -0
  95. package/lib/implementations/napari-js/napari-region-overlay.d.ts +6 -1
  96. package/lib/implementations/napari-js/napari-scene.d.ts +33 -0
  97. package/lib/implementations/napari-js/napari-spatial-hover.d.ts +3 -1
  98. package/lib/implementations/napari-js/napari-visualizer.service.d.ts +48 -0
  99. package/lib/implementations/napari-js/napari-volume-region-meshes.d.ts +66 -0
  100. package/lib/implementations/napari-js/napari-volume-scene.d.ts +45 -1
  101. package/lib/implementations/napari-js/napari-volume-slice-planes.d.ts +43 -0
  102. package/lib/implementations/osd/openseadragon-viewer-options.d.ts +2 -0
  103. package/lib/implementations/osd/openseadragon-visualizer.service.d.ts +2 -0
  104. package/lib/implementations/osd/osd-region-overlay-draw.d.ts +4 -3
  105. package/lib/implementations/osd/osd-region-overlay.d.ts +10 -3
  106. package/lib/implementations/osd/osd-tile-loading.d.ts +43 -0
  107. package/lib/implementations/osd/osd-viewer-like.d.ts +14 -0
  108. package/lib/implementations/osd/slice-cache.d.ts +13 -3
  109. package/lib/implementations/tile-server/tile-protocol.d.ts +3 -0
  110. package/lib/models/class-preset.d.ts +7 -0
  111. package/lib/models/polygon-factory.d.ts +5 -0
  112. package/lib/models/region-geojson.d.ts +40 -0
  113. package/lib/models/region.d.ts +19 -0
  114. package/lib/region-editor/class-tree/class-tree.component.d.ts +78 -0
  115. package/lib/region-editor/class-tree/class-tree.d.ts +31 -0
  116. package/lib/region-editor/classes-panel/classes-panel.component.d.ts +36 -6
  117. package/lib/region-editor/region-editor.component.d.ts +159 -17
  118. package/lib/region-editor/region-metrics.d.ts +8 -0
  119. package/lib/region-editor/region-persistence.service.d.ts +17 -5
  120. package/lib/region-editor/region-table/region-table.component.d.ts +10 -4
  121. package/lib/region-import/label-classes.d.ts +39 -0
  122. package/lib/region-import/label-volume.d.ts +31 -0
  123. package/lib/region-import/region-import.d.ts +46 -0
  124. package/lib/region-overlay/region-geometry.d.ts +4 -3
  125. package/lib/region-overlay/region-source-layer.d.ts +96 -0
  126. package/lib/region-overlay/region-style.d.ts +52 -0
  127. package/lib/region-source/http-region-source.d.ts +45 -0
  128. package/lib/region-source/region-source-ops.d.ts +89 -0
  129. package/lib/region-source/region-source-worker.d.ts +7 -0
  130. package/lib/region-source/region-source.d.ts +82 -0
  131. package/lib/region-source/region-tiles.d.ts +289 -0
  132. package/lib/region-source/worker-region-source.d.ts +65 -0
  133. package/lib/routing-visualizer.service.d.ts +168 -1
  134. package/lib/section-pane/section-pane.component.d.ts +47 -0
  135. package/lib/store/class-color.util.d.ts +6 -3
  136. package/lib/store/class-signatures.d.ts +11 -0
  137. package/lib/store/region-scope-cache.d.ts +2 -0
  138. package/lib/store/region-source-scope.d.ts +74 -0
  139. package/lib/store/region-store.service.d.ts +216 -2
  140. package/lib/store/visualizer-store.service.d.ts +10 -0
  141. package/lib/toolbar/region-tools/region-tools.component.d.ts +3 -1
  142. package/lib/toolbar/stack-controls/stack-controls.component.d.ts +20 -9
  143. package/lib/toolbar/toolbar.component.d.ts +9 -2
  144. package/lib/visualizer/region-load.d.ts +23 -4
  145. package/lib/visualizer/volume-sections.d.ts +64 -0
  146. package/lib/visualizer.component.d.ts +40 -0
  147. package/package.json +2 -2
  148. package/src/lib/assets/slice.svg +23 -0
  149. package/fesm2022/jax-data-science-sci-image-visualizer-jax-data-science-sci-image-visualizer-Csxlnq7I.mjs.map +0 -1
@@ -0,0 +1,65 @@
1
+ /**
2
+ * A {@link RegionSource} over a GeoJSON string, parsed and tiled in the region-source Web Worker.
3
+ *
4
+ * One worker serves every open source. Where no worker can start (jsdom, SSR, a blocked worker
5
+ * URL) the same tables run on the main thread; if the worker dies, each source re-opens itself
6
+ * there from its text (which the host holds anyway: it handed it over) and carries on — whether
7
+ * it had a call in flight then or not (see {@link RegionSourceWorkerClient.generation}).
8
+ */
9
+ import { RegionSource } from './region-source';
10
+ import { RegionSourceRequest, RegionSourceResults } from './region-source-ops';
11
+ import type { ReconstructOptions, SliceOutlines } from '../geometry/reconstruct';
12
+ import type { Mesh } from 'napari-js/geometry';
13
+ /** Makes the worker; may be async, as the default one is (it imports the factory on demand). */
14
+ export type RegionSourceWorkerFactory = () => Worker | Promise<Worker>;
15
+ /** Owns the region-source worker and the calls in flight on it. */
16
+ export declare class RegionSourceWorkerClient {
17
+ private readonly factory?;
18
+ private worker;
19
+ private starting;
20
+ private unavailable;
21
+ private nextId;
22
+ private readonly pending;
23
+ /** The main-thread tables, once anything runs here. */
24
+ private local;
25
+ private tables;
26
+ /**
27
+ * `factory` is optional: without one the real worker module is imported on demand —
28
+ * dynamically, because it holds an `import.meta.url` that ts-jest's CommonJS compile
29
+ * rejects.
30
+ */
31
+ constructor(factory?: RegionSourceWorkerFactory | undefined);
32
+ /** Whether calls now run on the main thread. */
33
+ get inThread(): boolean;
34
+ /**
35
+ * Which table set calls run on: bumped when the worker is lost. A handle opened under another
36
+ * names a table that is gone (or, here, another source's), so its source must open again.
37
+ */
38
+ get generation(): number;
39
+ /** Run `request` in the worker, or here when there is none. */
40
+ call<R extends RegionSourceRequest>(request: R): Promise<RegionSourceResults[R['op']]>;
41
+ /** {@link call}, with the {@link generation} the request ran on. */
42
+ run<R extends RegionSourceRequest>(request: R): Promise<{
43
+ result: RegionSourceResults[R['op']];
44
+ generation: number;
45
+ }>;
46
+ /** Terminate the worker; calls in flight reject. */
47
+ dispose(): void;
48
+ private ensureWorker;
49
+ private startWorker;
50
+ private onReply;
51
+ /** Stop the worker for good: every later call runs here, every call in flight is lost. */
52
+ private lose;
53
+ }
54
+ /** The worker client every GeoJSON source shares. */
55
+ export declare function sharedRegionSourceClient(): RegionSourceWorkerClient;
56
+ /**
57
+ * Open a GeoJSON FeatureCollection string as a tiled region source. Rejects on invalid JSON or
58
+ * a collection without `features`.
59
+ */
60
+ export declare function openGeoJsonRegionSource(text: string, client?: RegionSourceWorkerClient): Promise<RegionSource>;
61
+ /**
62
+ * The 3D reconstruction of a region from its outlines on a stack (see `geometry/reconstruct`),
63
+ * meshed in the region-source worker (on the main thread where there is none).
64
+ */
65
+ export declare function reconstructInWorker(slices: readonly SliceOutlines[], options?: ReconstructOptions, client?: RegionSourceWorkerClient): Promise<Mesh>;
@@ -11,6 +11,10 @@ import { IVisualizer, LoadedImage, PixelData, IntensityProfile, IIsosurfaceContr
11
11
  import { SpatialDataPort } from './contracts/ports/spatial-data.port';
12
12
  import { CanvasToolOptions, ColormapNode, IBrushOptions, IWandOptions } from './contracts/display-types';
13
13
  import { RegionStore } from './store/region-store.service';
14
+ import { RegionSource, RegionSourceView } from './region-source/region-source';
15
+ import type { RegionIndexPage, RegionIndexQuery } from './region-source/region-tiles';
16
+ import type { RegionStyle } from './region-overlay/region-style';
17
+ import type { RegionSourceOpener, RegionSourceSlices } from './store/region-source-scope';
14
18
  import { SpatialSelectionStore } from './store/spatial-selection.service';
15
19
  import { ViewerCapabilities } from './contracts/capabilities.contract';
16
20
  import { IRegionOverlay } from './contracts/region-overlay.contract';
@@ -21,7 +25,10 @@ import { NapariVisualizerService } from './implementations/napari-js/napari-visu
21
25
  import { VizConfig } from './contracts/viz-config';
22
26
  import { PlotModeViewport } from './contracts/plot-type-contribution.contract';
23
27
  import { IntensityProfileService } from './intensity/intensity-profile.service';
28
+ import type { SectionAxis, SectionViews } from './contracts/section-view.contract';
24
29
  import * as i0 from "@angular/core";
30
+ /** How long after the last edit the surfaces of the classes it touched are rebuilt (ms). */
31
+ export declare const REGION_SURFACE_REBUILD_MS = 600;
25
32
  /**
26
33
  * The visualizer chain's front door: implements `IVisualizer`, `IRegionEditorApi`
27
34
  * and `IChannelHistogramApi` (bound to the `VISUALIZER` / `REGION_EDITOR_API` /
@@ -68,7 +75,57 @@ export declare class RoutingVisualizerService implements IVisualizer, IRegionEdi
68
75
  private plottedFileName;
69
76
  /** The div the backends render into (every backend shares it); '' before the first plot. */
70
77
  private plotDiv;
78
+ /** Whether a napari volume view is the current plot type. */
79
+ private readonly volumeView$;
80
+ /** Whether the volume view's slice pane is wanted (see {@link setSliceEditor}). */
81
+ private readonly sliceEditor$;
82
+ /** Whether the volume view draws the region reconstructions through the volume. */
83
+ private readonly regionsThroughVolume$;
84
+ /** Region reconstructions built so far, by image, resolution and classes (with those classes). */
85
+ private readonly meshCache;
86
+ /** Bumped per {@link showRegionClasses3d} (and per new image), so only the latest one shows. */
87
+ private meshRequest;
88
+ /** The class groups shown in 3D, and the image they belong to. */
89
+ private readonly classes3d$;
90
+ private classes3dImage;
91
+ /** The groups last asked for in 3D, with their colours: what an edit's rebuild shows again. */
92
+ private shown3d;
93
+ /**
94
+ * Each class's fingerprint on the live slice (see classSignatures), which image and slice, and
95
+ * what the region sources hold (see RegionStore.getSourceStateKey). Null while nothing follows
96
+ * the edits (no surface built, no sections).
97
+ */
98
+ private liveClasses;
99
+ /** The pending rebuild of the surfaces an edit touched. */
100
+ private rebuildTimer;
101
+ private readonly regionUpdates;
102
+ /** The div the slice pane renders into while it is wanted (null: no split). */
103
+ private sliceDiv;
104
+ /** Whether OSD is mounted in the slice pane: region, tool and overlay calls go to it. */
105
+ private sliceMounted;
106
+ /** The image the slice pane shows. */
107
+ private sliceFile;
108
+ /** Bumped per slice-pane mount or teardown, so only the latest one lands. */
109
+ private sliceRequest;
110
+ /** The sections beside the split volume view (the planes x and y through the stack). */
111
+ private readonly sections;
112
+ /** The z plane dragged in the volume: the slice to show (see {@link getSliceDrag$}). */
113
+ private readonly sliceDrag$;
114
+ private readonly sectionSubs;
115
+ /** The image info and screen height of the last plot (what the slice pane mounts). */
116
+ private plottedInfo;
117
+ /** The current region import (see regionImportTicket): its id and the image it was taken for. */
118
+ private importTicket;
119
+ private plottedHeight;
71
120
  constructor(plotly: PlotlyService, osd: OpenSeadragonVisualizerService, napari: NapariVisualizerService, store: VisualizerStore, config: VizConfig, regionStore: RegionStore, selectionStore: SpatialSelectionStore, intensity: IntensityProfileService, spatialData?: SpatialDataPort | null);
121
+ /** A class's colour: its classification colour, else its region source's, else a default. */
122
+ private classColor;
123
+ /** The sections beside the split volume view (nulls while it is not split). */
124
+ getSectionViews$(): Observable<SectionViews>;
125
+ /** Move a section's plane to `at` (image px). */
126
+ setSectionPlane(axis: SectionAxis, at: number): void;
127
+ /** The slice picked by dragging the z plane in the volume: the host shows it (its slider). */
128
+ getSliceDrag$(): Observable<number>;
72
129
  private isImageType;
73
130
  /** The 2D napari types (image, region-centroid scatter, spatial omics) — a 2D fallback chain
74
131
  * (OSD, then Plotly).
@@ -92,11 +149,27 @@ export declare class RoutingVisualizerService implements IVisualizer, IRegionEdi
92
149
  private imageBackend;
93
150
  /** Backend currently on screen — what ongoing zoom/tool/region ops act on. */
94
151
  private renderer;
152
+ /**
153
+ * Backend region, tool and overlay calls act on: the slice pane's OSD while the volume view is
154
+ * split (regions are edited there), else the backend on screen. View calls (zoom, fit, colour,
155
+ * export) stay with {@link renderer}.
156
+ */
157
+ private regionBackend;
95
158
  get capabilities(): ViewerCapabilities;
96
159
  load(imageInfo: IImageInfo, zIndex: number, signal?: AbortSignal): Promise<LoadedImage>;
97
160
  /** Try OSD; on failure fall back to Plotly for this image (not permanent — see reset()). */
98
161
  private loadViaOsdThenPlotly;
99
162
  plot(plotDiv: string, imageLoaded: unknown, imageInfo: IImageInfo, screenHeight: number, plotType: PlotType, inPlace?: boolean): Promise<boolean>;
163
+ /**
164
+ * Split the volume view: show the slice being edited in `div` (OpenSeadragon, with every region
165
+ * tool) beside the 3D view, or stop (null). Kept across re-plots of a volume view; another plot
166
+ * type takes the pane down and a volume view brings it back. Resolves whether the pane shows.
167
+ */
168
+ setSliceEditor(div: string | null): Promise<boolean>;
169
+ /** Mount (or refresh in place) OSD in the slice pane on the displayed slice. */
170
+ private mountSlice;
171
+ /** Take the slice pane's viewer down (the split stays wanted while {@link sliceDiv} is set). */
172
+ private unmountSlice;
100
173
  reloadAndPlot(): void;
101
174
  reset(): void;
102
175
  relayout(trueImageSize?: number[]): void;
@@ -190,9 +263,102 @@ export declare class RoutingVisualizerService implements IVisualizer, IRegionEdi
190
263
  /** Download `regions` as GeoJSON, named after the image last plotted. */
191
264
  exportRegions(regions: Region[]): void;
192
265
  getGeoJsonString(regions: Region[]): string;
266
+ /** Hold a large region set as a tiled region source (see RegionStore.attachRegionSource). */
267
+ attachRegionSource(source: RegionSource | RegionSourceOpener, slices?: RegionSourceSlices): void;
268
+ importRegionSource(geoJsonStr: string): Promise<boolean>;
269
+ dropRegionSource(): Promise<void>;
270
+ /**
271
+ * A ticket for a region import that is about to read or decode its files: the import methods
272
+ * given it change nothing once it is stale — another import took a ticket since, another image
273
+ * was plotted, or the service was destroyed — so an import that finishes late never lands on an
274
+ * image it was not started for.
275
+ */
276
+ regionImportTicket(): number;
277
+ /** Whether `ticket` is still the current import's, on the image it was taken for. */
278
+ private importTicketValid;
279
+ private importImageKey;
280
+ /**
281
+ * Replace the image's regions and region sources with one source per slice, as an imported label
282
+ * volume or folder of per-slice region files gives them: `openers` by slice index, each opened
283
+ * the first time its slice is shown. A single image takes slice 0's. Returns how many slices
284
+ * have a source, or null (changing nothing) when `ticket` is stale (see
285
+ * {@link regionImportTicket}). The sources are marked imported, so a save writes every slice.
286
+ */
287
+ importSliceRegionSources(openers: ReadonlyMap<number, RegionSourceOpener>, ticket?: number): number | null;
288
+ /**
289
+ * Replace the image's regions and region sources with one imported source (a region set the
290
+ * host's server serves): over every slice of a stack when it is z-indexed, else on the slice
291
+ * shown, as {@link applyImageRois} lays out an image's own. Resolves false, changing nothing
292
+ * (and disposing the source), when the import went stale while it opened: another import, or
293
+ * another image (see {@link regionImportTicket}; one is taken here when `ticket` is not given).
294
+ */
295
+ importRegionSourceOpener(open: RegionSourceOpener, ticket?: number): Promise<boolean>;
296
+ /** Empty every slice of a stack (its regions and undo history) for regions imported over it. */
297
+ private enterImportedStack;
298
+ getRegionSourceView$(): Observable<RegionSourceView | null>;
299
+ getRegionSourceIndex(query: Omit<RegionIndexQuery, 'exclude'>): Promise<RegionIndexPage>;
300
+ selectSourceFeatures(ids: readonly string[], additive?: boolean): Promise<number[]>;
301
+ deleteSourceFeatures(ids: readonly string[]): void;
302
+ getRegionStyle$(): Observable<RegionStyle>;
303
+ setRegionStyle(patch: Partial<RegionStyle>): void;
304
+ /** Whether a napari volume (or isosurface) view is on screen: regions can be shown in 3D. */
305
+ getVolumeView$(): Observable<boolean>;
306
+ /** Whether the volume view's slice pane is wanted (it shows while a volume view is on screen). */
307
+ getSliceEditor$(): Observable<boolean>;
308
+ /** Whether the volume view draws the region reconstructions through the volume. */
309
+ getRegionsThroughVolume$(): Observable<boolean>;
310
+ /**
311
+ * Draw the region reconstructions through the volume (it hides none of them: surfaces inside its
312
+ * bright structures, an OCT's layer boundaries) or hidden behind what it shows (the default).
313
+ */
314
+ setRegionsThroughVolume(through: boolean): void;
315
+ /** The class groups shown in 3D on this image ([] after a switch to another image). */
316
+ getRegionClasses3d$(): Observable<ReadonlyArray<{
317
+ key: string;
318
+ classes: readonly string[];
319
+ }>>;
320
+ /** Hide every region surface and forget them (a build still running is dropped). */
321
+ private clearRegionClasses3d;
322
+ /** Highlight the surfaces of these group keys in the volume view (none: all as usual). */
323
+ highlightRegionClasses3d(keys: readonly string[]): void;
324
+ /** A surface clicked in the volume view with the selection tool (its group key), or none (null). */
325
+ getRegionPicked3d$(): Observable<{
326
+ key: string | null;
327
+ additive: boolean;
328
+ }>;
329
+ /**
330
+ * Show these groups of classes in the volume view as 3D reconstructions (each group one surface
331
+ * in its colour: an atlas structure with its substructures), and only these; [] hides them.
332
+ * Reconstructed from every slice's outlines at the volume's resolution, cached per image.
333
+ */
334
+ showRegionClasses3d(groups: ReadonlyArray<{
335
+ key: string;
336
+ classes: readonly string[];
337
+ color: string;
338
+ label?: string;
339
+ }>): Promise<void>;
340
+ /**
341
+ * The regions changed: when the live slice's regions of some classes did (an edit, an undo, not
342
+ * a slice or image switch), their reconstructions are stale. They are dropped, and those shown
343
+ * in 3D are rebuilt once the edits pause.
344
+ */
345
+ private onRegionsChanged;
346
+ /** Fingerprint the live slice's classes, unless already: what the next edit is compared with. */
347
+ private trackLiveClasses;
348
+ /** Which slice of which image the live regions are. */
349
+ private liveSliceKey;
350
+ /** Each class's volume over the whole stack, in px² × slices (see RegionStore.classVolumes). */
351
+ getClassVolumes(classes: readonly string[]): Promise<Record<string, number>>;
352
+ getRegionSourceClassCounts(stack?: boolean): Promise<Record<string, number>>;
353
+ getHiddenClasses$(): Observable<ReadonlySet<string>>;
354
+ setClassesHidden(classes: readonly string[], hidden: boolean): void;
355
+ selectRegionClasses(classes: readonly string[], additive?: boolean): Promise<void>;
356
+ getGeoJsonStringWithSource(regions: Region[], slice?: number): Promise<string>;
193
357
  enterStackMode(slices: Map<number, Region[]>, initialZ?: number, saveLayout?: 'combined' | 'per-slice-file'): void;
194
358
  exitStackMode(): void;
195
359
  isStackMode(): boolean;
360
+ /** The slice the regions are shown for (recorded outside stack mode too). */
361
+ getDisplaySlice(): number;
196
362
  getStackSaveLayout(): 'combined' | 'per-slice-file';
197
363
  setDisplaySlice(z: number): void;
198
364
  getSliceRegions(): Region[];
@@ -261,7 +427,8 @@ export declare class RoutingVisualizerService implements IVisualizer, IRegionEdi
261
427
  getInvert$(): Observable<boolean>;
262
428
  setInvert(on: boolean): void;
263
429
  /**
264
- * The active backend's region overlay. Falls back to Plotly's when the active backend
430
+ * The active backend's region overlay (the slice pane's while the volume view is split). Falls
431
+ * back to Plotly's when the active backend
265
432
  * (OSD or napari-js) is selected but a plot isn't mounted yet, so callers always get a
266
433
  * usable overlay.
267
434
  */
@@ -0,0 +1,47 @@
1
+ import { AfterViewInit, EventEmitter, NgZone, OnChanges, OnDestroy } from '@angular/core';
2
+ import type { SectionAxis, SectionView } from '../contracts/section-view.contract';
3
+ import * as i0 from "@angular/core";
4
+ export declare class SectionPaneComponent implements AfterViewInit, OnChanges, OnDestroy {
5
+ private readonly zone;
6
+ axis: SectionAxis;
7
+ view: SectionView | null;
8
+ /** A point clicked, in section coordinates (u across, v down). */
9
+ readonly pick: EventEmitter<{
10
+ u: number;
11
+ v: number;
12
+ }>;
13
+ private canvasRef;
14
+ private zoom;
15
+ private pan;
16
+ private press;
17
+ private image;
18
+ private resize?;
19
+ private frame;
20
+ constructor(zone: NgZone);
21
+ protected get axisColor(): string;
22
+ protected get label(): string;
23
+ ngAfterViewInit(): void;
24
+ ngOnChanges(): void;
25
+ ngOnDestroy(): void;
26
+ /** Back to the whole section, centred. */
27
+ fit(): void;
28
+ protected onWheel(e: WheelEvent): void;
29
+ protected onDown(e: PointerEvent): void;
30
+ protected onMove(e: PointerEvent): void;
31
+ protected onUp(e: PointerEvent): void;
32
+ private local;
33
+ /** Section units → CSS px in the pane: scale per unit across and down, and the origin. */
34
+ private transform;
35
+ private toSection;
36
+ /** Redraw on the next frame (outside Angular: a canvas paint needs no change detection). */
37
+ private draw;
38
+ private paint;
39
+ /** Each class's cut: its outlines filled and stroked, its lines drawn (a dot for one point). */
40
+ private paintRegions;
41
+ /** The other planes: across (u) and down (v), dashed in their axis colours. */
42
+ private paintCrosshair;
43
+ /** The section's image on a canvas of its own size (made again only for a new image). */
44
+ private imageCanvas;
45
+ static ɵfac: i0.ɵɵFactoryDeclaration<SectionPaneComponent, never>;
46
+ static ɵcmp: i0.ɵɵComponentDeclaration<SectionPaneComponent, "viz-section-pane", never, { "axis": { "alias": "axis"; "required": true; }; "view": { "alias": "view"; "required": false; }; }, { "pick": "pick"; }, never, never, true, never>;
47
+ }
@@ -30,7 +30,10 @@ export declare function findPreset(label: string, set: PresetSet): ClassPreset |
30
30
  * HSL hue. Same name -> same colour, every run.
31
31
  */
32
32
  export declare function fallbackColorFor(label: string, palette: string[]): string;
33
- /** Resolve a colour for `label`: a matching preset's colour, else the deterministic fallback. */
33
+ /**
34
+ * Resolve a colour for `label`: a matching preset's colour, else the colour an imported file
35
+ * gave the class, else the deterministic fallback.
36
+ */
34
37
  export declare function colorForLabel(label: string, set: PresetSet): string;
35
38
  /** Options for {@link applyPresetColors}. */
36
39
  export interface ApplyPresetColorsOptions {
@@ -49,8 +52,8 @@ export interface ApplyPresetColorsOptions {
49
52
  /**
50
53
  * Resolve each labelled region's colour from the preset set (jit-ui#70). The
51
54
  * presets are the source of truth: a matching preset gives the class colour,
52
- * an unknown class its deterministic fallback, **overriding any colour already
53
- * on the region** (e.g. embedded in imported GeoJSON). Unlabelled regions and
55
+ * an unknown class the colour an imported file gave it (`importedColors`) or else
56
+ * its deterministic fallback, **overriding any colour already on the region**. Unlabelled regions and
54
57
  * ones the user recoloured (`colorOverridden`) are left untouched. Unknown
55
58
  * classes are reported through `onPromote` when `autoPromote` is on.
56
59
  *
@@ -0,0 +1,11 @@
1
+ import { Region } from '../models/region';
2
+ /**
3
+ * A fingerprint of each class's regions (by label): their ids and geometry folded into one number
4
+ * per class. Two sets give the same fingerprint for a class when its regions did not change, so
5
+ * comparing a slice's fingerprints before and after an edit names the classes the edit touched
6
+ * (a recoloured or relabelled region touches its old class and its new one). Profile lines and
7
+ * unlabelled regions are left out: they are in no class.
8
+ */
9
+ export declare function classSignatures(regions: readonly Region[]): Map<string, number>;
10
+ /** The classes whose fingerprints differ between `before` and `after` (added and removed included). */
11
+ export declare function changedClasses(before: ReadonlyMap<string, number>, after: ReadonlyMap<string, number>): Set<string>;
@@ -26,6 +26,8 @@ export declare class RegionScopeCache {
26
26
  private initialNonEmpty;
27
27
  /** The cache key for an image: its first URL, else its file name. */
28
28
  static imageKey(imageInfo: IImageInfo | undefined): string | undefined;
29
+ /** The active image's cache key (see {@link imageKey}). */
30
+ get activeImage(): string | undefined;
29
31
  /** True while a z-stack is loaded and regions are held per slice. */
30
32
  get stackMode(): boolean;
31
33
  /** The current display slice (zero-based; 0 outside stack mode unless set). */
@@ -0,0 +1,74 @@
1
+ import type { RegionSource } from '../region-source/region-source';
2
+ /** Opens a region source on demand (and again after it was closed to save memory). */
3
+ export type RegionSourceOpener = () => Promise<RegionSource>;
4
+ /** Which slices a source serves: one slice (plane `plane` of the source), or every slice z
5
+ * from the source's plane z (a z-indexed GeoJSON over a whole stack). */
6
+ export type RegionSourceSlices = {
7
+ slice: number;
8
+ plane?: number;
9
+ } | 'planes';
10
+ /** The region source behind one slice: the source and which of its planes the slice shows. */
11
+ export interface RegionSourceBinding {
12
+ source: RegionSource;
13
+ plane: number;
14
+ }
15
+ /** Sources held open, past which the least recently used one is closed (never the one shown). */
16
+ export declare const OPEN_REGION_SOURCES = 6;
17
+ /**
18
+ * The region sources of every image the store has seen, per slice, and per slice the ids of
19
+ * the source features taken out of the source (into the working set, or deleted) — those the
20
+ * source no longer draws and an export leaves out.
21
+ *
22
+ * Sources open lazily, the first time their slice is shown or read, and at most
23
+ * {@link OPEN_REGION_SOURCES} stay open: the least recently used are closed and re-opened from
24
+ * their opener when used again (a source's ids are stable, so what was taken stays taken). The
25
+ * source of the slice on screen ({@link show}) is never closed for another: a read across every
26
+ * slice must not close the source the viewer draws and takes from.
27
+ */
28
+ export declare class RegionSourceScope {
29
+ private readonly images;
30
+ /** Open entries, least recently used first. */
31
+ private readonly openOrder;
32
+ /** The entry of the slice on screen: kept open. */
33
+ private shown;
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;
40
+ /** Drop every source of `image` (closing the open ones) and what was taken from them. */
41
+ detachImage(image: string): void;
42
+ /** Drop the source of one slice of `image`. */
43
+ detachSlice(image: string, slice: number): void;
44
+ /** The slice on screen (null: none): its source stays open while others are read. */
45
+ show(image: string | undefined, slice: number | null): void;
46
+ /** Whether `image` has a source for `slice`. */
47
+ has(image: string | undefined, slice: number): boolean;
48
+ /** Whether `slice` of `image` has a source of its own (not a `'planes'` source's plane). */
49
+ hasOwnSource(image: string | undefined, slice: number): boolean;
50
+ /** Every slice of `image` with a source of its own (not counting a `'planes'` source). */
51
+ slicesWithSource(image: string | undefined): number[];
52
+ /** Whether `image` has one source over all its slices. */
53
+ hasPlanesSource(image: string | undefined): boolean;
54
+ /**
55
+ * The source behind `slice` of `image`, opening it if needed. Resolves null when there is
56
+ * none, and rejects when it cannot be opened.
57
+ */
58
+ binding(image: string | undefined, slice: number): Promise<RegionSourceBinding | null>;
59
+ /** The ids taken from `slice`'s source. */
60
+ taken(image: string | undefined, slice: number): ReadonlySet<string>;
61
+ /** Every id taken from any slice of `image` (a `'planes'` source's ids are unique across them). */
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[];
65
+ /** The slices of `image` with anything taken from their source. */
66
+ slicesWithTaken(image: string | undefined): number[];
67
+ /** Replace the ids taken from `slice`'s source (copy-on-write: `ids` is kept as given). */
68
+ setTaken(image: string | undefined, slice: number, ids: ReadonlySet<string>): void;
69
+ private entry;
70
+ private imageSources;
71
+ private openEntry;
72
+ private close;
73
+ private closeSource;
74
+ }