@jax-data-science/sci-image-visualizer 0.5.0 → 0.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +49 -0
- package/esm2022/lib/contracts/display-types.mjs +28 -1
- package/esm2022/lib/contracts/plot-type-contribution.contract.mjs +1 -1
- package/esm2022/lib/contracts/ports/spatial-data.port.mjs +3 -1
- package/esm2022/lib/contracts/spatial-dataset.contract.mjs +3 -1
- package/esm2022/lib/contracts/toolbar-tool.contract.mjs +46 -4
- package/esm2022/lib/contracts/visualizer.contract.mjs +1 -1
- package/esm2022/lib/implementations/napari-js/napari-navigator.mjs +195 -0
- package/esm2022/lib/implementations/napari-js/napari-region-overlay.mjs +10 -2
- package/esm2022/lib/implementations/napari-js/napari-spatial-tiles.mjs +1098 -0
- package/esm2022/lib/implementations/napari-js/napari-spatial-tooltip.mjs +6 -3
- package/esm2022/lib/implementations/napari-js/napari-visualizer.service.mjs +186 -10
- package/esm2022/lib/implementations/osd/openseadragon-visualizer.service.mjs +2 -2
- package/esm2022/lib/implementations/plotly/plotly.service.mjs +2 -3
- package/esm2022/lib/implementations/spatial-data-http/spatial-data-http.service.mjs +120 -2
- package/esm2022/lib/implementations/spatial-data-http/spatial-wire.mjs +76 -1
- package/esm2022/lib/routing-visualizer.service.mjs +10 -1
- package/esm2022/lib/spatial/spatial-tiles.mjs +506 -0
- package/esm2022/lib/spatial-controls/spatial-controls.component.mjs +659 -19
- package/esm2022/lib/toolbar/brush/brush-tool.service.mjs +44 -3
- package/esm2022/lib/toolbar/toolbar.component.mjs +15 -3
- package/esm2022/lib/visualizer.component.mjs +221 -7
- package/fesm2022/jax-data-science-sci-image-visualizer.mjs +3238 -84
- package/fesm2022/jax-data-science-sci-image-visualizer.mjs.map +1 -1
- package/lib/contracts/display-types.d.ts +104 -1
- package/lib/contracts/plot-type-contribution.contract.d.ts +27 -0
- package/lib/contracts/ports/spatial-data.port.d.ts +59 -1
- package/lib/contracts/spatial-dataset.contract.d.ts +167 -0
- package/lib/contracts/toolbar-tool.contract.d.ts +84 -5
- package/lib/contracts/visualizer.contract.d.ts +22 -1
- package/lib/implementations/napari-js/napari-navigator.d.ts +72 -0
- package/lib/implementations/napari-js/napari-region-overlay.d.ts +3 -0
- package/lib/implementations/napari-js/napari-spatial-tiles.d.ts +240 -0
- package/lib/implementations/napari-js/napari-visualizer.service.d.ts +42 -2
- package/lib/implementations/spatial-data-http/spatial-data-http.service.d.ts +26 -2
- package/lib/implementations/spatial-data-http/spatial-wire.d.ts +34 -1
- package/lib/spatial/spatial-tiles.d.ts +222 -0
- package/lib/spatial-controls/spatial-controls.component.d.ts +234 -3
- package/lib/toolbar/brush/brush-tool.service.d.ts +21 -0
- package/lib/toolbar/toolbar.component.d.ts +11 -3
- package/lib/visualizer.component.d.ts +54 -2
- package/package.json +1 -1
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { EventEmitter, OnDestroy, OnInit } from '@angular/core';
|
|
1
|
+
import { EventEmitter, NgZone, OnDestroy, OnInit } from '@angular/core';
|
|
2
2
|
import { IVisualizer, ISpatialControls } from '../contracts/visualizer.contract';
|
|
3
3
|
import { SpatialDataset } from '../contracts/spatial-dataset.contract';
|
|
4
|
-
import { ColormapNode, SpatialViewState } from '../contracts/display-types';
|
|
4
|
+
import { ColormapNode, SpatialViewState, TranscriptGlyphName } from '../contracts/display-types';
|
|
5
5
|
import { SpatialSelectionMask } from '../spatial/spatial-selection';
|
|
6
6
|
import * as i0 from "@angular/core";
|
|
7
7
|
/** One legend row for a categorical colouring. */
|
|
@@ -9,6 +9,14 @@ export interface SpatialLegendEntry {
|
|
|
9
9
|
label: string;
|
|
10
10
|
color: string;
|
|
11
11
|
}
|
|
12
|
+
/**
|
|
13
|
+
* `group,gene` rows (CSV or TSV, header optional) → gene groups, in file order.
|
|
14
|
+
* Exported for tests.
|
|
15
|
+
*/
|
|
16
|
+
export declare function parseGeneGroups(text: string): {
|
|
17
|
+
name: string;
|
|
18
|
+
genes: string[];
|
|
19
|
+
}[];
|
|
12
20
|
/**
|
|
13
21
|
* Spatial-omics controls: a non-modal, resizable, draggable dialog for choosing
|
|
14
22
|
* what the observation markers are coloured by, and how they are drawn.
|
|
@@ -25,6 +33,7 @@ export interface SpatialLegendEntry {
|
|
|
25
33
|
*/
|
|
26
34
|
export declare class SpatialControlsComponent implements OnInit, OnDestroy {
|
|
27
35
|
private readonly viz;
|
|
36
|
+
private readonly zone;
|
|
28
37
|
/** The embedded chart, so a dialog resize can re-fit it. */
|
|
29
38
|
private charts?;
|
|
30
39
|
/**
|
|
@@ -130,7 +139,7 @@ export declare class SpatialControlsComponent implements OnInit, OnDestroy {
|
|
|
130
139
|
private geneSearchToken;
|
|
131
140
|
private keyToken;
|
|
132
141
|
private readonly subs;
|
|
133
|
-
constructor(viz: IVisualizer);
|
|
142
|
+
constructor(viz: IVisualizer, zone: NgZone);
|
|
134
143
|
ngOnInit(): void;
|
|
135
144
|
ngOnDestroy(): void;
|
|
136
145
|
onVisibleChange(value: boolean): void;
|
|
@@ -145,6 +154,23 @@ export declare class SpatialControlsComponent implements OnInit, OnDestroy {
|
|
|
145
154
|
* hop further away.
|
|
146
155
|
*/
|
|
147
156
|
onGeneFilter(query: string): Promise<void>;
|
|
157
|
+
/**
|
|
158
|
+
* Opening either gene dropdown — "Colour by gene" or the transcript genes. Both share
|
|
159
|
+
* one list and one search, so each opens on the head of the full list rather than on
|
|
160
|
+
* whatever the other was last filtered to.
|
|
161
|
+
*
|
|
162
|
+
* A whole-transcriptome dataset does not inline its ~30k names; they are fetched here,
|
|
163
|
+
* once, on first open — the list is then resident and every keystroke filters locally,
|
|
164
|
+
* exactly as for a targeted panel. Until it arrives the dropdown falls back to asking
|
|
165
|
+
* the server per keystroke.
|
|
166
|
+
*/
|
|
167
|
+
ensureGeneList(): Promise<void>;
|
|
168
|
+
/** Most names fetched for the lazy list — well above any panel, whole-transcriptome included. */
|
|
169
|
+
private static readonly GENE_LIST_MAX;
|
|
170
|
+
private geneListLoading;
|
|
171
|
+
/** Options for `names`, plus the genes already chosen (a multi-select shows a chip only
|
|
172
|
+
* for a value it can find among its options). */
|
|
173
|
+
private withSelected;
|
|
148
174
|
/** A gene was picked; it supersedes any column selection. */
|
|
149
175
|
onGene(name: string | null): void;
|
|
150
176
|
/** Select every observation inside the drawn regions (their union). */
|
|
@@ -221,6 +247,211 @@ export declare class SpatialControlsComponent implements OnInit, OnDestroy {
|
|
|
221
247
|
/** Mirrors the renderer's cap, for the note only. */
|
|
222
248
|
private static readonly DENSITY_MAX_CLUSTERS;
|
|
223
249
|
onClip(value: [number, number]): void;
|
|
250
|
+
readonly cellDrawOptions: {
|
|
251
|
+
label: string;
|
|
252
|
+
value: string;
|
|
253
|
+
}[];
|
|
254
|
+
readonly transcriptColorOptions: {
|
|
255
|
+
label: string;
|
|
256
|
+
value: string;
|
|
257
|
+
}[];
|
|
258
|
+
readonly glyphOptions: {
|
|
259
|
+
label: string;
|
|
260
|
+
value: TranscriptGlyphName;
|
|
261
|
+
points: string;
|
|
262
|
+
}[];
|
|
263
|
+
readonly budgetOptions: {
|
|
264
|
+
label: string;
|
|
265
|
+
value: number;
|
|
266
|
+
}[];
|
|
267
|
+
/** Boundaries on offer: tiled (level-of-detail) or whole-dataset rings. */
|
|
268
|
+
get hasCells(): boolean;
|
|
269
|
+
get hasTranscripts(): boolean;
|
|
270
|
+
/** Whether outlines are on — the explicit choice, or automatically for data that has them. */
|
|
271
|
+
get cellsOn(): boolean;
|
|
272
|
+
get activeCellSet(): string | null;
|
|
273
|
+
/**
|
|
274
|
+
* Option lists for the cell/transcript controls. Built once per dataset rather than in
|
|
275
|
+
* getters: a getter returns a fresh array on every change-detection pass, and PrimeNG
|
|
276
|
+
* re-renders its buttons whenever the array identity changes — which made them
|
|
277
|
+
* impossible to click.
|
|
278
|
+
*/
|
|
279
|
+
cellSetOptions: {
|
|
280
|
+
label: string;
|
|
281
|
+
value: string;
|
|
282
|
+
}[];
|
|
283
|
+
transcriptModeOptions: {
|
|
284
|
+
label: string;
|
|
285
|
+
value: SpatialViewState['transcriptMode'];
|
|
286
|
+
}[];
|
|
287
|
+
private buildTileOptions;
|
|
288
|
+
/** Cell colour modes on offer (Xenium Explorer's "Cell Color"). */
|
|
289
|
+
cellColorOptions: {
|
|
290
|
+
label: string;
|
|
291
|
+
value: SpatialViewState['cellColorMode'];
|
|
292
|
+
}[];
|
|
293
|
+
/**
|
|
294
|
+
* The group picker: categorical columns under their section heading, a family of
|
|
295
|
+
* variants (k-means at k = 2…10) listed once. Values are a column name, or
|
|
296
|
+
* `family:<id>` for a family.
|
|
297
|
+
*/
|
|
298
|
+
groupOptions: {
|
|
299
|
+
label: string;
|
|
300
|
+
items: {
|
|
301
|
+
label: string;
|
|
302
|
+
value: string;
|
|
303
|
+
}[];
|
|
304
|
+
}[];
|
|
305
|
+
/** Variants of the active family (k = 2…10), when a family is active. */
|
|
306
|
+
groupVariantOptions: {
|
|
307
|
+
label: string;
|
|
308
|
+
value: string;
|
|
309
|
+
}[];
|
|
310
|
+
/** The last variant chosen per family, so switching away and back keeps k. */
|
|
311
|
+
private familyChoice;
|
|
312
|
+
private buildGroupOptions;
|
|
313
|
+
/** The picker's value for the active group column. */
|
|
314
|
+
get activeGroupEntry(): string | null;
|
|
315
|
+
private refreshVariants;
|
|
316
|
+
onGroupEntry(value: string): void;
|
|
317
|
+
onGroupVariant(name: string): void;
|
|
318
|
+
/** The active grouping's categories with colours and cell counts, largest first. */
|
|
319
|
+
groupRows: {
|
|
320
|
+
label: string;
|
|
321
|
+
color: string;
|
|
322
|
+
count: number;
|
|
323
|
+
}[];
|
|
324
|
+
groupTotal: number;
|
|
325
|
+
groupsExpanded: boolean;
|
|
326
|
+
private groupRowsFor;
|
|
327
|
+
groupImportError: string | null;
|
|
328
|
+
groupImporting: boolean;
|
|
329
|
+
private refreshGroups;
|
|
330
|
+
isGroupShown(label: string): boolean;
|
|
331
|
+
get allGroupsShown(): boolean;
|
|
332
|
+
onGroupShown(label: string, on: boolean): void;
|
|
333
|
+
onAllGroupsShown(on: boolean): void;
|
|
334
|
+
get canImportGroups(): boolean;
|
|
335
|
+
/** '+': a CSV/TSV of `cell_id` and group, named after the file. */
|
|
336
|
+
onImportGroupsFile(input: HTMLInputElement): Promise<void>;
|
|
337
|
+
get activeCellTypeColumn(): string | null;
|
|
338
|
+
onShowCells(on: boolean): void;
|
|
339
|
+
onCellSet(set: string): void;
|
|
340
|
+
onCellDraw(draw: SpatialViewState['cellDraw']): void;
|
|
341
|
+
onCellOpacity(value: number | undefined): void;
|
|
342
|
+
onCellTypeColumn(name: string | null): void;
|
|
343
|
+
onCellColorMode(mode: SpatialViewState['cellColorMode']): void;
|
|
344
|
+
onCellColorGene(gene: string | null): void;
|
|
345
|
+
onCellSingleColor(hex: string): void;
|
|
346
|
+
/** Fill opacity as a 0–100 number, for the box beside the slider. */
|
|
347
|
+
onCellOpacityPercent(v: number | null): void;
|
|
348
|
+
onShowImage(on: boolean): void;
|
|
349
|
+
onShowAnnotations(on: boolean): void;
|
|
350
|
+
/** Which collapsible sections are open. Per dialog instance, not persisted. */
|
|
351
|
+
open: Record<'images' | 'cells' | 'transcripts' | 'annotations' | 'observations', boolean>;
|
|
352
|
+
toggleSection(name: keyof SpatialControlsComponent['open']): void;
|
|
353
|
+
/** The mode the section header's switch turns back on. */
|
|
354
|
+
private lastTranscriptMode;
|
|
355
|
+
onTranscriptsOn(on: boolean): void;
|
|
356
|
+
/** Estimated transcripts in view, against the budget — Explorer's points bar. */
|
|
357
|
+
estimate: {
|
|
358
|
+
points: number;
|
|
359
|
+
max: number;
|
|
360
|
+
} | null;
|
|
361
|
+
/** The density window in use and its densest bin, for the threshold control. */
|
|
362
|
+
densityStats: {
|
|
363
|
+
lo: number;
|
|
364
|
+
hi: number;
|
|
365
|
+
max: number;
|
|
366
|
+
} | null;
|
|
367
|
+
get estimatePercent(): number;
|
|
368
|
+
get estimateOverMax(): boolean;
|
|
369
|
+
editingMax: boolean;
|
|
370
|
+
/** The selected genes as Explorer's tree: named groups, then the ungrouped ones. */
|
|
371
|
+
/** Rebuilt when the view changes — never per change-detection pass (see buildTileOptions). */
|
|
372
|
+
geneTree: {
|
|
373
|
+
name: string | null;
|
|
374
|
+
genes: string[];
|
|
375
|
+
}[];
|
|
376
|
+
geneMenu: {
|
|
377
|
+
label: string;
|
|
378
|
+
icon: string;
|
|
379
|
+
command: () => void;
|
|
380
|
+
disabled?: boolean;
|
|
381
|
+
}[];
|
|
382
|
+
private buildGeneTree;
|
|
383
|
+
/** Real genes in the panel — the tree's denominator. */
|
|
384
|
+
get geneTotal(): number;
|
|
385
|
+
collapsedGeneGroups: Set<string>;
|
|
386
|
+
geneTreeOpen: boolean;
|
|
387
|
+
toggleGeneGroup(name: string): void;
|
|
388
|
+
isGeneShown(gene: string): boolean;
|
|
389
|
+
areGenesShown(genes: string[]): boolean;
|
|
390
|
+
/** The eye toggle: hide or show genes without removing them from the selection. */
|
|
391
|
+
onGenesShown(genes: string[], on: boolean): void;
|
|
392
|
+
onGeneColor(gene: string, hex: string): void;
|
|
393
|
+
/** '±': every gene, or back to the chosen list. */
|
|
394
|
+
onToggleAllGenes(): void;
|
|
395
|
+
/** '⋮' menu. */
|
|
396
|
+
private buildGeneMenu;
|
|
397
|
+
/** The hidden file input the menu's import opens. */
|
|
398
|
+
private geneGroupFileRef?;
|
|
399
|
+
private get geneGroupInput();
|
|
400
|
+
trackByLabel: (_i: number, row: {
|
|
401
|
+
label: string;
|
|
402
|
+
}) => string;
|
|
403
|
+
trackByNode: (_i: number, node: {
|
|
404
|
+
name: string | null;
|
|
405
|
+
}) => string;
|
|
406
|
+
trackByLabelString: (_i: number, s: string) => string;
|
|
407
|
+
get cellOpacityPercent(): number;
|
|
408
|
+
get densityOpacityPercent(): number;
|
|
409
|
+
geneGroupError: string | null;
|
|
410
|
+
onNewGeneGroup(): void;
|
|
411
|
+
/**
|
|
412
|
+
* Import gene groups: CSV/TSV with a group and a gene column (header optional), e.g.
|
|
413
|
+
* marker genes per cell type. The genes are added to the selection.
|
|
414
|
+
*/
|
|
415
|
+
onImportGeneGroups(input: HTMLInputElement): Promise<void>;
|
|
416
|
+
readonly densityBins: number[];
|
|
417
|
+
get densityBinIndex(): number;
|
|
418
|
+
onDensityBinIndex(i: number | undefined): void;
|
|
419
|
+
onDensityOpacityPercent(v: number | null): void;
|
|
420
|
+
/**
|
|
421
|
+
* The threshold window shown: the one set, else the one derived. A stored array, not a
|
|
422
|
+
* getter: a range slider's `ngModel` given a fresh array every change-detection pass
|
|
423
|
+
* schedules another pass, forever — which hung the page the moment the density
|
|
424
|
+
* controls appeared.
|
|
425
|
+
*/
|
|
426
|
+
densityWindow: [number, number];
|
|
427
|
+
densitySliderMax: number;
|
|
428
|
+
densityStep: number;
|
|
429
|
+
private refreshDensityWindow;
|
|
430
|
+
onDensityRange(range: [number, number] | number[] | undefined): void;
|
|
431
|
+
onDensityRangeEnd(which: 0 | 1, v: number | null): void;
|
|
432
|
+
onDensityAuto(): void;
|
|
433
|
+
selectedDensityColormapNode: ColormapNode | null;
|
|
434
|
+
onDensityColormap(node: ColormapNode | null): void;
|
|
435
|
+
get densityColorBarCss(): string;
|
|
436
|
+
onTranscriptMode(mode: SpatialViewState['transcriptMode']): void;
|
|
437
|
+
onTranscriptGenes(genes: string[] | null): void;
|
|
438
|
+
/** "All genes" needs the grouping pyramid, or at least tiles to draw individually. */
|
|
439
|
+
get canShowAllGenes(): boolean;
|
|
440
|
+
/** Why "All genes" is not offered yet, while the server builds its pyramid. */
|
|
441
|
+
get allGenesPreparing(): string | null;
|
|
442
|
+
get showingAllGenes(): boolean;
|
|
443
|
+
onTranscriptAllGenes(on: boolean): void;
|
|
444
|
+
onTranscriptBudget(n: number): void;
|
|
445
|
+
onTranscriptColorBy(by: SpatialViewState['transcriptColorBy']): void;
|
|
446
|
+
onTranscriptScale(value: number | undefined): void;
|
|
447
|
+
onTranscriptOpacity(value: number | undefined): void;
|
|
448
|
+
onTranscriptQuality(includeLow: boolean): void;
|
|
449
|
+
onDensityOpacity(value: number | undefined): void;
|
|
450
|
+
glyphOf(gene: string, slot: number): TranscriptGlyphName;
|
|
451
|
+
onGlyph(gene: string, glyph: TranscriptGlyphName): void;
|
|
452
|
+
/** The colour gene `slot` is drawn in when transcripts are coloured by gene. */
|
|
453
|
+
geneColor(slot: number): string;
|
|
454
|
+
geneColorOf(gene: string): string;
|
|
224
455
|
reset(): void;
|
|
225
456
|
/**
|
|
226
457
|
* Description of the active column, when it has one. Surfaced because a
|
|
@@ -4,6 +4,15 @@ import * as i0 from "@angular/core";
|
|
|
4
4
|
/** Brush parameters. `size` is the brush *diameter* in matrix (image) pixels. */
|
|
5
5
|
export interface BrushOptions {
|
|
6
6
|
size?: number;
|
|
7
|
+
/**
|
|
8
|
+
* Paint as one class. With `label` set, new regions take this label, and the
|
|
9
|
+
* stroke only adopts or merges regions that already have it, so painting one
|
|
10
|
+
* class never grows another class's region. `color` colours the painted
|
|
11
|
+
* regions instead of the toolbar's shape colour. Leave both unset for the
|
|
12
|
+
* plain toolbar brush.
|
|
13
|
+
*/
|
|
14
|
+
label?: string;
|
|
15
|
+
color?: string;
|
|
7
16
|
}
|
|
8
17
|
/**
|
|
9
18
|
* The brush host is identical to the wand's — both need the cached-image
|
|
@@ -60,6 +69,8 @@ export declare class BrushToolService {
|
|
|
60
69
|
private lastMatrix;
|
|
61
70
|
private dragging;
|
|
62
71
|
private size;
|
|
72
|
+
/** The class being painted ({@link BrushOptions.label} / `color`); null = plain brush. */
|
|
73
|
+
private paintClass;
|
|
63
74
|
private readonly boundMouseDown;
|
|
64
75
|
private readonly boundMouseMove;
|
|
65
76
|
private readonly boundMouseUp;
|
|
@@ -68,6 +79,13 @@ export declare class BrushToolService {
|
|
|
68
79
|
bindHost(host: BrushToolHost): void;
|
|
69
80
|
/** Toggle the brush on/off. */
|
|
70
81
|
setMode(active: boolean, options?: BrushOptions): void;
|
|
82
|
+
/**
|
|
83
|
+
* Update size and/or class while armed. The class changes only when `label`
|
|
84
|
+
* or `color` is passed (as a key, even `undefined`), so a size-only update
|
|
85
|
+
* keeps it. Switching class drops the active region, so the next stroke
|
|
86
|
+
* starts a region of the new class.
|
|
87
|
+
*/
|
|
88
|
+
setOptions(options?: BrushOptions): void;
|
|
71
89
|
/** Live-update the brush size (matrix-pixel diameter). */
|
|
72
90
|
setSize(size: number): void;
|
|
73
91
|
/** Drop the active brush region so the next stroke starts a new one. */
|
|
@@ -102,6 +120,9 @@ export declare class BrushToolService {
|
|
|
102
120
|
* erase stroke deletes every pixel.
|
|
103
121
|
*/
|
|
104
122
|
private dropActiveShape;
|
|
123
|
+
/** Whether the stroke may adopt or merge `region`: always for the plain brush,
|
|
124
|
+
* otherwise only a region of the class being painted. */
|
|
125
|
+
private paintsInto;
|
|
105
126
|
/** A region's closed-polygon vertices (image/data coords), or null when it
|
|
106
127
|
* isn't a fillable closed polygon (rectangles, open polylines). */
|
|
107
128
|
private regionVerts;
|
|
@@ -3,7 +3,7 @@ import { MenuItem } from 'primeng/api';
|
|
|
3
3
|
import { IImageInfo } from '../contracts/image.contract';
|
|
4
4
|
import { PlotType, PlotTypeId } from '../contracts/plot-type';
|
|
5
5
|
import { ToolbarToolVisibility } from '../contracts/toolbar-config';
|
|
6
|
-
import { ToolbarToolContribution } from '../contracts/toolbar-tool.contract';
|
|
6
|
+
import { ToolbarDialogToolContribution, ToolbarToolContribution } from '../contracts/toolbar-tool.contract';
|
|
7
7
|
import { PlotTypeOption } from '../contracts/plot-type-contribution.contract';
|
|
8
8
|
import * as i0 from "@angular/core";
|
|
9
9
|
/**
|
|
@@ -90,6 +90,10 @@ export declare class ToolbarComponent implements OnChanges {
|
|
|
90
90
|
* per-tool parameter state; this component only draws them.
|
|
91
91
|
*/
|
|
92
92
|
contributedTools: ToolbarToolContribution[];
|
|
93
|
+
/** Dialog tools (TOOLBAR_TOOLS, kind: 'dialog'), sorted; shown in the Image view. */
|
|
94
|
+
dialogTools: ToolbarDialogToolContribution[];
|
|
95
|
+
/** Id of the dialog tool whose dialog is open, or null. */
|
|
96
|
+
openDialogToolId: string | null;
|
|
93
97
|
/** Active checkpoint per contributed tool, keyed by tool id. */
|
|
94
98
|
toolModelIds: Record<string, string>;
|
|
95
99
|
selectPlotType: EventEmitter<string>;
|
|
@@ -135,6 +139,8 @@ export declare class ToolbarComponent implements OnChanges {
|
|
|
135
139
|
segmentCellpose: EventEmitter<void>;
|
|
136
140
|
/** Run a contributed tool over the current view, by tool id. */
|
|
137
141
|
runTool: EventEmitter<string>;
|
|
142
|
+
/** A dialog tool's button was clicked: open its dialog, or close it if open. */
|
|
143
|
+
toggleDialogTool: EventEmitter<string>;
|
|
138
144
|
/** Pick a contributed tool's checkpoint. */
|
|
139
145
|
toolModelChange: EventEmitter<{
|
|
140
146
|
toolId: string;
|
|
@@ -205,7 +211,9 @@ export declare class ToolbarComponent implements OnChanges {
|
|
|
205
211
|
get contributedToolNames(): string;
|
|
206
212
|
/** Keeps each contributed tool's `p-menu` overlay alive across CD ticks —
|
|
207
213
|
* re-creating it mid-interaction swallows the click on a menu item. */
|
|
208
|
-
trackToolById(_index: number, tool:
|
|
214
|
+
trackToolById(_index: number, tool: {
|
|
215
|
+
id: string;
|
|
216
|
+
}): string;
|
|
209
217
|
/** The built-in type whose tools and controls apply to the current selection. */
|
|
210
218
|
get effectivePlotType(): PlotType;
|
|
211
219
|
/** The Image plot type renders as a natively pan/zoom-able raster, so the
|
|
@@ -242,5 +250,5 @@ export declare class ToolbarComponent implements OnChanges {
|
|
|
242
250
|
get isIntensityCapable(): boolean;
|
|
243
251
|
showHelp(): void;
|
|
244
252
|
static ɵfac: i0.ɵɵFactoryDeclaration<ToolbarComponent, never>;
|
|
245
|
-
static ɵcmp: i0.ɵɵComponentDeclaration<ToolbarComponent, "plotting-toolbar", never, { "imageInfo": { "alias": "imageInfo"; "required": false; }; "plotTypeOptions": { "alias": "plotTypeOptions"; "required": false; }; "selectedPlotType": { "alias": "selectedPlotType"; "required": false; }; "basePlotType": { "alias": "basePlotType"; "required": false; }; "isoRange": { "alias": "isoRange"; "required": false; }; "maxIndex": { "alias": "maxIndex"; "required": false; }; "zIndex": { "alias": "zIndex"; "required": false; }; "isHeatmap": { "alias": "isHeatmap"; "required": false; }; "is3dRegions": { "alias": "is3dRegions"; "required": false; }; "activeDragMode": { "alias": "activeDragMode"; "required": false; }; "activeSurface3dMode": { "alias": "activeSurface3dMode"; "required": false; }; "axesVisible": { "alias": "axesVisible"; "required": false; }; "wireframeActive": { "alias": "wireframeActive"; "required": false; }; "resolutionScale": { "alias": "resolutionScale"; "required": false; }; "wandSensitivity": { "alias": "wandSensitivity"; "required": false; }; "brushSize": { "alias": "brushSize"; "required": false; }; "vertexEraserRadius": { "alias": "vertexEraserRadius"; "required": false; }; "canUndo": { "alias": "canUndo"; "required": false; }; "canRedo": { "alias": "canRedo"; "required": false; }; "stackOptions": { "alias": "stackOptions"; "required": false; }; "tools": { "alias": "tools"; "required": false; }; "imageSmoothingEnabled": { "alias": "imageSmoothingEnabled"; "required": false; }; "samModels": { "alias": "samModels"; "required": false; }; "samModelId": { "alias": "samModelId"; "required": false; }; "contributedTools": { "alias": "contributedTools"; "required": false; }; "toolModelIds": { "alias": "toolModelIds"; "required": false; }; }, { "selectPlotType": "selectPlotType"; "addProfileLine": "addProfileLine"; "toggleImageSmoothing": "toggleImageSmoothing"; "isoRangeChange": "isoRangeChange"; "openChannelHistogram": "openChannelHistogram"; "openSpatialControls": "openSpatialControls"; "openRegionEditor": "openRegionEditor"; "selectStackOption": "selectStackOption"; "zScrub": "zScrub"; "zSlide": "zSlide"; "zIndexInput": "zIndexInput"; "reloadAndPlot": "reloadAndPlot"; "downloadImage": "downloadImage"; "autoscaleImage": "autoscaleImage"; "toggleDragMode": "toggleDragMode"; "zoomIn": "zoomIn"; "zoomOut": "zoomOut"; "toggleSurface3dMode": "toggleSurface3dMode"; "resetSurfaceCamera": "resetSurfaceCamera"; "toggleAxes": "toggleAxes"; "toggleWireframe": "toggleWireframe"; "selectResolution": "selectResolution"; "deleteRegion": "deleteRegion"; "undoRegion": "undoRegion"; "redoRegion": "redoRegion"; "segmentRegions": "segmentRegions"; "segmentCellpose": "segmentCellpose"; "runTool": "runTool"; "toolModelChange": "toolModelChange"; "openToolParams": "openToolParams"; "samModelChange": "samModelChange"; "wandSensitivityChange": "wandSensitivityChange"; "brushSizeChange": "brushSizeChange"; "vertexEraserRadiusChange": "vertexEraserRadiusChange"; }, never, ["*"], false, never>;
|
|
253
|
+
static ɵcmp: i0.ɵɵComponentDeclaration<ToolbarComponent, "plotting-toolbar", never, { "imageInfo": { "alias": "imageInfo"; "required": false; }; "plotTypeOptions": { "alias": "plotTypeOptions"; "required": false; }; "selectedPlotType": { "alias": "selectedPlotType"; "required": false; }; "basePlotType": { "alias": "basePlotType"; "required": false; }; "isoRange": { "alias": "isoRange"; "required": false; }; "maxIndex": { "alias": "maxIndex"; "required": false; }; "zIndex": { "alias": "zIndex"; "required": false; }; "isHeatmap": { "alias": "isHeatmap"; "required": false; }; "is3dRegions": { "alias": "is3dRegions"; "required": false; }; "activeDragMode": { "alias": "activeDragMode"; "required": false; }; "activeSurface3dMode": { "alias": "activeSurface3dMode"; "required": false; }; "axesVisible": { "alias": "axesVisible"; "required": false; }; "wireframeActive": { "alias": "wireframeActive"; "required": false; }; "resolutionScale": { "alias": "resolutionScale"; "required": false; }; "wandSensitivity": { "alias": "wandSensitivity"; "required": false; }; "brushSize": { "alias": "brushSize"; "required": false; }; "vertexEraserRadius": { "alias": "vertexEraserRadius"; "required": false; }; "canUndo": { "alias": "canUndo"; "required": false; }; "canRedo": { "alias": "canRedo"; "required": false; }; "stackOptions": { "alias": "stackOptions"; "required": false; }; "tools": { "alias": "tools"; "required": false; }; "imageSmoothingEnabled": { "alias": "imageSmoothingEnabled"; "required": false; }; "samModels": { "alias": "samModels"; "required": false; }; "samModelId": { "alias": "samModelId"; "required": false; }; "contributedTools": { "alias": "contributedTools"; "required": false; }; "dialogTools": { "alias": "dialogTools"; "required": false; }; "openDialogToolId": { "alias": "openDialogToolId"; "required": false; }; "toolModelIds": { "alias": "toolModelIds"; "required": false; }; }, { "selectPlotType": "selectPlotType"; "addProfileLine": "addProfileLine"; "toggleImageSmoothing": "toggleImageSmoothing"; "isoRangeChange": "isoRangeChange"; "openChannelHistogram": "openChannelHistogram"; "openSpatialControls": "openSpatialControls"; "openRegionEditor": "openRegionEditor"; "selectStackOption": "selectStackOption"; "zScrub": "zScrub"; "zSlide": "zSlide"; "zIndexInput": "zIndexInput"; "reloadAndPlot": "reloadAndPlot"; "downloadImage": "downloadImage"; "autoscaleImage": "autoscaleImage"; "toggleDragMode": "toggleDragMode"; "zoomIn": "zoomIn"; "zoomOut": "zoomOut"; "toggleSurface3dMode": "toggleSurface3dMode"; "resetSurfaceCamera": "resetSurfaceCamera"; "toggleAxes": "toggleAxes"; "toggleWireframe": "toggleWireframe"; "selectResolution": "selectResolution"; "deleteRegion": "deleteRegion"; "undoRegion": "undoRegion"; "redoRegion": "redoRegion"; "segmentRegions": "segmentRegions"; "segmentCellpose": "segmentCellpose"; "runTool": "runTool"; "toggleDialogTool": "toggleDialogTool"; "toolModelChange": "toolModelChange"; "openToolParams": "openToolParams"; "samModelChange": "samModelChange"; "wandSensitivityChange": "wandSensitivityChange"; "brushSizeChange": "brushSizeChange"; "vertexEraserRadiusChange": "vertexEraserRadiusChange"; }, never, ["*"], false, never>;
|
|
246
254
|
}
|
|
@@ -14,7 +14,7 @@ import { IVisualizer } from './contracts/visualizer.contract';
|
|
|
14
14
|
import { SamToolService } from './toolbar/segmentation/sam-tool.service';
|
|
15
15
|
import { SamPointToolService } from './toolbar/segmentation/sam-point-tool.service';
|
|
16
16
|
import { CellSegmentToolService } from './toolbar/segmentation/cell-segment-tool.service';
|
|
17
|
-
import { NumberParamSpec, SelectParamSpec, ToolParamSpec, ToolbarToolContribution } from './contracts/toolbar-tool.contract';
|
|
17
|
+
import { NumberParamSpec, SelectParamSpec, ToolParamSpec, ToolbarContribution, ToolbarDialogToolContribution, ToolbarToolContribution } from './contracts/toolbar-tool.contract';
|
|
18
18
|
import { ToolbarToolVisibility } from './contracts/toolbar-config';
|
|
19
19
|
import { VizConfig } from './contracts/viz-config';
|
|
20
20
|
import { SpatialDataPort } from './contracts/ports/spatial-data.port';
|
|
@@ -121,6 +121,8 @@ export declare class VisualizerComponent implements OnInit, OnChanges, AfterView
|
|
|
121
121
|
wandSensitivity: number;
|
|
122
122
|
/** Brush diameter in image-pixel coordinates (drives the painted disc size). */
|
|
123
123
|
brushSize: number;
|
|
124
|
+
/** Class the brush paints while a plot mode armed it (PlotModeTools.armBrush); null = plain brush. */
|
|
125
|
+
private brushClass;
|
|
124
126
|
/** SAM model picker options + current selection (jit-ui#90 P1). Only models
|
|
125
127
|
* with a hosted ONNX pair (configured via setSamModelUrls at app init) are
|
|
126
128
|
* offered, so the picker can't select a model that can't run. */
|
|
@@ -136,6 +138,22 @@ export declare class VisualizerComponent implements OnInit, OnChanges, AfterView
|
|
|
136
138
|
* and help dialog simply omit that group.
|
|
137
139
|
*/
|
|
138
140
|
contributedTools: ToolbarToolContribution[];
|
|
141
|
+
/**
|
|
142
|
+
* Dialog tools registered through {@link TOOLBAR_TOOLS} (`kind: 'dialog'`),
|
|
143
|
+
* sorted. Their buttons sit with the host's own actions and show in the Image
|
|
144
|
+
* view only; each opens a floating dialog the tool fills.
|
|
145
|
+
*/
|
|
146
|
+
dialogTools: ToolbarDialogToolContribution[];
|
|
147
|
+
/** The dialog tool the user has open (its session may be between renders). */
|
|
148
|
+
openDialogToolId: string | null;
|
|
149
|
+
/** The open dialog tool's live dialog, as the template renders it. */
|
|
150
|
+
toolDialog: {
|
|
151
|
+
title: string;
|
|
152
|
+
width: string;
|
|
153
|
+
host: HTMLElement;
|
|
154
|
+
} | null;
|
|
155
|
+
/** Dialog-tool sessions: the same lifecycle and isolation as contributed plot modes. */
|
|
156
|
+
private readonly toolDialogs;
|
|
139
157
|
/** Active checkpoint per contributed tool. */
|
|
140
158
|
toolModelIds: Record<string, string>;
|
|
141
159
|
/**
|
|
@@ -318,7 +336,7 @@ export declare class VisualizerComponent implements OnInit, OnChanges, AfterView
|
|
|
318
336
|
private wheelListener?;
|
|
319
337
|
/** Debounced z-slice scrubbing (see SliceScrubber — refactoring plan Step 7). */
|
|
320
338
|
private readonly scrubber;
|
|
321
|
-
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
|
|
339
|
+
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);
|
|
322
340
|
/**
|
|
323
341
|
* Plot types offered in the selector for the current image:
|
|
324
342
|
* - Outside **test mode**, only the curated default set (descriptors with a
|
|
@@ -454,6 +472,8 @@ export declare class VisualizerComponent implements OnInit, OnChanges, AfterView
|
|
|
454
472
|
onToggleImageSmoothing(): void;
|
|
455
473
|
resetAxes(): void;
|
|
456
474
|
toggleDragMode(mode: string): void;
|
|
475
|
+
/** Arm `mode` (or nothing) across every tool, keeping the toolbar in step. */
|
|
476
|
+
private applyDragMode;
|
|
457
477
|
/** Region draw/select/edit modes routed through the region overlay. The
|
|
458
478
|
* The vertex tools (drawpolygon/addpoint/deletepoint/move) are
|
|
459
479
|
* handled by the OpenSeadragon overlay; Plotly's overlay maps them to no-op. */
|
|
@@ -606,6 +626,38 @@ export declare class VisualizerComponent implements OnInit, OnChanges, AfterView
|
|
|
606
626
|
private fallBackFromPlotMode;
|
|
607
627
|
/** Run change detection; returns what it threw (logged), or null. */
|
|
608
628
|
private detectChangesSafely;
|
|
629
|
+
/** The toolbar button: open the tool's dialog, or close it if it is open. */
|
|
630
|
+
toggleDialogTool(id: string): void;
|
|
631
|
+
/** Close the open dialog tool: its body is torn down, then its session ends. */
|
|
632
|
+
closeDialogTool(): void;
|
|
633
|
+
/** Start (or restart, after a re-render) the open dialog tool's session. */
|
|
634
|
+
private activateOpenDialogTool;
|
|
635
|
+
/** The live dialog body's teardown, and a pending wait for its host to connect. */
|
|
636
|
+
private toolDialogTeardown;
|
|
637
|
+
private toolDialogFrame;
|
|
638
|
+
/**
|
|
639
|
+
* The session is live: render the dialog, then mount the tool's body once the host
|
|
640
|
+
* element is in the document, so `mount()` can measure it and start widgets that need
|
|
641
|
+
* a connected element.
|
|
642
|
+
*/
|
|
643
|
+
private showToolDialog;
|
|
644
|
+
/** How many animation frames to wait for the dialog to attach the body's host. */
|
|
645
|
+
private static readonly TOOL_DIALOG_ATTACH_FRAMES;
|
|
646
|
+
/**
|
|
647
|
+
* Mount `tool`'s body into `host` once it is connected (the dialog may attach it a
|
|
648
|
+
* frame later, when it moves itself to `<body>`). If it never connects within
|
|
649
|
+
* {@link TOOL_DIALOG_ATTACH_FRAMES} it is mounted anyway, with a warning, rather than
|
|
650
|
+
* leaving an empty dialog. A throwing `mount()` fails the session like a failed start.
|
|
651
|
+
*/
|
|
652
|
+
private mountToolDialogBody;
|
|
653
|
+
/** The session is about to end: tear the body down first, then drop the dialog. */
|
|
654
|
+
private hideToolDialog;
|
|
655
|
+
/** A dialog tool could not start: close it and say so. */
|
|
656
|
+
private dialogToolFailed;
|
|
657
|
+
/** Where the open dialog tool's host element is attached once its dialog renders. */
|
|
658
|
+
set toolDialogSlot(ref: ElementRef<HTMLElement> | undefined);
|
|
659
|
+
/** Toolbar tools for contributed modes. Calls can come from outside Angular, hence the zone. */
|
|
660
|
+
private readonly plotModeTools;
|
|
609
661
|
/** Deactivate whatever tool is armed and clear every tool mode. */
|
|
610
662
|
private deactivateActiveTool;
|
|
611
663
|
static ɵfac: i0.ɵɵFactoryDeclaration<VisualizerComponent, [null, null, null, null, null, null, null, null, null, null, { optional: true; }, { optional: true; }, { optional: true; }, { optional: true; }, { optional: true; }]>;
|