@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.
- package/esm2022/index.mjs +10 -1
- package/esm2022/lib/contracts/image.contract.mjs +1 -1
- package/esm2022/lib/contracts/ports/region-io.port.mjs +1 -1
- package/esm2022/lib/contracts/region-editor-api.contract.mjs +1 -1
- package/esm2022/lib/contracts/region-store.contract.mjs +1 -1
- package/esm2022/lib/contracts/section-view.contract.mjs +2 -0
- package/esm2022/lib/contracts/visualizer.contract.mjs +1 -1
- package/esm2022/lib/contracts/viz-config.mjs +1 -1
- package/esm2022/lib/geometry/loft.mjs +128 -0
- package/esm2022/lib/geometry/polylabel.mjs +156 -0
- package/esm2022/lib/geometry/reconstruct.mjs +315 -0
- package/esm2022/lib/geometry/reslice-image.mjs +57 -0
- package/esm2022/lib/geometry/section.mjs +215 -0
- package/esm2022/lib/implementations/napari-js/napari-loading-badge.mjs +11 -7
- package/esm2022/lib/implementations/napari-js/napari-loading-state.mjs +20 -3
- package/esm2022/lib/implementations/napari-js/napari-region-mesh-pointer.mjs +100 -0
- package/esm2022/lib/implementations/napari-js/napari-region-overlay.mjs +28 -5
- package/esm2022/lib/implementations/napari-js/napari-scene.mjs +1 -1
- package/esm2022/lib/implementations/napari-js/napari-spatial-hover.mjs +9 -2
- package/esm2022/lib/implementations/napari-js/napari-tool-bridge.mjs +5 -2
- package/esm2022/lib/implementations/napari-js/napari-visualizer.service.mjs +81 -1
- package/esm2022/lib/implementations/napari-js/napari-volume-region-meshes.mjs +129 -0
- package/esm2022/lib/implementations/napari-js/napari-volume-scene.mjs +115 -4
- package/esm2022/lib/implementations/napari-js/napari-volume-slice-planes.mjs +103 -0
- package/esm2022/lib/implementations/napari-js/region-overlay/region-svg-renderer.mjs +15 -3
- package/esm2022/lib/implementations/osd/openseadragon-viewer-options.mjs +18 -2
- package/esm2022/lib/implementations/osd/openseadragon-visualizer.service.mjs +9 -1
- package/esm2022/lib/implementations/osd/osd-region-overlay-draw.mjs +18 -7
- package/esm2022/lib/implementations/osd/osd-region-overlay.mjs +38 -8
- package/esm2022/lib/implementations/osd/osd-tile-loading.mjs +71 -0
- package/esm2022/lib/implementations/osd/osd-viewer-like.mjs +1 -1
- package/esm2022/lib/implementations/osd/slice-cache.mjs +35 -6
- package/esm2022/lib/implementations/tile-server/tile-protocol.mjs +1 -1
- package/esm2022/lib/models/class-preset.mjs +1 -1
- package/esm2022/lib/models/polygon-factory.mjs +17 -1
- package/esm2022/lib/models/region-geojson.mjs +44 -6
- package/esm2022/lib/models/region.mjs +1 -1
- package/esm2022/lib/region-editor/class-tree/class-tree.component.mjs +156 -0
- package/esm2022/lib/region-editor/class-tree/class-tree.mjs +108 -0
- package/esm2022/lib/region-editor/classes-panel/classes-panel.component.mjs +77 -13
- package/esm2022/lib/region-editor/region-editor.component.mjs +670 -42
- package/esm2022/lib/region-editor/region-metrics.mjs +20 -2
- package/esm2022/lib/region-editor/region-persistence.service.mjs +44 -10
- package/esm2022/lib/region-editor/region-table/region-table.component.mjs +24 -8
- package/esm2022/lib/region-import/label-classes.mjs +149 -0
- package/esm2022/lib/region-import/label-volume.mjs +194 -0
- package/esm2022/lib/region-import/region-import.mjs +71 -0
- package/esm2022/lib/region-overlay/region-geometry.mjs +3 -3
- package/esm2022/lib/region-overlay/region-source-layer.mjs +378 -0
- package/esm2022/lib/region-overlay/region-style.mjs +97 -0
- package/esm2022/lib/region-source/http-region-source.mjs +104 -0
- package/esm2022/lib/region-source/region-source-ops.mjs +53 -0
- package/esm2022/lib/region-source/region-source-worker.mjs +10 -0
- package/esm2022/lib/region-source/region-source.mjs +67 -0
- package/esm2022/lib/region-source/region-tiles.mjs +708 -0
- package/esm2022/lib/region-source/worker-region-source.mjs +229 -0
- package/esm2022/lib/routing-visualizer.service.mjs +510 -22
- package/esm2022/lib/section-pane/section-pane.component.mjs +299 -0
- package/esm2022/lib/store/class-color.util.mjs +10 -5
- package/esm2022/lib/store/class-signatures.mjs +63 -0
- package/esm2022/lib/store/region-scope-cache.mjs +5 -1
- package/esm2022/lib/store/region-source-scope.mjs +186 -0
- package/esm2022/lib/store/region-store.service.mjs +774 -12
- package/esm2022/lib/store/visualizer-store.service.mjs +33 -6
- package/esm2022/lib/toolbar/region-tools/region-tools.component.mjs +8 -2
- package/esm2022/lib/toolbar/stack-controls/stack-controls.component.mjs +55 -15
- package/esm2022/lib/toolbar/toolbar.component.mjs +19 -5
- package/esm2022/lib/visualizer/region-load.mjs +67 -4
- package/esm2022/lib/visualizer/volume-sections.mjs +175 -0
- package/esm2022/lib/visualizer.component.mjs +155 -7
- 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
- package/fesm2022/jax-data-science-sci-image-visualizer-jax-data-science-sci-image-visualizer-BELcx0jv.mjs.map +1 -0
- 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
- 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
- package/fesm2022/jax-data-science-sci-image-visualizer-region-source-worker-CAqBjM5L.mjs +12 -0
- package/fesm2022/jax-data-science-sci-image-visualizer-region-source-worker-CAqBjM5L.mjs.map +1 -0
- package/fesm2022/jax-data-science-sci-image-visualizer.mjs +3 -3
- package/fesm2022/region-source.worker.js +1067 -0
- package/index.d.ts +12 -0
- package/lib/contracts/image.contract.d.ts +4 -0
- package/lib/contracts/ports/region-io.port.d.ts +24 -0
- package/lib/contracts/region-editor-api.contract.d.ts +102 -0
- package/lib/contracts/region-store.contract.d.ts +22 -0
- package/lib/contracts/section-view.contract.d.ts +44 -0
- package/lib/contracts/visualizer.contract.d.ts +10 -0
- package/lib/contracts/viz-config.d.ts +8 -0
- package/lib/geometry/loft.d.ts +22 -0
- package/lib/geometry/polylabel.d.ts +23 -0
- package/lib/geometry/reconstruct.d.ts +54 -0
- package/lib/geometry/reslice-image.d.ts +33 -0
- package/lib/geometry/section.d.ts +52 -0
- package/lib/implementations/napari-js/napari-loading-badge.d.ts +4 -2
- package/lib/implementations/napari-js/napari-loading-state.d.ts +8 -1
- package/lib/implementations/napari-js/napari-region-mesh-pointer.d.ts +32 -0
- package/lib/implementations/napari-js/napari-region-overlay.d.ts +6 -1
- package/lib/implementations/napari-js/napari-scene.d.ts +33 -0
- package/lib/implementations/napari-js/napari-spatial-hover.d.ts +3 -1
- package/lib/implementations/napari-js/napari-visualizer.service.d.ts +48 -0
- package/lib/implementations/napari-js/napari-volume-region-meshes.d.ts +66 -0
- package/lib/implementations/napari-js/napari-volume-scene.d.ts +45 -1
- package/lib/implementations/napari-js/napari-volume-slice-planes.d.ts +43 -0
- package/lib/implementations/osd/openseadragon-viewer-options.d.ts +2 -0
- package/lib/implementations/osd/openseadragon-visualizer.service.d.ts +2 -0
- package/lib/implementations/osd/osd-region-overlay-draw.d.ts +4 -3
- package/lib/implementations/osd/osd-region-overlay.d.ts +10 -3
- package/lib/implementations/osd/osd-tile-loading.d.ts +43 -0
- package/lib/implementations/osd/osd-viewer-like.d.ts +14 -0
- package/lib/implementations/osd/slice-cache.d.ts +13 -3
- package/lib/implementations/tile-server/tile-protocol.d.ts +3 -0
- package/lib/models/class-preset.d.ts +7 -0
- package/lib/models/polygon-factory.d.ts +5 -0
- package/lib/models/region-geojson.d.ts +40 -0
- package/lib/models/region.d.ts +19 -0
- package/lib/region-editor/class-tree/class-tree.component.d.ts +78 -0
- package/lib/region-editor/class-tree/class-tree.d.ts +31 -0
- package/lib/region-editor/classes-panel/classes-panel.component.d.ts +36 -6
- package/lib/region-editor/region-editor.component.d.ts +159 -17
- package/lib/region-editor/region-metrics.d.ts +8 -0
- package/lib/region-editor/region-persistence.service.d.ts +17 -5
- package/lib/region-editor/region-table/region-table.component.d.ts +10 -4
- package/lib/region-import/label-classes.d.ts +39 -0
- package/lib/region-import/label-volume.d.ts +31 -0
- package/lib/region-import/region-import.d.ts +46 -0
- package/lib/region-overlay/region-geometry.d.ts +4 -3
- package/lib/region-overlay/region-source-layer.d.ts +96 -0
- package/lib/region-overlay/region-style.d.ts +52 -0
- package/lib/region-source/http-region-source.d.ts +45 -0
- package/lib/region-source/region-source-ops.d.ts +89 -0
- package/lib/region-source/region-source-worker.d.ts +7 -0
- package/lib/region-source/region-source.d.ts +82 -0
- package/lib/region-source/region-tiles.d.ts +289 -0
- package/lib/region-source/worker-region-source.d.ts +65 -0
- package/lib/routing-visualizer.service.d.ts +168 -1
- package/lib/section-pane/section-pane.component.d.ts +47 -0
- package/lib/store/class-color.util.d.ts +6 -3
- package/lib/store/class-signatures.d.ts +11 -0
- package/lib/store/region-scope-cache.d.ts +2 -0
- package/lib/store/region-source-scope.d.ts +74 -0
- package/lib/store/region-store.service.d.ts +216 -2
- package/lib/store/visualizer-store.service.d.ts +10 -0
- package/lib/toolbar/region-tools/region-tools.component.d.ts +3 -1
- package/lib/toolbar/stack-controls/stack-controls.component.d.ts +20 -9
- package/lib/toolbar/toolbar.component.d.ts +9 -2
- package/lib/visualizer/region-load.d.ts +23 -4
- package/lib/visualizer/volume-sections.d.ts +64 -0
- package/lib/visualizer.component.d.ts +40 -0
- package/package.json +2 -2
- package/src/lib/assets/slice.svg +23 -0
- package/fesm2022/jax-data-science-sci-image-visualizer-jax-data-science-sci-image-visualizer-Csxlnq7I.mjs.map +0 -1
package/index.d.ts
CHANGED
|
@@ -46,6 +46,18 @@ export { clearSamModelCache } from './lib/toolbar/segmentation/sam-onnx-core';
|
|
|
46
46
|
export * from './lib/models/region';
|
|
47
47
|
export * from './lib/models/class-preset';
|
|
48
48
|
export { ShapeSelection } from './lib/models/shape';
|
|
49
|
+
export { openGeoJsonRegionSource } from './lib/region-source/worker-region-source';
|
|
50
|
+
export { openHttpRegionSource } from './lib/region-source/http-region-source';
|
|
51
|
+
export type { HttpRegionSourceOptions, WireTileFeature } from './lib/region-source/http-region-source';
|
|
52
|
+
export { REGION_SOURCE_MIN_CHARS } from './lib/region-source/region-source';
|
|
53
|
+
export { isLabelVolumeName, readLabelVolume } from './lib/region-import/label-volume';
|
|
54
|
+
export type { LabelVolume } from './lib/region-import/label-volume';
|
|
55
|
+
export { labelClasses, labelSliceGeoJson } from './lib/region-import/label-classes';
|
|
56
|
+
export type { LabelClasses } from './lib/region-import/label-classes';
|
|
57
|
+
export { importFile, planRegionImport } from './lib/region-import/region-import';
|
|
58
|
+
export type { RegionImportFile, RegionImportPlan } from './lib/region-import/region-import';
|
|
59
|
+
export type { RegionSource, RegionSourceView, SourceFeature } from './lib/region-source/region-source';
|
|
60
|
+
export type { RegionIndexPage, RegionIndexQuery, RegionIndexRow, RegionSourceInfo, RegionTile, RegionTileKey, TileFeature, } from './lib/region-source/region-tiles';
|
|
49
61
|
export { VisualizationModule } from './lib/visualization.module';
|
|
50
62
|
export { RoutingVisualizerService } from './lib/routing-visualizer.service';
|
|
51
63
|
export { provideVisualization } from './lib/provide-visualization';
|
|
@@ -61,6 +61,10 @@ export interface IImageInfo {
|
|
|
61
61
|
* opposed to the scalar `roiJsonStr`, which is one ROI set for the whole
|
|
62
62
|
* image (a single file or a server z-stack). (jit-ui#93) */
|
|
63
63
|
roiJsonStrs?: (string | null)[];
|
|
64
|
+
/** Base URL of a server-side region source for this image (see `openHttpRegionSource`):
|
|
65
|
+
* its regions are drawn from the server's level-of-detail tiles instead of being loaded
|
|
66
|
+
* from `roiJsonStr`. On a stack, slice z shows the source's plane z. */
|
|
67
|
+
regionSourceUrl?: string;
|
|
64
68
|
/** Per-slice, per-channel plane URLs for a SERVERLESS multichannel image
|
|
65
69
|
* (`tiled: false` + `imageMeta[0].channelCount > 1`). `channelUrls[z][c]`
|
|
66
70
|
* is a complete single-band image of channel c at slice z. The OSD simple
|
|
@@ -25,6 +25,30 @@ export interface RegionIoPort {
|
|
|
25
25
|
z: number;
|
|
26
26
|
geoJsonStr: string;
|
|
27
27
|
}[]): Observable<void>;
|
|
28
|
+
/**
|
|
29
|
+
* "Import regions from server": let the user pick region files or a region set in the host's
|
|
30
|
+
* storage (the current project's bucket, say) and hand them over. Emits null when the user
|
|
31
|
+
* cancels. Without it, the Region Editor shows no server import.
|
|
32
|
+
*/
|
|
33
|
+
pickServerRegions?(): Observable<ServerRegionPick | null>;
|
|
28
34
|
}
|
|
35
|
+
/**
|
|
36
|
+
* Regions picked on the host's server (see {@link RegionIoPort.pickServerRegions}): files it
|
|
37
|
+
* downloaded, imported as the Region Editor imports chosen files (one GeoJSON; a label volume
|
|
38
|
+
* `.nii` / `.nii.gz` / `.nrrd` with its ontology JSON; a folder's per-slice GeoJSON files with its
|
|
39
|
+
* `regionset.json`), or a region set its server serves by level of detail (jit-service's
|
|
40
|
+
* `/regions/{id}/`), read through the host's `HttpClient` without downloading it.
|
|
41
|
+
*/
|
|
42
|
+
export type ServerRegionPick = {
|
|
43
|
+
kind: 'files';
|
|
44
|
+
files: Array<{
|
|
45
|
+
name: string;
|
|
46
|
+
data: Blob | ArrayBuffer | Uint8Array | string;
|
|
47
|
+
}>;
|
|
48
|
+
} | {
|
|
49
|
+
kind: 'source';
|
|
50
|
+
url: string;
|
|
51
|
+
name?: string;
|
|
52
|
+
};
|
|
29
53
|
/** DI token for the host's {@link RegionIoPort}. Required by the region editor. */
|
|
30
54
|
export declare const REGION_IO_PORT: InjectionToken<RegionIoPort>;
|
|
@@ -3,6 +3,9 @@ import { Observable } from 'rxjs';
|
|
|
3
3
|
import { Region } from '../models/region';
|
|
4
4
|
import { ClassPreset, PresetSet } from '../models/class-preset';
|
|
5
5
|
import { IImageMetadata } from './image.contract';
|
|
6
|
+
import type { RegionSource, RegionSourceView } from '../region-source/region-source';
|
|
7
|
+
import type { RegionIndexPage, RegionIndexQuery } from '../region-source/region-tiles';
|
|
8
|
+
import type { RegionStyle } from '../region-overlay/region-style';
|
|
6
9
|
/**
|
|
7
10
|
* Public, implementation-agnostic surface that the Region Editor (an *external*
|
|
8
11
|
* consumer of the visualization package) depends on. It deals only in
|
|
@@ -78,6 +81,105 @@ export interface IRegionEditorApi {
|
|
|
78
81
|
width: number;
|
|
79
82
|
height: number;
|
|
80
83
|
} | null;
|
|
84
|
+
/**
|
|
85
|
+
* Load `geoJsonStr` as the slice's region source when it is large enough
|
|
86
|
+
* (`VizConfig.regionSourceMinChars`): resolves true once it is open, false when it is small
|
|
87
|
+
* and should be imported as regions; rejects when it is not a GeoJSON FeatureCollection.
|
|
88
|
+
*/
|
|
89
|
+
importRegionSource?(geoJsonStr: string): Promise<boolean>;
|
|
90
|
+
/**
|
|
91
|
+
* A ticket for an import about to read or decode its files: an import method given a stale one
|
|
92
|
+
* (another import took a ticket since, or another image was plotted) changes nothing.
|
|
93
|
+
*/
|
|
94
|
+
regionImportTicket?(): number;
|
|
95
|
+
/**
|
|
96
|
+
* Replace the regions and region sources with one source per slice (an imported label volume,
|
|
97
|
+
* or a folder of per-slice region files): openers by slice index, each opened the first time its
|
|
98
|
+
* slice is shown. A single image takes slice 0's. Returns how many slices have one, or null
|
|
99
|
+
* (changing nothing) when `ticket` is stale. A save writes every imported slice.
|
|
100
|
+
*/
|
|
101
|
+
importSliceRegionSources?(openers: ReadonlyMap<number, () => Promise<RegionSource>>, ticket?: number): number | null;
|
|
102
|
+
/**
|
|
103
|
+
* Replace them with one imported source (a region set a server serves): over every slice of a
|
|
104
|
+
* stack when z-indexed, else on the slice shown. Resolves false, changing nothing, when the
|
|
105
|
+
* import went stale while the source opened.
|
|
106
|
+
*/
|
|
107
|
+
importRegionSourceOpener?(open: () => Promise<RegionSource>, ticket?: number): Promise<boolean>;
|
|
108
|
+
/**
|
|
109
|
+
* Drop the slice's region source, for regions imported in its place (a small file replacing a
|
|
110
|
+
* large one). The other slices keep theirs.
|
|
111
|
+
*/
|
|
112
|
+
dropRegionSource?(): Promise<void>;
|
|
113
|
+
/** The slice's region source (null without one) and every change of it. */
|
|
114
|
+
getRegionSourceView$?(): Observable<RegionSourceView | null>;
|
|
115
|
+
/** A page of the slice source's features that were not taken from it. */
|
|
116
|
+
getRegionSourceIndex?(query: Omit<RegionIndexQuery, 'exclude'>): Promise<RegionIndexPage>;
|
|
117
|
+
/** Take source features into the regions and select them (added with `additive`). */
|
|
118
|
+
selectSourceFeatures?(ids: readonly string[], additive?: boolean): Promise<number[]>;
|
|
119
|
+
/** Delete source features without taking them (one undo step). */
|
|
120
|
+
deleteSourceFeatures?(ids: readonly string[]): void;
|
|
121
|
+
/**
|
|
122
|
+
* Features per class still in the slice's region source (not taken); with `stack`, a z-stack's
|
|
123
|
+
* over every slice.
|
|
124
|
+
*/
|
|
125
|
+
getRegionSourceClassCounts?(stack?: boolean): Promise<Record<string, number>>;
|
|
126
|
+
/** The region look (outlines, or filled with labels inside) and every change of it. */
|
|
127
|
+
getRegionStyle$?(): Observable<RegionStyle>;
|
|
128
|
+
/** Choose the region look, field by field (overrides a region source's hint). */
|
|
129
|
+
setRegionStyle?(patch: Partial<RegionStyle>): void;
|
|
130
|
+
/** Whether a volume view is on screen (regions can then be shown in 3D). */
|
|
131
|
+
getVolumeView$?(): Observable<boolean>;
|
|
132
|
+
/**
|
|
133
|
+
* Whether the volume view's slice pane is wanted (one slice edited beside the 3D view). A volume
|
|
134
|
+
* view without it lists every slice's classes; with it, the slice's.
|
|
135
|
+
*/
|
|
136
|
+
getSliceEditor$?(): Observable<boolean>;
|
|
137
|
+
/** Whether the volume view draws the region reconstructions through the volume, and changes. */
|
|
138
|
+
getRegionsThroughVolume$?(): Observable<boolean>;
|
|
139
|
+
/**
|
|
140
|
+
* Draw the region reconstructions through the volume (it hides none: surfaces traced inside its
|
|
141
|
+
* bright structures) or hidden behind what it shows in front of them (the default).
|
|
142
|
+
*/
|
|
143
|
+
setRegionsThroughVolume?(through: boolean): void;
|
|
144
|
+
/**
|
|
145
|
+
* Show these groups of classes in the volume view as 3D reconstructions (one surface per group,
|
|
146
|
+
* in its colour), and only these; [] hides them.
|
|
147
|
+
*/
|
|
148
|
+
showRegionClasses3d?(groups: ReadonlyArray<{
|
|
149
|
+
key: string;
|
|
150
|
+
classes: readonly string[];
|
|
151
|
+
color: string;
|
|
152
|
+
label?: string;
|
|
153
|
+
}>): Promise<void>;
|
|
154
|
+
/**
|
|
155
|
+
* Each class's volume over the whole stack, in px² × slices: its outlines' area on every slice,
|
|
156
|
+
* one slice thick. Times the pixel size and the slice spacing, µm³.
|
|
157
|
+
*/
|
|
158
|
+
getClassVolumes?(classes: readonly string[]): Promise<Record<string, number>>;
|
|
159
|
+
/** Highlight the surfaces of these group keys in the volume view (none: all as usual). */
|
|
160
|
+
highlightRegionClasses3d?(keys: readonly string[]): void;
|
|
161
|
+
/** A surface clicked in the volume view with the selection tool (its group key), or none (null). */
|
|
162
|
+
getRegionPicked3d$?(): Observable<{
|
|
163
|
+
key: string | null;
|
|
164
|
+
additive: boolean;
|
|
165
|
+
}>;
|
|
166
|
+
/** The class groups shown in 3D on the image on screen; emits [] when another image is plotted. */
|
|
167
|
+
getRegionClasses3d$?(): Observable<ReadonlyArray<{
|
|
168
|
+
key: string;
|
|
169
|
+
classes: readonly string[];
|
|
170
|
+
}>>;
|
|
171
|
+
/** The classes hidden from view, and every change of them. */
|
|
172
|
+
getHiddenClasses$?(): Observable<ReadonlySet<string>>;
|
|
173
|
+
/**
|
|
174
|
+
* Hide (or show again) these classes: their regions and the region source's features are not
|
|
175
|
+
* drawn or picked, and their surfaces in the volume view are hidden.
|
|
176
|
+
*/
|
|
177
|
+
setClassesHidden?(classes: readonly string[], hidden: boolean): void;
|
|
178
|
+
/** Select every region of these classes on the slice, the source's included (taken). */
|
|
179
|
+
selectRegionClasses?(classes: readonly string[], additive?: boolean): Promise<void>;
|
|
180
|
+
/** {@link getGeoJsonString} merged with the region source behind the regions (see
|
|
181
|
+
* `RegionStore.getGeoJsonWithSource`); `slice` names a folder stack's slice. */
|
|
182
|
+
getGeoJsonStringWithSource?(regions: Region[], slice?: number): Promise<string>;
|
|
81
183
|
}
|
|
82
184
|
/** DI token the Region Editor injects instead of the concrete service. */
|
|
83
185
|
export declare const REGION_EDITOR_API: InjectionToken<IRegionEditorApi>;
|
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
import { Rectangle, Polygon, MultiPolygon } from '../models/region';
|
|
2
2
|
import { Region } from '../models/region';
|
|
3
|
+
import type { Observable } from 'rxjs';
|
|
4
|
+
import type { RegionSourceView } from '../region-source/region-source';
|
|
5
|
+
import type { RegionStyle } from '../region-overlay/region-style';
|
|
3
6
|
/**
|
|
4
7
|
* Region-native editing surface — typed geometry operations on the neutral
|
|
5
8
|
* {@link Region} model. The OpenSeadragon overlay (and any future editing UI)
|
|
@@ -72,3 +75,22 @@ export interface IRegionEditApi {
|
|
|
72
75
|
beginBatch(): void;
|
|
73
76
|
endBatch(): void;
|
|
74
77
|
}
|
|
78
|
+
/**
|
|
79
|
+
* The region-source side of the store, as the overlays use it: a large region set held as a
|
|
80
|
+
* tiled source (see `RegionStore.attachRegionSource`) that the overlays draw at the zoom's level
|
|
81
|
+
* of detail and pick from. Optional on the overlays' store: a store without it simply has no
|
|
82
|
+
* source to draw.
|
|
83
|
+
*/
|
|
84
|
+
export interface IRegionSourceApi {
|
|
85
|
+
/** The current slice's source as a layer draws it, and every change of it; null without one. */
|
|
86
|
+
getRegionSourceView$(): Observable<RegionSourceView | null>;
|
|
87
|
+
/** Take source features into the working set as regions and select them (added to the
|
|
88
|
+
* selection with `additive`). Resolves the region ids. */
|
|
89
|
+
selectSourceFeatures(ids: readonly string[], additive?: boolean): Promise<number[]>;
|
|
90
|
+
/** The region look (outlines, or filled with inside labels). */
|
|
91
|
+
getRegionStyle(): RegionStyle;
|
|
92
|
+
/** Whether a class's label is left out because a subclass of it is drawn too. */
|
|
93
|
+
isLabelCovered(label: string | undefined): boolean;
|
|
94
|
+
/** Whether regions labelled `label` are hidden: not drawn, not picked. */
|
|
95
|
+
isClassHidden(label: string | null | undefined): boolean;
|
|
96
|
+
}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The sections shown beside a split volume view: the planes x = const and y = const through the
|
|
3
|
+
* stack, each as an image cut from the volume with the regions' outlines cut by the same plane.
|
|
4
|
+
*
|
|
5
|
+
* Section coordinates `(u, v)` (see `geometry/section`): through x, u is the slice (slice k spans
|
|
6
|
+
* [k, k + 1)) and v the image y; through y, u is the image x and v the slice.
|
|
7
|
+
*/
|
|
8
|
+
export type SectionAxis = 'x' | 'y';
|
|
9
|
+
/** A class's outlines in a section, as interleaved `u, v`. */
|
|
10
|
+
export interface SectionRegions {
|
|
11
|
+
label: string;
|
|
12
|
+
/** `#rrggbb`. */
|
|
13
|
+
color: string;
|
|
14
|
+
/** Closed outlines, holes included (even-odd). */
|
|
15
|
+
rings: Float64Array[];
|
|
16
|
+
/** Open lines (a layer boundary across the slices); one point where it crosses one slice only. */
|
|
17
|
+
lines: Float64Array[];
|
|
18
|
+
}
|
|
19
|
+
export interface SectionView {
|
|
20
|
+
axis: SectionAxis;
|
|
21
|
+
/** Where the plane is: image x (through x) or y (through y), px. */
|
|
22
|
+
at: number;
|
|
23
|
+
/** The section's image, RGBA row by row, spanning [0, size[0]] × [0, size[1]]. */
|
|
24
|
+
image: {
|
|
25
|
+
width: number;
|
|
26
|
+
height: number;
|
|
27
|
+
data: Uint8ClampedArray;
|
|
28
|
+
};
|
|
29
|
+
/** Section units across (u) and down (v). */
|
|
30
|
+
size: [number, number];
|
|
31
|
+
/** The volume's world units per section unit across and down: draws it in its proportions. */
|
|
32
|
+
scale: [number, number];
|
|
33
|
+
regions: SectionRegions[];
|
|
34
|
+
/** The other two planes, across (a u) and down (a v); null where there is none. */
|
|
35
|
+
crosshair: {
|
|
36
|
+
u: number | null;
|
|
37
|
+
v: number | null;
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
/** Both sections; null until the split volume view has a volume to cut. */
|
|
41
|
+
export interface SectionViews {
|
|
42
|
+
x: SectionView | null;
|
|
43
|
+
y: SectionView | null;
|
|
44
|
+
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { InjectionToken } from '@angular/core';
|
|
2
|
+
import type { SectionAxis, SectionViews } from './section-view.contract';
|
|
2
3
|
import { Observable } from 'rxjs';
|
|
3
4
|
import { Image } from 'image-js';
|
|
4
5
|
import { IImageInfo, IImageMetadata } from './image.contract';
|
|
@@ -490,6 +491,15 @@ export interface IVisualizer extends IDataRenderer, IRegionStore, IToolControlle
|
|
|
490
491
|
/** This backend's region renderer. May be null until a plot is mounted
|
|
491
492
|
* (OpenSeadragon). Drives region draw/select modes uniformly. */
|
|
492
493
|
getRegionOverlay(): IRegionOverlay | null;
|
|
494
|
+
/** Split a volume view: the displayed slice, with every region tool, in the div `div` beside
|
|
495
|
+
* the 3D view; null closes it. Resolves whether the slice shows. Optional: the router's. */
|
|
496
|
+
setSliceEditor?(div: string | null): Promise<boolean>;
|
|
497
|
+
/** The slice editor's sections through x and y (nulls while it is closed). Optional: the router's. */
|
|
498
|
+
getSectionViews$?(): Observable<SectionViews>;
|
|
499
|
+
/** Move the slice editor's section plane through `axis` to `at` (image px). */
|
|
500
|
+
setSectionPlane?(axis: SectionAxis, at: number): void;
|
|
501
|
+
/** The slice picked by dragging the z plane in the volume (the host shows it). */
|
|
502
|
+
getSliceDrag$?(): Observable<number>;
|
|
493
503
|
/** Isosurface controls when this backend advertises `ViewerFeature.Isosurface`,
|
|
494
504
|
* else null — so consumers gate on the returned object, not a no-op method. */
|
|
495
505
|
getIsosurfaceControls(): IIsosurfaceControls | null;
|
|
@@ -21,6 +21,14 @@ export interface VizConfig {
|
|
|
21
21
|
* are unaffected.
|
|
22
22
|
*/
|
|
23
23
|
useNapariRenderer?: boolean;
|
|
24
|
+
/**
|
|
25
|
+
* An image's ROI GeoJSON (`roiJsonStr`, or a slice's `roiJsonStrs[z]`) at least this many
|
|
26
|
+
* characters long loads as a tiled region source rather than as regions: drawn from the tiles
|
|
27
|
+
* in view at the zoom's level of detail (OpenSeadragon and napari; Plotly does not draw it),
|
|
28
|
+
* each feature joining the regions when it is selected or edited. Default 1 000 000; 0 makes
|
|
29
|
+
* every ROI file a source, `Infinity` none.
|
|
30
|
+
*/
|
|
31
|
+
regionSourceMinChars?: number;
|
|
24
32
|
}
|
|
25
33
|
/** DI token for the host's {@link VizConfig}. Required by the router. */
|
|
26
34
|
export declare const VIZ_CONFIG: InjectionToken<VizConfig>;
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The sheet through open polylines traced on a stack of slices (a retinal layer boundary on each
|
|
3
|
+
* B-scan, say): each line joined to its counterpart on the next slice that has lines by a strip of
|
|
4
|
+
* triangles. Slices without lines in between are bridged straight across.
|
|
5
|
+
*
|
|
6
|
+
* Pure: usable from workers.
|
|
7
|
+
*/
|
|
8
|
+
import type { Mesh } from 'napari-js/geometry';
|
|
9
|
+
/** A class's open polylines on one slice: interleaved `x, y` image pixels. */
|
|
10
|
+
export interface SliceLines {
|
|
11
|
+
z: number;
|
|
12
|
+
lines: readonly ArrayLike<number>[];
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* The sheet through `slices`' lines, in image pixels (x, y) and slice indices (z: slice k's line at
|
|
16
|
+
* z = k). Every line is resampled at the same number of points, evenly along its length (about one
|
|
17
|
+
* per `step` px of the longest), so a line shared by the strips above and below it is one row of
|
|
18
|
+
* vertices. Lines are matched between neighbouring slices closest first, each at most once, and only
|
|
19
|
+
* when their boxes overlap; a line without a match ends the sheet there. Empty without two slices
|
|
20
|
+
* with lines.
|
|
21
|
+
*/
|
|
22
|
+
export declare function loftLines(slices: readonly SliceLines[], step?: number): Mesh;
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Where to put a label inside a polygon: its pole of inaccessibility, the inside point farthest
|
|
3
|
+
* from every edge (Garcia-Castellanos & Lombardo's grid search, as in Mapbox's polylabel). Unlike
|
|
4
|
+
* the centroid it is always inside, also for a U-shaped or ring-shaped region.
|
|
5
|
+
*
|
|
6
|
+
* Pure: usable from workers.
|
|
7
|
+
*/
|
|
8
|
+
/** A polygon as interleaved `x, y` rings: the exterior first, then its holes. */
|
|
9
|
+
export type FlatRings = readonly ArrayLike<number>[];
|
|
10
|
+
/** The pole of inaccessibility `[x, y]` and its distance to the nearest edge. */
|
|
11
|
+
export interface LabelPoint {
|
|
12
|
+
x: number;
|
|
13
|
+
y: number;
|
|
14
|
+
/** Distance from the point to the nearest edge: how much room a label has around it. */
|
|
15
|
+
distance: number;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* The pole of inaccessibility of `rings`, to within `precision` (default: 1/100 of the shorter
|
|
19
|
+
* side of the exterior's box, at least 0.5). Null for an exterior with fewer than three vertices.
|
|
20
|
+
*/
|
|
21
|
+
export declare function polylabel(rings: FlatRings, precision?: number): LabelPoint | null;
|
|
22
|
+
/** Distance from (x, y) to the nearest edge of `rings`, positive inside (even-odd), negative outside. */
|
|
23
|
+
export declare function signedDistance(x: number, y: number, rings: FlatRings): number;
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import type { Mesh } from 'napari-js/geometry';
|
|
2
|
+
/**
|
|
3
|
+
* A region's outlines on one slice: rings as interleaved `x, y` image pixels (holes included), and
|
|
4
|
+
* open polylines (a layer boundary), likewise.
|
|
5
|
+
*/
|
|
6
|
+
export interface SliceOutlines {
|
|
7
|
+
z: number;
|
|
8
|
+
rings: ArrayLike<number>[];
|
|
9
|
+
/**
|
|
10
|
+
* The feature each ring is part of (equal ids, one feature): a feature's rings fill even-odd (its
|
|
11
|
+
* holes), the features as their union, so one inside or over another cuts no hole in it. Absent:
|
|
12
|
+
* the rings are one feature.
|
|
13
|
+
*/
|
|
14
|
+
ringGroups?: ArrayLike<number>;
|
|
15
|
+
lines?: ArrayLike<number>[];
|
|
16
|
+
}
|
|
17
|
+
export interface ReconstructOptions {
|
|
18
|
+
/** In-plane voxel edge, image px (default 1). Raised to keep the mask within `maxVoxels`. */
|
|
19
|
+
pixelStep?: number;
|
|
20
|
+
/** At most this many voxels (default 32 M). */
|
|
21
|
+
maxVoxels?: number;
|
|
22
|
+
/** Laplacian smoothing passes (default 2). */
|
|
23
|
+
smooth?: number;
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* The mesh of the region outlined by `slices`, in image pixels (x, y) and slice indices (z: slice
|
|
27
|
+
* k's plane at z = k): the filled outlines' surface, and the sheet through the lines (see
|
|
28
|
+
* {@link loftLines}). Empty when no slice has an area and no two slices have lines.
|
|
29
|
+
*/
|
|
30
|
+
export declare function reconstruct(slices: readonly SliceOutlines[], opts?: ReconstructOptions): Mesh;
|
|
31
|
+
/**
|
|
32
|
+
* The area inside `rings` (interleaved `x, y`), even-odd: a ring inside an odd number of others is
|
|
33
|
+
* a hole. Exact for rings that do not cross (a polygon set's exteriors and holes).
|
|
34
|
+
*/
|
|
35
|
+
export declare function ringsArea(rings: readonly ArrayLike<number>[]): number;
|
|
36
|
+
/**
|
|
37
|
+
* The rings of each feature (see {@link SliceOutlines.ringGroups}), in the order first met; one
|
|
38
|
+
* feature of every ring without `groups`.
|
|
39
|
+
*/
|
|
40
|
+
export declare function featureRings(rings: readonly ArrayLike<number>[], groups?: ArrayLike<number>): ArrayLike<number>[][];
|
|
41
|
+
/**
|
|
42
|
+
* The area of a slice's outlines (px²): each feature's (even-odd, see {@link ringsArea}), the
|
|
43
|
+
* features as their union, so a feature inside or over another of the slice adds only what it
|
|
44
|
+
* covers beyond it. Features whose extents overlap are measured together, by the length of their
|
|
45
|
+
* union along each row, exact between the rows through their vertices where no outline crosses
|
|
46
|
+
* another (and refined where one does).
|
|
47
|
+
*/
|
|
48
|
+
export declare function outlinesArea(rings: readonly ArrayLike<number>[], groups?: ArrayLike<number>): number;
|
|
49
|
+
/**
|
|
50
|
+
* The volume of the region outlined by `slices`, in px² × slices (one slice thick per outline):
|
|
51
|
+
* the sum of each slice's area (see {@link outlinesArea}; Cavalieri's estimator). Times µm per px²
|
|
52
|
+
* and per slice, µm³.
|
|
53
|
+
*/
|
|
54
|
+
export declare function outlinedVolume(slices: readonly SliceOutlines[]): number;
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import type { Colormap } from 'napari-js';
|
|
2
|
+
import type { SectionAxis } from './section';
|
|
3
|
+
/** One channel of a volume as it is displayed. */
|
|
4
|
+
export interface VolumeChannelVoxels {
|
|
5
|
+
/** uint8 voxels, x fastest, then y, then z. */
|
|
6
|
+
data: Uint8Array;
|
|
7
|
+
/** The colormap the 3D view draws the channel with (a tint, or the display colormap). */
|
|
8
|
+
colormap: Colormap;
|
|
9
|
+
/** Display window over 0..255. */
|
|
10
|
+
min: number;
|
|
11
|
+
max: number;
|
|
12
|
+
/** napari-js gamma (see `toNapariGamma`): the windowed value t shows as t^γ. */
|
|
13
|
+
gamma: number;
|
|
14
|
+
visible: boolean;
|
|
15
|
+
}
|
|
16
|
+
export interface VolumeVoxels {
|
|
17
|
+
width: number;
|
|
18
|
+
height: number;
|
|
19
|
+
depth: number;
|
|
20
|
+
channels: readonly VolumeChannelVoxels[];
|
|
21
|
+
invert: boolean;
|
|
22
|
+
}
|
|
23
|
+
/** An RGBA image, row by row. */
|
|
24
|
+
export interface RgbaImage {
|
|
25
|
+
width: number;
|
|
26
|
+
height: number;
|
|
27
|
+
data: Uint8ClampedArray;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* The image of the plane `axis = index` (a voxel index): through x, slices across and y down;
|
|
31
|
+
* through y, x across and slices down — the section coordinates of `geometry/section`.
|
|
32
|
+
*/
|
|
33
|
+
export declare function resliceImage(vol: VolumeVoxels, axis: SectionAxis, index: number): RgbaImage;
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { SliceOutlines } from './reconstruct';
|
|
2
|
+
/** The plane: x = const (a section along y and the slices) or y = const (along x and the slices). */
|
|
3
|
+
export type SectionAxis = 'x' | 'y';
|
|
4
|
+
/** A class's outlines in a section, as interleaved `u, v`. */
|
|
5
|
+
export interface ClassSection {
|
|
6
|
+
/** Closed outlines, holes included (even-odd). */
|
|
7
|
+
rings: Float64Array[];
|
|
8
|
+
/** Open lines; a line of one point is where the class crosses on one slice only. */
|
|
9
|
+
lines: Float64Array[];
|
|
10
|
+
}
|
|
11
|
+
export interface SectionOptions {
|
|
12
|
+
/** Slices in the stack. */
|
|
13
|
+
depth: number;
|
|
14
|
+
/** Image px across the section's in-plane axis: the image height through x, its width through y. */
|
|
15
|
+
extent: number;
|
|
16
|
+
/** In-plane cell size of the closed shapes' cut, image px (default 1). */
|
|
17
|
+
step?: number;
|
|
18
|
+
/** Farthest a line moves between neighbouring slices and is still joined, image px (default extent / 10). */
|
|
19
|
+
maxJump?: number;
|
|
20
|
+
}
|
|
21
|
+
/** `[x0, y0, x1, y1]`, image px. */
|
|
22
|
+
type Box = [number, number, number, number];
|
|
23
|
+
/** A ring or line with its extent. */
|
|
24
|
+
interface Indexed {
|
|
25
|
+
points: ArrayLike<number>;
|
|
26
|
+
box: Box;
|
|
27
|
+
}
|
|
28
|
+
interface IndexedSlice {
|
|
29
|
+
z: number;
|
|
30
|
+
rings: Indexed[];
|
|
31
|
+
/** Each ring's feature (see SliceOutlines.ringGroups); absent: one feature. */
|
|
32
|
+
ringGroups?: ArrayLike<number>;
|
|
33
|
+
lines: Indexed[];
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Every class's outlines with each ring's and line's extent (and the class's): made once, it cuts
|
|
37
|
+
* any number of sections visiting only the outlines a plane crosses.
|
|
38
|
+
*/
|
|
39
|
+
export interface SectionIndex {
|
|
40
|
+
readonly classes: ReadonlyMap<string, {
|
|
41
|
+
box: Box;
|
|
42
|
+
slices: readonly IndexedSlice[];
|
|
43
|
+
}>;
|
|
44
|
+
}
|
|
45
|
+
/** Index every class's outlines for cutting (see {@link SectionIndex}). */
|
|
46
|
+
export declare function indexOutlines(byClass: ReadonlyMap<string, readonly SliceOutlines[]>): SectionIndex;
|
|
47
|
+
/**
|
|
48
|
+
* Each class's cut by the plane `axis = at`; classes the plane misses are left out. Pass an
|
|
49
|
+
* {@link indexOutlines} index to cut many sections of the same outlines.
|
|
50
|
+
*/
|
|
51
|
+
export declare function sectionOutlines(outlines: SectionIndex | ReadonlyMap<string, readonly SliceOutlines[]>, axis: SectionAxis, at: number, opts: SectionOptions): Map<string, ClassSection>;
|
|
52
|
+
export {};
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* "Transcripts reloading…" at the bottom of the canvas while a layer's data is in flight: one
|
|
3
3
|
* line naming every layer still loading, on a semi-opaque backing so it reads over any tissue.
|
|
4
|
+
* Longer work names itself ("Building HPF in 3D…") and joins the line.
|
|
4
5
|
*
|
|
5
6
|
* Shown only once something has been loading for {@link SHOW_AFTER_MS}, so a redraw served from
|
|
6
7
|
* cache does not flash it.
|
|
@@ -9,10 +10,11 @@ export declare const SHOW_AFTER_MS = 150;
|
|
|
9
10
|
export declare class NapariLoadingBadge {
|
|
10
11
|
private readonly el;
|
|
11
12
|
private names;
|
|
13
|
+
private tasks;
|
|
12
14
|
private timer;
|
|
13
15
|
constructor(host: HTMLElement);
|
|
14
|
-
/** The layers loading now; empty hides the badge. */
|
|
15
|
-
set(names: readonly string[]): void;
|
|
16
|
+
/** The layers loading now, and the tasks running (their messages); both empty hides the badge. */
|
|
17
|
+
set(names: readonly string[], tasks?: readonly string[]): void;
|
|
16
18
|
/** The text currently set (shown or about to be). */
|
|
17
19
|
get text(): string;
|
|
18
20
|
destroy(): void;
|
|
@@ -9,6 +9,9 @@ export type LoadingSource = 'Image' | 'Observations';
|
|
|
9
9
|
* the counts are dropped, and an `end` from a load that began before it is a no-op, so a load
|
|
10
10
|
* that settles after a re-plot can neither un-count the new scene's work nor drive a count below
|
|
11
11
|
* zero (which hid the next scene's "Observations reloading…" until a second load overlapped it).
|
|
12
|
+
*
|
|
13
|
+
* A {@link beginTask} is work that outlives a scene (a region's 3D reconstruction, built for
|
|
14
|
+
* whichever volume is on screen when it is done): its message stays across a reset.
|
|
12
15
|
*/
|
|
13
16
|
export declare class LoadingBadgeState {
|
|
14
17
|
private host;
|
|
@@ -16,15 +19,19 @@ export declare class LoadingBadgeState {
|
|
|
16
19
|
private readonly counts;
|
|
17
20
|
private tileLayers;
|
|
18
21
|
private generation;
|
|
22
|
+
private readonly tasks;
|
|
19
23
|
/** The element the badge is drawn into (the plot host); set per plot. */
|
|
20
24
|
attach(host: HTMLElement): void;
|
|
21
25
|
/** One load of `source` started; call the returned function once it settles. */
|
|
22
26
|
begin(source: LoadingSource): () => void;
|
|
27
|
+
/** A task started, shown by its `message` ("Building HPF in 3D…"); call the returned function
|
|
28
|
+
* once it settles. */
|
|
29
|
+
beginTask(message: string): () => void;
|
|
23
30
|
/** The spatial tile layers still loading (their own names, in their order). */
|
|
24
31
|
setTileLayers(layers: readonly string[]): void;
|
|
25
32
|
/** The text the badge has set (shown, or about to be once the show delay passes). */
|
|
26
33
|
get text(): string;
|
|
27
|
-
/** A new scene: forget every count and remove the badge. */
|
|
34
|
+
/** A new scene: forget every count and remove the badge (tasks show again on the next attach). */
|
|
28
35
|
reset(): void;
|
|
29
36
|
private show;
|
|
30
37
|
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import type { RegionMesh3D } from './napari-volume-region-meshes';
|
|
2
|
+
export interface RegionMeshPointerOptions {
|
|
3
|
+
/** The surface under canvas point (`x`, `y`) (CSS px), or null. */
|
|
4
|
+
pickAt(x: number, y: number): RegionMesh3D | null;
|
|
5
|
+
/** Whether a click picks (the selection tool armed, surfaces shown); otherwise clicks are left alone. */
|
|
6
|
+
active(): boolean;
|
|
7
|
+
/** Whether hovering names the surface under the pointer (surfaces shown, whatever the tool). */
|
|
8
|
+
hoverable(): boolean;
|
|
9
|
+
/** A click on a surface (its key), or on none (null); `additive` with Shift / Ctrl / ⌘. */
|
|
10
|
+
onPick(key: string | null, additive: boolean): void;
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Clicks and hover on the region surfaces of a volume view: a click (a press that does not orbit)
|
|
14
|
+
* picks the surface under it, or none; resting over a surface shows its name in a tooltip (and a
|
|
15
|
+
* pointer cursor when a click would pick it). Listens on the canvas without stopping events, so the
|
|
16
|
+
* camera still orbits.
|
|
17
|
+
*/
|
|
18
|
+
export declare class RegionMeshPointer {
|
|
19
|
+
private readonly canvas;
|
|
20
|
+
private readonly opts;
|
|
21
|
+
private readonly tip;
|
|
22
|
+
private down;
|
|
23
|
+
private hoverTimer;
|
|
24
|
+
constructor(canvas: HTMLElement, host: HTMLElement, opts: RegionMeshPointerOptions);
|
|
25
|
+
destroy(): void;
|
|
26
|
+
private local;
|
|
27
|
+
private readonly onDown;
|
|
28
|
+
private readonly onUp;
|
|
29
|
+
private readonly onMove;
|
|
30
|
+
private readonly onLeave;
|
|
31
|
+
private hide;
|
|
32
|
+
}
|
|
@@ -56,6 +56,9 @@ export declare class NapariRegionOverlay implements IRegionOverlay {
|
|
|
56
56
|
private readonly store;
|
|
57
57
|
private readonly svg;
|
|
58
58
|
private readonly renderer;
|
|
59
|
+
/** The image's region source, drawn under the regions at the zoom's level of detail; null
|
|
60
|
+
* where world is not the image (the 3D view's screen-space lassos). */
|
|
61
|
+
private readonly sourceLayer;
|
|
59
62
|
/** Client ↔ svg-local ↔ world conversions, with the svg origin read once per gesture/redraw. */
|
|
60
63
|
private readonly projection;
|
|
61
64
|
private readonly subs;
|
|
@@ -72,7 +75,9 @@ export declare class NapariRegionOverlay implements IRegionOverlay {
|
|
|
72
75
|
/** In-progress manipulation (select/move modes): dragging a body, a polygon vertex, or a
|
|
73
76
|
* rectangle corner. `anchor` is the fixed opposite corner for a rectangle resize. */
|
|
74
77
|
private edit;
|
|
75
|
-
constructor(host: HTMLElement, viewer: OverlayViewer, store: RegionStore
|
|
78
|
+
constructor(host: HTMLElement, viewer: OverlayViewer, store: RegionStore, opts?: {
|
|
79
|
+
regionSource?: boolean;
|
|
80
|
+
});
|
|
76
81
|
/**
|
|
77
82
|
* Whether a region tool currently owns the pointer.
|
|
78
83
|
*
|
|
@@ -1,4 +1,7 @@
|
|
|
1
|
+
import type { RegionMesh3D } from './napari-volume-region-meshes';
|
|
1
2
|
import type { Viewer } from 'napari-js';
|
|
3
|
+
import type { VolumeFrame } from './napari-volume-region-meshes';
|
|
4
|
+
import type { PlaneAxis, SlicePlanes } from './napari-volume-slice-planes';
|
|
2
5
|
import { IImageInfo } from '../../contracts/image.contract';
|
|
3
6
|
import { IHistogram } from '../../contracts/channel-histogram-api.contract';
|
|
4
7
|
import { IIsosurfaceControls, ISurface3dControls } from '../../contracts/visualizer.contract';
|
|
@@ -34,6 +37,23 @@ export interface NapariScene {
|
|
|
34
37
|
setNavigatorVisible?(visible: boolean): void;
|
|
35
38
|
/** Observations projected to canvas pixels (the spatial 3D cloud), or null. */
|
|
36
39
|
screenProjection?(obs: SpatialObservations): Float32Array | null;
|
|
40
|
+
/** Show these region reconstructions in the 3D view (volume scenes only). */
|
|
41
|
+
setRegionMeshes?(meshes: readonly RegionMesh3D[]): void;
|
|
42
|
+
/** Highlight the reconstructions of these keys (none: all as usual). */
|
|
43
|
+
setRegionHighlight?(keys: readonly string[]): void;
|
|
44
|
+
/** Hide the reconstructions of these keys. */
|
|
45
|
+
setRegionHidden?(keys: readonly string[]): void;
|
|
46
|
+
/**
|
|
47
|
+
* Draw the region reconstructions through the volume (it hides none of them) rather than hidden
|
|
48
|
+
* where it is in front of them (see VolumeScene.setRegionsThroughVolume).
|
|
49
|
+
*/
|
|
50
|
+
setRegionsThroughVolume?(through: boolean): void;
|
|
51
|
+
/** Show the planes of the sections beside the 3D view (volume scenes only). */
|
|
52
|
+
setSlicePlanes?(planes: SlicePlanes): void;
|
|
53
|
+
/** The assembled volume the sections are cut from (volume scenes only). */
|
|
54
|
+
volumeVoxels?(): VolumeVoxelsOnScreen | null;
|
|
55
|
+
/** Image px per voxel of the assembled volume, in-plane (volume scenes only). */
|
|
56
|
+
voxelStep?(): number | null;
|
|
37
57
|
/** Remove everything the scene added; called before the viewer is disposed. */
|
|
38
58
|
dispose(): void;
|
|
39
59
|
}
|
|
@@ -59,6 +79,15 @@ export interface StackProgress {
|
|
|
59
79
|
}
|
|
60
80
|
/** Everything a scene is built from: the viewer and its DOM, the service's collaborators, and the
|
|
61
81
|
* service state a scene reads live. */
|
|
82
|
+
/** A volume as assembled for display (voxels per channel, key 0 the grayscale one) and its frame. */
|
|
83
|
+
export interface VolumeVoxelsOnScreen {
|
|
84
|
+
width: number;
|
|
85
|
+
height: number;
|
|
86
|
+
depth: number;
|
|
87
|
+
channels: ReadonlyMap<number, Uint8Array>;
|
|
88
|
+
multichannel: boolean;
|
|
89
|
+
frame: VolumeFrame;
|
|
90
|
+
}
|
|
62
91
|
export interface SceneContext {
|
|
63
92
|
readonly viewer: Viewer;
|
|
64
93
|
readonly host: HTMLElement;
|
|
@@ -90,4 +119,8 @@ export interface SceneContext {
|
|
|
90
119
|
fitCameraSoon(): void;
|
|
91
120
|
outsideZone<T>(fn: () => T): T;
|
|
92
121
|
inZone<T>(fn: () => T): T;
|
|
122
|
+
/** A region reconstruction was clicked (its key), or the volume beside them (null). */
|
|
123
|
+
regionMeshPicked(key: string | null, additive: boolean): void;
|
|
124
|
+
/** A section's plane dragged in the volume to `value` along its axis. */
|
|
125
|
+
slicePlaneMoved(axis: PlaneAxis, value: number): void;
|
|
93
126
|
}
|