@jax-data-science/sci-image-visualizer 0.8.2 → 0.9.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 +201 -460
- package/esm2022/index.mjs +28 -15
- package/esm2022/lib/channel-histogram/channel-histogram.component.mjs +163 -91
- package/esm2022/lib/contracts/capabilities.contract.mjs +4 -3
- package/esm2022/lib/contracts/cell-segmenter.contract.mjs +1 -1
- package/esm2022/lib/contracts/channel-histogram-api.contract.mjs +5 -1
- package/esm2022/lib/contracts/color.mjs +60 -0
- package/esm2022/lib/contracts/colormap-lut.mjs +213 -57
- package/esm2022/lib/contracts/coordinate-transform.contract.mjs +1 -1
- package/esm2022/lib/contracts/display-types.mjs +11 -1
- package/esm2022/lib/contracts/instance-segmenter.contract.mjs +1 -1
- package/esm2022/lib/contracts/intensity.mjs +48 -5
- package/esm2022/lib/contracts/plot-type-contribution.contract.mjs +1 -1
- package/esm2022/lib/contracts/plot-type.mjs +134 -17
- package/esm2022/lib/contracts/ports/image-state.port.mjs +4 -1
- package/esm2022/lib/contracts/ports/preferences.port.mjs +5 -1
- package/esm2022/lib/contracts/ports/region-io.port.mjs +2 -1
- package/esm2022/lib/contracts/ports/spatial-data.port.mjs +5 -1
- package/esm2022/lib/contracts/ports/tile-access.port.mjs +2 -1
- package/esm2022/lib/contracts/region-editor-api.contract.mjs +1 -1
- package/esm2022/lib/contracts/region-overlay.contract.mjs +1 -1
- package/esm2022/lib/contracts/sam.contract.mjs +1 -1
- package/esm2022/lib/contracts/semantic-segmenter.contract.mjs +1 -1
- package/esm2022/lib/contracts/spatial-dataset.contract.mjs +3 -1
- package/esm2022/lib/contracts/toolbar-tool.contract.mjs +6 -4
- package/esm2022/lib/contracts/visualizer.contract.mjs +1 -1
- package/esm2022/lib/contracts/viz-config.mjs +2 -1
- package/esm2022/lib/geometry/contour.mjs +63 -0
- package/esm2022/lib/geometry/raster.mjs +98 -0
- package/esm2022/lib/geometry/ring.mjs +201 -0
- package/esm2022/lib/hex-color-picker/hex-color-picker.component.mjs +202 -102
- package/esm2022/lib/implementations/base-store-visualizer.mjs +201 -48
- package/esm2022/lib/implementations/napari-js/napari-axes-gizmo.mjs +65 -0
- package/esm2022/lib/implementations/napari-js/napari-display-state.mjs +136 -0
- package/esm2022/lib/implementations/napari-js/napari-helpers.mjs +199 -0
- package/esm2022/lib/implementations/napari-js/napari-image-2d-scene.mjs +602 -0
- package/esm2022/lib/implementations/napari-js/napari-loading-badge.mjs +3 -4
- package/esm2022/lib/implementations/napari-js/napari-loading-state.mjs +66 -0
- package/esm2022/lib/implementations/napari-js/napari-region-overlay.mjs +157 -591
- package/esm2022/lib/implementations/napari-js/napari-scene.mjs +2 -0
- package/esm2022/lib/implementations/napari-js/napari-spatial-2d-scene.mjs +614 -0
- package/esm2022/lib/implementations/napari-js/napari-spatial-3d-scene.mjs +769 -0
- package/esm2022/lib/implementations/napari-js/napari-spatial-encoding.mjs +199 -0
- package/esm2022/lib/implementations/napari-js/napari-spatial-hover.mjs +263 -0
- package/esm2022/lib/implementations/napari-js/napari-spatial-scene.mjs +159 -0
- package/esm2022/lib/implementations/napari-js/napari-spatial-tiles.mjs +106 -1408
- package/esm2022/lib/implementations/napari-js/napari-spatial-tooltip.mjs +2 -2
- package/esm2022/lib/implementations/napari-js/napari-surface-scene.mjs +271 -0
- package/esm2022/lib/implementations/napari-js/napari-tile-client.mjs +562 -0
- package/esm2022/lib/implementations/napari-js/napari-tool-bridge.mjs +344 -0
- package/esm2022/lib/implementations/napari-js/napari-visualizer.service.mjs +361 -4184
- package/esm2022/lib/implementations/napari-js/napari-volume-scene.mjs +439 -0
- package/esm2022/lib/implementations/napari-js/napari-volume-z-handle.mjs +6 -6
- package/esm2022/lib/implementations/napari-js/region-overlay/overlay-projection.mjs +96 -0
- package/esm2022/lib/implementations/napari-js/region-overlay/region-edit.mjs +35 -0
- package/esm2022/lib/implementations/napari-js/region-overlay/region-svg-renderer.mjs +182 -0
- package/esm2022/lib/implementations/napari-js/spatial-tiles/categorical-lookup.mjs +30 -0
- package/esm2022/lib/implementations/napari-js/spatial-tiles/cell-layers.mjs +274 -0
- package/esm2022/lib/implementations/napari-js/spatial-tiles/density-layer.mjs +144 -0
- package/esm2022/lib/implementations/napari-js/spatial-tiles/layer-groups.mjs +165 -0
- package/esm2022/lib/implementations/napari-js/spatial-tiles/plan-context.mjs +78 -0
- package/esm2022/lib/implementations/napari-js/spatial-tiles/transcript-hover.mjs +182 -0
- package/esm2022/lib/implementations/napari-js/spatial-tiles/transcript-jobs.mjs +369 -0
- package/esm2022/lib/implementations/napari-js/spatial-tiles/transcript-layers.mjs +306 -0
- package/esm2022/lib/implementations/osd/display-pipeline.mjs +102 -40
- package/esm2022/lib/implementations/osd/histogram-sampler.mjs +56 -31
- package/esm2022/lib/implementations/osd/openseadragon-viewer-options.mjs +128 -0
- package/esm2022/lib/implementations/osd/openseadragon-visualizer.service.mjs +333 -1685
- package/esm2022/lib/implementations/osd/osd-coordinate-transform.mjs +1 -1
- package/esm2022/lib/implementations/osd/osd-coords.mjs +5 -6
- package/esm2022/lib/implementations/osd/osd-export.mjs +122 -0
- package/esm2022/lib/implementations/osd/osd-lib.mjs +15 -1
- package/esm2022/lib/implementations/osd/osd-navigator-chrome.mjs +205 -0
- package/esm2022/lib/implementations/osd/osd-pixel-readback.mjs +68 -0
- package/esm2022/lib/implementations/osd/osd-region-overlay-draw.mjs +153 -0
- package/esm2022/lib/implementations/osd/osd-region-overlay.mjs +185 -718
- package/esm2022/lib/implementations/osd/osd-scale-bar.mjs +52 -60
- package/esm2022/lib/implementations/osd/osd-tile-source.mjs +105 -0
- package/esm2022/lib/implementations/osd/osd-viewer-like.mjs +2 -0
- package/esm2022/lib/implementations/osd/osd-viewer-mount.mjs +44 -0
- package/esm2022/lib/implementations/osd/osd-viewport.mjs +184 -0
- package/esm2022/lib/implementations/osd/osd-zoom.mjs +7 -1
- package/esm2022/lib/implementations/osd/simple-source.mjs +395 -0
- package/esm2022/lib/implementations/osd/slice-cache.mjs +53 -48
- package/esm2022/lib/implementations/osd/tile-client.mjs +32 -11
- package/esm2022/lib/implementations/osd/tile-recolor.mjs +330 -0
- package/esm2022/lib/implementations/plotly/omics-trace-builders.mjs +161 -73
- package/esm2022/lib/implementations/plotly/plotly-coordinate-transform.mjs +1 -1
- package/esm2022/lib/implementations/plotly/plotly-image-loader.mjs +112 -0
- package/esm2022/lib/implementations/plotly/plotly-image-recolor.mjs +178 -0
- package/esm2022/lib/implementations/plotly/plotly-intensity-inset.mjs +33 -0
- package/esm2022/lib/implementations/plotly/plotly-isosurface-controls.mjs +83 -0
- package/esm2022/lib/implementations/plotly/plotly-layouts.mjs +121 -0
- package/esm2022/lib/implementations/plotly/plotly-readback.mjs +117 -0
- package/esm2022/lib/implementations/plotly/plotly-region-overlay.mjs +19 -10
- package/esm2022/lib/implementations/plotly/plotly-shape-projection.mjs +223 -0
- package/esm2022/lib/implementations/plotly/plotly-trace-builders.mjs +79 -19
- package/esm2022/lib/implementations/plotly/plotly-zoom-controller.mjs +223 -0
- package/esm2022/lib/implementations/plotly/plotly.service.mjs +439 -1655
- package/esm2022/lib/implementations/region-centroids.mjs +47 -0
- package/esm2022/lib/implementations/simple-slice-access.service.mjs +22 -12
- package/esm2022/lib/implementations/spatial-data-http/spatial-data-http.service.mjs +172 -92
- package/esm2022/lib/implementations/spatial-data-http/spatial-wire.mjs +103 -22
- package/esm2022/lib/implementations/tile-server/index.mjs +6 -0
- package/esm2022/lib/implementations/tile-server/native-histogram.mjs +30 -0
- package/esm2022/lib/implementations/tile-server/poll-descriptor.mjs +65 -0
- package/esm2022/lib/implementations/tile-server/tile-protocol.mjs +42 -0
- package/esm2022/lib/implementations/tile-server/transport.mjs +135 -0
- package/esm2022/lib/intensity/intensity-profile.mjs +107 -0
- package/esm2022/lib/intensity/intensity-profile.service.mjs +223 -0
- package/esm2022/lib/intensity-inset/intensity-inset.component.mjs +133 -0
- package/esm2022/lib/models/bezier.mjs +1 -11
- package/esm2022/lib/models/class-preset.mjs +41 -3
- package/esm2022/lib/models/geometry.mjs +27 -164
- package/esm2022/lib/models/polygon-edit.mjs +254 -0
- package/esm2022/lib/models/polygon-factory.mjs +118 -0
- package/esm2022/lib/models/region-clone.mjs +68 -0
- package/esm2022/lib/models/region-geojson.mjs +373 -0
- package/esm2022/lib/models/region.mjs +34 -33
- package/esm2022/lib/models/shape.mjs +18 -16
- package/esm2022/lib/plot-mode/contribution-host.mjs +297 -0
- package/esm2022/lib/plot-mode/plot-mode-controller.mjs +9 -6
- package/esm2022/lib/plot-mode/plot-type-menu.mjs +85 -0
- package/esm2022/lib/plot-mode/tool-params-model.mjs +87 -0
- package/esm2022/lib/plot.utilities.mjs +296 -473
- package/esm2022/lib/processing/image-crop.mjs +1 -1
- package/esm2022/lib/processing/processing-image.mjs +28 -15
- package/esm2022/lib/provide-visualization.mjs +40 -14
- package/esm2022/lib/region-editor/classes-panel/classes-panel.component.mjs +99 -0
- package/esm2022/lib/region-editor/file-stem.mjs +13 -0
- package/esm2022/lib/region-editor/manage-classes-dialog/manage-classes-dialog.component.mjs +118 -0
- package/esm2022/lib/region-editor/mask-export.service.mjs +98 -0
- package/esm2022/lib/region-editor/mask-raster.mjs +11 -5
- package/esm2022/lib/region-editor/region-color-dialog/region-color-dialog.component.mjs +56 -0
- package/esm2022/lib/region-editor/region-editor-help/region-editor-help.component.mjs +28 -0
- package/esm2022/lib/region-editor/region-editor.component.mjs +402 -651
- package/esm2022/lib/region-editor/region-metrics.mjs +68 -0
- package/esm2022/lib/region-editor/region-persistence.service.mjs +134 -0
- package/esm2022/lib/region-editor/region-table/region-table.component.mjs +153 -0
- package/esm2022/lib/region-editor/save-mask-dialog/save-mask-dialog.component.mjs +91 -0
- package/esm2022/lib/region-editor/save-regions-dialog/save-regions-dialog.component.mjs +92 -0
- package/esm2022/lib/region-ops.service.mjs +28 -70
- package/esm2022/lib/region-overlay/region-geometry.mjs +360 -0
- package/esm2022/lib/region-overlay/region-hit-test.mjs +103 -0
- package/esm2022/lib/region-overlay/svg-region-renderer.mjs +228 -0
- package/esm2022/lib/render-orchestrator.mjs +14 -11
- package/esm2022/lib/render-session.mjs +207 -0
- package/esm2022/lib/routing-visualizer.service.mjs +459 -411
- package/esm2022/lib/spatial/density-raster.mjs +14 -0
- package/esm2022/lib/spatial/embedding-compute-coordinator.mjs +239 -0
- package/esm2022/lib/spatial/embedding-compute.mjs +43 -10
- package/esm2022/lib/spatial/gene-search.mjs +1 -1
- package/esm2022/lib/spatial/glyphs.mjs +97 -0
- package/esm2022/lib/spatial/lod.mjs +187 -0
- package/esm2022/lib/spatial/spatial-controls.facade.mjs +200 -0
- package/esm2022/lib/spatial/spatial-density.mjs +25 -16
- package/esm2022/lib/spatial/spatial-encoding.mjs +26 -82
- package/esm2022/lib/spatial/spatial-expression.mjs +43 -42
- package/esm2022/lib/spatial/spatial-framing.mjs +1 -1
- package/esm2022/lib/spatial/spatial-heatmap.mjs +6 -3
- package/esm2022/lib/spatial/spatial-hover.mjs +5 -33
- package/esm2022/lib/spatial/spatial-panel-model.mjs +282 -0
- package/esm2022/lib/spatial/spatial-sections.mjs +1 -1
- package/esm2022/lib/spatial/spatial-selection.mjs +33 -46
- package/esm2022/lib/spatial/spatial-tile-merge.mjs +219 -0
- package/esm2022/lib/spatial/spatial-tiles.mjs +12 -648
- package/esm2022/lib/spatial/spatial-volume-image.mjs +2 -4
- package/esm2022/lib/spatial/stats.mjs +71 -0
- package/esm2022/lib/spatial/transcript-grouping.mjs +307 -0
- package/esm2022/lib/spatial-controls/spatial-cells-panel/spatial-cells-panel.component.mjs +150 -0
- package/esm2022/lib/spatial-controls/spatial-charts/chart-data-model.mjs +309 -0
- package/esm2022/lib/spatial-controls/spatial-charts/chart-help.mjs +145 -0
- package/esm2022/lib/spatial-controls/spatial-charts/plotly-chart-host.mjs +158 -0
- package/esm2022/lib/spatial-controls/spatial-charts/spatial-chart-window/spatial-chart-window.component.mjs +47 -0
- package/esm2022/lib/spatial-controls/spatial-charts/spatial-charts.component.mjs +297 -802
- package/esm2022/lib/spatial-controls/spatial-charts/spatial-embedding-controls/spatial-embedding-controls.component.mjs +89 -0
- package/esm2022/lib/spatial-controls/spatial-charts/spatial-heatmap-controls/spatial-heatmap-controls.component.mjs +52 -0
- package/esm2022/lib/spatial-controls/spatial-controls.component.mjs +143 -1238
- package/esm2022/lib/spatial-controls/spatial-gene-picker.mjs +153 -0
- package/esm2022/lib/spatial-controls/spatial-gene-tree/spatial-gene-tree.component.mjs +241 -0
- package/esm2022/lib/spatial-controls/spatial-groups-panel/spatial-groups-panel.component.mjs +193 -0
- package/esm2022/lib/spatial-controls/spatial-key/spatial-key.component.mjs +132 -0
- package/esm2022/lib/spatial-controls/spatial-key/spatial-key.model.mjs +67 -0
- package/esm2022/lib/spatial-controls/spatial-marker-genes-form/spatial-marker-genes-form.component.mjs +147 -0
- package/esm2022/lib/spatial-controls/spatial-observations-panel/spatial-observations-panel.component.mjs +300 -0
- package/esm2022/lib/spatial-controls/spatial-transcripts-panel/spatial-transcripts-panel.component.mjs +370 -0
- package/esm2022/lib/store/class-color.util.mjs +46 -3
- package/esm2022/lib/store/region-history.mjs +146 -0
- package/esm2022/lib/store/region-scope-cache.mjs +140 -0
- package/esm2022/lib/store/region-selection.mjs +82 -0
- package/esm2022/lib/store/region-store.service.mjs +279 -675
- package/esm2022/lib/store/spatial-selection.service.mjs +2 -2
- package/esm2022/lib/store/visualizer-store.service.mjs +49 -71
- package/esm2022/lib/toast-outlets.mjs +5 -4
- package/esm2022/lib/toolbar/brush/brush-tool.service.mjs +92 -434
- package/esm2022/lib/toolbar/canvas-tools.mjs +20 -0
- package/esm2022/lib/toolbar/crop/slide-crop.mjs +26 -42
- package/esm2022/lib/toolbar/plot-type-selector/plot-type-selector.component.mjs +85 -0
- package/esm2022/lib/toolbar/region-tools/region-tool-buttons.mjs +74 -0
- package/esm2022/lib/toolbar/region-tools/region-tools.component.mjs +114 -0
- package/esm2022/lib/toolbar/segmentation/cell-segment-tool.service.mjs +74 -78
- package/esm2022/lib/toolbar/segmentation/cellpose-segmenter.service.mjs +50 -8
- package/esm2022/lib/toolbar/segmentation/onnx-sam-session.mjs +61 -42
- package/esm2022/lib/toolbar/segmentation/pending-calls.mjs +47 -0
- package/esm2022/lib/toolbar/segmentation/sam-model-registry.mjs +12 -4
- package/esm2022/lib/toolbar/segmentation/sam-onnx-core.mjs +70 -14
- package/esm2022/lib/toolbar/segmentation/sam-point-tool.service.mjs +135 -172
- package/esm2022/lib/toolbar/segmentation/sam-prompt.mjs +9 -90
- package/esm2022/lib/toolbar/segmentation/sam-session.service.mjs +183 -0
- package/esm2022/lib/toolbar/segmentation/sam-tool.service.mjs +95 -150
- package/esm2022/lib/toolbar/segmentation/segmentation-commit.mjs +12 -0
- package/esm2022/lib/toolbar/segmentation/segmentation-runner.mjs +108 -0
- package/esm2022/lib/toolbar/segmentation-tools/segmentation-tools.component.mjs +155 -0
- package/esm2022/lib/toolbar/stack-controls/stack-controls.component.mjs +81 -0
- package/esm2022/lib/toolbar/tool-kit/async-tool-status.mjs +37 -0
- package/esm2022/lib/toolbar/tool-kit/canvas-tool-manager.mjs +63 -0
- package/esm2022/lib/toolbar/tool-kit/canvas-tool.mjs +2 -0
- package/esm2022/lib/toolbar/tool-kit/frame-pixels.mjs +108 -0
- package/esm2022/lib/toolbar/tool-kit/mask-stroke-editor.mjs +306 -0
- package/esm2022/lib/toolbar/tool-kit/matrix-frame.mjs +61 -0
- package/esm2022/lib/toolbar/tool-kit/tool-overlay.mjs +140 -0
- package/esm2022/lib/toolbar/tool-kit/undo-gesture.mjs +24 -0
- package/esm2022/lib/toolbar/tool-slider/tool-slider.component.mjs +63 -0
- package/esm2022/lib/toolbar/toolbar-help-dialog/toolbar-help-dialog.component.mjs +50 -0
- package/esm2022/lib/toolbar/toolbar.component.mjs +68 -117
- package/esm2022/lib/toolbar/vertex-eraser/vertex-eraser-tool.service.mjs +93 -115
- package/esm2022/lib/toolbar/view-controls/view-controls.component.mjs +107 -0
- package/esm2022/lib/toolbar/wand/wand-region-grow.mjs +321 -0
- package/esm2022/lib/toolbar/wand/wand-tool.service.mjs +121 -416
- package/esm2022/lib/toolbar/wand/wand.service.mjs +30 -894
- package/esm2022/lib/toolbar/zoom-to-box/zoom-to-box-tool.service.mjs +48 -90
- package/esm2022/lib/util/mark-for-check.mjs +17 -0
- package/esm2022/lib/util/supersede.mjs +56 -0
- package/esm2022/lib/visualization.module.mjs +39 -141
- package/esm2022/lib/visualizer/floating-drag.directive.mjs +58 -0
- package/esm2022/lib/visualizer/region-actions.mjs +149 -0
- package/esm2022/lib/visualizer/region-load.mjs +60 -0
- package/esm2022/lib/visualizer/spatial-dataset-binder.mjs +163 -0
- package/esm2022/lib/visualizer/tool-modes.mjs +113 -0
- package/esm2022/lib/visualizer/viewer-shortcuts.mjs +167 -0
- package/esm2022/lib/visualizer/visualizer-context-menu.mjs +119 -0
- package/esm2022/lib/visualizer.component.mjs +480 -1902
- package/esm2022/lib/workers/spatial-math-ops.mjs +43 -0
- package/esm2022/lib/workers/spatial-math-worker.mjs +10 -0
- package/esm2022/lib/workers/spatial-math.mjs +190 -0
- package/fesm2022/jax-data-science-sci-image-visualizer-jax-data-science-sci-image-visualizer-Csxlnq7I.mjs +41083 -0
- package/fesm2022/jax-data-science-sci-image-visualizer-jax-data-science-sci-image-visualizer-Csxlnq7I.mjs.map +1 -0
- package/fesm2022/jax-data-science-sci-image-visualizer-onnx-sam-session-Bkujqg7m.mjs +238 -0
- package/fesm2022/jax-data-science-sci-image-visualizer-onnx-sam-session-Bkujqg7m.mjs.map +1 -0
- package/fesm2022/jax-data-science-sci-image-visualizer-spatial-math-worker-BzVFFqGS.mjs +12 -0
- package/fesm2022/jax-data-science-sci-image-visualizer-spatial-math-worker-BzVFFqGS.mjs.map +1 -0
- package/fesm2022/jax-data-science-sci-image-visualizer.mjs +41 -34430
- package/fesm2022/jax-data-science-sci-image-visualizer.mjs.map +1 -1
- package/fesm2022/mask.worker.js +36 -917
- package/fesm2022/onnx-sam.worker.js +52 -16
- package/fesm2022/spatial-math.worker.js +471 -0
- package/fesm2022/tsne.worker.js +32 -15
- package/index.d.ts +13 -10
- package/lib/channel-histogram/channel-histogram.component.d.ts +53 -43
- package/lib/contracts/capabilities.contract.d.ts +4 -2
- package/lib/contracts/cell-segmenter.contract.d.ts +1 -0
- package/lib/contracts/channel-histogram-api.contract.d.ts +4 -0
- package/lib/contracts/color.d.ts +27 -0
- package/lib/contracts/colormap-lut.d.ts +19 -4
- package/lib/contracts/coordinate-transform.contract.d.ts +3 -3
- package/lib/contracts/display-types.d.ts +21 -0
- package/lib/contracts/instance-segmenter.contract.d.ts +5 -0
- package/lib/contracts/intensity.d.ts +13 -2
- package/lib/contracts/plot-type.d.ts +3 -1
- package/lib/contracts/ports/image-state.port.d.ts +6 -2
- package/lib/contracts/ports/preferences.port.d.ts +4 -0
- package/lib/contracts/ports/region-io.port.d.ts +1 -0
- package/lib/contracts/ports/spatial-data.port.d.ts +4 -10
- package/lib/contracts/ports/tile-access.port.d.ts +1 -0
- package/lib/contracts/region-editor-api.contract.d.ts +1 -1
- package/lib/contracts/region-overlay.contract.d.ts +5 -0
- package/lib/contracts/sam.contract.d.ts +7 -0
- package/lib/contracts/semantic-segmenter.contract.d.ts +6 -0
- package/lib/contracts/spatial-dataset.contract.d.ts +19 -6
- package/lib/contracts/toolbar-tool.contract.d.ts +1 -0
- package/lib/contracts/visualizer.contract.d.ts +221 -54
- package/lib/contracts/viz-config.d.ts +1 -0
- package/lib/geometry/contour.d.ts +24 -0
- package/lib/geometry/raster.d.ts +42 -0
- package/lib/geometry/ring.d.ts +67 -0
- package/lib/hex-color-picker/hex-color-picker.component.d.ts +61 -27
- package/lib/implementations/base-store-visualizer.d.ts +61 -15
- package/lib/implementations/napari-js/napari-axes-gizmo.d.ts +36 -0
- package/lib/implementations/napari-js/napari-display-state.d.ts +76 -0
- package/lib/implementations/napari-js/napari-helpers.d.ts +129 -0
- package/lib/implementations/napari-js/napari-image-2d-scene.d.ts +162 -0
- package/lib/implementations/napari-js/napari-loading-badge.d.ts +0 -1
- package/lib/implementations/napari-js/napari-loading-state.d.ts +30 -0
- package/lib/implementations/napari-js/napari-region-overlay.d.ts +62 -70
- package/lib/implementations/napari-js/napari-scene.d.ts +93 -0
- package/lib/implementations/napari-js/napari-spatial-2d-scene.d.ts +163 -0
- package/lib/implementations/napari-js/napari-spatial-3d-scene.d.ts +212 -0
- package/lib/implementations/napari-js/napari-spatial-encoding.d.ts +114 -0
- package/lib/implementations/napari-js/napari-spatial-hover.d.ts +89 -0
- package/lib/implementations/napari-js/napari-spatial-scene.d.ts +118 -0
- package/lib/implementations/napari-js/napari-spatial-tiles.d.ts +56 -263
- package/lib/implementations/napari-js/napari-spatial-tooltip.d.ts +1 -1
- package/lib/implementations/napari-js/napari-surface-scene.d.ts +76 -0
- package/lib/implementations/napari-js/napari-tile-client.d.ts +214 -0
- package/lib/implementations/napari-js/napari-tool-bridge.d.ts +179 -0
- package/lib/implementations/napari-js/napari-visualizer.service.d.ts +121 -878
- package/lib/implementations/napari-js/napari-volume-scene.d.ts +104 -0
- package/lib/implementations/napari-js/napari-volume-z-handle.d.ts +8 -12
- package/lib/implementations/napari-js/region-overlay/overlay-projection.d.ts +59 -0
- package/lib/implementations/napari-js/region-overlay/region-edit.d.ts +15 -0
- package/lib/implementations/napari-js/region-overlay/region-svg-renderer.d.ts +54 -0
- package/lib/implementations/napari-js/spatial-tiles/categorical-lookup.d.ts +26 -0
- package/lib/implementations/napari-js/spatial-tiles/cell-layers.d.ts +70 -0
- package/lib/implementations/napari-js/spatial-tiles/density-layer.d.ts +61 -0
- package/lib/implementations/napari-js/spatial-tiles/layer-groups.d.ts +67 -0
- package/lib/implementations/napari-js/spatial-tiles/plan-context.d.ts +38 -0
- package/lib/implementations/napari-js/spatial-tiles/transcript-hover.d.ts +71 -0
- package/lib/implementations/napari-js/spatial-tiles/transcript-jobs.d.ts +105 -0
- package/lib/implementations/napari-js/spatial-tiles/transcript-layers.d.ts +56 -0
- package/lib/implementations/osd/display-pipeline.d.ts +38 -9
- package/lib/implementations/osd/histogram-sampler.d.ts +22 -12
- package/lib/implementations/osd/openseadragon-viewer-options.d.ts +35 -0
- package/lib/implementations/osd/openseadragon-visualizer.service.d.ts +78 -354
- package/lib/implementations/osd/osd-coordinate-transform.d.ts +2 -1
- package/lib/implementations/osd/osd-coords.d.ts +6 -4
- package/lib/implementations/osd/osd-export.d.ts +36 -0
- package/lib/implementations/osd/osd-lib.d.ts +7 -0
- package/lib/implementations/osd/osd-navigator-chrome.d.ts +69 -0
- package/lib/implementations/osd/osd-pixel-readback.d.ts +22 -0
- package/lib/implementations/osd/osd-region-overlay-draw.d.ts +37 -0
- package/lib/implementations/osd/osd-region-overlay.d.ts +36 -48
- package/lib/implementations/osd/osd-scale-bar.d.ts +8 -6
- package/lib/implementations/osd/osd-tile-source.d.ts +49 -0
- package/lib/implementations/osd/osd-viewer-like.d.ts +100 -0
- package/lib/implementations/osd/osd-viewer-mount.d.ts +14 -0
- package/lib/implementations/osd/osd-viewport.d.ts +77 -0
- package/lib/implementations/osd/osd-zoom.d.ts +6 -0
- package/lib/implementations/osd/simple-source.d.ts +161 -0
- package/lib/implementations/osd/slice-cache.d.ts +12 -3
- package/lib/implementations/osd/tile-client.d.ts +11 -14
- package/lib/implementations/osd/tile-recolor.d.ts +141 -0
- package/lib/implementations/plotly/omics-trace-builders.d.ts +32 -20
- package/lib/implementations/plotly/plotly-image-loader.d.ts +49 -0
- package/lib/implementations/plotly/plotly-image-recolor.d.ts +75 -0
- package/lib/implementations/plotly/plotly-intensity-inset.d.ts +8 -0
- package/lib/implementations/plotly/plotly-isosurface-controls.d.ts +38 -0
- package/lib/implementations/plotly/plotly-layouts.d.ts +188 -0
- package/lib/implementations/plotly/plotly-readback.d.ts +41 -0
- package/lib/implementations/plotly/plotly-region-overlay.d.ts +2 -2
- package/lib/implementations/plotly/plotly-shape-projection.d.ts +92 -0
- package/lib/implementations/plotly/plotly-trace-builders.d.ts +23 -12
- package/lib/implementations/plotly/plotly-zoom-controller.d.ts +86 -0
- package/lib/implementations/plotly/plotly.service.d.ts +136 -401
- package/lib/implementations/region-centroids.d.ts +14 -0
- package/lib/implementations/simple-slice-access.service.d.ts +7 -4
- package/lib/implementations/spatial-data-http/spatial-data-http.service.d.ts +42 -18
- package/lib/implementations/spatial-data-http/spatial-wire.d.ts +34 -9
- package/lib/implementations/tile-server/index.d.ts +5 -0
- package/lib/implementations/tile-server/native-histogram.d.ts +25 -0
- package/lib/implementations/tile-server/poll-descriptor.d.ts +39 -0
- package/lib/implementations/tile-server/tile-protocol.d.ts +80 -0
- package/lib/implementations/tile-server/transport.d.ts +62 -0
- package/lib/intensity/intensity-profile.d.ts +66 -0
- package/lib/intensity/intensity-profile.service.d.ts +108 -0
- package/lib/intensity-inset/intensity-inset.component.d.ts +58 -0
- package/lib/models/bezier.d.ts +0 -5
- package/lib/models/class-preset.d.ts +18 -0
- package/lib/models/geometry.d.ts +14 -48
- package/lib/models/polygon-edit.d.ts +72 -0
- package/lib/models/polygon-factory.d.ts +40 -0
- package/lib/models/region-clone.d.ts +20 -0
- package/lib/models/region-geojson.d.ts +17 -0
- package/lib/models/region.d.ts +40 -4
- package/lib/models/shape.d.ts +8 -0
- package/lib/plot-mode/contribution-host.d.ts +125 -0
- package/lib/plot-mode/plot-type-menu.d.ts +60 -0
- package/lib/plot-mode/tool-params-model.d.ts +49 -0
- package/lib/plot.utilities.d.ts +19 -30
- package/lib/processing/processing-image.d.ts +5 -2
- package/lib/provide-visualization.d.ts +19 -2
- package/lib/region-editor/classes-panel/classes-panel.component.d.ts +56 -0
- package/lib/region-editor/file-stem.d.ts +7 -0
- package/lib/region-editor/manage-classes-dialog/manage-classes-dialog.component.d.ts +45 -0
- package/lib/region-editor/mask-export.service.d.ts +54 -0
- package/lib/region-editor/mask-raster.d.ts +2 -8
- package/lib/region-editor/region-color-dialog/region-color-dialog.component.d.ts +29 -0
- package/lib/region-editor/region-editor-help/region-editor-help.component.d.ts +11 -0
- package/lib/region-editor/region-editor.component.d.ts +166 -199
- package/lib/region-editor/region-metrics.d.ts +26 -0
- package/lib/region-editor/region-persistence.service.d.ts +69 -0
- package/lib/region-editor/region-table/region-table.component.d.ts +83 -0
- package/lib/region-editor/save-mask-dialog/save-mask-dialog.component.d.ts +36 -0
- package/lib/region-editor/save-regions-dialog/save-regions-dialog.component.d.ts +37 -0
- package/lib/region-ops.service.d.ts +1 -7
- package/lib/region-overlay/region-geometry.d.ts +157 -0
- package/lib/region-overlay/region-hit-test.d.ts +38 -0
- package/lib/region-overlay/svg-region-renderer.d.ts +110 -0
- package/lib/render-orchestrator.d.ts +6 -2
- package/lib/render-session.d.ts +75 -0
- package/lib/routing-visualizer.service.d.ts +110 -58
- package/lib/spatial/density-raster.d.ts +6 -0
- package/lib/spatial/embedding-compute-coordinator.d.ts +123 -0
- package/lib/spatial/embedding-compute.d.ts +21 -2
- package/lib/spatial/glyphs.d.ts +16 -0
- package/lib/spatial/lod.d.ts +94 -0
- package/lib/spatial/spatial-controls.facade.d.ts +64 -0
- package/lib/spatial/spatial-density.d.ts +15 -5
- package/lib/spatial/spatial-encoding.d.ts +11 -44
- package/lib/spatial/spatial-expression.d.ts +40 -22
- package/lib/spatial/spatial-framing.d.ts +1 -0
- package/lib/spatial/spatial-heatmap.d.ts +2 -0
- package/lib/spatial/spatial-hover.d.ts +4 -16
- package/lib/spatial/spatial-panel-model.d.ts +135 -0
- package/lib/spatial/spatial-selection.d.ts +21 -26
- package/lib/spatial/spatial-tile-merge.d.ts +41 -0
- package/lib/spatial/spatial-tiles.d.ts +9 -256
- package/lib/spatial/stats.d.ts +38 -0
- package/lib/spatial/transcript-grouping.d.ts +119 -0
- package/lib/spatial-controls/spatial-cells-panel/spatial-cells-panel.component.d.ts +64 -0
- package/lib/spatial-controls/spatial-charts/chart-data-model.d.ts +153 -0
- package/lib/spatial-controls/spatial-charts/chart-help.d.ts +69 -0
- package/lib/spatial-controls/spatial-charts/plotly-chart-host.d.ts +98 -0
- package/lib/spatial-controls/spatial-charts/spatial-chart-window/spatial-chart-window.component.d.ts +26 -0
- package/lib/spatial-controls/spatial-charts/spatial-charts.component.d.ts +101 -260
- package/lib/spatial-controls/spatial-charts/spatial-embedding-controls/spatial-embedding-controls.component.d.ts +43 -0
- package/lib/spatial-controls/spatial-charts/spatial-heatmap-controls/spatial-heatmap-controls.component.d.ts +27 -0
- package/lib/spatial-controls/spatial-controls.component.d.ts +68 -448
- package/lib/spatial-controls/spatial-gene-picker.d.ts +86 -0
- package/lib/spatial-controls/spatial-gene-tree/spatial-gene-tree.component.d.ts +102 -0
- package/lib/spatial-controls/spatial-groups-panel/spatial-groups-panel.component.d.ts +72 -0
- package/lib/spatial-controls/spatial-key/spatial-key.component.d.ts +66 -0
- package/lib/spatial-controls/spatial-key/spatial-key.model.d.ts +33 -0
- package/lib/spatial-controls/spatial-marker-genes-form/spatial-marker-genes-form.component.d.ts +64 -0
- package/lib/spatial-controls/spatial-observations-panel/spatial-observations-panel.component.d.ts +117 -0
- package/lib/spatial-controls/spatial-transcripts-panel/spatial-transcripts-panel.component.d.ts +142 -0
- package/lib/store/class-color.util.d.ts +35 -1
- package/lib/store/region-history.d.ts +66 -0
- package/lib/store/region-scope-cache.d.ts +63 -0
- package/lib/store/region-selection.d.ts +36 -0
- package/lib/store/region-store.service.d.ts +104 -112
- package/lib/store/visualizer-store.service.d.ts +22 -33
- package/lib/toast-outlets.d.ts +4 -3
- package/lib/toolbar/brush/brush-tool.service.d.ts +31 -98
- package/lib/toolbar/canvas-tools.d.ts +20 -0
- package/lib/toolbar/crop/slide-crop.d.ts +10 -4
- package/lib/toolbar/plot-type-selector/plot-type-selector.component.d.ts +38 -0
- package/lib/toolbar/region-tools/region-tool-buttons.d.ts +21 -0
- package/lib/toolbar/region-tools/region-tools.component.d.ts +60 -0
- package/lib/toolbar/segmentation/cell-segment-tool.service.d.ts +10 -14
- package/lib/toolbar/segmentation/cellpose-segmenter.service.d.ts +12 -2
- package/lib/toolbar/segmentation/onnx-sam-session.d.ts +22 -3
- package/lib/toolbar/segmentation/pending-calls.d.ts +31 -0
- package/lib/toolbar/segmentation/sam-model-registry.d.ts +9 -3
- package/lib/toolbar/segmentation/sam-onnx-core.d.ts +18 -5
- package/lib/toolbar/segmentation/sam-point-tool.service.d.ts +46 -32
- package/lib/toolbar/segmentation/sam-prompt.d.ts +7 -31
- package/lib/toolbar/segmentation/sam-session.service.d.ts +74 -0
- package/lib/toolbar/segmentation/sam-tool.service.d.ts +23 -30
- package/lib/toolbar/segmentation/segmentation-commit.d.ts +8 -0
- package/lib/toolbar/segmentation/segmentation-runner.d.ts +52 -0
- package/lib/toolbar/segmentation-tools/segmentation-tools.component.d.ts +87 -0
- package/lib/toolbar/stack-controls/stack-controls.component.d.ts +40 -0
- package/lib/toolbar/tool-kit/async-tool-status.d.ts +21 -0
- package/lib/toolbar/tool-kit/canvas-tool-manager.d.ts +36 -0
- package/lib/toolbar/tool-kit/canvas-tool.d.ts +86 -0
- package/lib/toolbar/tool-kit/frame-pixels.d.ts +45 -0
- package/lib/toolbar/tool-kit/mask-stroke-editor.d.ts +125 -0
- package/lib/toolbar/tool-kit/matrix-frame.d.ts +40 -0
- package/lib/toolbar/tool-kit/tool-overlay.d.ts +60 -0
- package/lib/toolbar/tool-kit/undo-gesture.d.ts +17 -0
- package/lib/toolbar/tool-slider/tool-slider.component.d.ts +33 -0
- package/lib/toolbar/toolbar-help-dialog/toolbar-help-dialog.component.d.ts +24 -0
- package/lib/toolbar/toolbar.component.d.ts +47 -83
- package/lib/toolbar/vertex-eraser/vertex-eraser-tool.service.d.ts +33 -40
- package/lib/toolbar/view-controls/view-controls.component.d.ts +54 -0
- package/lib/toolbar/wand/wand-region-grow.d.ts +49 -0
- package/lib/toolbar/wand/wand-tool.service.d.ts +39 -124
- package/lib/toolbar/wand/wand.service.d.ts +22 -116
- package/lib/toolbar/zoom-to-box/zoom-to-box-tool.service.d.ts +17 -37
- package/lib/util/mark-for-check.d.ts +11 -0
- package/lib/util/supersede.d.ts +53 -0
- package/lib/visualization.module.d.ts +18 -39
- package/lib/visualizer/floating-drag.directive.d.ts +30 -0
- package/lib/visualizer/region-actions.d.ts +54 -0
- package/lib/visualizer/region-load.d.ts +27 -0
- package/lib/visualizer/spatial-dataset-binder.d.ts +74 -0
- package/lib/visualizer/tool-modes.d.ts +49 -0
- package/lib/visualizer/viewer-shortcuts.d.ts +71 -0
- package/lib/visualizer/visualizer-context-menu.d.ts +55 -0
- package/lib/visualizer.component.d.ts +201 -447
- package/lib/workers/spatial-math-ops.d.ts +65 -0
- package/lib/workers/spatial-math-worker.d.ts +7 -0
- package/lib/workers/spatial-math.d.ts +74 -0
- package/package.json +12 -3
- package/src/lib/styles/_viz-icons-rules.scss +73 -0
- package/src/lib/styles/viz-icons.scss +14 -0
- package/esm2022/lib/implementations/napari-js/napari-axes-labels.mjs +0 -97
- package/esm2022/lib/implementations/napari-js/napari-navigator.mjs +0 -195
- package/esm2022/lib/implementations/napari-js/napari-scale-bar.mjs +0 -92
- package/fesm2022/jax-data-science-sci-image-visualizer-onnx-sam-session-BwP-A11m.mjs +0 -329
- package/fesm2022/jax-data-science-sci-image-visualizer-onnx-sam-session-BwP-A11m.mjs.map +0 -1
- package/lib/implementations/napari-js/napari-axes-labels.d.ts +0 -49
- package/lib/implementations/napari-js/napari-navigator.d.ts +0 -72
- package/lib/implementations/napari-js/napari-scale-bar.d.ts +0 -35
- package/src/lib/assets/cell-detection.svg +0 -37
- package/src/lib/assets/click.svg +0 -1
- package/src/lib/assets/colormap-luts.json +0 -1
- package/src/lib/assets/edit-selection-white.svg +0 -47
- package/src/lib/assets/icons/colormap-earth.png +0 -0
- package/src/lib/assets/icons/colormap-placeholder.png +0 -0
- package/src/lib/assets/icons/colormap-pubu.png +0 -0
- package/src/lib/assets/interactive-segmentation-cursor.svg +0 -1
- package/src/lib/assets/picture-segmentation.svg +0 -43
- package/src/lib/assets/test/download-379.svg +0 -1
- package/src/lib/assets/test/download-98.svg +0 -1
- package/src/lib/assets/test/json-1.svg +0 -1
- package/src/lib/assets/test/load-53.svg +0 -1
- package/src/lib/assets/test/mask-44.svg +0 -1
- package/src/lib/assets/test/mask-download-44.svg +0 -15
- package/src/lib/assets/test/mask-save-44.svg +0 -11
- package/src/lib/assets/test/overlay-1.svg +0 -1
- package/src/lib/assets/test/overlay-4.svg +0 -1
- package/src/lib/assets/test/region-26.svg +0 -1
- package/src/lib/assets/test/save-56.svg +0 -1
- package/src/lib/assets/test/upload-43.svg +0 -1
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
import { Subscription } from 'rxjs';
|
|
2
|
+
import { takeUntil } from 'rxjs/operators';
|
|
3
|
+
/**
|
|
4
|
+
* One viewer's segmentation runs and their sticky progress toast (jit-ui#90): the
|
|
5
|
+
* box-prompt SAM and Cellpose tools, contributed whole-view tools, and the
|
|
6
|
+
* interactive SAM point tool whose feeds it bridges.
|
|
7
|
+
*
|
|
8
|
+
* The toast is keyed per viewer (`toastKey`), so a run in a pipeline preview does not
|
|
9
|
+
* show in the main view; results and failures go to the viewer's `resultKey` outlet,
|
|
10
|
+
* which the sticky toast's teardown does not clear. The toast template binds
|
|
11
|
+
* {@link status}, {@link progress}, {@link downloading} and {@link busy}.
|
|
12
|
+
*/
|
|
13
|
+
export class SegmentationRunner {
|
|
14
|
+
constructor(messages, toastKey, resultKey,
|
|
15
|
+
/** Re-render the toast (its feeds may fire outside the zone). */
|
|
16
|
+
changed) {
|
|
17
|
+
this.messages = messages;
|
|
18
|
+
this.toastKey = toastKey;
|
|
19
|
+
this.resultKey = resultKey;
|
|
20
|
+
this.changed = changed;
|
|
21
|
+
this.status = '';
|
|
22
|
+
/** Encoder download, 0..100. */
|
|
23
|
+
this.progress = 0;
|
|
24
|
+
this.downloading = false;
|
|
25
|
+
/** Any segmentation work in flight (the indeterminate spinner). */
|
|
26
|
+
this.busy = false;
|
|
27
|
+
/** Whether the sticky toast is up — re-adding it would stack one per point click. */
|
|
28
|
+
this.shown = false;
|
|
29
|
+
}
|
|
30
|
+
/** Surface the interactive SAM point tool's status and download progress, which runs
|
|
31
|
+
* inside the renderer on each click (the first click pulls the encoder). */
|
|
32
|
+
bindPointTool(tool, until$) {
|
|
33
|
+
tool.progress$.pipe(takeUntil(until$)).subscribe((f) => this.onProgress(f));
|
|
34
|
+
tool.status$.pipe(takeUntil(until$)).subscribe((m) => {
|
|
35
|
+
this.status = m;
|
|
36
|
+
this.changed();
|
|
37
|
+
});
|
|
38
|
+
tool.busy$.pipe(takeUntil(until$)).subscribe((busy) => {
|
|
39
|
+
this.busy = busy;
|
|
40
|
+
if (busy)
|
|
41
|
+
this.show('SAM point segmentation');
|
|
42
|
+
this.changed();
|
|
43
|
+
});
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Run `op` with the tool's status and download progress in the sticky toast, then
|
|
47
|
+
* report the outcome: the region count (or the tool's last status line) on success,
|
|
48
|
+
* the error on failure. The toast stays until the run settles.
|
|
49
|
+
*/
|
|
50
|
+
async run(label, tool, op) {
|
|
51
|
+
this.status = 'Starting…';
|
|
52
|
+
this.progress = 0;
|
|
53
|
+
this.downloading = false;
|
|
54
|
+
this.busy = true;
|
|
55
|
+
// The last non-empty status is what the result reports: `tool` is only an
|
|
56
|
+
// Observable pair, so there is no `.value` to sample once the run settles.
|
|
57
|
+
let lastStatus = '';
|
|
58
|
+
const subs = new Subscription();
|
|
59
|
+
subs.add(tool.progress$.subscribe((f) => this.onProgress(f)));
|
|
60
|
+
subs.add(tool.status$.subscribe((m) => {
|
|
61
|
+
if (!m)
|
|
62
|
+
return;
|
|
63
|
+
lastStatus = m;
|
|
64
|
+
this.status = m;
|
|
65
|
+
this.changed();
|
|
66
|
+
}));
|
|
67
|
+
this.show(label);
|
|
68
|
+
try {
|
|
69
|
+
const n = await op();
|
|
70
|
+
this.messages.add({
|
|
71
|
+
key: this.resultKey,
|
|
72
|
+
severity: n > 0 ? 'success' : 'warn',
|
|
73
|
+
summary: label,
|
|
74
|
+
detail: lastStatus || (n > 0 ? `Added ${n} region(s).` : 'No regions added.'),
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
catch (e) {
|
|
78
|
+
this.messages.add({ key: this.resultKey, severity: 'error', summary: `${label} failed`, detail: String(e) });
|
|
79
|
+
}
|
|
80
|
+
finally {
|
|
81
|
+
subs.unsubscribe();
|
|
82
|
+
this.hide();
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
/** Show the sticky toast once (idempotent). */
|
|
86
|
+
show(summary) {
|
|
87
|
+
if (this.shown)
|
|
88
|
+
return;
|
|
89
|
+
this.shown = true;
|
|
90
|
+
this.messages.add({ key: this.toastKey, sticky: true, severity: 'info', summary });
|
|
91
|
+
}
|
|
92
|
+
/** Dismiss the sticky toast and reset its progress/spinner state. */
|
|
93
|
+
hide() {
|
|
94
|
+
this.shown = false;
|
|
95
|
+
this.busy = false;
|
|
96
|
+
this.downloading = false;
|
|
97
|
+
this.progress = 0;
|
|
98
|
+
this.messages.clear(this.toastKey);
|
|
99
|
+
this.changed();
|
|
100
|
+
}
|
|
101
|
+
onProgress(f) {
|
|
102
|
+
this.downloading = f >= 0 && f < 1;
|
|
103
|
+
if (f >= 0)
|
|
104
|
+
this.progress = Math.min(100, Math.round(f * 100));
|
|
105
|
+
this.changed();
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic2VnbWVudGF0aW9uLXJ1bm5lci5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uLy4uL3NyYy9saWIvdG9vbGJhci9zZWdtZW50YXRpb24vc2VnbWVudGF0aW9uLXJ1bm5lci50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQWMsWUFBWSxFQUFFLE1BQU0sTUFBTSxDQUFDO0FBQ2hELE9BQU8sRUFBRSxTQUFTLEVBQUUsTUFBTSxnQkFBZ0IsQ0FBQztBQVUzQzs7Ozs7Ozs7O0dBU0c7QUFDSCxNQUFNLE9BQU8sa0JBQWtCO0lBVTdCLFlBQ21CLFFBQStDLEVBQ3ZELFFBQWdCLEVBQ2hCLFNBQWlCO0lBQzFCLGlFQUFpRTtJQUNoRCxPQUFtQjtRQUpuQixhQUFRLEdBQVIsUUFBUSxDQUF1QztRQUN2RCxhQUFRLEdBQVIsUUFBUSxDQUFRO1FBQ2hCLGNBQVMsR0FBVCxTQUFTLENBQVE7UUFFVCxZQUFPLEdBQVAsT0FBTyxDQUFZO1FBZHRDLFdBQU0sR0FBRyxFQUFFLENBQUM7UUFDWixnQ0FBZ0M7UUFDaEMsYUFBUSxHQUFHLENBQUMsQ0FBQztRQUNiLGdCQUFXLEdBQUcsS0FBSyxDQUFDO1FBQ3BCLG1FQUFtRTtRQUNuRSxTQUFJLEdBQUcsS0FBSyxDQUFDO1FBQ2IscUZBQXFGO1FBQzdFLFVBQUssR0FBRyxLQUFLLENBQUM7SUFRbkIsQ0FBQztJQUVKO2lGQUM2RTtJQUM3RSxhQUFhLENBQUMsSUFBMkQsRUFBRSxNQUEyQjtRQUNwRyxJQUFJLENBQUMsU0FBUyxDQUFDLElBQUksQ0FBQyxTQUFTLENBQUMsTUFBTSxDQUFDLENBQUMsQ0FBQyxTQUFTLENBQUMsQ0FBQyxDQUFDLEVBQUUsRUFBRSxDQUFDLElBQUksQ0FBQyxVQUFVLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQztRQUM1RSxJQUFJLENBQUMsT0FBTyxDQUFDLElBQUksQ0FBQyxTQUFTLENBQUMsTUFBTSxDQUFDLENBQUMsQ0FBQyxTQUFTLENBQUMsQ0FBQyxDQUFDLEVBQUUsRUFBRTtZQUNuRCxJQUFJLENBQUMsTUFBTSxHQUFHLENBQUMsQ0FBQztZQUNoQixJQUFJLENBQUMsT0FBTyxFQUFFLENBQUM7UUFDakIsQ0FBQyxDQUFDLENBQUM7UUFDSCxJQUFJLENBQUMsS0FBSyxDQUFDLElBQUksQ0FBQyxTQUFTLENBQUMsTUFBTSxDQUFDLENBQUMsQ0FBQyxTQUFTLENBQUMsQ0FBQyxJQUFJLEVBQUUsRUFBRTtZQUNwRCxJQUFJLENBQUMsSUFBSSxHQUFHLElBQUksQ0FBQztZQUNqQixJQUFJLElBQUk7Z0JBQUUsSUFBSSxDQUFDLElBQUksQ0FBQyx3QkFBd0IsQ0FBQyxDQUFDO1lBQzlDLElBQUksQ0FBQyxPQUFPLEVBQUUsQ0FBQztRQUNqQixDQUFDLENBQUMsQ0FBQztJQUNMLENBQUM7SUFFRDs7OztPQUlHO0lBQ0gsS0FBSyxDQUFDLEdBQUcsQ0FBQyxLQUFhLEVBQUUsSUFBMEIsRUFBRSxFQUF5QjtRQUM1RSxJQUFJLENBQUMsTUFBTSxHQUFHLFdBQVcsQ0FBQztRQUMxQixJQUFJLENBQUMsUUFBUSxHQUFHLENBQUMsQ0FBQztRQUNsQixJQUFJLENBQUMsV0FBVyxHQUFHLEtBQUssQ0FBQztRQUN6QixJQUFJLENBQUMsSUFBSSxHQUFHLElBQUksQ0FBQztRQUNqQiwwRUFBMEU7UUFDMUUsMkVBQTJFO1FBQzNFLElBQUksVUFBVSxHQUFHLEVBQUUsQ0FBQztRQUNwQixNQUFNLElBQUksR0FBRyxJQUFJLFlBQVksRUFBRSxDQUFDO1FBQ2hDLElBQUksQ0FBQyxHQUFHLENBQUMsSUFBSSxDQUFDLFNBQVMsQ0FBQyxTQUFTLENBQUMsQ0FBQyxDQUFDLEVBQUUsRUFBRSxDQUFDLElBQUksQ0FBQyxVQUFVLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDO1FBQzlELElBQUksQ0FBQyxHQUFHLENBQ04sSUFBSSxDQUFDLE9BQU8sQ0FBQyxTQUFTLENBQUMsQ0FBQyxDQUFDLEVBQUUsRUFBRTtZQUMzQixJQUFJLENBQUMsQ0FBQztnQkFBRSxPQUFPO1lBQ2YsVUFBVSxHQUFHLENBQUMsQ0FBQztZQUNmLElBQUksQ0FBQyxNQUFNLEdBQUcsQ0FBQyxDQUFDO1lBQ2hCLElBQUksQ0FBQyxPQUFPLEVBQUUsQ0FBQztRQUNqQixDQUFDLENBQUMsQ0FDSCxDQUFDO1FBQ0YsSUFBSSxDQUFDLElBQUksQ0FBQyxLQUFLLENBQUMsQ0FBQztRQUNqQixJQUFJLENBQUM7WUFDSCxNQUFNLENBQUMsR0FBRyxNQUFNLEVBQUUsRUFBRSxDQUFDO1lBQ3JCLElBQUksQ0FBQyxRQUFRLENBQUMsR0FBRyxDQUFDO2dCQUNoQixHQUFHLEVBQUUsSUFBSSxDQUFDLFNBQVM7Z0JBQ25CLFFBQVEsRUFBRSxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUMsQ0FBQyxTQUFTLENBQUMsQ0FBQyxDQUFDLE1BQU07Z0JBQ3BDLE9BQU8sRUFBRSxLQUFLO2dCQUNkLE1BQU0sRUFBRSxVQUFVLElBQUksQ0FBQyxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUMsQ0FBQyxTQUFTLENBQUMsYUFBYSxDQUFDLENBQUMsQ0FBQyxtQkFBbUIsQ0FBQzthQUM5RSxDQUFDLENBQUM7UUFDTCxDQUFDO1FBQUMsT0FBTyxDQUFDLEVBQUUsQ0FBQztZQUNYLElBQUksQ0FBQyxRQUFRLENBQUMsR0FBRyxDQUFDLEVBQUUsR0FBRyxFQUFFLElBQUksQ0FBQyxTQUFTLEVBQUUsUUFBUSxFQUFFLE9BQU8sRUFBRSxPQUFPLEVBQUUsR0FBRyxLQUFLLFNBQVMsRUFBRSxNQUFNLEVBQUUsTUFBTSxDQUFDLENBQUMsQ0FBQyxFQUFFLENBQUMsQ0FBQztRQUMvRyxDQUFDO2dCQUFTLENBQUM7WUFDVCxJQUFJLENBQUMsV0FBVyxFQUFFLENBQUM7WUFDbkIsSUFBSSxDQUFDLElBQUksRUFBRSxDQUFDO1FBQ2QsQ0FBQztJQUNILENBQUM7SUFFRCwrQ0FBK0M7SUFDL0MsSUFBSSxDQUFDLE9BQWU7UUFDbEIsSUFBSSxJQUFJLENBQUMsS0FBSztZQUFFLE9BQU87UUFDdkIsSUFBSSxDQUFDLEtBQUssR0FBRyxJQUFJLENBQUM7UUFDbEIsSUFBSSxDQUFDLFFBQVEsQ0FBQyxHQUFHLENBQUMsRUFBRSxHQUFHLEVBQUUsSUFBSSxDQUFDLFFBQVEsRUFBRSxNQUFNLEVBQUUsSUFBSSxFQUFFLFFBQVEsRUFBRSxNQUFNLEVBQUUsT0FBTyxFQUFFLENBQUMsQ0FBQztJQUNyRixDQUFDO0lBRUQscUVBQXFFO0lBQ3JFLElBQUk7UUFDRixJQUFJLENBQUMsS0FBSyxHQUFHLEtBQUssQ0FBQztRQUNuQixJQUFJLENBQUMsSUFBSSxHQUFHLEtBQUssQ0FBQztRQUNsQixJQUFJLENBQUMsV0FBVyxHQUFHLEtBQUssQ0FBQztRQUN6QixJQUFJLENBQUMsUUFBUSxHQUFHLENBQUMsQ0FBQztRQUNsQixJQUFJLENBQUMsUUFBUSxDQUFDLEtBQUssQ0FBQyxJQUFJLENBQUMsUUFBUSxDQUFDLENBQUM7UUFDbkMsSUFBSSxDQUFDLE9BQU8sRUFBRSxDQUFDO0lBQ2pCLENBQUM7SUFFTyxVQUFVLENBQUMsQ0FBUztRQUMxQixJQUFJLENBQUMsV0FBVyxHQUFHLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxHQUFHLENBQUMsQ0FBQztRQUNuQyxJQUFJLENBQUMsSUFBSSxDQUFDO1lBQUUsSUFBSSxDQUFDLFFBQVEsR0FBRyxJQUFJLENBQUMsR0FBRyxDQUFDLEdBQUcsRUFBRSxJQUFJLENBQUMsS0FBSyxDQUFDLENBQUMsR0FBRyxHQUFHLENBQUMsQ0FBQyxDQUFDO1FBQy9ELElBQUksQ0FBQyxPQUFPLEVBQUUsQ0FBQztJQUNqQixDQUFDO0NBQ0YiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBPYnNlcnZhYmxlLCBTdWJzY3JpcHRpb24gfSBmcm9tICdyeGpzJztcbmltcG9ydCB7IHRha2VVbnRpbCB9IGZyb20gJ3J4anMvb3BlcmF0b3JzJztcbmltcG9ydCB7IE1lc3NhZ2VTZXJ2aWNlIH0gZnJvbSAncHJpbWVuZy9hcGknO1xuXG4vKiogQSBzZWdtZW50YXRpb24gdG9vbCdzIGxpdmUgZmVlZHM6IHN0YXR1cyBsaW5lIGFuZCBlbmNvZGVyLWRvd25sb2FkIHByb2dyZXNzICgwLi4xLCA8MCA9IG5vbmUpLlxuICogIE9ic2VydmFibGVzLCBub3Qgc3ViamVjdHMsIHNvIGEgY29udHJpYnV0ZWQgdG9vbCBuZWVkIG5vdCBleHBvc2UgaXRzIGludGVybmFscy4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgU2VnbWVudGF0aW9uUHJvZ3Jlc3Mge1xuICBzdGF0dXMkOiBPYnNlcnZhYmxlPHN0cmluZz47XG4gIHByb2dyZXNzJDogT2JzZXJ2YWJsZTxudW1iZXI+O1xufVxuXG4vKipcbiAqIE9uZSB2aWV3ZXIncyBzZWdtZW50YXRpb24gcnVucyBhbmQgdGhlaXIgc3RpY2t5IHByb2dyZXNzIHRvYXN0IChqaXQtdWkjOTApOiB0aGVcbiAqIGJveC1wcm9tcHQgU0FNIGFuZCBDZWxscG9zZSB0b29scywgY29udHJpYnV0ZWQgd2hvbGUtdmlldyB0b29scywgYW5kIHRoZVxuICogaW50ZXJhY3RpdmUgU0FNIHBvaW50IHRvb2wgd2hvc2UgZmVlZHMgaXQgYnJpZGdlcy5cbiAqXG4gKiBUaGUgdG9hc3QgaXMga2V5ZWQgcGVyIHZpZXdlciAoYHRvYXN0S2V5YCksIHNvIGEgcnVuIGluIGEgcGlwZWxpbmUgcHJldmlldyBkb2VzIG5vdFxuICogc2hvdyBpbiB0aGUgbWFpbiB2aWV3OyByZXN1bHRzIGFuZCBmYWlsdXJlcyBnbyB0byB0aGUgdmlld2VyJ3MgYHJlc3VsdEtleWAgb3V0bGV0LFxuICogd2hpY2ggdGhlIHN0aWNreSB0b2FzdCdzIHRlYXJkb3duIGRvZXMgbm90IGNsZWFyLiBUaGUgdG9hc3QgdGVtcGxhdGUgYmluZHNcbiAqIHtAbGluayBzdGF0dXN9LCB7QGxpbmsgcHJvZ3Jlc3N9LCB7QGxpbmsgZG93bmxvYWRpbmd9IGFuZCB7QGxpbmsgYnVzeX0uXG4gKi9cbmV4cG9ydCBjbGFzcyBTZWdtZW50YXRpb25SdW5uZXIge1xuICBzdGF0dXMgPSAnJztcbiAgLyoqIEVuY29kZXIgZG93bmxvYWQsIDAuLjEwMC4gKi9cbiAgcHJvZ3Jlc3MgPSAwO1xuICBkb3dubG9hZGluZyA9IGZhbHNlO1xuICAvKiogQW55IHNlZ21lbnRhdGlvbiB3b3JrIGluIGZsaWdodCAodGhlIGluZGV0ZXJtaW5hdGUgc3Bpbm5lcikuICovXG4gIGJ1c3kgPSBmYWxzZTtcbiAgLyoqIFdoZXRoZXIgdGhlIHN0aWNreSB0b2FzdCBpcyB1cCDigJQgcmUtYWRkaW5nIGl0IHdvdWxkIHN0YWNrIG9uZSBwZXIgcG9pbnQgY2xpY2suICovXG4gIHByaXZhdGUgc2hvd24gPSBmYWxzZTtcblxuICBjb25zdHJ1Y3RvcihcbiAgICBwcml2YXRlIHJlYWRvbmx5IG1lc3NhZ2VzOiBQaWNrPE1lc3NhZ2VTZXJ2aWNlLCAnYWRkJyB8ICdjbGVhcic+LFxuICAgIHJlYWRvbmx5IHRvYXN0S2V5OiBzdHJpbmcsXG4gICAgcmVhZG9ubHkgcmVzdWx0S2V5OiBzdHJpbmcsXG4gICAgLyoqIFJlLXJlbmRlciB0aGUgdG9hc3QgKGl0cyBmZWVkcyBtYXkgZmlyZSBvdXRzaWRlIHRoZSB6b25lKS4gKi9cbiAgICBwcml2YXRlIHJlYWRvbmx5IGNoYW5nZWQ6ICgpID0+IHZvaWQsXG4gICkge31cblxuICAvKiogU3VyZmFjZSB0aGUgaW50ZXJhY3RpdmUgU0FNIHBvaW50IHRvb2wncyBzdGF0dXMgYW5kIGRvd25sb2FkIHByb2dyZXNzLCB3aGljaCBydW5zXG4gICAqICBpbnNpZGUgdGhlIHJlbmRlcmVyIG9uIGVhY2ggY2xpY2sgKHRoZSBmaXJzdCBjbGljayBwdWxscyB0aGUgZW5jb2RlcikuICovXG4gIGJpbmRQb2ludFRvb2wodG9vbDogU2VnbWVudGF0aW9uUHJvZ3Jlc3MgJiB7IGJ1c3kkOiBPYnNlcnZhYmxlPGJvb2xlYW4+IH0sIHVudGlsJDogT2JzZXJ2YWJsZTx1bmtub3duPik6IHZvaWQge1xuICAgIHRvb2wucHJvZ3Jlc3MkLnBpcGUodGFrZVVudGlsKHVudGlsJCkpLnN1YnNjcmliZSgoZikgPT4gdGhpcy5vblByb2dyZXNzKGYpKTtcbiAgICB0b29sLnN0YXR1cyQucGlwZSh0YWtlVW50aWwodW50aWwkKSkuc3Vic2NyaWJlKChtKSA9PiB7XG4gICAgICB0aGlzLnN0YXR1cyA9IG07XG4gICAgICB0aGlzLmNoYW5nZWQoKTtcbiAgICB9KTtcbiAgICB0b29sLmJ1c3kkLnBpcGUodGFrZVVudGlsKHVudGlsJCkpLnN1YnNjcmliZSgoYnVzeSkgPT4ge1xuICAgICAgdGhpcy5idXN5ID0gYnVzeTtcbiAgICAgIGlmIChidXN5KSB0aGlzLnNob3coJ1NBTSBwb2ludCBzZWdtZW50YXRpb24nKTtcbiAgICAgIHRoaXMuY2hhbmdlZCgpO1xuICAgIH0pO1xuICB9XG5cbiAgLyoqXG4gICAqIFJ1biBgb3BgIHdpdGggdGhlIHRvb2wncyBzdGF0dXMgYW5kIGRvd25sb2FkIHByb2dyZXNzIGluIHRoZSBzdGlja3kgdG9hc3QsIHRoZW5cbiAgICogcmVwb3J0IHRoZSBvdXRjb21lOiB0aGUgcmVnaW9uIGNvdW50IChvciB0aGUgdG9vbCdzIGxhc3Qgc3RhdHVzIGxpbmUpIG9uIHN1Y2Nlc3MsXG4gICAqIHRoZSBlcnJvciBvbiBmYWlsdXJlLiBUaGUgdG9hc3Qgc3RheXMgdW50aWwgdGhlIHJ1biBzZXR0bGVzLlxuICAgKi9cbiAgYXN5bmMgcnVuKGxhYmVsOiBzdHJpbmcsIHRvb2w6IFNlZ21lbnRhdGlvblByb2dyZXNzLCBvcDogKCkgPT4gUHJvbWlzZTxudW1iZXI+KTogUHJvbWlzZTx2b2lkPiB7XG4gICAgdGhpcy5zdGF0dXMgPSAnU3RhcnRpbmfigKYnO1xuICAgIHRoaXMucHJvZ3Jlc3MgPSAwO1xuICAgIHRoaXMuZG93bmxvYWRpbmcgPSBmYWxzZTtcbiAgICB0aGlzLmJ1c3kgPSB0cnVlO1xuICAgIC8vIFRoZSBsYXN0IG5vbi1lbXB0eSBzdGF0dXMgaXMgd2hhdCB0aGUgcmVzdWx0IHJlcG9ydHM6IGB0b29sYCBpcyBvbmx5IGFuXG4gICAgLy8gT2JzZXJ2YWJsZSBwYWlyLCBzbyB0aGVyZSBpcyBubyBgLnZhbHVlYCB0byBzYW1wbGUgb25jZSB0aGUgcnVuIHNldHRsZXMuXG4gICAgbGV0IGxhc3RTdGF0dXMgPSAnJztcbiAgICBjb25zdCBzdWJzID0gbmV3IFN1YnNjcmlwdGlvbigpO1xuICAgIHN1YnMuYWRkKHRvb2wucHJvZ3Jlc3MkLnN1YnNjcmliZSgoZikgPT4gdGhpcy5vblByb2dyZXNzKGYpKSk7XG4gICAgc3Vicy5hZGQoXG4gICAgICB0b29sLnN0YXR1cyQuc3Vic2NyaWJlKChtKSA9PiB7XG4gICAgICAgIGlmICghbSkgcmV0dXJuO1xuICAgICAgICBsYXN0U3RhdHVzID0gbTtcbiAgICAgICAgdGhpcy5zdGF0dXMgPSBtO1xuICAgICAgICB0aGlzLmNoYW5nZWQoKTtcbiAgICAgIH0pLFxuICAgICk7XG4gICAgdGhpcy5zaG93KGxhYmVsKTtcbiAgICB0cnkge1xuICAgICAgY29uc3QgbiA9IGF3YWl0IG9wKCk7XG4gICAgICB0aGlzLm1lc3NhZ2VzLmFkZCh7XG4gICAgICAgIGtleTogdGhpcy5yZXN1bHRLZXksXG4gICAgICAgIHNldmVyaXR5OiBuID4gMCA/ICdzdWNjZXNzJyA6ICd3YXJuJyxcbiAgICAgICAgc3VtbWFyeTogbGFiZWwsXG4gICAgICAgIGRldGFpbDogbGFzdFN0YXR1cyB8fCAobiA+IDAgPyBgQWRkZWQgJHtufSByZWdpb24ocykuYCA6ICdObyByZWdpb25zIGFkZGVkLicpLFxuICAgICAgfSk7XG4gICAgfSBjYXRjaCAoZSkge1xuICAgICAgdGhpcy5tZXNzYWdlcy5hZGQoeyBrZXk6IHRoaXMucmVzdWx0S2V5LCBzZXZlcml0eTogJ2Vycm9yJywgc3VtbWFyeTogYCR7bGFiZWx9IGZhaWxlZGAsIGRldGFpbDogU3RyaW5nKGUpIH0pO1xuICAgIH0gZmluYWxseSB7XG4gICAgICBzdWJzLnVuc3Vic2NyaWJlKCk7XG4gICAgICB0aGlzLmhpZGUoKTtcbiAgICB9XG4gIH1cblxuICAvKiogU2hvdyB0aGUgc3RpY2t5IHRvYXN0IG9uY2UgKGlkZW1wb3RlbnQpLiAqL1xuICBzaG93KHN1bW1hcnk6IHN0cmluZyk6IHZvaWQge1xuICAgIGlmICh0aGlzLnNob3duKSByZXR1cm47XG4gICAgdGhpcy5zaG93biA9IHRydWU7XG4gICAgdGhpcy5tZXNzYWdlcy5hZGQoeyBrZXk6IHRoaXMudG9hc3RLZXksIHN0aWNreTogdHJ1ZSwgc2V2ZXJpdHk6ICdpbmZvJywgc3VtbWFyeSB9KTtcbiAgfVxuXG4gIC8qKiBEaXNtaXNzIHRoZSBzdGlja3kgdG9hc3QgYW5kIHJlc2V0IGl0cyBwcm9ncmVzcy9zcGlubmVyIHN0YXRlLiAqL1xuICBoaWRlKCk6IHZvaWQge1xuICAgIHRoaXMuc2hvd24gPSBmYWxzZTtcbiAgICB0aGlzLmJ1c3kgPSBmYWxzZTtcbiAgICB0aGlzLmRvd25sb2FkaW5nID0gZmFsc2U7XG4gICAgdGhpcy5wcm9ncmVzcyA9IDA7XG4gICAgdGhpcy5tZXNzYWdlcy5jbGVhcih0aGlzLnRvYXN0S2V5KTtcbiAgICB0aGlzLmNoYW5nZWQoKTtcbiAgfVxuXG4gIHByaXZhdGUgb25Qcm9ncmVzcyhmOiBudW1iZXIpOiB2b2lkIHtcbiAgICB0aGlzLmRvd25sb2FkaW5nID0gZiA+PSAwICYmIGYgPCAxO1xuICAgIGlmIChmID49IDApIHRoaXMucHJvZ3Jlc3MgPSBNYXRoLm1pbigxMDAsIE1hdGgucm91bmQoZiAqIDEwMCkpO1xuICAgIHRoaXMuY2hhbmdlZCgpO1xuICB9XG59XG4iXX0=
|
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
import { ChangeDetectionStrategy, Component, EventEmitter, Input, Output, } from '@angular/core';
|
|
2
|
+
import { CommonModule } from '@angular/common';
|
|
3
|
+
import { SharedModule } from 'primeng/api';
|
|
4
|
+
import { ButtonModule } from 'primeng/button';
|
|
5
|
+
import { MenuModule } from 'primeng/menu';
|
|
6
|
+
import { TooltipModule } from 'primeng/tooltip';
|
|
7
|
+
import { MODEL_INFO } from '../model-info';
|
|
8
|
+
import * as i0 from "@angular/core";
|
|
9
|
+
import * as i1 from "@angular/common";
|
|
10
|
+
import * as i2 from "primeng/api";
|
|
11
|
+
import * as i3 from "primeng/button";
|
|
12
|
+
import * as i4 from "primeng/menu";
|
|
13
|
+
import * as i5 from "primeng/tooltip";
|
|
14
|
+
/**
|
|
15
|
+
* The toolbar's segmentation group: SAM box prompt, SAM point prompts and the
|
|
16
|
+
* shared SAM model picker, cellpose, and the contributed no-prompt tools (run,
|
|
17
|
+
* pick checkpoint, parameters). Presentational: the host runs every action.
|
|
18
|
+
*/
|
|
19
|
+
export class SegmentationToolsComponent {
|
|
20
|
+
constructor() {
|
|
21
|
+
/** The armed tool's mode (`samPoint` highlights the point-prompt button), or null. */
|
|
22
|
+
this.activeDragMode = null;
|
|
23
|
+
/** SAM model picker options + current selection (jit-ui#90 P1). */
|
|
24
|
+
this.samModels = [];
|
|
25
|
+
/** The selected SAM model id. */
|
|
26
|
+
this.samModelId = '';
|
|
27
|
+
/** Contributed no-prompt tools, already filtered and sorted by the host. */
|
|
28
|
+
this.contributedTools = [];
|
|
29
|
+
/** Active checkpoint per contributed tool, keyed by tool id. */
|
|
30
|
+
this.toolModelIds = {};
|
|
31
|
+
/** Run box-prompted SAM segmentation on the drawn rectangles (jit-ui#90). */
|
|
32
|
+
this.segmentRegions = new EventEmitter();
|
|
33
|
+
/** Run cellpose-SAM (auto) inside each drawn rectangle's crop (jit-ui#90). */
|
|
34
|
+
this.segmentCellpose = new EventEmitter();
|
|
35
|
+
/** The SAM point tool's toggle ('samPoint'). */
|
|
36
|
+
this.toggleDragMode = new EventEmitter();
|
|
37
|
+
/** A SAM model was picked from the model menu (its id). */
|
|
38
|
+
this.samModelChange = new EventEmitter();
|
|
39
|
+
/** Run a contributed tool over the current view (its id). */
|
|
40
|
+
this.runTool = new EventEmitter();
|
|
41
|
+
/** A contributed tool's checkpoint was picked. */
|
|
42
|
+
this.toolModelChange = new EventEmitter();
|
|
43
|
+
/** Open a contributed tool's parameter dialog (its id). */
|
|
44
|
+
this.openToolParams = new EventEmitter();
|
|
45
|
+
/** Model picker for the Segment button's dropdown menu. The active model
|
|
46
|
+
* (`samModelId`) is marked with a check; selecting an item emits
|
|
47
|
+
* `samModelChange` (jit-ui#90 P1).
|
|
48
|
+
*
|
|
49
|
+
* Held as a stable array (rebuilt only when `samModels`/`samModelId` change),
|
|
50
|
+
* NOT a getter: a getter returns a fresh array with new `command` closures on
|
|
51
|
+
* every change-detection tick, which makes the bound `p-menu` overlay rebuild
|
|
52
|
+
* its DOM mid-interaction and swallow the click on a menu item.
|
|
53
|
+
*
|
|
54
|
+
* `tooltip` carries the model's description from {@link MODEL_INFO}; the
|
|
55
|
+
* menus' shared item template turns it into the hover info icon. p-menu's own
|
|
56
|
+
* rendering ignores the field (it reads `item.title`), so it is free to use. */
|
|
57
|
+
this.samMenuItems = [];
|
|
58
|
+
/**
|
|
59
|
+
* Model menus for the contributed tools, keyed by tool id. Same stable-array
|
|
60
|
+
* reasoning as {@link samMenuItems} — and it is why this is a map rebuilt in
|
|
61
|
+
* `ngOnChanges` rather than a method called from the template, which would
|
|
62
|
+
* hand `p-menu` a new array every tick.
|
|
63
|
+
*
|
|
64
|
+
* A contributed tool supplies its own per-model description, so unlike the
|
|
65
|
+
* SAM menu these do not consult {@link MODEL_INFO}: this library has no
|
|
66
|
+
* copy for checkpoints it does not know about.
|
|
67
|
+
*/
|
|
68
|
+
this.toolMenuItems = {};
|
|
69
|
+
}
|
|
70
|
+
ngOnChanges(changes) {
|
|
71
|
+
if (changes['samModels'] || changes['samModelId']) {
|
|
72
|
+
this.samMenuItems = this.samModels.map((m) => ({
|
|
73
|
+
label: m.label,
|
|
74
|
+
icon: m.id === this.samModelId ? 'pi pi-check' : 'pi pi-fw',
|
|
75
|
+
tooltip: MODEL_INFO[m.id],
|
|
76
|
+
infoLabel: this.infoLabel(m.label, MODEL_INFO[m.id]),
|
|
77
|
+
command: () => this.samModelChange.emit(m.id),
|
|
78
|
+
}));
|
|
79
|
+
}
|
|
80
|
+
if (changes['contributedTools'] || changes['toolModelIds']) {
|
|
81
|
+
this.toolMenuItems = {};
|
|
82
|
+
for (const tool of this.contributedTools) {
|
|
83
|
+
const active = this.toolModelIds[tool.id] ?? tool.defaultModelId();
|
|
84
|
+
this.toolMenuItems[tool.id] = tool.models().map((m) => ({
|
|
85
|
+
label: m.label,
|
|
86
|
+
icon: m.id === active ? 'pi pi-check' : 'pi pi-fw',
|
|
87
|
+
tooltip: m.info,
|
|
88
|
+
infoLabel: this.infoLabel(m.label, m.info),
|
|
89
|
+
command: () => this.toolModelChange.emit({ toolId: tool.id, modelId: m.id }),
|
|
90
|
+
}));
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* Strip markup from a model description so it can be read aloud.
|
|
96
|
+
*
|
|
97
|
+
* The copy in MODEL_INFO and in a contribution's `ToolModelOption.info` is
|
|
98
|
+
* written for a visual tooltip rendered with `[escape]="false"`, so it carries
|
|
99
|
+
* `<b>` and `<br>`. Passed to `aria-label` verbatim a screen reader announces
|
|
100
|
+
* the tags, so they are removed and `<br>` becomes a sentence break. Entities
|
|
101
|
+
* used in that copy (` `, `×`, `&`) are decoded for the same
|
|
102
|
+
* reason.
|
|
103
|
+
*/
|
|
104
|
+
plainText(html) {
|
|
105
|
+
return (html ?? '')
|
|
106
|
+
.replace(/<br\s*\/?>/gi, '. ')
|
|
107
|
+
.replace(/<[^>]+>/g, '')
|
|
108
|
+
.replace(/ /g, ' ')
|
|
109
|
+
.replace(/×/g, 'x')
|
|
110
|
+
.replace(/&/g, '&')
|
|
111
|
+
.replace(/\s+/g, ' ')
|
|
112
|
+
.trim();
|
|
113
|
+
}
|
|
114
|
+
/** The info button's `aria-label` (`infoLabel` on a menu item), built once with the
|
|
115
|
+
* menu rather than by a template call on every check; none without a description. */
|
|
116
|
+
infoLabel(label, info) {
|
|
117
|
+
return info ? `About ${label}: ${this.plainText(info)}` : undefined;
|
|
118
|
+
}
|
|
119
|
+
/** Keeps each contributed tool's `p-menu` overlay alive across CD ticks —
|
|
120
|
+
* re-creating it mid-interaction swallows the click on a menu item. */
|
|
121
|
+
trackToolById(_index, tool) {
|
|
122
|
+
return tool.id;
|
|
123
|
+
}
|
|
124
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.9", ngImport: i0, type: SegmentationToolsComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
125
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "17.3.9", type: SegmentationToolsComponent, isStandalone: true, selector: "toolbar-segmentation-tools", inputs: { activeDragMode: "activeDragMode", samModels: "samModels", samModelId: "samModelId", contributedTools: "contributedTools", toolModelIds: "toolModelIds" }, outputs: { segmentRegions: "segmentRegions", segmentCellpose: "segmentCellpose", toggleDragMode: "toggleDragMode", samModelChange: "samModelChange", runTool: "runTool", toolModelChange: "toolModelChange", openToolParams: "openToolParams" }, usesOnChanges: true, ngImport: i0, template: "<!-- SAM (jit-ui#90): box-prompt segment, interactive point prompts, and a\n model picker. -->\n<span class=\"toolbar-separator\"></span>\n<!-- SAM controls grouped: box-prompt Segment, then the point-prompt tool,\n then the model-picker dropdown (the chevron) which governs BOTH tools.\n Falls back to Segment + point with no model picker when none are set. -->\n<span *ngIf=\"samModels.length; else segmentPlain\" class=\"p-buttonset segment-split\">\n <p-button\n size=\"small\"\n [text]=\"true\"\n ariaLabel=\"Segment with SAM (box prompt)\"\n pTooltip=\"Segment the drawn rectangles with SAM (box prompt)\"\n tooltipPosition=\"bottom\"\n (onClick)=\"segmentRegions.emit()\"\n >\n <img src=\"assets/plotting/sam-box-prompt.svg\" class=\"toolbar-icon-dark\" style=\"width: 1rem\" />\n </p-button>\n <ng-container [ngTemplateOutlet]=\"samPointBtn\"></ng-container>\n <p-button\n icon=\"pi pi-chevron-down\"\n size=\"small\"\n [text]=\"true\"\n ariaLabel=\"Pick the SAM model\"\n pTooltip=\"Pick the SAM model (used by both segment tools)\"\n tooltipPosition=\"bottom\"\n (onClick)=\"samModelMenu.toggle($event)\"\n >\n </p-button>\n</span>\n<ng-template #segmentPlain>\n <span class=\"p-buttonset segment-split\">\n <p-button\n size=\"small\"\n [text]=\"true\"\n ariaLabel=\"Segment with SAM (box prompt)\"\n pTooltip=\"Segment the drawn rectangles with SAM (box prompt)\"\n tooltipPosition=\"bottom\"\n (onClick)=\"segmentRegions.emit()\"\n >\n <img src=\"assets/plotting/sam-box-prompt.svg\" class=\"toolbar-icon-dark\" style=\"width: 1rem\" />\n </p-button>\n <ng-container [ngTemplateOutlet]=\"samPointBtn\"></ng-container>\n </span>\n</ng-template>\n<!-- Point-prompt tool \u2014 shared between the models / no-models layouts so it\n always sits just left of the model dropdown. -->\n<ng-template #samPointBtn>\n <p-button\n size=\"small\"\n ariaLabel=\"SAM point prompts\"\n [text]=\"activeDragMode !== 'samPoint'\"\n pTooltip=\"SAM point prompts: click a fiber to segment it as a new region;\n Shift/Alt-click to refine (exclude) the current one.<br>Esc undoes it.\"\n [escape]=\"false\"\n tooltipPosition=\"bottom\"\n (onClick)=\"toggleDragMode.emit('samPoint')\"\n >\n <img\n src=\"assets/plotting/sam-point-prompt.svg\"\n [class]=\"activeDragMode === 'samPoint' ? 'toolbar-icon-active' : 'toolbar-icon-dark'\"\n style=\"width: 1rem\"\n />\n </p-button>\n</ng-template>\n<p-menu #samModelMenu styleClass=\"model-menu\" [model]=\"samMenuItems\" [popup]=\"true\" appendTo=\"body\">\n <ng-template pTemplate=\"item\" let-item>\n <ng-container\n [ngTemplateOutlet]=\"modelMenuItem\"\n [ngTemplateOutletContext]=\"{ $implicit: item }\"\n ></ng-container>\n </ng-template>\n</p-menu>\n\n<!-- Shared item body for all three model pickers (SAM / YOLO / retinal):\n the standard check-or-blank icon and label, plus an info icon carrying\n the model's description as a hover tooltip. This replaced a single\n \"About the SAM models\" overlay panel \u2014 per-model text sits next to the\n model it describes, and YOLO/retinal get the same affordance.\n\n p-menu puts its click handler on the wrapping `.p-menuitem-content`,\n outside this template, so `command` still fires and the whole row stays\n clickable \u2014 which is also why the info icon has to stop propagation, or\n reading about a model would switch to it. -->\n<ng-template #modelMenuItem let-item>\n <a class=\"p-menuitem-link model-menu-item\">\n <span class=\"p-menuitem-icon\" [ngClass]=\"item.icon\"></span>\n <span class=\"p-menuitem-text\">{{ item.label }}</span>\n <!-- `bottom` like every other tooltip in this toolbar, and for room:\n these menus open under buttons that can sit near the right edge,\n where a `right` tooltip has a few hundred px and squeezes its text\n into a narrow column instead of using its max-width. -->\n <!-- A focusable <button>, not a bare <i>. As an <i> the description\n was reachable only by hovering a mouse: not tabbable, no\n accessible name, nothing for a screen reader to announce \u2014 so\n keyboard and AT users could pick a checkpoint but never read what\n it was. PrimeNG's tooltip shows on focus as well as hover, so\n making it a button restores it for free.\n\n `aria-describedby` is deliberately not used: the tooltip is\n rendered into `body` on demand and has no stable id to point at.\n The description is carried on `aria-label` instead, which is\n announced whether or not the tooltip is showing. It is stripped of\n markup first, since the copy contains `<b>`/`<br>` for the visual\n tooltip and those would otherwise be read out literally. -->\n <button\n *ngIf=\"item.tooltip\"\n type=\"button\"\n class=\"pi pi-info-circle model-info-icon\"\n [attr.aria-label]=\"item.infoLabel\"\n [pTooltip]=\"item.tooltip\"\n [escape]=\"false\"\n tooltipPosition=\"bottom\"\n appendTo=\"body\"\n tooltipStyleClass=\"model-info-tooltip\"\n (click)=\"$event.stopPropagation()\"\n (keydown.enter)=\"$event.stopPropagation()\"\n (keydown.space)=\"$event.stopPropagation()\"\n ></button>\n </a>\n</ng-template>\n<p-button\n size=\"small\"\n [text]=\"true\"\n ariaLabel=\"Segment cells (cellpose-SAM)\"\n pTooltip=\"Auto-segment cells inside each drawn rectangle (cellpose-SAM)\"\n tooltipPosition=\"bottom\"\n (onClick)=\"segmentCellpose.emit()\"\n>\n <img src=\"assets/plotting/cells.svg\" class=\"toolbar-icon-dark\" style=\"width: 1rem\" />\n</p-button>\n\n<!-- Contributed no-prompt tools (TOOLBAR_TOOLS). Unlike the SAM and\n cellpose tools these take no prompt \u2014 they sweep the whole current\n view rather than being pointed at something \u2014 so there is nothing to\n draw first. Each renders the same split button: run, pick checkpoint,\n open parameters.\n\n Nothing here names a specific tool. The library ships none; a host\n registers them, which is what lets this package be published without\n the closed model dependencies. -->\n<ng-container *ngFor=\"let tool of contributedTools; trackBy: trackToolById\">\n <span class=\"p-buttonset segment-split\">\n <p-button\n size=\"small\"\n [text]=\"true\"\n [ariaLabel]=\"tool.label\"\n [pTooltip]=\"tool.runTooltip\"\n tooltipPosition=\"bottom\"\n (onClick)=\"runTool.emit(tool.id)\"\n >\n <!-- `toolbar-icon-dark` is hardcoded rather than bound, unlike the\n toggle tools: these fire a run and have no active state. -->\n <img\n *ngIf=\"tool.icon.src\"\n [src]=\"tool.icon.src\"\n class=\"toolbar-icon-dark\"\n style=\"width: 1rem\"\n [alt]=\"tool.label\"\n />\n <i *ngIf=\"tool.icon.pi\" class=\"pi {{ tool.icon.pi }}\"></i>\n </p-button>\n <p-button\n icon=\"pi pi-chevron-down\"\n size=\"small\"\n [text]=\"true\"\n [ariaLabel]=\"'Pick the model for ' + tool.label\"\n [pTooltip]=\"tool.modelTooltip || 'Pick the model'\"\n tooltipPosition=\"bottom\"\n (onClick)=\"toolMenu.toggle($event)\"\n >\n </p-button>\n <p-button\n *ngIf=\"tool.params.length\"\n icon=\"pi pi-sliders-h\"\n size=\"small\"\n [text]=\"true\"\n [ariaLabel]=\"'Parameters for ' + tool.label\"\n [pTooltip]=\"tool.paramsTooltip || 'Parameters'\"\n tooltipPosition=\"bottom\"\n (onClick)=\"openToolParams.emit(tool.id)\"\n >\n </p-button>\n </span>\n <p-menu #toolMenu styleClass=\"model-menu\" [model]=\"toolMenuItems[tool.id] || []\" [popup]=\"true\" appendTo=\"body\">\n <ng-template pTemplate=\"item\" let-item>\n <ng-container\n [ngTemplateOutlet]=\"modelMenuItem\"\n [ngTemplateOutletContext]=\"{ $implicit: item }\"\n ></ng-container>\n </ng-template>\n </p-menu>\n</ng-container>\n", styles: [".toolbar-text{color:var(--primary-color);font-size:.875rem}.toolbar-separator{border-left:1px solid var(--surface-border);height:1.5rem;margin:0 .25rem;align-self:center}.toolbar-icon-dark{filter:brightness(0) invert(47%) sepia(98%) saturate(567%) hue-rotate(181deg) brightness(103%) contrast(98%)}.toolbar-icon-active{filter:brightness(0) invert(1)}.wand-sensitivity-value{min-width:2rem;text-align:right}:host{display:contents}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i1.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "ngmodule", type: SharedModule }, { kind: "directive", type: i2.PrimeTemplate, selector: "[pTemplate]", inputs: ["type", "pTemplate"] }, { kind: "ngmodule", type: ButtonModule }, { kind: "component", type: i3.Button, selector: "p-button", inputs: ["type", "iconPos", "icon", "badge", "label", "disabled", "loading", "loadingIcon", "raised", "rounded", "text", "plain", "severity", "outlined", "link", "tabindex", "size", "style", "styleClass", "badgeClass", "ariaLabel", "autofocus"], outputs: ["onClick", "onFocus", "onBlur"] }, { kind: "ngmodule", type: MenuModule }, { kind: "component", type: i4.Menu, selector: "p-menu", inputs: ["model", "popup", "style", "styleClass", "appendTo", "autoZIndex", "baseZIndex", "showTransitionOptions", "hideTransitionOptions", "ariaLabel", "ariaLabelledBy", "id", "tabindex"], outputs: ["onShow", "onHide", "onBlur", "onFocus"] }, { kind: "directive", type: i5.Tooltip, selector: "[pTooltip]", inputs: ["tooltipPosition", "tooltipEvent", "appendTo", "positionStyle", "tooltipStyleClass", "tooltipZIndex", "escape", "showDelay", "hideDelay", "life", "positionTop", "positionLeft", "autoHide", "fitContent", "hideOnEscape", "pTooltip", "tooltipDisabled", "tooltipOptions"] }, { kind: "ngmodule", type: TooltipModule }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
|
126
|
+
}
|
|
127
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.9", ngImport: i0, type: SegmentationToolsComponent, decorators: [{
|
|
128
|
+
type: Component,
|
|
129
|
+
args: [{ selector: 'toolbar-segmentation-tools', standalone: true, imports: [CommonModule, SharedModule, ButtonModule, MenuModule, TooltipModule], changeDetection: ChangeDetectionStrategy.OnPush, template: "<!-- SAM (jit-ui#90): box-prompt segment, interactive point prompts, and a\n model picker. -->\n<span class=\"toolbar-separator\"></span>\n<!-- SAM controls grouped: box-prompt Segment, then the point-prompt tool,\n then the model-picker dropdown (the chevron) which governs BOTH tools.\n Falls back to Segment + point with no model picker when none are set. -->\n<span *ngIf=\"samModels.length; else segmentPlain\" class=\"p-buttonset segment-split\">\n <p-button\n size=\"small\"\n [text]=\"true\"\n ariaLabel=\"Segment with SAM (box prompt)\"\n pTooltip=\"Segment the drawn rectangles with SAM (box prompt)\"\n tooltipPosition=\"bottom\"\n (onClick)=\"segmentRegions.emit()\"\n >\n <img src=\"assets/plotting/sam-box-prompt.svg\" class=\"toolbar-icon-dark\" style=\"width: 1rem\" />\n </p-button>\n <ng-container [ngTemplateOutlet]=\"samPointBtn\"></ng-container>\n <p-button\n icon=\"pi pi-chevron-down\"\n size=\"small\"\n [text]=\"true\"\n ariaLabel=\"Pick the SAM model\"\n pTooltip=\"Pick the SAM model (used by both segment tools)\"\n tooltipPosition=\"bottom\"\n (onClick)=\"samModelMenu.toggle($event)\"\n >\n </p-button>\n</span>\n<ng-template #segmentPlain>\n <span class=\"p-buttonset segment-split\">\n <p-button\n size=\"small\"\n [text]=\"true\"\n ariaLabel=\"Segment with SAM (box prompt)\"\n pTooltip=\"Segment the drawn rectangles with SAM (box prompt)\"\n tooltipPosition=\"bottom\"\n (onClick)=\"segmentRegions.emit()\"\n >\n <img src=\"assets/plotting/sam-box-prompt.svg\" class=\"toolbar-icon-dark\" style=\"width: 1rem\" />\n </p-button>\n <ng-container [ngTemplateOutlet]=\"samPointBtn\"></ng-container>\n </span>\n</ng-template>\n<!-- Point-prompt tool \u2014 shared between the models / no-models layouts so it\n always sits just left of the model dropdown. -->\n<ng-template #samPointBtn>\n <p-button\n size=\"small\"\n ariaLabel=\"SAM point prompts\"\n [text]=\"activeDragMode !== 'samPoint'\"\n pTooltip=\"SAM point prompts: click a fiber to segment it as a new region;\n Shift/Alt-click to refine (exclude) the current one.<br>Esc undoes it.\"\n [escape]=\"false\"\n tooltipPosition=\"bottom\"\n (onClick)=\"toggleDragMode.emit('samPoint')\"\n >\n <img\n src=\"assets/plotting/sam-point-prompt.svg\"\n [class]=\"activeDragMode === 'samPoint' ? 'toolbar-icon-active' : 'toolbar-icon-dark'\"\n style=\"width: 1rem\"\n />\n </p-button>\n</ng-template>\n<p-menu #samModelMenu styleClass=\"model-menu\" [model]=\"samMenuItems\" [popup]=\"true\" appendTo=\"body\">\n <ng-template pTemplate=\"item\" let-item>\n <ng-container\n [ngTemplateOutlet]=\"modelMenuItem\"\n [ngTemplateOutletContext]=\"{ $implicit: item }\"\n ></ng-container>\n </ng-template>\n</p-menu>\n\n<!-- Shared item body for all three model pickers (SAM / YOLO / retinal):\n the standard check-or-blank icon and label, plus an info icon carrying\n the model's description as a hover tooltip. This replaced a single\n \"About the SAM models\" overlay panel \u2014 per-model text sits next to the\n model it describes, and YOLO/retinal get the same affordance.\n\n p-menu puts its click handler on the wrapping `.p-menuitem-content`,\n outside this template, so `command` still fires and the whole row stays\n clickable \u2014 which is also why the info icon has to stop propagation, or\n reading about a model would switch to it. -->\n<ng-template #modelMenuItem let-item>\n <a class=\"p-menuitem-link model-menu-item\">\n <span class=\"p-menuitem-icon\" [ngClass]=\"item.icon\"></span>\n <span class=\"p-menuitem-text\">{{ item.label }}</span>\n <!-- `bottom` like every other tooltip in this toolbar, and for room:\n these menus open under buttons that can sit near the right edge,\n where a `right` tooltip has a few hundred px and squeezes its text\n into a narrow column instead of using its max-width. -->\n <!-- A focusable <button>, not a bare <i>. As an <i> the description\n was reachable only by hovering a mouse: not tabbable, no\n accessible name, nothing for a screen reader to announce \u2014 so\n keyboard and AT users could pick a checkpoint but never read what\n it was. PrimeNG's tooltip shows on focus as well as hover, so\n making it a button restores it for free.\n\n `aria-describedby` is deliberately not used: the tooltip is\n rendered into `body` on demand and has no stable id to point at.\n The description is carried on `aria-label` instead, which is\n announced whether or not the tooltip is showing. It is stripped of\n markup first, since the copy contains `<b>`/`<br>` for the visual\n tooltip and those would otherwise be read out literally. -->\n <button\n *ngIf=\"item.tooltip\"\n type=\"button\"\n class=\"pi pi-info-circle model-info-icon\"\n [attr.aria-label]=\"item.infoLabel\"\n [pTooltip]=\"item.tooltip\"\n [escape]=\"false\"\n tooltipPosition=\"bottom\"\n appendTo=\"body\"\n tooltipStyleClass=\"model-info-tooltip\"\n (click)=\"$event.stopPropagation()\"\n (keydown.enter)=\"$event.stopPropagation()\"\n (keydown.space)=\"$event.stopPropagation()\"\n ></button>\n </a>\n</ng-template>\n<p-button\n size=\"small\"\n [text]=\"true\"\n ariaLabel=\"Segment cells (cellpose-SAM)\"\n pTooltip=\"Auto-segment cells inside each drawn rectangle (cellpose-SAM)\"\n tooltipPosition=\"bottom\"\n (onClick)=\"segmentCellpose.emit()\"\n>\n <img src=\"assets/plotting/cells.svg\" class=\"toolbar-icon-dark\" style=\"width: 1rem\" />\n</p-button>\n\n<!-- Contributed no-prompt tools (TOOLBAR_TOOLS). Unlike the SAM and\n cellpose tools these take no prompt \u2014 they sweep the whole current\n view rather than being pointed at something \u2014 so there is nothing to\n draw first. Each renders the same split button: run, pick checkpoint,\n open parameters.\n\n Nothing here names a specific tool. The library ships none; a host\n registers them, which is what lets this package be published without\n the closed model dependencies. -->\n<ng-container *ngFor=\"let tool of contributedTools; trackBy: trackToolById\">\n <span class=\"p-buttonset segment-split\">\n <p-button\n size=\"small\"\n [text]=\"true\"\n [ariaLabel]=\"tool.label\"\n [pTooltip]=\"tool.runTooltip\"\n tooltipPosition=\"bottom\"\n (onClick)=\"runTool.emit(tool.id)\"\n >\n <!-- `toolbar-icon-dark` is hardcoded rather than bound, unlike the\n toggle tools: these fire a run and have no active state. -->\n <img\n *ngIf=\"tool.icon.src\"\n [src]=\"tool.icon.src\"\n class=\"toolbar-icon-dark\"\n style=\"width: 1rem\"\n [alt]=\"tool.label\"\n />\n <i *ngIf=\"tool.icon.pi\" class=\"pi {{ tool.icon.pi }}\"></i>\n </p-button>\n <p-button\n icon=\"pi pi-chevron-down\"\n size=\"small\"\n [text]=\"true\"\n [ariaLabel]=\"'Pick the model for ' + tool.label\"\n [pTooltip]=\"tool.modelTooltip || 'Pick the model'\"\n tooltipPosition=\"bottom\"\n (onClick)=\"toolMenu.toggle($event)\"\n >\n </p-button>\n <p-button\n *ngIf=\"tool.params.length\"\n icon=\"pi pi-sliders-h\"\n size=\"small\"\n [text]=\"true\"\n [ariaLabel]=\"'Parameters for ' + tool.label\"\n [pTooltip]=\"tool.paramsTooltip || 'Parameters'\"\n tooltipPosition=\"bottom\"\n (onClick)=\"openToolParams.emit(tool.id)\"\n >\n </p-button>\n </span>\n <p-menu #toolMenu styleClass=\"model-menu\" [model]=\"toolMenuItems[tool.id] || []\" [popup]=\"true\" appendTo=\"body\">\n <ng-template pTemplate=\"item\" let-item>\n <ng-container\n [ngTemplateOutlet]=\"modelMenuItem\"\n [ngTemplateOutletContext]=\"{ $implicit: item }\"\n ></ng-container>\n </ng-template>\n </p-menu>\n</ng-container>\n", styles: [".toolbar-text{color:var(--primary-color);font-size:.875rem}.toolbar-separator{border-left:1px solid var(--surface-border);height:1.5rem;margin:0 .25rem;align-self:center}.toolbar-icon-dark{filter:brightness(0) invert(47%) sepia(98%) saturate(567%) hue-rotate(181deg) brightness(103%) contrast(98%)}.toolbar-icon-active{filter:brightness(0) invert(1)}.wand-sensitivity-value{min-width:2rem;text-align:right}:host{display:contents}\n"] }]
|
|
130
|
+
}], propDecorators: { activeDragMode: [{
|
|
131
|
+
type: Input
|
|
132
|
+
}], samModels: [{
|
|
133
|
+
type: Input
|
|
134
|
+
}], samModelId: [{
|
|
135
|
+
type: Input
|
|
136
|
+
}], contributedTools: [{
|
|
137
|
+
type: Input
|
|
138
|
+
}], toolModelIds: [{
|
|
139
|
+
type: Input
|
|
140
|
+
}], segmentRegions: [{
|
|
141
|
+
type: Output
|
|
142
|
+
}], segmentCellpose: [{
|
|
143
|
+
type: Output
|
|
144
|
+
}], toggleDragMode: [{
|
|
145
|
+
type: Output
|
|
146
|
+
}], samModelChange: [{
|
|
147
|
+
type: Output
|
|
148
|
+
}], runTool: [{
|
|
149
|
+
type: Output
|
|
150
|
+
}], toolModelChange: [{
|
|
151
|
+
type: Output
|
|
152
|
+
}], openToolParams: [{
|
|
153
|
+
type: Output
|
|
154
|
+
}] } });
|
|
155
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic2VnbWVudGF0aW9uLXRvb2xzLmNvbXBvbmVudC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uLy4uL3NyYy9saWIvdG9vbGJhci9zZWdtZW50YXRpb24tdG9vbHMvc2VnbWVudGF0aW9uLXRvb2xzLmNvbXBvbmVudC50cyIsIi4uLy4uLy4uLy4uLy4uL3NyYy9saWIvdG9vbGJhci9zZWdtZW50YXRpb24tdG9vbHMvc2VnbWVudGF0aW9uLXRvb2xzLmNvbXBvbmVudC5odG1sIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sRUFDTCx1QkFBdUIsRUFDdkIsU0FBUyxFQUNULFlBQVksRUFDWixLQUFLLEVBRUwsTUFBTSxHQUVQLE1BQU0sZUFBZSxDQUFDO0FBQ3ZCLE9BQU8sRUFBRSxZQUFZLEVBQUUsTUFBTSxpQkFBaUIsQ0FBQztBQUMvQyxPQUFPLEVBQVksWUFBWSxFQUFFLE1BQU0sYUFBYSxDQUFDO0FBQ3JELE9BQU8sRUFBRSxZQUFZLEVBQUUsTUFBTSxnQkFBZ0IsQ0FBQztBQUM5QyxPQUFPLEVBQUUsVUFBVSxFQUFFLE1BQU0sY0FBYyxDQUFDO0FBQzFDLE9BQU8sRUFBRSxhQUFhLEVBQUUsTUFBTSxpQkFBaUIsQ0FBQztBQUdoRCxPQUFPLEVBQUUsVUFBVSxFQUFFLE1BQU0sZUFBZSxDQUFDOzs7Ozs7O0FBRTNDOzs7O0dBSUc7QUFTSCxNQUFNLE9BQU8sMEJBQTBCO0lBUnZDO1FBU0Usc0ZBQXNGO1FBQzdFLG1CQUFjLEdBQWtCLElBQUksQ0FBQztRQUM5QyxtRUFBbUU7UUFDMUQsY0FBUyxHQUFvQyxFQUFFLENBQUM7UUFDekQsaUNBQWlDO1FBQ3hCLGVBQVUsR0FBRyxFQUFFLENBQUM7UUFDekIsNEVBQTRFO1FBQ25FLHFCQUFnQixHQUE4QixFQUFFLENBQUM7UUFDMUQsZ0VBQWdFO1FBQ3ZELGlCQUFZLEdBQTJCLEVBQUUsQ0FBQztRQUVuRCw2RUFBNkU7UUFDbkUsbUJBQWMsR0FBRyxJQUFJLFlBQVks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TTtnQkFFRyxjQUFjO3NCQUF2QixNQUFNO2dCQUVHLGNBQWM7c0JBQXZCLE1BQU07Z0JBRUcsT0FBTztzQkFBaEIsTUFBTTtnQkFFRyxlQUFlO3NCQUF4QixNQUFNO2dCQUVHLGNBQWM7c0JBQXZCLE1BQU0iLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQge1xuICBDaGFuZ2VEZXRlY3Rpb25TdHJhdGVneSxcbiAgQ29tcG9uZW50LFxuICBFdmVudEVtaXR0ZXIsXG4gIElucHV0LFxuICBPbkNoYW5nZXMsXG4gIE91dHB1dCxcbiAgU2ltcGxlQ2hhbmdlcyxcbn0gZnJvbSAnQGFuZ3VsYXIvY29yZSc7XG5pbXBvcnQgeyBDb21tb25Nb2R1bGUgfSBmcm9tICdAYW5ndWxhci9jb21tb24nO1xuaW1wb3J0IHsgTWVudUl0ZW0sIFNoYXJlZE1vZHVsZSB9IGZyb20gJ3ByaW1lbmcvYXBpJztcbmltcG9ydCB7IEJ1dHRvbk1vZHVsZSB9IGZyb20gJ3ByaW1lbmcvYnV0dG9uJztcbmltcG9ydCB7IE1lbnVNb2R1bGUgfSBmcm9tICdwcmltZW5nL21lbnUnO1xuaW1wb3J0IHsgVG9vbHRpcE1vZHVsZSB9IGZyb20gJ3ByaW1lbmcvdG9vbHRpcCc7XG5cbmltcG9ydCB7IFRvb2xiYXJUb29sQ29udHJpYnV0aW9uIH0gZnJvbSAnLi4vLi4vY29udHJhY3RzL3Rvb2xiYXItdG9vbC5jb250cmFjdCc7XG5pbXBvcnQgeyBNT0RFTF9JTkZPIH0gZnJvbSAnLi4vbW9kZWwtaW5mbyc7XG5cbi8qKlxuICogVGhlIHRvb2xiYXIncyBzZWdtZW50YXRpb24gZ3JvdXA6IFNBTSBib3ggcHJvbXB0LCBTQU0gcG9pbnQgcHJvbXB0cyBhbmQgdGhlXG4gKiBzaGFyZWQgU0FNIG1vZGVsIHBpY2tlciwgY2VsbHBvc2UsIGFuZCB0aGUgY29udHJpYnV0ZWQgbm8tcHJvbXB0IHRvb2xzIChydW4sXG4gKiBwaWNrIGNoZWNrcG9pbnQsIHBhcmFtZXRlcnMpLiBQcmVzZW50YXRpb25hbDogdGhlIGhvc3QgcnVucyBldmVyeSBhY3Rpb24uXG4gKi9cbkBDb21wb25lbnQoe1xuICBzZWxlY3RvcjogJ3Rvb2xiYXItc2VnbWVudGF0aW9uLXRvb2xzJyxcbiAgc3RhbmRhbG9uZTogdHJ1ZSxcbiAgaW1wb3J0czogW0NvbW1vbk1vZHVsZSwgU2hhcmVkTW9kdWxlLCBCdXR0b25Nb2R1bGUsIE1lbnVNb2R1bGUsIFRvb2x0aXBNb2R1bGVdLFxuICB0ZW1wbGF0ZVVybDogJy4vc2VnbWVudGF0aW9uLXRvb2xzLmNvbXBvbmVudC5odG1sJyxcbiAgc3R5bGVVcmxzOiBbJy4vc2VnbWVudGF0aW9uLXRvb2xzLmNvbXBvbmVudC5zY3NzJ10sXG4gIGNoYW5nZURldGVjdGlvbjogQ2hhbmdlRGV0ZWN0aW9uU3RyYXRlZ3kuT25QdXNoLFxufSlcbmV4cG9ydCBjbGFzcyBTZWdtZW50YXRpb25Ub29sc0NvbXBvbmVudCBpbXBsZW1lbnRzIE9uQ2hhbmdlcyB7XG4gIC8qKiBUaGUgYXJtZWQgdG9vbCdzIG1vZGUgKGBzYW1Qb2ludGAgaGlnaGxpZ2h0cyB0aGUgcG9pbnQtcHJvbXB0IGJ1dHRvbiksIG9yIG51bGwuICovXG4gIEBJbnB1dCgpIGFjdGl2ZURyYWdNb2RlOiBzdHJpbmcgfCBudWxsID0gbnVsbDtcbiAgLyoqIFNBTSBtb2RlbCBwaWNrZXIgb3B0aW9ucyArIGN1cnJlbnQgc2VsZWN0aW9uIChqaXQtdWkjOTAgUDEpLiAqL1xuICBASW5wdXQoKSBzYW1Nb2RlbHM6IHsgaWQ6IHN0cmluZzsgbGFiZWw6IHN0cmluZyB9W10gPSBbXTtcbiAgLyoqIFRoZSBzZWxlY3RlZCBTQU0gbW9kZWwgaWQuICovXG4gIEBJbnB1dCgpIHNhbU1vZGVsSWQgPSAnJztcbiAgLyoqIENvbnRyaWJ1dGVkIG5vLXByb21wdCB0b29scywgYWxyZWFkeSBmaWx0ZXJlZCBhbmQgc29ydGVkIGJ5IHRoZSBob3N0LiAqL1xuICBASW5wdXQoKSBjb250cmlidXRlZFRvb2xzOiBUb29sYmFyVG9vbENvbnRyaWJ1dGlvbltdID0gW107XG4gIC8qKiBBY3RpdmUgY2hlY2twb2ludCBwZXIgY29udHJpYnV0ZWQgdG9vbCwga2V5ZWQgYnkgdG9vbCBpZC4gKi9cbiAgQElucHV0KCkgdG9vbE1vZGVsSWRzOiBSZWNvcmQ8c3RyaW5nLCBzdHJpbmc+ID0ge307XG5cbiAgLyoqIFJ1biBib3gtcHJvbXB0ZWQgU0FNIHNlZ21lbnRhdGlvbiBvbiB0aGUgZHJhd24gcmVjdGFuZ2xlcyAoaml0LXVpIzkwKS4gKi9cbiAgQE91dHB1dCgpIHNlZ21lbnRSZWdpb25zID0gbmV3IEV2ZW50RW1pdHRlcjx2b2lkPigpO1xuICAvKiogUnVuIGNlbGxwb3NlLVNBTSAoYXV0bykgaW5zaWRlIGVhY2ggZHJhd24gcmVjdGFuZ2xlJ3MgY3JvcCAoaml0LXVpIzkwKS4gKi9cbiAgQE91dHB1dCgpIHNlZ21lbnRDZWxscG9zZSA9IG5ldyBFdmVudEVtaXR0ZXI8dm9pZD4oKTtcbiAgLyoqIFRoZSBTQU0gcG9pbnQgdG9vbCdzIHRvZ2dsZSAoJ3NhbVBvaW50JykuICovXG4gIEBPdXRwdXQoKSB0b2dnbGVEcmFnTW9kZSA9IG5ldyBFdmVudEVtaXR0ZXI8c3RyaW5nPigpO1xuICAvKiogQSBTQU0gbW9kZWwgd2FzIHBpY2tlZCBmcm9tIHRoZSBtb2RlbCBtZW51IChpdHMgaWQpLiAqL1xuICBAT3V0cHV0KCkgc2FtTW9kZWxDaGFuZ2UgPSBuZXcgRXZlbnRFbWl0dGVyPHN0cmluZz4oKTtcbiAgLyoqIFJ1biBhIGNvbnRyaWJ1dGVkIHRvb2wgb3ZlciB0aGUgY3VycmVudCB2aWV3IChpdHMgaWQpLiAqL1xuICBAT3V0cHV0KCkgcnVuVG9vbCA9IG5ldyBFdmVudEVtaXR0ZXI8c3RyaW5nPigpO1xuICAvKiogQSBjb250cmlidXRlZCB0b29sJ3MgY2hlY2twb2ludCB3YXMgcGlja2VkLiAqL1xuICBAT3V0cHV0KCkgdG9vbE1vZGVsQ2hhbmdlID0gbmV3IEV2ZW50RW1pdHRlcjx7IHRvb2xJZDogc3RyaW5nOyBtb2RlbElkOiBzdHJpbmcgfT4oKTtcbiAgLyoqIE9wZW4gYSBjb250cmlidXRlZCB0b29sJ3MgcGFyYW1ldGVyIGRpYWxvZyAoaXRzIGlkKS4gKi9cbiAgQE91dHB1dCgpIG9wZW5Ub29sUGFyYW1zID0gbmV3IEV2ZW50RW1pdHRlcjxzdHJpbmc+KCk7XG5cbiAgLyoqIE1vZGVsIHBpY2tlciBmb3IgdGhlIFNlZ21lbnQgYnV0dG9uJ3MgZHJvcGRvd24gbWVudS4gVGhlIGFjdGl2ZSBtb2RlbFxuICAgKiAgKGBzYW1Nb2RlbElkYCkgaXMgbWFya2VkIHdpdGggYSBjaGVjazsgc2VsZWN0aW5nIGFuIGl0ZW0gZW1pdHNcbiAgICogIGBzYW1Nb2RlbENoYW5nZWAgKGppdC11aSM5MCBQMSkuXG4gICAqXG4gICAqICBIZWxkIGFzIGEgc3RhYmxlIGFycmF5IChyZWJ1aWx0IG9ubHkgd2hlbiBgc2FtTW9kZWxzYC9gc2FtTW9kZWxJZGAgY2hhbmdlKSxcbiAgICogIE5PVCBhIGdldHRlcjogYSBnZXR0ZXIgcmV0dXJucyBhIGZyZXNoIGFycmF5IHdpdGggbmV3IGBjb21tYW5kYCBjbG9zdXJlcyBvblxuICAgKiAgZXZlcnkgY2hhbmdlLWRldGVjdGlvbiB0aWNrLCB3aGljaCBtYWtlcyB0aGUgYm91bmQgYHAtbWVudWAgb3ZlcmxheSByZWJ1aWxkXG4gICAqICBpdHMgRE9NIG1pZC1pbnRlcmFjdGlvbiBhbmQgc3dhbGxvdyB0aGUgY2xpY2sgb24gYSBtZW51IGl0ZW0uXG4gICAqXG4gICAqICBgdG9vbHRpcGAgY2FycmllcyB0aGUgbW9kZWwncyBkZXNjcmlwdGlvbiBmcm9tIHtAbGluayBNT0RFTF9JTkZPfTsgdGhlXG4gICAqICBtZW51cycgc2hhcmVkIGl0ZW0gdGVtcGxhdGUgdHVybnMgaXQgaW50byB0aGUgaG92ZXIgaW5mbyBpY29uLiBwLW1lbnUncyBvd25cbiAgICogIHJlbmRlcmluZyBpZ25vcmVzIHRoZSBmaWVsZCAoaXQgcmVhZHMgYGl0ZW0udGl0bGVgKSwgc28gaXQgaXMgZnJlZSB0byB1c2UuICovXG4gIHByb3RlY3RlZCBzYW1NZW51SXRlbXM6IE1lbnVJdGVtW10gPSBbXTtcbiAgLyoqXG4gICAqIE1vZGVsIG1lbnVzIGZvciB0aGUgY29udHJpYnV0ZWQgdG9vbHMsIGtleWVkIGJ5IHRvb2wgaWQuIFNhbWUgc3RhYmxlLWFycmF5XG4gICAqIHJlYXNvbmluZyBhcyB7QGxpbmsgc2FtTWVudUl0ZW1zfSDigJQgYW5kIGl0IGlzIHdoeSB0aGlzIGlzIGEgbWFwIHJlYnVpbHQgaW5cbiAgICogYG5nT25DaGFuZ2VzYCByYXRoZXIgdGhhbiBhIG1ldGhvZCBjYWxsZWQgZnJvbSB0aGUgdGVtcGxhdGUsIHdoaWNoIHdvdWxkXG4gICAqIGhhbmQgYHAtbWVudWAgYSBuZXcgYXJyYXkgZXZlcnkgdGljay5cbiAgICpcbiAgICogQSBjb250cmlidXRlZCB0b29sIHN1cHBsaWVzIGl0cyBvd24gcGVyLW1vZGVsIGRlc2NyaXB0aW9uLCBzbyB1bmxpa2UgdGhlXG4gICAqIFNBTSBtZW51IHRoZXNlIGRvIG5vdCBjb25zdWx0IHtAbGluayBNT0RFTF9JTkZPfTogdGhpcyBsaWJyYXJ5IGhhcyBub1xuICAgKiBjb3B5IGZvciBjaGVja3BvaW50cyBpdCBkb2VzIG5vdCBrbm93IGFib3V0LlxuICAgKi9cbiAgcHJvdGVjdGVkIHRvb2xNZW51SXRlbXM6IFJlY29yZDxzdHJpbmcsIE1lbnVJdGVtW10+ID0ge307XG5cbiAgbmdPbkNoYW5nZXMoY2hhbmdlczogU2ltcGxlQ2hhbmdlcyk6IHZvaWQge1xuICAgIGlmIChjaGFuZ2VzWydzYW1Nb2RlbHMnXSB8fCBjaGFuZ2VzWydzYW1Nb2RlbElkJ10pIHtcbiAgICAgIHRoaXMuc2FtTWVudUl0ZW1zID0gdGhpcy5zYW1Nb2RlbHMubWFwKChtKSA9PiAoe1xuICAgICAgICBsYWJlbDogbS5sYWJlbCxcbiAgICAgICAgaWNvbjogbS5pZCA9PT0gdGhpcy5zYW1Nb2RlbElkID8gJ3BpIHBpLWNoZWNrJyA6ICdwaSBwaS1mdycsXG4gICAgICAgIHRvb2x0aXA6IE1PREVMX0lORk9bbS5pZF0sXG4gICAgICAgIGluZm9MYWJlbDogdGhpcy5pbmZvTGFiZWwobS5sYWJlbCwgTU9ERUxfSU5GT1ttLmlkXSksXG4gICAgICAgIGNvbW1hbmQ6ICgpID0+IHRoaXMuc2FtTW9kZWxDaGFuZ2UuZW1pdChtLmlkKSxcbiAgICAgIH0pKTtcbiAgICB9XG4gICAgaWYgKGNoYW5nZXNbJ2NvbnRyaWJ1dGVkVG9vbHMnXSB8fCBjaGFuZ2VzWyd0b29sTW9kZWxJZHMnXSkge1xuICAgICAgdGhpcy50b29sTWVudUl0ZW1zID0ge307XG4gICAgICBmb3IgKGNvbnN0IHRvb2wgb2YgdGhpcy5jb250cmlidXRlZFRvb2xzKSB7XG4gICAgICAgIGNvbnN0IGFjdGl2ZSA9IHRoaXMudG9vbE1vZGVsSWRzW3Rvb2wuaWRdID8/IHRvb2wuZGVmYXVsdE1vZGVsSWQoKTtcbiAgICAgICAgdGhpcy50b29sTWVudUl0ZW1zW3Rvb2wuaWRdID0gdG9vbC5tb2RlbHMoKS5tYXAoKG0pID0+ICh7XG4gICAgICAgICAgbGFiZWw6IG0ubGFiZWwsXG4gICAgICAgICAgaWNvbjogbS5pZCA9PT0gYWN0aXZlID8gJ3BpIHBpLWNoZWNrJyA6ICdwaSBwaS1mdycsXG4gICAgICAgICAgdG9vbHRpcDogbS5pbmZvLFxuICAgICAgICAgIGluZm9MYWJlbDogdGhpcy5pbmZvTGFiZWwobS5sYWJlbCwgbS5pbmZvKSxcbiAgICAgICAgICBjb21tYW5kOiAoKSA9PiB0aGlzLnRvb2xNb2RlbENoYW5nZS5lbWl0KHsgdG9vbElkOiB0b29sLmlkLCBtb2RlbElkOiBtLmlkIH0pLFxuICAgICAgICB9KSk7XG4gICAgICB9XG4gICAgfVxuICB9XG5cbiAgLyoqXG4gICAqIFN0cmlwIG1hcmt1cCBmcm9tIGEgbW9kZWwgZGVzY3JpcHRpb24gc28gaXQgY2FuIGJlIHJlYWQgYWxvdWQuXG4gICAqXG4gICAqIFRoZSBjb3B5IGluIE1PREVMX0lORk8gYW5kIGluIGEgY29udHJpYnV0aW9uJ3MgYFRvb2xNb2RlbE9wdGlvbi5pbmZvYCBpc1xuICAgKiB3cml0dGVuIGZvciBhIHZpc3VhbCB0b29sdGlwIHJlbmRlcmVkIHdpdGggYFtlc2NhcGVdPVwiZmFsc2VcImAsIHNvIGl0IGNhcnJpZXNcbiAgICogYDxiPmAgYW5kIGA8YnI+YC4gUGFzc2VkIHRvIGBhcmlhLWxhYmVsYCB2ZXJiYXRpbSBhIHNjcmVlbiByZWFkZXIgYW5ub3VuY2VzXG4gICAqIHRoZSB0YWdzLCBzbyB0aGV5IGFyZSByZW1vdmVkIGFuZCBgPGJyPmAgYmVjb21lcyBhIHNlbnRlbmNlIGJyZWFrLiBFbnRpdGllc1xuICAgKiB1c2VkIGluIHRoYXQgY29weSAoYCZuYnNwO2AsIGAmdGltZXM7YCwgYCZhbXA7YCkgYXJlIGRlY29kZWQgZm9yIHRoZSBzYW1lXG4gICAqIHJlYXNvbi5cbiAgICovXG4gIHByb3RlY3RlZCBwbGFpblRleHQoaHRtbDogc3RyaW5nKTogc3RyaW5nIHtcbiAgICByZXR1cm4gKGh0bWwgPz8gJycpXG4gICAgICAucmVwbGFjZSgvPGJyXFxzKlxcLz8+L2dpLCAnLiAnKVxuICAgICAgLnJlcGxhY2UoLzxbXj5dKz4vZywgJycpXG4gICAgICAucmVwbGFjZSgvJm5ic3A7L2csICcgJylcbiAgICAgIC5yZXBsYWNlKC8mdGltZXM7L2csICd4JylcbiAgICAgIC5yZXBsYWNlKC8mYW1wOy9nLCAnJicpXG4gICAgICAucmVwbGFjZSgvXFxzKy9nLCAnICcpXG4gICAgICAudHJpbSgpO1xuICB9XG5cbiAgLyoqIFRoZSBpbmZvIGJ1dHRvbidzIGBhcmlhLWxhYmVsYCAoYGluZm9MYWJlbGAgb24gYSBtZW51IGl0ZW0pLCBidWlsdCBvbmNlIHdpdGggdGhlXG4gICAqICBtZW51IHJhdGhlciB0aGFuIGJ5IGEgdGVtcGxhdGUgY2FsbCBvbiBldmVyeSBjaGVjazsgbm9uZSB3aXRob3V0IGEgZGVzY3JpcHRpb24uICovXG4gIHByaXZhdGUgaW5mb0xhYmVsKGxhYmVsOiBzdHJpbmcsIGluZm86IHN0cmluZyB8IHVuZGVmaW5lZCk6IHN0cmluZyB8IHVuZGVmaW5lZCB7XG4gICAgcmV0dXJuIGluZm8gPyBgQWJvdXQgJHtsYWJlbH06ICR7dGhpcy5wbGFpblRleHQoaW5mbyl9YCA6IHVuZGVmaW5lZDtcbiAgfVxuXG4gIC8qKiBLZWVwcyBlYWNoIGNvbnRyaWJ1dGVkIHRvb2wncyBgcC1tZW51YCBvdmVybGF5IGFsaXZlIGFjcm9zcyBDRCB0aWNrcyDigJRcbiAgICogIHJlLWNyZWF0aW5nIGl0IG1pZC1pbnRlcmFjdGlvbiBzd2FsbG93cyB0aGUgY2xpY2sgb24gYSBtZW51IGl0ZW0uICovXG4gIHByb3RlY3RlZCB0cmFja1Rvb2xCeUlkKF9pbmRleDogbnVtYmVyLCB0b29sOiB7IGlkOiBzdHJpbmcgfSk6IHN0cmluZyB7XG4gICAgcmV0dXJuIHRvb2wuaWQ7XG4gIH1cbn1cbiIsIjwhLS0gU0FNIChqaXQtdWkjOTApOiBib3gtcHJvbXB0IHNlZ21lbnQsIGludGVyYWN0aXZlIHBvaW50IHByb21wdHMsIGFuZCBhXG4gICAgIG1vZGVsIHBpY2tlci4gLS0+XG48c3BhbiBjbGFzcz1cInRvb2xiYXItc2VwYXJhdG9yXCI+PC9zcGFuPlxuPCEtLSBTQU0gY29udHJvbHMgZ3JvdXBlZDogYm94LXByb21wdCBTZWdtZW50LCB0aGVuIHRoZSBwb2ludC1wcm9tcHQgdG9vbCxcbiAgICAgdGhlbiB0aGUgbW9kZWwtcGlja2VyIGRyb3Bkb3duICh0aGUgY2hldnJvbikgd2hpY2ggZ292ZXJucyBCT1RIIHRvb2xzLlxuICAgICBGYWxscyBiYWNrIHRvIFNlZ21lbnQgKyBwb2ludCB3aXRoIG5vIG1vZGVsIHBpY2tlciB3aGVuIG5vbmUgYXJlIHNldC4gLS0+XG48c3BhbiAqbmdJZj1cInNhbU1vZGVscy5sZW5ndGg7IGVsc2Ugc2VnbWVudFBsYWluXCIgY2xhc3M9XCJwLWJ1dHRvbnNldCBzZWdtZW50LXNwbGl0XCI+XG4gIDxwLWJ1dHRvblxuICAgIHNpemU9XCJzbWFsbFwiXG4gICAgW3RleHRdPVwidHJ1ZVwiXG4gICAgYXJpYUxhYmVsPVwiU2VnbWVudCB3aXRoIFNBTSAoYm94IHByb21wdClcIlxuICAgIHBUb29sdGlwPVwiU2VnbWVudCB0aGUgZHJhd24gcmVjdGFuZ2xlcyB3aXRoIFNBTSAoYm94IHByb21wdClcIlxuICAgIHRvb2x0aXBQb3NpdGlvbj1cImJvdHRvbVwiXG4gICAgKG9uQ2xpY2spPVwic2VnbWVudFJlZ2lvbnMuZW1pdCgpXCJcbiAgPlxuICAgIDxpbWcgc3JjPVwiYXNzZXRzL3Bsb3R0aW5nL3NhbS1ib3gtcHJvbXB0LnN2Z1wiIGNsYXNzPVwidG9vbGJhci1pY29uLWRhcmtcIiBzdHlsZT1cIndpZHRoOiAxcmVtXCIgLz5cbiAgPC9wLWJ1dHRvbj5cbiAgPG5nLWNvbnRhaW5lciBbbmdUZW1wbGF0ZU91dGxldF09XCJzYW1Qb2ludEJ0blwiPjwvbmctY29udGFpbmVyPlxuICA8cC1idXR0b25cbiAgICBpY29uPVwicGkgcGktY2hldnJvbi1kb3duXCJcbiAgICBzaXplPVwic21hbGxcIlxuICAgIFt0ZXh0XT1cInRydWVcIlxuICAgIGFyaWFMYWJlbD1cIlBpY2sgdGhlIFNBTSBtb2RlbFwiXG4gICAgcFRvb2x0aXA9XCJQaWNrIHRoZSBTQU0gbW9kZWwgKHVzZWQgYnkgYm90aCBzZWdtZW50IHRvb2xzKVwiXG4gICAgdG9vbHRpcFBvc2l0aW9uPVwiYm90dG9tXCJcbiAgICAob25DbGljayk9XCJzYW1Nb2RlbE1lbnUudG9nZ2xlKCRldmVudClcIlxuICA+XG4gIDwvcC1idXR0b24+XG48L3NwYW4+XG48bmctdGVtcGxhdGUgI3NlZ21lbnRQbGFpbj5cbiAgPHNwYW4gY2xhc3M9XCJwLWJ1dHRvbnNldCBzZWdtZW50LXNwbGl0XCI+XG4gICAgPHAtYnV0dG9uXG4gICAgICBzaXplPVwic21hbGxcIlxuICAgICAgW3RleHRdPVwidHJ1ZVwiXG4gICAgICBhcmlhTGFiZWw9XCJTZWdtZW50IHdpdGggU0FNIChib3ggcHJvbXB0KVwiXG4gICAgICBwVG9vbHRpcD1cIlNlZ21lbnQgdGhlIGRyYXduIHJlY3RhbmdsZXMgd2l0aCBTQU0gKGJveCBwcm9tcHQpXCJcbiAgICAgIHRvb2x0aXBQb3NpdGlvbj1cImJvdHRvbVwiXG4gICAgICAob25DbGljayk9XCJzZWdtZW50UmVnaW9ucy5lbWl0KClcIlxuICAgID5cbiAgICAgIDxpbWcgc3JjPVwiYXNzZXRzL3Bsb3R0aW5nL3NhbS1ib3gtcHJvbXB0LnN2Z1wiIGNsYXNzPVwidG9vbGJhci1pY29uLWRhcmtcIiBzdHlsZT1cIndpZHRoOiAxcmVtXCIgLz5cbiAgICA8L3AtYnV0dG9uPlxuICAgIDxuZy1jb250YWluZXIgW25nVGVtcGxhdGVPdXRsZXRdPVwic2FtUG9pbnRCdG5cIj48L25nLWNvbnRhaW5lcj5cbiAgPC9zcGFuPlxuPC9uZy10ZW1wbGF0ZT5cbjwhLS0gUG9pbnQtcHJvbXB0IHRvb2wg4oCUIHNoYXJlZCBiZXR3ZWVuIHRoZSBtb2RlbHMgLyBuby1tb2RlbHMgbGF5b3V0cyBzbyBpdFxuICAgICBhbHdheXMgc2l0cyBqdXN0IGxlZnQgb2YgdGhlIG1vZGVsIGRyb3Bkb3duLiAtLT5cbjxuZy10ZW1wbGF0ZSAjc2FtUG9pbnRCdG4+XG4gIDxwLWJ1dHRvblxuICAgIHNpemU9XCJzbWFsbFwiXG4gICAgYXJpYUxhYmVsPVwiU0FNIHBvaW50IHByb21wdHNcIlxuICAgIFt0ZXh0XT1cImFjdGl2ZURyYWdNb2RlICE9PSAnc2FtUG9pbnQnXCJcbiAgICBwVG9vbHRpcD1cIlNBTSBwb2ludCBwcm9tcHRzOiBjbGljayBhIGZpYmVyIHRvIHNlZ21lbnQgaXQgYXMgYSBuZXcgcmVnaW9uO1xuICAgICAgICAgICAgU2hpZnQvQWx0LWNsaWNrIHRvIHJlZmluZSAoZXhjbHVkZSkgdGhlIGN1cnJlbnQgb25lLjxicj5Fc2MgdW5kb2VzIGl0LlwiXG4gICAgW2VzY2FwZV09XCJmYWxzZVwiXG4gICAgdG9vbHRpcFBvc2l0aW9uPVwiYm90dG9tXCJcbiAgICAob25DbGljayk9XCJ0b2dnbGVEcmFnTW9kZS5lbWl0KCdzYW1Qb2ludCcpXCJcbiAgPlxuICAgIDxpbWdcbiAgICAgIHNyYz1cImFzc2V0cy9wbG90dGluZy9zYW0tcG9pbnQtcHJvbXB0LnN2Z1wiXG4gICAgICBbY2xhc3NdPVwiYWN0aXZlRHJhZ01vZGUgPT09ICdzYW1Qb2ludCcgPyAndG9vbGJhci1pY29uLWFjdGl2ZScgOiAndG9vbGJhci1pY29uLWRhcmsnXCJcbiAgICAgIHN0eWxlPVwid2lkdGg6IDFyZW1cIlxuICAgIC8+XG4gIDwvcC1idXR0b24+XG48L25nLXRlbXBsYXRlPlxuPHAtbWVudSAjc2FtTW9kZWxNZW51IHN0eWxlQ2xhc3M9XCJtb2RlbC1tZW51XCIgW21vZGVsXT1cInNhbU1lbnVJdGVtc1wiIFtwb3B1cF09XCJ0cnVlXCIgYXBwZW5kVG89XCJib2R5XCI+XG4gIDxuZy10ZW1wbGF0ZSBwVGVtcGxhdGU9XCJpdGVtXCIgbGV0LWl0ZW0+XG4gICAgPG5nLWNvbnRhaW5lclxuICAgICAgW25nVGVtcGxhdGVPdXRsZXRdPVwibW9kZWxNZW51SXRlbVwiXG4gICAgICBbbmdUZW1wbGF0ZU91dGxldENvbnRleHRdPVwieyAkaW1wbGljaXQ6IGl0ZW0gfVwiXG4gICAgPjwvbmctY29udGFpbmVyPlxuICA8L25nLXRlbXBsYXRlPlxuPC9wLW1lbnU+XG5cbjwhLS0gU2hhcmVkIGl0ZW0gYm9keSBmb3IgYWxsIHRocmVlIG1vZGVsIHBpY2tlcnMgKFNBTSAvIFlPTE8gLyByZXRpbmFsKTpcbiAgICAgdGhlIHN0YW5kYXJkIGNoZWNrLW9yLWJsYW5rIGljb24gYW5kIGxhYmVsLCBwbHVzIGFuIGluZm8gaWNvbiBjYXJyeWluZ1xuICAgICB0aGUgbW9kZWwncyBkZXNjcmlwdGlvbiBhcyBhIGhvdmVyIHRvb2x0aXAuIFRoaXMgcmVwbGFjZWQgYSBzaW5nbGVcbiAgICAgXCJBYm91dCB0aGUgU0FNIG1vZGVsc1wiIG92ZXJsYXkgcGFuZWwg4oCUIHBlci1tb2RlbCB0ZXh0IHNpdHMgbmV4dCB0byB0aGVcbiAgICAgbW9kZWwgaXQgZGVzY3JpYmVzLCBhbmQgWU9MTy9yZXRpbmFsIGdldCB0aGUgc2FtZSBhZmZvcmRhbmNlLlxuXG4gICAgIHAtbWVudSBwdXRzIGl0cyBjbGljayBoYW5kbGVyIG9uIHRoZSB3cmFwcGluZyBgLnAtbWVudWl0ZW0tY29udGVudGAsXG4gICAgIG91dHNpZGUgdGhpcyB0ZW1wbGF0ZSwgc28gYGNvbW1hbmRgIHN0aWxsIGZpcmVzIGFuZCB0aGUgd2hvbGUgcm93IHN0YXlzXG4gICAgIGNsaWNrYWJsZSDigJQgd2hpY2ggaXMgYWxzbyB3aHkgdGhlIGluZm8gaWNvbiBoYXMgdG8gc3RvcCBwcm9wYWdhdGlvbiwgb3JcbiAgICAgcmVhZGluZyBhYm91dCBhIG1vZGVsIHdvdWxkIHN3aXRjaCB0byBpdC4gLS0+XG48bmctdGVtcGxhdGUgI21vZGVsTWVudUl0ZW0gbGV0LWl0ZW0+XG4gIDxhIGNsYXNzPVwicC1tZW51aXRlbS1saW5rIG1vZGVsLW1lbnUtaXRlbVwiPlxuICAgIDxzcGFuIGNsYXNzPVwicC1tZW51aXRlbS1pY29uXCIgW25nQ2xhc3NdPVwiaXRlbS5pY29uXCI+PC9zcGFuPlxuICAgIDxzcGFuIGNsYXNzPVwicC1tZW51aXRlbS10ZXh0XCI+e3sgaXRlbS5sYWJlbCB9fTwvc3Bhbj5cbiAgICA8IS0tIGBib3R0b21gIGxpa2UgZXZlcnkgb3RoZXIgdG9vbHRpcCBpbiB0aGlzIHRvb2xiYXIsIGFuZCBmb3Igcm9vbTpcbiAgICAgICAgIHRoZXNlIG1lbnVzIG9wZW4gdW5kZXIgYnV0dG9ucyB0aGF0IGNhbiBzaXQgbmVhciB0aGUgcmlnaHQgZWRnZSxcbiAgICAgICAgIHdoZXJlIGEgYHJpZ2h0YCB0b29sdGlwIGhhcyBhIGZldyBodW5kcmVkIHB4IGFuZCBzcXVlZXplcyBpdHMgdGV4dFxuICAgICAgICAgaW50byBhIG5hcnJvdyBjb2x1bW4gaW5zdGVhZCBvZiB1c2luZyBpdHMgbWF4LXdpZHRoLiAtLT5cbiAgICA8IS0tIEEgZm9jdXNhYmxlIDxidXR0b24+LCBub3QgYSBiYXJlIDxpPi4gQXMgYW4gPGk+IHRoZSBkZXNjcmlwdGlvblxuICAgICAgICAgd2FzIHJlYWNoYWJsZSBvbmx5IGJ5IGhvdmVyaW5nIGEgbW91c2U6IG5vdCB0YWJiYWJsZSwgbm9cbiAgICAgICAgIGFjY2Vzc2libGUgbmFtZSwgbm90aGluZyBmb3IgYSBzY3JlZW4gcmVhZGVyIHRvIGFubm91bmNlIOKAlCBzb1xuICAgICAgICAga2V5Ym9hcmQgYW5kIEFUIHVzZXJzIGNvdWxkIHBpY2sgYSBjaGVja3BvaW50IGJ1dCBuZXZlciByZWFkIHdoYXRcbiAgICAgICAgIGl0IHdhcy4gUHJpbWVORydzIHRvb2x0aXAgc2hvd3Mgb24gZm9jdXMgYXMgd2VsbCBhcyBob3Zlciwgc29cbiAgICAgICAgIG1ha2luZyBpdCBhIGJ1dHRvbiByZXN0b3JlcyBpdCBmb3IgZnJlZS5cblxuICAgICAgICAgYGFyaWEtZGVzY3JpYmVkYnlgIGlzIGRlbGliZXJhdGVseSBub3QgdXNlZDogdGhlIHRvb2x0aXAgaXNcbiAgICAgICAgIHJlbmRlcmVkIGludG8gYGJvZHlgIG9uIGRlbWFuZCBhbmQgaGFzIG5vIHN0YWJsZSBpZCB0byBwb2ludCBhdC5cbiAgICAgICAgIFRoZSBkZXNjcmlwdGlvbiBpcyBjYXJyaWVkIG9uIGBhcmlhLWxhYmVsYCBpbnN0ZWFkLCB3aGljaCBpc1xuICAgICAgICAgYW5ub3VuY2VkIHdoZXRoZXIgb3Igbm90IHRoZSB0b29sdGlwIGlzIHNob3dpbmcuIEl0IGlzIHN0cmlwcGVkIG9mXG4gICAgICAgICBtYXJrdXAgZmlyc3QsIHNpbmNlIHRoZSBjb3B5IGNvbnRhaW5zIGA8Yj5gL2A8YnI+YCBmb3IgdGhlIHZpc3VhbFxuICAgICAgICAgdG9vbHRpcCBhbmQgdGhvc2Ugd291bGQgb3RoZXJ3aXNlIGJlIHJlYWQgb3V0IGxpdGVyYWxseS4gLS0+XG4gICAgPGJ1dHRvblxuICAgICAgKm5nSWY9XCJpdGVtLnRvb2x0aXBcIlxuICAgICAgdHlwZT1cImJ1dHRvblwiXG4gICAgICBjbGFzcz1cInBpIHBpLWluZm8tY2lyY2xlIG1vZGVsLWluZm8taWNvblwiXG4gICAgICBbYXR0ci5hcmlhLWxhYmVsXT1cIml0ZW0uaW5mb0xhYmVsXCJcbiAgICAgIFtwVG9vbHRpcF09XCJpdGVtLnRvb2x0aXBcIlxuICAgICAgW2VzY2FwZV09XCJmYWxzZVwiXG4gICAgICB0b29sdGlwUG9zaXRpb249XCJib3R0b21cIlxuICAgICAgYXBwZW5kVG89XCJib2R5XCJcbiAgICAgIHRvb2x0aXBTdHlsZUNsYXNzPVwibW9kZWwtaW5mby10b29sdGlwXCJcbiAgICAgIChjbGljayk9XCIkZXZlbnQuc3RvcFByb3BhZ2F0aW9uKClcIlxuICAgICAgKGtleWRvd24uZW50ZXIpPVwiJGV2ZW50LnN0b3BQcm9wYWdhdGlvbigpXCJcbiAgICAgIChrZXlkb3duLnNwYWNlKT1cIiRldmVudC5zdG9wUHJvcGFnYXRpb24oKVwiXG4gICAgPjwvYnV0dG9uPlxuICA8L2E+XG48L25nLXRlbXBsYXRlPlxuPHAtYnV0dG9uXG4gIHNpemU9XCJzbWFsbFwiXG4gIFt0ZXh0XT1cInRydWVcIlxuICBhcmlhTGFiZWw9XCJTZWdtZW50IGNlbGxzIChjZWxscG9zZS1TQU0pXCJcbiAgcFRvb2x0aXA9XCJBdXRvLXNlZ21lbnQgY2VsbHMgaW5zaWRlIGVhY2ggZHJhd24gcmVjdGFuZ2xlIChjZWxscG9zZS1TQU0pXCJcbiAgdG9vbHRpcFBvc2l0aW9uPVwiYm90dG9tXCJcbiAgKG9uQ2xpY2spPVwic2VnbWVudENlbGxwb3NlLmVtaXQoKVwiXG4+XG4gIDxpbWcgc3JjPVwiYXNzZXRzL3Bsb3R0aW5nL2NlbGxzLnN2Z1wiIGNsYXNzPVwidG9vbGJhci1pY29uLWRhcmtcIiBzdHlsZT1cIndpZHRoOiAxcmVtXCIgLz5cbjwvcC1idXR0b24+XG5cbjwhLS0gQ29udHJpYnV0ZWQgbm8tcHJvbXB0IHRvb2xzIChUT09MQkFSX1RPT0xTKS4gVW5saWtlIHRoZSBTQU0gYW5kXG4gICAgIGNlbGxwb3NlIHRvb2xzIHRoZXNlIHRha2Ugbm8gcHJvbXB0IOKAlCB0aGV5IHN3ZWVwIHRoZSB3aG9sZSBjdXJyZW50XG4gICAgIHZpZXcgcmF0aGVyIHRoYW4gYmVpbmcgcG9pbnRlZCBhdCBzb21ldGhpbmcg4oCUIHNvIHRoZXJlIGlzIG5vdGhpbmcgdG9cbiAgICAgZHJhdyBmaXJzdC4gRWFjaCByZW5kZXJzIHRoZSBzYW1lIHNwbGl0IGJ1dHRvbjogcnVuLCBwaWNrIGNoZWNrcG9pbnQsXG4gICAgIG9wZW4gcGFyYW1ldGVycy5cblxuICAgICBOb3RoaW5nIGhlcmUgbmFtZXMgYSBzcGVjaWZpYyB0b29sLiBUaGUgbGlicmFyeSBzaGlwcyBub25lOyBhIGhvc3RcbiAgICAgcmVnaXN0ZXJzIHRoZW0sIHdoaWNoIGlzIHdoYXQgbGV0cyB0aGlzIHBhY2thZ2UgYmUgcHVibGlzaGVkIHdpdGhvdXRcbiAgICAgdGhlIGNsb3NlZCBtb2RlbCBkZXBlbmRlbmNpZXMuIC0tPlxuPG5nLWNvbnRhaW5lciAqbmdGb3I9XCJsZXQgdG9vbCBvZiBjb250cmlidXRlZFRvb2xzOyB0cmFja0J5OiB0cmFja1Rvb2xCeUlkXCI+XG4gIDxzcGFuIGNsYXNzPVwicC1idXR0b25zZXQgc2VnbWVudC1zcGxpdFwiPlxuICAgIDxwLWJ1dHRvblxuICAgICAgc2l6ZT1cInNtYWxsXCJcbiAgICAgIFt0ZXh0XT1cInRydWVcIlxuICAgICAgW2FyaWFMYWJlbF09XCJ0b29sLmxhYmVsXCJcbiAgICAgIFtwVG9vbHRpcF09XCJ0b29sLnJ1blRvb2x0aXBcIlxuICAgICAgdG9vbHRpcFBvc2l0aW9uPVwiYm90dG9tXCJcbiAgICAgIChvbkNsaWNrKT1cInJ1blRvb2wuZW1pdCh0b29sLmlkKVwiXG4gICAgPlxuICAgICAgPCEtLSBgdG9vbGJhci1pY29uLWRhcmtgIGlzIGhhcmRjb2RlZCByYXRoZXIgdGhhbiBib3VuZCwgdW5saWtlIHRoZVxuICAgICAgICAgICB0b2dnbGUgdG9vbHM6IHRoZXNlIGZpcmUgYSBydW4gYW5kIGhhdmUgbm8gYWN0aXZlIHN0YXRlLiAtLT5cbiAgICAgIDxpbWdcbiAgICAgICAgKm5nSWY9XCJ0b29sLmljb24uc3JjXCJcbiAgICAgICAgW3NyY109XCJ0b29sLmljb24uc3JjXCJcbiAgICAgICAgY2xhc3M9XCJ0b29sYmFyLWljb24tZGFya1wiXG4gICAgICAgIHN0eWxlPVwid2lkdGg6IDFyZW1cIlxuICAgICAgICBbYWx0XT1cInRvb2wubGFiZWxcIlxuICAgICAgLz5cbiAgICAgIDxpICpuZ0lmPVwidG9vbC5pY29uLnBpXCIgY2xhc3M9XCJwaSB7eyB0b29sLmljb24ucGkgfX1cIj48L2k+XG4gICAgPC9wLWJ1dHRvbj5cbiAgICA8cC1idXR0b25cbiAgICAgIGljb249XCJwaSBwaS1jaGV2cm9uLWRvd25cIlxuICAgICAgc2l6ZT1cInNtYWxsXCJcbiAgICAgIFt0ZXh0XT1cInRydWVcIlxuICAgICAgW2FyaWFMYWJlbF09XCInUGljayB0aGUgbW9kZWwgZm9yICcgKyB0b29sLmxhYmVsXCJcbiAgICAgIFtwVG9vbHRpcF09XCJ0b29sLm1vZGVsVG9vbHRpcCB8fCAnUGljayB0aGUgbW9kZWwnXCJcbiAgICAgIHRvb2x0aXBQb3NpdGlvbj1cImJvdHRvbVwiXG4gICAgICAob25DbGljayk9XCJ0b29sTWVudS50b2dnbGUoJGV2ZW50KVwiXG4gICAgPlxuICAgIDwvcC1idXR0b24+XG4gICAgPHAtYnV0dG9uXG4gICAgICAqbmdJZj1cInRvb2wucGFyYW1zLmxlbmd0aFwiXG4gICAgICBpY29uPVwicGkgcGktc2xpZGVycy1oXCJcbiAgICAgIHNpemU9XCJzbWFsbFwiXG4gICAgICBbdGV4dF09XCJ0cnVlXCJcbiAgICAgIFthcmlhTGFiZWxdPVwiJ1BhcmFtZXRlcnMgZm9yICcgKyB0b29sLmxhYmVsXCJcbiAgICAgIFtwVG9vbHRpcF09XCJ0b29sLnBhcmFtc1Rvb2x0aXAgfHwgJ1BhcmFtZXRlcnMnXCJcbiAgICAgIHRvb2x0aXBQb3NpdGlvbj1cImJvdHRvbVwiXG4gICAgICAob25DbGljayk9XCJvcGVuVG9vbFBhcmFtcy5lbWl0KHRvb2wuaWQpXCJcbiAgICA+XG4gICAgPC9wLWJ1dHRvbj5cbiAgPC9zcGFuPlxuICA8cC1tZW51ICN0b29sTWVudSBzdHlsZUNsYXNzPVwibW9kZWwtbWVudVwiIFttb2RlbF09XCJ0b29sTWVudUl0ZW1zW3Rvb2wuaWRdIHx8IFtdXCIgW3BvcHVwXT1cInRydWVcIiBhcHBlbmRUbz1cImJvZHlcIj5cbiAgICA8bmctdGVtcGxhdGUgcFRlbXBsYXRlPVwiaXRlbVwiIGxldC1pdGVtPlxuICAgICAgPG5nLWNvbnRhaW5lclxuICAgICAgICBbbmdUZW1wbGF0ZU91dGxldF09XCJtb2RlbE1lbnVJdGVtXCJcbiAgICAgICAgW25nVGVtcGxhdGVPdXRsZXRDb250ZXh0XT1cInsgJGltcGxpY2l0OiBpdGVtIH1cIlxuICAgICAgPjwvbmctY29udGFpbmVyPlxuICAgIDwvbmctdGVtcGxhdGU+XG4gIDwvcC1tZW51PlxuPC9uZy1jb250YWluZXI+XG4iXX0=
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import { ChangeDetectionStrategy, Component, EventEmitter, Input, Output } from '@angular/core';
|
|
2
|
+
import { CommonModule } from '@angular/common';
|
|
3
|
+
import { FormsModule } from '@angular/forms';
|
|
4
|
+
import { ButtonModule } from 'primeng/button';
|
|
5
|
+
import { InputNumberModule } from 'primeng/inputnumber';
|
|
6
|
+
import { SliderModule } from 'primeng/slider';
|
|
7
|
+
import { TooltipModule } from 'primeng/tooltip';
|
|
8
|
+
import * as i0 from "@angular/core";
|
|
9
|
+
import * as i1 from "@angular/common";
|
|
10
|
+
import * as i2 from "@angular/forms";
|
|
11
|
+
import * as i3 from "primeng/button";
|
|
12
|
+
import * as i4 from "primeng/inputnumber";
|
|
13
|
+
import * as i5 from "primeng/slider";
|
|
14
|
+
import * as i6 from "primeng/tooltip";
|
|
15
|
+
/**
|
|
16
|
+
* The toolbar's z-stack group: a live slice scrubber for the views that swap
|
|
17
|
+
* slices in place, or (Plotly heatmap) the single-image / stack toggle with a
|
|
18
|
+
* slice-number field. Presentational: the host owns `zIndex`.
|
|
19
|
+
*/
|
|
20
|
+
export class StackControlsComponent {
|
|
21
|
+
constructor() {
|
|
22
|
+
/** Show the live slice scrubber. */
|
|
23
|
+
this.liveScrubber = false;
|
|
24
|
+
/** Show the single-image / stack toggle (Plotly heatmap). */
|
|
25
|
+
this.stackToggle = false;
|
|
26
|
+
/** Stack mode is on (the toggle's state). */
|
|
27
|
+
this.showStack = false;
|
|
28
|
+
/** The two stack-mode choices of the toggle. */
|
|
29
|
+
this.stackOptions = [
|
|
30
|
+
{ name: 'Single image', val: 'false' },
|
|
31
|
+
{ name: 'Stack', val: 'true' },
|
|
32
|
+
];
|
|
33
|
+
/** The current slice (0-based). */
|
|
34
|
+
this.zIndex = 0;
|
|
35
|
+
/** The last slice index. */
|
|
36
|
+
this.maxIndex = 0;
|
|
37
|
+
/** The live scrubber moved (fires while dragging). */
|
|
38
|
+
this.zScrub = new EventEmitter();
|
|
39
|
+
/** The live scrubber was released on a slice. */
|
|
40
|
+
this.zSlide = new EventEmitter();
|
|
41
|
+
/** A stack-mode choice was picked. */
|
|
42
|
+
this.selectStackOption = new EventEmitter();
|
|
43
|
+
/** A slice number was typed (blank reports the current slice). */
|
|
44
|
+
this.zIndexInput = new EventEmitter();
|
|
45
|
+
/** Enter in the slice field / the reload button: re-plot at the typed slice. */
|
|
46
|
+
this.reloadAndPlot = new EventEmitter();
|
|
47
|
+
}
|
|
48
|
+
/** The slice field reports what was typed (blank keeps the current slice). */
|
|
49
|
+
onSliceInput(value) {
|
|
50
|
+
this.zIndexInput.emit(value == null || value === '' ? this.zIndex : Number(value));
|
|
51
|
+
}
|
|
52
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.9", ngImport: i0, type: StackControlsComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
53
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "17.3.9", type: StackControlsComponent, isStandalone: true, selector: "toolbar-stack-controls", inputs: { liveScrubber: "liveScrubber", stackToggle: "stackToggle", showStack: "showStack", stackOptions: "stackOptions", zIndex: "zIndex", maxIndex: "maxIndex" }, outputs: { zScrub: "zScrub", zSlide: "zSlide", selectStackOption: "selectStackOption", zIndexInput: "zIndexInput", reloadAndPlot: "reloadAndPlot" }, ngImport: i0, template: "<span class=\"toolbar-separator\"></span>\n<!-- Live views: scrub z-slices (the renderer swaps slices in place). -->\n<ng-container *ngIf=\"liveScrubber\">\n <span class=\"flex align-items-center mx-1 toolbar-text\">Slice</span>\n <p-slider\n [ngModel]=\"zIndex\"\n [min]=\"0\"\n [max]=\"maxIndex\"\n ariaLabel=\"Slice\"\n (onChange)=\"zScrub.emit($event.value)\"\n (onSlideEnd)=\"zSlide.emit($event.value)\"\n pTooltip=\"Slice through the stack (\u2190 / \u2192 keys)\"\n tooltipPosition=\"bottom\"\n [style]=\"{ width: '16rem' }\"\n styleClass=\"wand-sensitivity-slider\"\n ></p-slider>\n <span class=\"flex align-items-center mx-1 toolbar-text\">{{ zIndex }} of {{ maxIndex }}</span>\n</ng-container>\n<!-- Heatmap view: single-image (high-def zoom) vs stack (frame slider). Plotly-only \u2014\n hidden for napari, which has no single/stack toggle or per-frame fetch, and for the\n spatial-omics modes: a 3D omics dataset publishes its reference volume as a z-stack\n image, and these modes draw observations, not one of its slices. -->\n<ng-container *ngIf=\"stackToggle\">\n <p-button\n icon=\"pi pi-image\"\n size=\"small\"\n ariaLabel=\"Single image mode\"\n [text]=\"showStack\"\n pTooltip=\"Single image mode: enables high-def zoom\"\n tooltipPosition=\"bottom\"\n (onClick)=\"selectStackOption.emit(stackOptions[0])\"\n >\n </p-button>\n <p-button\n icon=\"pi pi-images\"\n size=\"small\"\n ariaLabel=\"Stack mode\"\n [text]=\"!showStack\"\n pTooltip=\"Stack mode, enables slicing through image frames\"\n tooltipPosition=\"bottom\"\n (onClick)=\"selectStackOption.emit(stackOptions[1])\"\n >\n </p-button>\n <ng-container *ngIf=\"!showStack\">\n <span class=\"flex align-items-center mx-1 toolbar-text\">Slice</span>\n <div class=\"p-inputgroup\" style=\"width: auto\">\n <p-inputNumber\n styleClass=\"w-3rem toolbar-input\"\n ariaLabel=\"Slice number\"\n pTooltip=\"View image in stack (⏎)\"\n [ngModel]=\"zIndex\"\n [min]=\"0\"\n [max]=\"maxIndex\"\n (onInput)=\"onSliceInput($event.value)\"\n (keydown.enter)=\"reloadAndPlot.emit()\"\n />\n <p-button\n icon=\"pi pi-refresh\"\n size=\"small\"\n [text]=\"true\"\n ariaLabel=\"Plot this slice\"\n (onClick)=\"reloadAndPlot.emit()\"\n pTooltip=\"Plot this slice\"\n tooltipPosition=\"bottom\"\n >\n </p-button>\n </div>\n <span class=\"flex align-items-center mx-1 toolbar-text\">of {{ maxIndex }}</span>\n </ng-container>\n</ng-container>\n", styles: [".toolbar-text{color:var(--primary-color);font-size:.875rem}.toolbar-separator{border-left:1px solid var(--surface-border);height:1.5rem;margin:0 .25rem;align-self:center}.toolbar-icon-dark{filter:brightness(0) invert(47%) sepia(98%) saturate(567%) hue-rotate(181deg) brightness(103%) contrast(98%)}.toolbar-icon-active{filter:brightness(0) invert(1)}.wand-sensitivity-value{min-width:2rem;text-align:right}:host{display:contents}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: ButtonModule }, { kind: "component", type: i3.Button, selector: "p-button", inputs: ["type", "iconPos", "icon", "badge", "label", "disabled", "loading", "loadingIcon", "raised", "rounded", "text", "plain", "severity", "outlined", "link", "tabindex", "size", "style", "styleClass", "badgeClass", "ariaLabel", "autofocus"], outputs: ["onClick", "onFocus", "onBlur"] }, { kind: "ngmodule", type: InputNumberModule }, { kind: "component", type: i4.InputNumber, selector: "p-inputNumber", inputs: ["showButtons", "format", "buttonLayout", "inputId", "styleClass", "style", "placeholder", "size", "maxlength", "tabindex", "title", "ariaLabelledBy", "ariaLabel", "ariaRequired", "name", "required", "autocomplete", "min", "max", "incrementButtonClass", "decrementButtonClass", "incrementButtonIcon", "decrementButtonIcon", "readonly", "step", "allowEmpty", "locale", "localeMatcher", "mode", "currency", "currencyDisplay", "useGrouping", "variant", "minFractionDigits", "maxFractionDigits", "prefix", "suffix", "inputStyle", "inputStyleClass", "showClear", "autofocus", "disabled"], outputs: ["onInput", "onFocus", "onBlur", "onKeyDown", "onClear"] }, { kind: "ngmodule", type: SliderModule }, { kind: "component", type: i5.Slider, selector: "p-slider", inputs: ["animate", "disabled", "min", "max", "orientation", "step", "range", "style", "styleClass", "ariaLabel", "ariaLabelledBy", "tabindex", "autofocus"], outputs: ["onChange", "onSlideEnd"] }, { kind: "ngmodule", type: TooltipModule }, { kind: "directive", type: i6.Tooltip, selector: "[pTooltip]", inputs: ["tooltipPosition", "tooltipEvent", "appendTo", "positionStyle", "tooltipStyleClass", "tooltipZIndex", "escape", "showDelay", "hideDelay", "life", "positionTop", "positionLeft", "autoHide", "fitContent", "hideOnEscape", "pTooltip", "tooltipDisabled", "tooltipOptions"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
|
54
|
+
}
|
|
55
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.9", ngImport: i0, type: StackControlsComponent, decorators: [{
|
|
56
|
+
type: Component,
|
|
57
|
+
args: [{ selector: 'toolbar-stack-controls', standalone: true, imports: [CommonModule, FormsModule, ButtonModule, InputNumberModule, SliderModule, TooltipModule], changeDetection: ChangeDetectionStrategy.OnPush, template: "<span class=\"toolbar-separator\"></span>\n<!-- Live views: scrub z-slices (the renderer swaps slices in place). -->\n<ng-container *ngIf=\"liveScrubber\">\n <span class=\"flex align-items-center mx-1 toolbar-text\">Slice</span>\n <p-slider\n [ngModel]=\"zIndex\"\n [min]=\"0\"\n [max]=\"maxIndex\"\n ariaLabel=\"Slice\"\n (onChange)=\"zScrub.emit($event.value)\"\n (onSlideEnd)=\"zSlide.emit($event.value)\"\n pTooltip=\"Slice through the stack (\u2190 / \u2192 keys)\"\n tooltipPosition=\"bottom\"\n [style]=\"{ width: '16rem' }\"\n styleClass=\"wand-sensitivity-slider\"\n ></p-slider>\n <span class=\"flex align-items-center mx-1 toolbar-text\">{{ zIndex }} of {{ maxIndex }}</span>\n</ng-container>\n<!-- Heatmap view: single-image (high-def zoom) vs stack (frame slider). Plotly-only \u2014\n hidden for napari, which has no single/stack toggle or per-frame fetch, and for the\n spatial-omics modes: a 3D omics dataset publishes its reference volume as a z-stack\n image, and these modes draw observations, not one of its slices. -->\n<ng-container *ngIf=\"stackToggle\">\n <p-button\n icon=\"pi pi-image\"\n size=\"small\"\n ariaLabel=\"Single image mode\"\n [text]=\"showStack\"\n pTooltip=\"Single image mode: enables high-def zoom\"\n tooltipPosition=\"bottom\"\n (onClick)=\"selectStackOption.emit(stackOptions[0])\"\n >\n </p-button>\n <p-button\n icon=\"pi pi-images\"\n size=\"small\"\n ariaLabel=\"Stack mode\"\n [text]=\"!showStack\"\n pTooltip=\"Stack mode, enables slicing through image frames\"\n tooltipPosition=\"bottom\"\n (onClick)=\"selectStackOption.emit(stackOptions[1])\"\n >\n </p-button>\n <ng-container *ngIf=\"!showStack\">\n <span class=\"flex align-items-center mx-1 toolbar-text\">Slice</span>\n <div class=\"p-inputgroup\" style=\"width: auto\">\n <p-inputNumber\n styleClass=\"w-3rem toolbar-input\"\n ariaLabel=\"Slice number\"\n pTooltip=\"View image in stack (⏎)\"\n [ngModel]=\"zIndex\"\n [min]=\"0\"\n [max]=\"maxIndex\"\n (onInput)=\"onSliceInput($event.value)\"\n (keydown.enter)=\"reloadAndPlot.emit()\"\n />\n <p-button\n icon=\"pi pi-refresh\"\n size=\"small\"\n [text]=\"true\"\n ariaLabel=\"Plot this slice\"\n (onClick)=\"reloadAndPlot.emit()\"\n pTooltip=\"Plot this slice\"\n tooltipPosition=\"bottom\"\n >\n </p-button>\n </div>\n <span class=\"flex align-items-center mx-1 toolbar-text\">of {{ maxIndex }}</span>\n </ng-container>\n</ng-container>\n", styles: [".toolbar-text{color:var(--primary-color);font-size:.875rem}.toolbar-separator{border-left:1px solid var(--surface-border);height:1.5rem;margin:0 .25rem;align-self:center}.toolbar-icon-dark{filter:brightness(0) invert(47%) sepia(98%) saturate(567%) hue-rotate(181deg) brightness(103%) contrast(98%)}.toolbar-icon-active{filter:brightness(0) invert(1)}.wand-sensitivity-value{min-width:2rem;text-align:right}:host{display:contents}\n"] }]
|
|
58
|
+
}], propDecorators: { liveScrubber: [{
|
|
59
|
+
type: Input
|
|
60
|
+
}], stackToggle: [{
|
|
61
|
+
type: Input
|
|
62
|
+
}], showStack: [{
|
|
63
|
+
type: Input
|
|
64
|
+
}], stackOptions: [{
|
|
65
|
+
type: Input
|
|
66
|
+
}], zIndex: [{
|
|
67
|
+
type: Input
|
|
68
|
+
}], maxIndex: [{
|
|
69
|
+
type: Input
|
|
70
|
+
}], zScrub: [{
|
|
71
|
+
type: Output
|
|
72
|
+
}], zSlide: [{
|
|
73
|
+
type: Output
|
|
74
|
+
}], selectStackOption: [{
|
|
75
|
+
type: Output
|
|
76
|
+
}], zIndexInput: [{
|
|
77
|
+
type: Output
|
|
78
|
+
}], reloadAndPlot: [{
|
|
79
|
+
type: Output
|
|
80
|
+
}] } });
|
|
81
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic3RhY2stY29udHJvbHMuY29tcG9uZW50LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vLi4vc3JjL2xpYi90b29sYmFyL3N0YWNrLWNvbnRyb2xzL3N0YWNrLWNvbnRyb2xzLmNvbXBvbmVudC50cyIsIi4uLy4uLy4uLy4uLy4uL3NyYy9saWIvdG9vbGJhci9zdGFjay1jb250cm9scy9zdGFjay1jb250cm9scy5jb21wb25lbnQuaHRtbCJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQUUsdUJBQXVCLEVBQUUsU0FBUyxFQUFFLFlBQVksRUFBRSxLQUFLLEVBQUUsTUFBTSxFQUFFLE1BQU0sZUFBZSxDQUFDO0FBQ2hHLE9BQU8sRUFBRSxZQUFZLEVBQUUsTUFBTSxpQkFBaUIsQ0FBQztBQUMvQyxPQUFPLEVBQUUsV0FBVyxFQUFFLE1BQU0sZ0JBQWdCLENBQUM7QUFDN0MsT0FBTyxFQUFFLFlBQVksRUFBRSxNQUFNLGdCQUFnQixDQUFDO0FBQzlDLE9BQU8sRUFBRSxpQkFBaUIsRUFBRSxNQUFNLHFCQUFxQixDQUFDO0FBQ3hELE9BQU8sRUFBRSxZQUFZLEVBQUUsTUFBTSxnQkFBZ0IsQ0FBQztBQUM5QyxPQUFPLEVBQUUsYUFBYSxFQUFFLE1BQU0saUJBQWlCLENBQUM7Ozs7Ozs7O0FBUWhEOzs7O0dBSUc7QUFTSCxNQUFNLE9BQU8sc0JBQXNCO0lBUm5DO1FBU0Usb0NBQW9DO1FBQzNCLGlCQUFZLEdBQUcsS0FBSyxDQUFDO1FBQzlCLDZEQUE2RDtRQUNwRCxnQkFBVyxHQUFHLEtBQUssQ0FBQztRQUM3Qiw2Q0FBNkM7UUFDcEMsY0FBUyxHQUFHLEtBQUssQ0FBQztRQUMzQixnREFBZ0Q7UUFDdkMsaUJBQVksR0FBa0I7WUFDckMsRUFBRSxJQUFJLEVBQUUsY0FBYyxFQUFFLEdBQUcsRUFBRSxPQUFPLEVBQUU7WUFDdEMsRUFBRSxJQUFJLEVBQUUsT0FBTyxFQUFFLEdBQUcsRUFBRSxNQUFNLEVBQUU7U0FDL0IsQ0FBQztRQUNGLG1DQUFtQztRQUMxQixXQUFNLEdBQUcsQ0FBQyxDQUFDO1FBQ3BCLDRCQUE0QjtRQUNuQixhQUFRLEdBQUcsQ0FBQyxDQUFDO1FBRXRCLHNEQUFzRDtRQUM1QyxXQUFNLEdBQUcsSUFBSSxZQUFZLEVBQXNCLENBQUM7UUFDMUQsaURBQWlEO1FBQ3ZDLFdBQU0sR0FBRyxJQUFJLFlBQVksRUFBc0IsQ0FBQztRQUMxRCxzQ0FBc0M7UUFDNUIsc0JBQWlCLEdBQUcsSUFBSSxZQUFZLEVBQWUsQ0FBQztRQUM5RCxrRUFBa0U7UUFDeEQsZ0JBQVcsR0FBRyxJQUFJLFlBQVksRUFBVSxDQUFDO1FBQ25ELGdGQUFnRjtRQUN0RSxrQkFBYSxHQUFHLElBQUksWUFBWSxFQUFRLENBQUM7S0FNcEQ7SUFKQyw4RUFBOEU7SUFDcEUsWUFBWSxDQUFDLEtBQTZCO1FBQ2xELElBQUksQ0FBQyxXQUFXLENBQUMsSUFBSSxDQUFDLEtBQUssSUFBSSxJQUFJLElBQUksS0FBSyxLQUFLLEVBQUUsQ0FBQyxDQUFDLENBQUMsSUFBSSxDQUFDLE1BQU0sQ0FBQyxDQUFDLENBQUMsTUFBTSxDQUFDLEtBQUssQ0FBQyxDQUFDLENBQUM7SUFDckYsQ0FBQzs4R0EvQlUsc0JBQXNCO2tHQUF0QixzQkFBc0IsMllDM0JuQyx5bEZBc0VBLHdlRGhEWSxZQUFZLGtJQUFFLFdBQVcsOFZBQUUsWUFBWSw2WEFBRSxpQkFBaUIseXZCQUFFLFlBQVksK1JBQUUsYUFBYTs7MkZBS3RGLHNCQUFzQjtrQkFSbEMsU0FBUzsrQkFDRSx3QkFBd0IsY0FDdEIsSUFBSSxXQUNQLENBQUMsWUFBWSxFQUFFLFdBQVcsRUFBRSxZQUFZLEVBQUUsaUJBQWlCLEVBQUUsWUFBWSxFQUFFLGFBQWEsQ0FBQyxtQkFHakYsdUJBQXVCLENBQUMsTUFBTTs4QkFJdEMsWUFBWTtzQkFBcEIsS0FBSztnQkFFRyxXQUFXO3NCQUFuQixLQUFLO2dCQUVHLFNBQVM7c0JBQWpCLEtBQUs7Z0JBRUcsWUFBWTtzQkFBcEIsS0FBSztnQkFLRyxNQUFNO3NCQUFkLEtBQUs7Z0JBRUcsUUFBUTtzQkFBaEIsS0FBSztnQkFHSSxNQUFNO3NCQUFmLE1BQU07Z0JBRUcsTUFBTTtzQkFBZixNQUFNO2dCQUVHLGlCQUFpQjtzQkFBMUIsTUFBTTtnQkFFRyxXQUFXO3NCQUFwQixNQUFNO2dCQUVHLGFBQWE7c0JBQXRCLE1BQU0iLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBDaGFuZ2VEZXRlY3Rpb25TdHJhdGVneSwgQ29tcG9uZW50LCBFdmVudEVtaXR0ZXIsIElucHV0LCBPdXRwdXQgfSBmcm9tICdAYW5ndWxhci9jb3JlJztcbmltcG9ydCB7IENvbW1vbk1vZHVsZSB9IGZyb20gJ0Bhbmd1bGFyL2NvbW1vbic7XG5pbXBvcnQgeyBGb3Jtc01vZHVsZSB9IGZyb20gJ0Bhbmd1bGFyL2Zvcm1zJztcbmltcG9ydCB7IEJ1dHRvbk1vZHVsZSB9IGZyb20gJ3ByaW1lbmcvYnV0dG9uJztcbmltcG9ydCB7IElucHV0TnVtYmVyTW9kdWxlIH0gZnJvbSAncHJpbWVuZy9pbnB1dG51bWJlcic7XG5pbXBvcnQgeyBTbGlkZXJNb2R1bGUgfSBmcm9tICdwcmltZW5nL3NsaWRlcic7XG5pbXBvcnQgeyBUb29sdGlwTW9kdWxlIH0gZnJvbSAncHJpbWVuZy90b29sdGlwJztcblxuLyoqIEEgc3RhY2stbW9kZSBjaG9pY2UgKGB2YWxgICdmYWxzZScgPSBzaW5nbGUgaW1hZ2UsICd0cnVlJyA9IHN0YWNrKS4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgU3RhY2tPcHRpb24ge1xuICBuYW1lOiBzdHJpbmc7XG4gIHZhbDogc3RyaW5nO1xufVxuXG4vKipcbiAqIFRoZSB0b29sYmFyJ3Mgei1zdGFjayBncm91cDogYSBsaXZlIHNsaWNlIHNjcnViYmVyIGZvciB0aGUgdmlld3MgdGhhdCBzd2FwXG4gKiBzbGljZXMgaW4gcGxhY2UsIG9yIChQbG90bHkgaGVhdG1hcCkgdGhlIHNpbmdsZS1pbWFnZSAvIHN0YWNrIHRvZ2dsZSB3aXRoIGFcbiAqIHNsaWNlLW51bWJlciBmaWVsZC4gUHJlc2VudGF0aW9uYWw6IHRoZSBob3N0IG93bnMgYHpJbmRleGAuXG4gKi9cbkBDb21wb25lbnQoe1xuICBzZWxlY3RvcjogJ3Rvb2xiYXItc3RhY2stY29udHJvbHMnLFxuICBzdGFuZGFsb25lOiB0cnVlLFxuICBpbXBvcnRzOiBbQ29tbW9uTW9kdWxlLCBGb3Jtc01vZHVsZSwgQnV0dG9uTW9kdWxlLCBJbnB1dE51bWJlck1vZHVsZSwgU2xpZGVyTW9kdWxlLCBUb29sdGlwTW9kdWxlXSxcbiAgdGVtcGxhdGVVcmw6ICcuL3N0YWNrLWNvbnRyb2xzLmNvbXBvbmVudC5odG1sJyxcbiAgc3R5bGVVcmxzOiBbJy4vc3RhY2stY29udHJvbHMuY29tcG9uZW50LnNjc3MnXSxcbiAgY2hhbmdlRGV0ZWN0aW9uOiBDaGFuZ2VEZXRlY3Rpb25TdHJhdGVneS5PblB1c2gsXG59KVxuZXhwb3J0IGNsYXNzIFN0YWNrQ29udHJvbHNDb21wb25lbnQge1xuICAvKiogU2hvdyB0aGUgbGl2ZSBzbGljZSBzY3J1YmJlci4gKi9cbiAgQElucHV0KCkgbGl2ZVNjcnViYmVyID0gZmFsc2U7XG4gIC8qKiBTaG93IHRoZSBzaW5nbGUtaW1hZ2UgLyBzdGFjayB0b2dnbGUgKFBsb3RseSBoZWF0bWFwKS4gKi9cbiAgQElucHV0KCkgc3RhY2tUb2dnbGUgPSBmYWxzZTtcbiAgLyoqIFN0YWNrIG1vZGUgaXMgb24gKHRoZSB0b2dnbGUncyBzdGF0ZSkuICovXG4gIEBJbnB1dCgpIHNob3dTdGFjayA9IGZhbHNlO1xuICAvKiogVGhlIHR3byBzdGFjay1tb2RlIGNob2ljZXMgb2YgdGhlIHRvZ2dsZS4gKi9cbiAgQElucHV0KCkgc3RhY2tPcHRpb25zOiBTdGFja09wdGlvbltdID0gW1xuICAgIHsgbmFtZTogJ1NpbmdsZSBpbWFnZScsIHZhbDogJ2ZhbHNlJyB9LFxuICAgIHsgbmFtZTogJ1N0YWNrJywgdmFsOiAndHJ1ZScgfSxcbiAgXTtcbiAgLyoqIFRoZSBjdXJyZW50IHNsaWNlICgwLWJhc2VkKS4gKi9cbiAgQElucHV0KCkgekluZGV4ID0gMDtcbiAgLyoqIFRoZSBsYXN0IHNsaWNlIGluZGV4LiAqL1xuICBASW5wdXQoKSBtYXhJbmRleCA9IDA7XG5cbiAgLyoqIFRoZSBsaXZlIHNjcnViYmVyIG1vdmVkIChmaXJlcyB3aGlsZSBkcmFnZ2luZykuICovXG4gIEBPdXRwdXQoKSB6U2NydWIgPSBuZXcgRXZlbnRFbWl0dGVyPG51bWJlciB8IHVuZGVmaW5lZD4oKTtcbiAgLyoqIFRoZSBsaXZlIHNjcnViYmVyIHdhcyByZWxlYXNlZCBvbiBhIHNsaWNlLiAqL1xuICBAT3V0cHV0KCkgelNsaWRlID0gbmV3IEV2ZW50RW1pdHRlcjxudW1iZXIgfCB1bmRlZmluZWQ+KCk7XG4gIC8qKiBBIHN0YWNrLW1vZGUgY2hvaWNlIHdhcyBwaWNrZWQuICovXG4gIEBPdXRwdXQoKSBzZWxlY3RTdGFja09wdGlvbiA9IG5ldyBFdmVudEVtaXR0ZXI8U3RhY2tPcHRpb24+KCk7XG4gIC8qKiBBIHNsaWNlIG51bWJlciB3YXMgdHlwZWQgKGJsYW5rIHJlcG9ydHMgdGhlIGN1cnJlbnQgc2xpY2UpLiAqL1xuICBAT3V0cHV0KCkgekluZGV4SW5wdXQgPSBuZXcgRXZlbnRFbWl0dGVyPG51bWJlcj4oKTtcbiAgLyoqIEVudGVyIGluIHRoZSBzbGljZSBmaWVsZCAvIHRoZSByZWxvYWQgYnV0dG9uOiByZS1wbG90IGF0IHRoZSB0eXBlZCBzbGljZS4gKi9cbiAgQE91dHB1dCgpIHJlbG9hZEFuZFBsb3QgPSBuZXcgRXZlbnRFbWl0dGVyPHZvaWQ+KCk7XG5cbiAgLyoqIFRoZSBzbGljZSBmaWVsZCByZXBvcnRzIHdoYXQgd2FzIHR5cGVkIChibGFuayBrZWVwcyB0aGUgY3VycmVudCBzbGljZSkuICovXG4gIHByb3RlY3RlZCBvblNsaWNlSW5wdXQodmFsdWU6IHN0cmluZyB8IG51bWJlciB8IG51bGwpOiB2b2lkIHtcbiAgICB0aGlzLnpJbmRleElucHV0LmVtaXQodmFsdWUgPT0gbnVsbCB8fCB2YWx1ZSA9PT0gJycgPyB0aGlzLnpJbmRleCA6IE51bWJlcih2YWx1ZSkpO1xuICB9XG59XG4iLCI8c3BhbiBjbGFzcz1cInRvb2xiYXItc2VwYXJhdG9yXCI+PC9zcGFuPlxuPCEtLSBMaXZlIHZpZXdzOiBzY3J1YiB6LXNsaWNlcyAodGhlIHJlbmRlcmVyIHN3YXBzIHNsaWNlcyBpbiBwbGFjZSkuIC0tPlxuPG5nLWNvbnRhaW5lciAqbmdJZj1cImxpdmVTY3J1YmJlclwiPlxuICA8c3BhbiBjbGFzcz1cImZsZXggYWxpZ24taXRlbXMtY2VudGVyIG14LTEgdG9vbGJhci10ZXh0XCI+U2xpY2U8L3NwYW4+XG4gIDxwLXNsaWRlclxuICAgIFtuZ01vZGVsXT1cInpJbmRleFwiXG4gICAgW21pbl09XCIwXCJcbiAgICBbbWF4XT1cIm1heEluZGV4XCJcbiAgICBhcmlhTGFiZWw9XCJTbGljZVwiXG4gICAgKG9uQ2hhbmdlKT1cInpTY3J1Yi5lbWl0KCRldmVudC52YWx1ZSlcIlxuICAgIChvblNsaWRlRW5kKT1cInpTbGlkZS5lbWl0KCRldmVudC52YWx1ZSlcIlxuICAgIHBUb29sdGlwPVwiU2xpY2UgdGhyb3VnaCB0aGUgc3RhY2sgKOKGkCAvIOKGkiBrZXlzKVwiXG4gICAgdG9vbHRpcFBvc2l0aW9uPVwiYm90dG9tXCJcbiAgICBbc3R5bGVdPVwieyB3aWR0aDogJzE2cmVtJyB9XCJcbiAgICBzdHlsZUNsYXNzPVwid2FuZC1zZW5zaXRpdml0eS1zbGlkZXJcIlxuICA+PC9wLXNsaWRlcj5cbiAgPHNwYW4gY2xhc3M9XCJmbGV4IGFsaWduLWl0ZW1zLWNlbnRlciBteC0xIHRvb2xiYXItdGV4dFwiPnt7IHpJbmRleCB9fSBvZiB7eyBtYXhJbmRleCB9fTwvc3Bhbj5cbjwvbmctY29udGFpbmVyPlxuPCEtLSBIZWF0bWFwIHZpZXc6IHNpbmdsZS1pbWFnZSAoaGlnaC1kZWYgem9vbSkgdnMgc3RhY2sgKGZyYW1lIHNsaWRlcikuIFBsb3RseS1vbmx5IOKAlFxuICAgICBoaWRkZW4gZm9yIG5hcGFyaSwgd2hpY2ggaGFzIG5vIHNpbmdsZS9zdGFjayB0b2dnbGUgb3IgcGVyLWZyYW1lIGZldGNoLCBhbmQgZm9yIHRoZVxuICAgICBzcGF0aWFsLW9taWNzIG1vZGVzOiBhIDNEIG9taWNzIGRhdGFzZXQgcHVibGlzaGVzIGl0cyByZWZlcmVuY2Ugdm9sdW1lIGFzIGEgei1zdGFja1xuICAgICBpbWFnZSwgYW5kIHRoZXNlIG1vZGVzIGRyYXcgb2JzZXJ2YXRpb25zLCBub3Qgb25lIG9mIGl0cyBzbGljZXMuIC0tPlxuPG5nLWNvbnRhaW5lciAqbmdJZj1cInN0YWNrVG9nZ2xlXCI+XG4gIDxwLWJ1dHRvblxuICAgIGljb249XCJwaSBwaS1pbWFnZVwiXG4gICAgc2l6ZT1cInNtYWxsXCJcbiAgICBhcmlhTGFiZWw9XCJTaW5nbGUgaW1hZ2UgbW9kZVwiXG4gICAgW3RleHRdPVwic2hvd1N0YWNrXCJcbiAgICBwVG9vbHRpcD1cIlNpbmdsZSBpbWFnZSBtb2RlOiBlbmFibGVzIGhpZ2gtZGVmIHpvb21cIlxuICAgIHRvb2x0aXBQb3NpdGlvbj1cImJvdHRvbVwiXG4gICAgKG9uQ2xpY2spPVwic2VsZWN0U3RhY2tPcHRpb24uZW1pdChzdGFja09wdGlvbnNbMF0pXCJcbiAgPlxuICA8L3AtYnV0dG9uPlxuICA8cC1idXR0b25cbiAgICBpY29uPVwicGkgcGktaW1hZ2VzXCJcbiAgICBzaXplPVwic21hbGxcIlxuICAgIGFyaWFMYWJlbD1cIlN0YWNrIG1vZGVcIlxuICAgIFt0ZXh0XT1cIiFzaG93U3RhY2tcIlxuICAgIHBUb29sdGlwPVwiU3RhY2sgbW9kZSwgZW5hYmxlcyBzbGljaW5nIHRocm91Z2ggaW1hZ2UgZnJhbWVzXCJcbiAgICB0b29sdGlwUG9zaXRpb249XCJib3R0b21cIlxuICAgIChvbkNsaWNrKT1cInNlbGVjdFN0YWNrT3B0aW9uLmVtaXQoc3RhY2tPcHRpb25zWzFdKVwiXG4gID5cbiAgPC9wLWJ1dHRvbj5cbiAgPG5nLWNvbnRhaW5lciAqbmdJZj1cIiFzaG93U3RhY2tcIj5cbiAgICA8c3BhbiBjbGFzcz1cImZsZXggYWxpZ24taXRlbXMtY2VudGVyIG14LTEgdG9vbGJhci10ZXh0XCI+U2xpY2U8L3NwYW4+XG4gICAgPGRpdiBjbGFzcz1cInAtaW5wdXRncm91cFwiIHN0eWxlPVwid2lkdGg6IGF1dG9cIj5cbiAgICAgIDxwLWlucHV0TnVtYmVyXG4gICAgICAgIHN0eWxlQ2xhc3M9XCJ3LTNyZW0gdG9vbGJhci1pbnB1dFwiXG4gICAgICAgIGFyaWFMYWJlbD1cIlNsaWNlIG51bWJlclwiXG4gICAgICAgIHBUb29sdGlwPVwiVmlldyBpbWFnZSBpbiBzdGFjayAoJiN4MjNDRTspXCJcbiAgICAgICAgW25nTW9kZWxdPVwiekluZGV4XCJcbiAgICAgICAgW21pbl09XCIwXCJcbiAgICAgICAgW21heF09XCJtYXhJbmRleFwiXG4gICAgICAgIChvbklucHV0KT1cIm9uU2xpY2VJbnB1dCgkZXZlbnQudmFsdWUpXCJcbiAgICAgICAgKGtleWRvd24uZW50ZXIpPVwicmVsb2FkQW5kUGxvdC5lbWl0KClcIlxuICAgICAgLz5cbiAgICAgIDxwLWJ1dHRvblxuICAgICAgICBpY29uPVwicGkgcGktcmVmcmVzaFwiXG4gICAgICAgIHNpemU9XCJzbWFsbFwiXG4gICAgICAgIFt0ZXh0XT1cInRydWVcIlxuICAgICAgICBhcmlhTGFiZWw9XCJQbG90IHRoaXMgc2xpY2VcIlxuICAgICAgICAob25DbGljayk9XCJyZWxvYWRBbmRQbG90LmVtaXQoKVwiXG4gICAgICAgIHBUb29sdGlwPVwiUGxvdCB0aGlzIHNsaWNlXCJcbiAgICAgICAgdG9vbHRpcFBvc2l0aW9uPVwiYm90dG9tXCJcbiAgICAgID5cbiAgICAgIDwvcC1idXR0b24+XG4gICAgPC9kaXY+XG4gICAgPHNwYW4gY2xhc3M9XCJmbGV4IGFsaWduLWl0ZW1zLWNlbnRlciBteC0xIHRvb2xiYXItdGV4dFwiPm9mIHt7IG1heEluZGV4IH19PC9zcGFuPlxuICA8L25nLWNvbnRhaW5lcj5cbjwvbmctY29udGFpbmVyPlxuIl19
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { BehaviorSubject } from 'rxjs';
|
|
2
|
+
/**
|
|
3
|
+
* Status, busy flag and progress of a long-running (download / inference) tool,
|
|
4
|
+
* plus the re-entrancy guard that goes with them.
|
|
5
|
+
*/
|
|
6
|
+
export class AsyncToolStatus {
|
|
7
|
+
constructor() {
|
|
8
|
+
/** Status text for a toast / spinner label. */
|
|
9
|
+
this.status$ = new BehaviorSubject('');
|
|
10
|
+
/** True from the start of a run until it settles. */
|
|
11
|
+
this.busy$ = new BehaviorSubject(false);
|
|
12
|
+
/** Download progress: -1 = not downloading, 0..1 = downloading. */
|
|
13
|
+
this.progress$ = new BehaviorSubject(-1);
|
|
14
|
+
}
|
|
15
|
+
get busy() {
|
|
16
|
+
return this.busy$.value;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Run `job` unless a run is already in flight (then resolve `undefined` at
|
|
20
|
+
* once). Busy is set *before* the first await — a model download is exactly
|
|
21
|
+
* the window a second press must not start another run in — and busy and
|
|
22
|
+
* progress are reset however the job ends.
|
|
23
|
+
*/
|
|
24
|
+
async run(job) {
|
|
25
|
+
if (this.busy$.value)
|
|
26
|
+
return undefined;
|
|
27
|
+
this.busy$.next(true);
|
|
28
|
+
try {
|
|
29
|
+
return await job();
|
|
30
|
+
}
|
|
31
|
+
finally {
|
|
32
|
+
this.busy$.next(false);
|
|
33
|
+
this.progress$.next(-1);
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYXN5bmMtdG9vbC1zdGF0dXMuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi9zcmMvbGliL3Rvb2xiYXIvdG9vbC1raXQvYXN5bmMtdG9vbC1zdGF0dXMudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUFFLGVBQWUsRUFBRSxNQUFNLE1BQU0sQ0FBQztBQUV2Qzs7O0dBR0c7QUFDSCxNQUFNLE9BQU8sZUFBZTtJQUE1QjtRQUNFLCtDQUErQztRQUN0QyxZQUFPLEdBQUcsSUFBSSxlQUFlLENBQVMsRUFBRSxDQUFDLENBQUM7UUFDbkQscURBQXFEO1FBQzVDLFVBQUssR0FBRyxJQUFJLGVBQWUsQ0FBVSxLQUFLLENBQUMsQ0FBQztRQUNyRCxtRUFBbUU7UUFDMUQsY0FBUyxHQUFHLElBQUksZUFBZSxDQUFTLENBQUMsQ0FBQyxDQUFDLENBQUM7SUFzQnZELENBQUM7SUFwQkMsSUFBSSxJQUFJO1FBQ04sT0FBTyxJQUFJLENBQUMsS0FBSyxDQUFDLEtBQUssQ0FBQztJQUMxQixDQUFDO0lBRUQ7Ozs7O09BS0c7SUFDSCxLQUFLLENBQUMsR0FBRyxDQUFJLEdBQXFCO1FBQ2hDLElBQUksSUFBSSxDQUFDLEtBQUssQ0FBQyxLQUFLO1lBQUUsT0FBTyxTQUFTLENBQUM7UUFDdkMsSUFBSSxDQUFDLEtBQUssQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLENBQUM7UUFDdEIsSUFBSSxDQUFDO1lBQ0gsT0FBTyxNQUFNLEdBQUcsRUFBRSxDQUFDO1FBQ3JCLENBQUM7Z0JBQVMsQ0FBQztZQUNULElBQUksQ0FBQyxLQUFLLENBQUMsSUFBSSxDQUFDLEtBQUssQ0FBQyxDQUFDO1lBQ3ZCLElBQUksQ0FBQyxTQUFTLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUM7UUFDMUIsQ0FBQztJQUNILENBQUM7Q0FDRiIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IEJlaGF2aW9yU3ViamVjdCB9IGZyb20gJ3J4anMnO1xuXG4vKipcbiAqIFN0YXR1cywgYnVzeSBmbGFnIGFuZCBwcm9ncmVzcyBvZiBhIGxvbmctcnVubmluZyAoZG93bmxvYWQgLyBpbmZlcmVuY2UpIHRvb2wsXG4gKiBwbHVzIHRoZSByZS1lbnRyYW5jeSBndWFyZCB0aGF0IGdvZXMgd2l0aCB0aGVtLlxuICovXG5leHBvcnQgY2xhc3MgQXN5bmNUb29sU3RhdHVzIHtcbiAgLyoqIFN0YXR1cyB0ZXh0IGZvciBhIHRvYXN0IC8gc3Bpbm5lciBsYWJlbC4gKi9cbiAgcmVhZG9ubHkgc3RhdHVzJCA9IG5ldyBCZWhhdmlvclN1YmplY3Q8c3RyaW5nPignJyk7XG4gIC8qKiBUcnVlIGZyb20gdGhlIHN0YXJ0IG9mIGEgcnVuIHVudGlsIGl0IHNldHRsZXMuICovXG4gIHJlYWRvbmx5IGJ1c3kkID0gbmV3IEJlaGF2aW9yU3ViamVjdDxib29sZWFuPihmYWxzZSk7XG4gIC8qKiBEb3dubG9hZCBwcm9ncmVzczogLTEgPSBub3QgZG93bmxvYWRpbmcsIDAuLjEgPSBkb3dubG9hZGluZy4gKi9cbiAgcmVhZG9ubHkgcHJvZ3Jlc3MkID0gbmV3IEJlaGF2aW9yU3ViamVjdDxudW1iZXI+KC0xKTtcblxuICBnZXQgYnVzeSgpOiBib29sZWFuIHtcbiAgICByZXR1cm4gdGhpcy5idXN5JC52YWx1ZTtcbiAgfVxuXG4gIC8qKlxuICAgKiBSdW4gYGpvYmAgdW5sZXNzIGEgcnVuIGlzIGFscmVhZHkgaW4gZmxpZ2h0ICh0aGVuIHJlc29sdmUgYHVuZGVmaW5lZGAgYXRcbiAgICogb25jZSkuIEJ1c3kgaXMgc2V0ICpiZWZvcmUqIHRoZSBmaXJzdCBhd2FpdCDigJQgYSBtb2RlbCBkb3dubG9hZCBpcyBleGFjdGx5XG4gICAqIHRoZSB3aW5kb3cgYSBzZWNvbmQgcHJlc3MgbXVzdCBub3Qgc3RhcnQgYW5vdGhlciBydW4gaW4g4oCUIGFuZCBidXN5IGFuZFxuICAgKiBwcm9ncmVzcyBhcmUgcmVzZXQgaG93ZXZlciB0aGUgam9iIGVuZHMuXG4gICAqL1xuICBhc3luYyBydW48VD4oam9iOiAoKSA9PiBQcm9taXNlPFQ+KTogUHJvbWlzZTxUIHwgdW5kZWZpbmVkPiB7XG4gICAgaWYgKHRoaXMuYnVzeSQudmFsdWUpIHJldHVybiB1bmRlZmluZWQ7XG4gICAgdGhpcy5idXN5JC5uZXh0KHRydWUpO1xuICAgIHRyeSB7XG4gICAgICByZXR1cm4gYXdhaXQgam9iKCk7XG4gICAgfSBmaW5hbGx5IHtcbiAgICAgIHRoaXMuYnVzeSQubmV4dChmYWxzZSk7XG4gICAgICB0aGlzLnByb2dyZXNzJC5uZXh0KC0xKTtcbiAgICB9XG4gIH1cbn1cbiJdfQ==
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* One backend's canvas tools. Each backend (Plotly, OpenSeadragon, napari-js)
|
|
3
|
+
* creates its own manager with its own {@link CanvasToolHost} and its own tool
|
|
4
|
+
* instances, so arming a tool never re-binds a tool another backend is using,
|
|
5
|
+
* and a backend switch never carries a stroke or SAM points across (RT-21).
|
|
6
|
+
* At most one tool is armed at a time.
|
|
7
|
+
*/
|
|
8
|
+
export class CanvasToolManager {
|
|
9
|
+
constructor(host, tools) {
|
|
10
|
+
this.host = host;
|
|
11
|
+
this.tools = new Map();
|
|
12
|
+
this.active = null;
|
|
13
|
+
for (const tool of tools)
|
|
14
|
+
this.tools.set(tool.id, tool);
|
|
15
|
+
}
|
|
16
|
+
/** The armed tool's id, or null. */
|
|
17
|
+
get activeId() {
|
|
18
|
+
return this.active?.id ?? null;
|
|
19
|
+
}
|
|
20
|
+
/** Whether this manager has a tool for `id`. */
|
|
21
|
+
has(id) {
|
|
22
|
+
return id != null && this.tools.has(id);
|
|
23
|
+
}
|
|
24
|
+
/** The tool with this id, typed by the caller. */
|
|
25
|
+
get(id) {
|
|
26
|
+
return this.tools.get(id);
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Arm `id` with `options`, disarming the armed tool first. null — or an id
|
|
30
|
+
* this manager has no tool for, such as a region draw mode — disarms only.
|
|
31
|
+
* Arming the armed tool again forwards `options` and keeps its work in progress.
|
|
32
|
+
*/
|
|
33
|
+
activate(id, options) {
|
|
34
|
+
const next = this.has(id) ? this.tools.get(id) : null;
|
|
35
|
+
if (this.active && this.active !== next)
|
|
36
|
+
this.deactivate();
|
|
37
|
+
if (!next)
|
|
38
|
+
return;
|
|
39
|
+
this.active = next;
|
|
40
|
+
next.activate(this.host, options);
|
|
41
|
+
}
|
|
42
|
+
/** Disarm the armed tool, if any. */
|
|
43
|
+
deactivate() {
|
|
44
|
+
const tool = this.active;
|
|
45
|
+
this.active = null;
|
|
46
|
+
tool?.deactivate();
|
|
47
|
+
}
|
|
48
|
+
/** Forward live options to a tool, armed or not. */
|
|
49
|
+
setOptions(id, options) {
|
|
50
|
+
this.tools.get(id)?.setOptions?.(options);
|
|
51
|
+
}
|
|
52
|
+
/** Drop one tool's work in progress (it stays armed). */
|
|
53
|
+
reset(id) {
|
|
54
|
+
this.tools.get(id)?.reset?.();
|
|
55
|
+
}
|
|
56
|
+
/** Drop every tool's work in progress — after undo/redo or an image switch,
|
|
57
|
+
* where a stroke or prompt no longer matches the regions on screen. */
|
|
58
|
+
resetAll() {
|
|
59
|
+
for (const tool of this.tools.values())
|
|
60
|
+
tool.reset?.();
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2FudmFzLXRvb2wtbWFuYWdlci5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uLy4uL3NyYy9saWIvdG9vbGJhci90b29sLWtpdC9jYW52YXMtdG9vbC1tYW5hZ2VyLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUdBOzs7Ozs7R0FNRztBQUNILE1BQU0sT0FBTyxpQkFBaUI7SUFJNUIsWUFDbUIsSUFBb0IsRUFDckMsS0FBd0M7UUFEdkIsU0FBSSxHQUFKLElBQUksQ0FBZ0I7UUFKdEIsVUFBSyxHQUFHLElBQUksR0FBRyxFQUFzQyxDQUFDO1FBQy9ELFdBQU0sR0FBZ0MsSUFBSSxDQUFDO1FBTWpELEtBQUssTUFBTSxJQUFJLElBQUksS0FBSztZQUFFLElBQUksQ0FBQyxLQUFLLENBQUMsR0FBRyxDQUFDLElBQUksQ0FBQyxFQUFFLEVBQUUsSUFBNEIsQ0FBQyxDQUFDO0lBQ2xGLENBQUM7SUFFRCxvQ0FBb0M7SUFDcEMsSUFBSSxRQUFRO1FBQ1YsT0FBTyxJQUFJLENBQUMsTUFBTSxFQUFFLEVBQUUsSUFBSSxJQUFJLENBQUM7SUFDakMsQ0FBQztJQUVELGdEQUFnRDtJQUNoRCxHQUFHLENBQUMsRUFBNkI7UUFDL0IsT0FBTyxFQUFFLElBQUksSUFBSSxJQUFJLElBQUksQ0FBQyxLQUFLLENBQUMsR0FBRyxDQUFDLEVBQWtCLENBQUMsQ0FBQztJQUMxRCxDQUFDO0lBRUQsa0RBQWtEO0lBQ2xELEdBQUcsQ0FBK0IsRUFBZ0I7UUFDaEQsT0FBTyxJQUFJLENBQUMsS0FBSyxDQUFDLEdBQUcsQ0FBQyxFQUFFLENBQWtCLENBQUM7SUFDN0MsQ0FBQztJQUVEOzs7O09BSUc7SUFDSCxRQUFRLENBQUMsRUFBaUIsRUFBRSxPQUFpQjtRQUMzQyxNQUFNLElBQUksR0FBRyxJQUFJLENBQUMsR0FBRyxDQUFDLEVBQUUsQ0FBQyxDQUFDLENBQUMsQ0FBQyxJQUFJLENBQUMsS0FBSyxDQUFDLEdBQUcsQ0FBQyxFQUFFLENBQUUsQ0FBQyxDQUFDLENBQUMsSUFBSSxDQUFDO1FBQ3ZELElBQUksSUFBSSxDQUFDLE1BQU0sSUFBSSxJQUFJLENBQUMsTUFBTSxLQUFLLElBQUk7WUFBRSxJQUFJLENBQUMsVUFBVSxFQUFFLENBQUM7UUFDM0QsSUFBSSxDQUFDLElBQUk7WUFBRSxPQUFPO1FBQ2xCLElBQUksQ0FBQyxNQUFNLEdBQUcsSUFBSSxDQUFDO1FBQ25CLElBQUksQ0FBQyxRQUFRLENBQUMsSUFBSSxDQUFDLElBQUksRUFBRSxPQUFPLENBQUMsQ0FBQztJQUNwQyxDQUFDO0lBRUQscUNBQXFDO0lBQ3JDLFVBQVU7UUFDUixNQUFNLElBQUksR0FBRyxJQUFJLENBQUMsTUFBTSxDQUFDO1FBQ3pCLElBQUksQ0FBQyxNQUFNLEdBQUcsSUFBSSxDQUFDO1FBQ25CLElBQUksRUFBRSxVQUFVLEVBQUUsQ0FBQztJQUNyQixDQUFDO0lBRUQsb0RBQW9EO0lBQ3BELFVBQVUsQ0FBQyxFQUFnQixFQUFFLE9BQWdCO1FBQzNDLElBQUksQ0FBQyxLQUFLLENBQUMsR0FBRyxDQUFDLEVBQUUsQ0FBQyxFQUFFLFVBQVUsRUFBRSxDQUFDLE9BQU8sQ0FBQyxDQUFDO0lBQzVDLENBQUM7SUFFRCx5REFBeUQ7SUFDekQsS0FBSyxDQUFDLEVBQWdCO1FBQ3BCLElBQUksQ0FBQyxLQUFLLENBQUMsR0FBRyxDQUFDLEVBQUUsQ0FBQyxFQUFFLEtBQUssRUFBRSxFQUFFLENBQUM7SUFDaEMsQ0FBQztJQUVEOzRFQUN3RTtJQUN4RSxRQUFRO1FBQ04sS0FBSyxNQUFNLElBQUksSUFBSSxJQUFJLENBQUMsS0FBSyxDQUFDLE1BQU0sRUFBRTtZQUFFLElBQUksQ0FBQyxLQUFLLEVBQUUsRUFBRSxDQUFDO0lBQ3pELENBQUM7Q0FDRiIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB0eXBlIHsgQ2FudmFzVG9vbElkIH0gZnJvbSAnLi4vLi4vY29udHJhY3RzL2Rpc3BsYXktdHlwZXMnO1xuaW1wb3J0IHsgQ2FudmFzVG9vbEhvc3QsIElDYW52YXNUb29sIH0gZnJvbSAnLi9jYW52YXMtdG9vbCc7XG5cbi8qKlxuICogT25lIGJhY2tlbmQncyBjYW52YXMgdG9vbHMuIEVhY2ggYmFja2VuZCAoUGxvdGx5LCBPcGVuU2VhZHJhZ29uLCBuYXBhcmktanMpXG4gKiBjcmVhdGVzIGl0cyBvd24gbWFuYWdlciB3aXRoIGl0cyBvd24ge0BsaW5rIENhbnZhc1Rvb2xIb3N0fSBhbmQgaXRzIG93biB0b29sXG4gKiBpbnN0YW5jZXMsIHNvIGFybWluZyBhIHRvb2wgbmV2ZXIgcmUtYmluZHMgYSB0b29sIGFub3RoZXIgYmFja2VuZCBpcyB1c2luZyxcbiAqIGFuZCBhIGJhY2tlbmQgc3dpdGNoIG5ldmVyIGNhcnJpZXMgYSBzdHJva2Ugb3IgU0FNIHBvaW50cyBhY3Jvc3MgKFJULTIxKS5cbiAqIEF0IG1vc3Qgb25lIHRvb2wgaXMgYXJtZWQgYXQgYSB0aW1lLlxuICovXG5leHBvcnQgY2xhc3MgQ2FudmFzVG9vbE1hbmFnZXIge1xuICBwcml2YXRlIHJlYWRvbmx5IHRvb2xzID0gbmV3IE1hcDxDYW52YXNUb29sSWQsIElDYW52YXNUb29sPHVua25vd24+PigpO1xuICBwcml2YXRlIGFjdGl2ZTogSUNhbnZhc1Rvb2w8dW5rbm93bj4gfCBudWxsID0gbnVsbDtcblxuICBjb25zdHJ1Y3RvcihcbiAgICBwcml2YXRlIHJlYWRvbmx5IGhvc3Q6IENhbnZhc1Rvb2xIb3N0LFxuICAgIHRvb2xzOiBSZWFkb25seUFycmF5PElDYW52YXNUb29sPG5ldmVyPj4sXG4gICkge1xuICAgIGZvciAoY29uc3QgdG9vbCBvZiB0b29scykgdGhpcy50b29scy5zZXQodG9vbC5pZCwgdG9vbCBhcyBJQ2FudmFzVG9vbDx1bmtub3duPik7XG4gIH1cblxuICAvKiogVGhlIGFybWVkIHRvb2wncyBpZCwgb3IgbnVsbC4gKi9cbiAgZ2V0IGFjdGl2ZUlkKCk6IENhbnZhc1Rvb2xJZCB8IG51bGwge1xuICAgIHJldHVybiB0aGlzLmFjdGl2ZT8uaWQgPz8gbnVsbDtcbiAgfVxuXG4gIC8qKiBXaGV0aGVyIHRoaXMgbWFuYWdlciBoYXMgYSB0b29sIGZvciBgaWRgLiAqL1xuICBoYXMoaWQ6IHN0cmluZyB8IG51bGwgfCB1bmRlZmluZWQpOiBpZCBpcyBDYW52YXNUb29sSWQge1xuICAgIHJldHVybiBpZCAhPSBudWxsICYmIHRoaXMudG9vbHMuaGFzKGlkIGFzIENhbnZhc1Rvb2xJZCk7XG4gIH1cblxuICAvKiogVGhlIHRvb2wgd2l0aCB0aGlzIGlkLCB0eXBlZCBieSB0aGUgY2FsbGVyLiAqL1xuICBnZXQ8VCBleHRlbmRzIElDYW52YXNUb29sPG5ldmVyPj4oaWQ6IENhbnZhc1Rvb2xJZCk6IFQgfCB1bmRlZmluZWQge1xuICAgIHJldHVybiB0aGlzLnRvb2xzLmdldChpZCkgYXMgVCB8IHVuZGVmaW5lZDtcbiAgfVxuXG4gIC8qKlxuICAgKiBBcm0gYGlkYCB3aXRoIGBvcHRpb25zYCwgZGlzYXJtaW5nIHRoZSBhcm1lZCB0b29sIGZpcnN0LiBudWxsIOKAlCBvciBhbiBpZFxuICAgKiB0aGlzIG1hbmFnZXIgaGFzIG5vIHRvb2wgZm9yLCBzdWNoIGFzIGEgcmVnaW9uIGRyYXcgbW9kZSDigJQgZGlzYXJtcyBvbmx5LlxuICAgKiBBcm1pbmcgdGhlIGFybWVkIHRvb2wgYWdhaW4gZm9yd2FyZHMgYG9wdGlvbnNgIGFuZCBrZWVwcyBpdHMgd29yayBpbiBwcm9ncmVzcy5cbiAgICovXG4gIGFjdGl2YXRlKGlkOiBzdHJpbmcgfCBudWxsLCBvcHRpb25zPzogdW5rbm93bik6IHZvaWQge1xuICAgIGNvbnN0IG5leHQgPSB0aGlzLmhhcyhpZCkgPyB0aGlzLnRvb2xzLmdldChpZCkhIDogbnVsbDtcbiAgICBpZiAodGhpcy5hY3RpdmUgJiYgdGhpcy5hY3RpdmUgIT09IG5leHQpIHRoaXMuZGVhY3RpdmF0ZSgpO1xuICAgIGlmICghbmV4dCkgcmV0dXJuO1xuICAgIHRoaXMuYWN0aXZlID0gbmV4dDtcbiAgICBuZXh0LmFjdGl2YXRlKHRoaXMuaG9zdCwgb3B0aW9ucyk7XG4gIH1cblxuICAvKiogRGlzYXJtIHRoZSBhcm1lZCB0b29sLCBpZiBhbnkuICovXG4gIGRlYWN0aXZhdGUoKTogdm9pZCB7XG4gICAgY29uc3QgdG9vbCA9IHRoaXMuYWN0aXZlO1xuICAgIHRoaXMuYWN0aXZlID0gbnVsbDtcbiAgICB0b29sPy5kZWFjdGl2YXRlKCk7XG4gIH1cblxuICAvKiogRm9yd2FyZCBsaXZlIG9wdGlvbnMgdG8gYSB0b29sLCBhcm1lZCBvciBub3QuICovXG4gIHNldE9wdGlvbnMoaWQ6IENhbnZhc1Rvb2xJZCwgb3B0aW9uczogdW5rbm93bik6IHZvaWQge1xuICAgIHRoaXMudG9vbHMuZ2V0KGlkKT8uc2V0T3B0aW9ucz8uKG9wdGlvbnMpO1xuICB9XG5cbiAgLyoqIERyb3Agb25lIHRvb2wncyB3b3JrIGluIHByb2dyZXNzIChpdCBzdGF5cyBhcm1lZCkuICovXG4gIHJlc2V0KGlkOiBDYW52YXNUb29sSWQpOiB2b2lkIHtcbiAgICB0aGlzLnRvb2xzLmdldChpZCk/LnJlc2V0Py4oKTtcbiAgfVxuXG4gIC8qKiBEcm9wIGV2ZXJ5IHRvb2wncyB3b3JrIGluIHByb2dyZXNzIOKAlCBhZnRlciB1bmRvL3JlZG8gb3IgYW4gaW1hZ2Ugc3dpdGNoLFxuICAgKiAgd2hlcmUgYSBzdHJva2Ugb3IgcHJvbXB0IG5vIGxvbmdlciBtYXRjaGVzIHRoZSByZWdpb25zIG9uIHNjcmVlbi4gKi9cbiAgcmVzZXRBbGwoKTogdm9pZCB7XG4gICAgZm9yIChjb25zdCB0b29sIG9mIHRoaXMudG9vbHMudmFsdWVzKCkpIHRvb2wucmVzZXQ/LigpO1xuICB9XG59XG4iXX0=
|