@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,187 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Level-of-detail planning for tiled spatial geometry — cell outlines and transcripts.
|
|
3
|
+
*
|
|
4
|
+
* The renderer knows its camera (a world-space centre, a zoom in canvas pixels per world
|
|
5
|
+
* unit, a canvas size); a tiled dataset knows its grids (one per level, in observation
|
|
6
|
+
* units). This module is the bridge: which level the zoom calls for and which tiles are on
|
|
7
|
+
* screen. Everything here is pure, so the policy — the part that decides whether the view
|
|
8
|
+
* is fast and legible — is testable without a GPU.
|
|
9
|
+
*
|
|
10
|
+
* Observation units map onto world units through the dataset's `imageRef` affine
|
|
11
|
+
* (`world = data · scale + translate`), so "pixels per observation unit" is
|
|
12
|
+
* `zoom · scale`. For a Xenium bundle the data unit is the micron and the world unit the
|
|
13
|
+
* morphology pixel.
|
|
14
|
+
*/
|
|
15
|
+
import { worldViewport } from 'napari-js';
|
|
16
|
+
import { quantile } from './stats';
|
|
17
|
+
// ── What the view draws ───────────────────────────────────────────────────────────────
|
|
18
|
+
/** Whether cell outlines are drawn: the user's choice, else on when the dataset has any. */
|
|
19
|
+
export function cellsShown(dataset, view) {
|
|
20
|
+
const available = !!(dataset?.polygonTiles || dataset?.polygons);
|
|
21
|
+
return available && (view.showCells ?? true);
|
|
22
|
+
}
|
|
23
|
+
/** A column holding a hand-curated cell-type annotation, by naming convention. */
|
|
24
|
+
export function isCuratedColumn(name) {
|
|
25
|
+
return /curated/i.test(name);
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* The categorical column that names each cell's type: the view's choice when it is a
|
|
29
|
+
* column of this dataset, else the first categorical column that is not a curated
|
|
30
|
+
* annotation (a pipeline's clustering is the default; curation is opted into), else
|
|
31
|
+
* any categorical column.
|
|
32
|
+
*/
|
|
33
|
+
export function cellTypeColumnFor(dataset, view) {
|
|
34
|
+
const categorical = dataset.columns.filter((c) => c.kind === 'categorical');
|
|
35
|
+
if (view.cellTypeColumn && categorical.some((c) => c.name === view.cellTypeColumn)) {
|
|
36
|
+
return view.cellTypeColumn;
|
|
37
|
+
}
|
|
38
|
+
return (categorical.find((c) => !isCuratedColumn(c.name)) ?? categorical[0])?.name ?? null;
|
|
39
|
+
}
|
|
40
|
+
// ── Tiles in view ─────────────────────────────────────────────────────────────────────
|
|
41
|
+
/** A stable string id for a tile key, `level/gx/gy` — usable as a Map key. */
|
|
42
|
+
export function tileId(k) {
|
|
43
|
+
return `${k.level}/${k.gx}/${k.gy}`;
|
|
44
|
+
}
|
|
45
|
+
/** Canvas pixels per observation unit along x, for a camera zoom and a data→world affine. */
|
|
46
|
+
export function pixelsPerDataUnit(zoom, ref) {
|
|
47
|
+
return zoom * Math.abs(ref?.scale?.[0] ?? 1);
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* The part of observation space the camera shows, padded by `margin` (a fraction of the
|
|
51
|
+
* viewport) so tiles just off screen are already there when a pan brings them in: napari-js's
|
|
52
|
+
* `worldViewport`, mapped back through the inverse of the data→world affine.
|
|
53
|
+
*/
|
|
54
|
+
export function visibleDataRect(center, zoom, canvasW, canvasH, ref, margin = 0.15) {
|
|
55
|
+
if (!(zoom > 0) || !(canvasW > 0) || !(canvasH > 0))
|
|
56
|
+
return null;
|
|
57
|
+
const sx = ref?.scale?.[0] ?? 1;
|
|
58
|
+
const sy = ref?.scale?.[1] ?? 1;
|
|
59
|
+
const tx = ref?.translate?.[0] ?? 0;
|
|
60
|
+
const ty = ref?.translate?.[1] ?? 0;
|
|
61
|
+
// The world rect of a canvas grown by the margin on each side (napari-js's worldViewport).
|
|
62
|
+
const v = worldViewport(center[0], center[1], zoom, canvasW * (1 + 2 * margin), canvasH * (1 + 2 * margin));
|
|
63
|
+
const wx0 = v.x;
|
|
64
|
+
const wx1 = v.x + v.width;
|
|
65
|
+
const wy0 = v.y;
|
|
66
|
+
const wy1 = v.y + v.height;
|
|
67
|
+
const ax = (wx0 - tx) / sx;
|
|
68
|
+
const bx = (wx1 - tx) / sx;
|
|
69
|
+
const ay = (wy0 - ty) / sy;
|
|
70
|
+
const by = (wy1 - ty) / sy;
|
|
71
|
+
return { x0: Math.min(ax, bx), y0: Math.min(ay, by), x1: Math.max(ax, bx), y1: Math.max(ay, by) };
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Tiles of one level intersecting `rect`, clipped to the dataset's `bounds` (so zooming
|
|
75
|
+
* out over empty canvas does not ask for tiles that cannot exist). Ordered from the
|
|
76
|
+
* rectangle's centre outward, so the middle of the screen fills in first.
|
|
77
|
+
*
|
|
78
|
+
* Tile `g` covers `[g·s, (g+1)·s)`. The view's far edge is open — a tile starting exactly
|
|
79
|
+
* at `rect.x1` shows nothing — but the bounds' far edge is closed: the bounds are the
|
|
80
|
+
* extreme observations' coordinates, so one sits exactly on `bounds[2]`, in the tile
|
|
81
|
+
* starting there.
|
|
82
|
+
*/
|
|
83
|
+
export function tilesInRect(rect, level, levels, bounds, limit = Infinity) {
|
|
84
|
+
const size = levels[level]?.tileSize;
|
|
85
|
+
if (!(size > 0))
|
|
86
|
+
return [];
|
|
87
|
+
let { x0, y0 } = rect;
|
|
88
|
+
// Last tile along an axis: the one before the open view edge, at most the closed bound's.
|
|
89
|
+
let gx1 = Math.ceil(rect.x1 / size) - 1;
|
|
90
|
+
let gy1 = Math.ceil(rect.y1 / size) - 1;
|
|
91
|
+
if (bounds) {
|
|
92
|
+
x0 = Math.max(x0, bounds[0]);
|
|
93
|
+
y0 = Math.max(y0, bounds[1]);
|
|
94
|
+
if (Math.min(rect.x1, bounds[2]) < x0 || Math.min(rect.y1, bounds[3]) < y0)
|
|
95
|
+
return [];
|
|
96
|
+
gx1 = Math.min(gx1, Math.floor(bounds[2] / size));
|
|
97
|
+
gy1 = Math.min(gy1, Math.floor(bounds[3] / size));
|
|
98
|
+
}
|
|
99
|
+
const gx0 = Math.floor(x0 / size);
|
|
100
|
+
const gy0 = Math.floor(y0 / size);
|
|
101
|
+
const cx = (rect.x0 + rect.x1) / 2 / size;
|
|
102
|
+
const cy = (rect.y0 + rect.y1) / 2 / size;
|
|
103
|
+
const out = [];
|
|
104
|
+
for (let gy = gy0; gy <= gy1; gy++) {
|
|
105
|
+
for (let gx = gx0; gx <= gx1; gx++)
|
|
106
|
+
out.push({ level, gx, gy });
|
|
107
|
+
}
|
|
108
|
+
out.sort((a, b) => (a.gx + 0.5 - cx) ** 2 + (a.gy + 0.5 - cy) ** 2 - ((b.gx + 0.5 - cx) ** 2 + (b.gy + 0.5 - cy) ** 2));
|
|
109
|
+
return out.length > limit ? out.slice(0, limit) : out;
|
|
110
|
+
}
|
|
111
|
+
/** {@link tilesInRect} for a grid whose tile (0, 0) starts at `origin`. */
|
|
112
|
+
export function tilesInRectFrom(origin, rect, level, levels, bounds, limit = Infinity) {
|
|
113
|
+
const [ox, oy] = origin;
|
|
114
|
+
const shifted = { x0: rect.x0 - ox, y0: rect.y0 - oy, x1: rect.x1 - ox, y1: rect.y1 - oy };
|
|
115
|
+
const b = bounds ? [bounds[0] - ox, bounds[1] - oy, bounds[2] - ox, bounds[3] - oy] : null;
|
|
116
|
+
return tilesInRect(shifted, level, levels, b, limit);
|
|
117
|
+
}
|
|
118
|
+
/** Area of `rect` inside `bounds` (the whole rect when there are none). */
|
|
119
|
+
export function visibleArea(rect, bounds) {
|
|
120
|
+
const x0 = bounds ? Math.max(rect.x0, bounds[0]) : rect.x0;
|
|
121
|
+
const y0 = bounds ? Math.max(rect.y0, bounds[1]) : rect.y0;
|
|
122
|
+
const x1 = bounds ? Math.min(rect.x1, bounds[2]) : rect.x1;
|
|
123
|
+
const y1 = bounds ? Math.min(rect.y1, bounds[3]) : rect.y1;
|
|
124
|
+
return Math.max(0, x1 - x0) * Math.max(0, y1 - y0);
|
|
125
|
+
}
|
|
126
|
+
// ── Levels ────────────────────────────────────────────────────────────────────────────
|
|
127
|
+
/**
|
|
128
|
+
* Typical cell diameter, in observation units, used to judge how large cells appear.
|
|
129
|
+
* Derived from the per-observation radius when there is one; 12 µm otherwise.
|
|
130
|
+
*/
|
|
131
|
+
export function typicalCellDiameter(radius, fallback = 12) {
|
|
132
|
+
if (typeof radius === 'number')
|
|
133
|
+
return radius > 0 ? radius * 2 : fallback;
|
|
134
|
+
if (!radius?.length)
|
|
135
|
+
return fallback;
|
|
136
|
+
// The median of a sample is plenty — this sets a threshold, not a measurement.
|
|
137
|
+
const median = quantile(radius, 0.5, { filter: 'positive', sampleSize: 2048 });
|
|
138
|
+
return median === null ? fallback : median * 2;
|
|
139
|
+
}
|
|
140
|
+
/**
|
|
141
|
+
* On-screen cell diameter (px) at or above which each polygon level is used. A level
|
|
142
|
+
* halves the vertices of the one below, so each should take over when the cell is about
|
|
143
|
+
* half as large on screen. Below the last finite threshold outlines are not drawn at
|
|
144
|
+
* all — a cell a few pixels wide is a dot, and the observation markers already draw it
|
|
145
|
+
* as one.
|
|
146
|
+
*
|
|
147
|
+
* Xenium's fourth level (3 vertices per cell) is deliberately never used: seen on
|
|
148
|
+
* screen it is a field of triangles, which reads as an artefact rather than as cells.
|
|
149
|
+
* The dots below 8 px say the same thing more honestly.
|
|
150
|
+
*/
|
|
151
|
+
export const POLYGON_LEVEL_MIN_CELL_PX = [36, 18, 8, Infinity];
|
|
152
|
+
/**
|
|
153
|
+
* Which polygon level suits this zoom, or -1 for "too small to outline".
|
|
154
|
+
* `detail` > 1 prefers finer levels (sharper, slower); < 1 coarser.
|
|
155
|
+
*/
|
|
156
|
+
export function polygonLevelFor(pxPerUnit, cellDiameter, levelCount, detail = 1) {
|
|
157
|
+
const cellPx = pxPerUnit * cellDiameter * detail;
|
|
158
|
+
const table = POLYGON_LEVEL_MIN_CELL_PX;
|
|
159
|
+
for (let l = 0; l < levelCount; l++) {
|
|
160
|
+
// Past the table, keep halving: each level still halves the vertices.
|
|
161
|
+
const min = table[l] ?? table[table.length - 1] / 2 ** (l - table.length + 1);
|
|
162
|
+
if (cellPx >= min)
|
|
163
|
+
return l;
|
|
164
|
+
}
|
|
165
|
+
return -1;
|
|
166
|
+
}
|
|
167
|
+
/**
|
|
168
|
+
* Which transcript level suits this zoom: the one whose tiles come out closest to
|
|
169
|
+
* `targetTilePx` on screen. Coarser levels aggregate more, so this keeps the number of
|
|
170
|
+
* markers per screen roughly constant however far out the camera is — the property that
|
|
171
|
+
* keeps the view fast.
|
|
172
|
+
*/
|
|
173
|
+
export function transcriptLevelFor(pxPerUnit, levels, targetTilePx = 512) {
|
|
174
|
+
if (!levels.length || !(pxPerUnit > 0))
|
|
175
|
+
return 0;
|
|
176
|
+
let best = 0;
|
|
177
|
+
let bestErr = Infinity;
|
|
178
|
+
for (let l = 0; l < levels.length; l++) {
|
|
179
|
+
const err = Math.abs(Math.log2((levels[l].tileSize * pxPerUnit) / targetTilePx));
|
|
180
|
+
if (err < bestErr) {
|
|
181
|
+
bestErr = err;
|
|
182
|
+
best = l;
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
return best;
|
|
186
|
+
}
|
|
187
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibG9kLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vc3JjL2xpYi9zcGF0aWFsL2xvZC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQTs7Ozs7Ozs7Ozs7OztHQWFHO0FBRUgsT0FBTyxFQUFFLGFBQWEsRUFBRSxNQUFNLFdBQVcsQ0FBQztBQVMxQyxPQUFPLEVBQUUsUUFBUSxFQUFFLE1BQU0sU0FBUyxDQUFDO0FBaUJuQyx5RkFBeUY7QUFFekYsNEZBQTRGO0FBQzVGLE1BQU0sVUFBVSxVQUFVLENBQ3hCLE9BQWlFLEVBQ2pFLElBQXlDO0lBRXpDLE1BQU0sU0FBUyxHQUFHLENBQUMsQ0FBQyxDQUFDLE9BQU8sRUFBRSxZQUFZLElBQUksT0FBTyxFQUFFLFFBQVEsQ0FBQyxDQUFDO0lBQ2pFLE9BQU8sU0FBUyxJQUFJLENBQUMsSUFBSSxDQUFDLFNBQVMsSUFBSSxJQUFJLENBQUMsQ0FBQztBQUMvQyxDQUFDO0FBRUQsa0ZBQWtGO0FBQ2xGLE1BQU0sVUFBVSxlQUFlLENBQUMsSUFBWTtJQUMxQyxPQUFPLFVBQVUsQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLENBQUM7QUFDL0IsQ0FBQztBQUVEOzs7OztHQUtHO0FBQ0gsTUFBTSxVQUFVLGlCQUFpQixDQUMvQixPQUF1QixFQUN2QixJQUE4QztJQUU5QyxNQUFNLFdBQVcsR0FBRyxPQUFPLENBQUMsT0FBTyxDQUFDLE1BQU0sQ0FBQyxDQUFDLENBQUMsRUFBRSxFQUFFLENBQUMsQ0FBQyxDQUFDLElBQUksS0FBSyxhQUFhLENBQUMsQ0FBQztJQUM1RSxJQUFJLElBQUksQ0FBQyxjQUFjLElBQUksV0FBVyxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUMsRUFBRSxFQUFFLENBQUMsQ0FBQyxDQUFDLElBQUksS0FBSyxJQUFJLENBQUMsY0FBYyxDQUFDLEVBQUUsQ0FBQztRQUNuRixPQUFPLElBQUksQ0FBQyxjQUFjLENBQUM7SUFDN0IsQ0FBQztJQUNELE9BQU8sQ0FBQyxXQUFXLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQyxFQUFFLEVBQUUsQ0FBQyxDQUFDLGVBQWUsQ0FBQyxDQUFDLENBQUMsSUFBSSxDQUFDLENBQUMsSUFBSSxXQUFXLENBQUMsQ0FBQyxDQUFDLENBQUMsRUFBRSxJQUFJLElBQUksSUFBSSxDQUFDO0FBQzdGLENBQUM7QUFFRCx5RkFBeUY7QUFFekYsOEVBQThFO0FBQzlFLE1BQU0sVUFBVSxNQUFNLENBQUMsQ0FBVTtJQUMvQixPQUFPLEdBQUcsQ0FBQyxDQUFDLEtBQUssSUFBSSxDQUFDLENBQUMsRUFBRSxJQUFJLENBQUMsQ0FBQyxFQUFFLEVBQUUsQ0FBQztBQUN0QyxDQUFDO0FBRUQsNkZBQTZGO0FBQzdGLE1BQU0sVUFBVSxpQkFBaUIsQ0FBQyxJQUFZLEVBQUUsR0FBNEI7SUFDMUUsT0FBTyxJQUFJLEdBQUcsSUFBSSxDQUFDLEdBQUcsQ0FBQyxHQUFHLEVBQUUsS0FBSyxFQUFFLENBQUMsQ0FBQyxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUM7QUFDL0MsQ0FBQztBQUVEOzs7O0dBSUc7QUFDSCxNQUFNLFVBQVUsZUFBZSxDQUM3QixNQUFpQyxFQUNqQyxJQUFZLEVBQ1osT0FBZSxFQUNmLE9BQWUsRUFDZixHQUE0QixFQUM1QixNQUFNLEdBQUcsSUFBSTtJQUViLElBQUksQ0FBQyxDQUFDLElBQUksR0FBRyxDQUFDLENBQUMsSUFBSSxDQUFDLENBQUMsT0FBTyxHQUFHLENBQUMsQ0FBQyxJQUFJLENBQUMsQ0FBQyxPQUFPLEdBQUcsQ0FBQyxDQUFDO1FBQUUsT0FBTyxJQUFJLENBQUM7SUFDakUsTUFBTSxFQUFFLEdBQUcsR0FBRyxFQUFFLEtBQUssRUFBRSxDQUFDLENBQUMsQ0FBQyxJQUFJLENBQUMsQ0FBQztJQUNoQyxNQUFNLEVBQUUsR0FBRyxHQUFHLEVBQUUsS0FBSyxFQUFFLENBQUMsQ0FBQyxDQUFDLElBQUksQ0FBQyxDQUFDO0lBQ2hDLE1BQU0sRUFBRSxHQUFHLEdBQUcsRUFBRSxTQUFTLEVBQUUsQ0FBQyxDQUFDLENBQUMsSUFBSSxDQUFDLENBQUM7SUFDcEMsTUFBTSxFQUFFLEdBQUcsR0FBRyxFQUFFLFNBQVMsRUFBRSxDQUFDLENBQUMsQ0FBQyxJQUFJLENBQUMsQ0FBQztJQUNwQywyRkFBMkY7SUFDM0YsTUFBTSxDQUFDLEdBQUcsYUFBYSxDQUFDLE1BQU0sQ0FBQyxDQUFDLENBQUMsRUFBRSxNQUFNLENBQUMsQ0FBQyxDQUFDLEVBQUUsSUFBSSxFQUFFLE9BQU8sR0FBRyxDQUFDLENBQUMsR0FBRyxDQUFDLEdBQUcsTUFBTSxDQUFDLEVBQUUsT0FBTyxHQUFHLENBQUMsQ0FBQyxHQUFHLENBQUMsR0FBRyxNQUFNLENBQUMsQ0FBQyxDQUFDO0lBQzVHLE1BQU0sR0FBRyxHQUFHLENBQUMsQ0FBQyxDQUFDLENBQUM7SUFDaEIsTUFBTSxHQUFHLEdBQUcsQ0FBQyxDQUFDLENBQUMsR0FBRyxDQUFDLENBQUMsS0FBSyxDQUFDO0lBQzFCLE1BQU0sR0FBRyxHQUFHLENBQUMsQ0FBQyxDQUFDLENBQUM7SUFDaEIsTUFBTSxHQUFHLEdBQUcsQ0FBQyxDQUFDLENBQUMsR0FBRyxDQUFDLENBQUMsTUFBTSxDQUFDO0lBQzNCLE1BQU0sRUFBRSxHQUFHLENBQUMsR0FBRyxHQUFHLEVBQUUsQ0FBQyxHQUFHLEVBQUUsQ0FBQztJQUMzQixNQUFNLEVBQUUsR0FBRyxDQUFDLEdBQUcsR0FBRyxFQUFFLENBQUMsR0FBRyxFQUFFLENBQUM7SUFDM0IsTUFBTSxFQUFFLEdBQUcsQ0FBQyxHQUFHLEdBQUcsRUFBRSxDQUFDLEdBQUcsRUFBRSxDQUFDO0lBQzNCLE1BQU0sRUFBRSxHQUFHLENBQUMsR0FBRyxHQUFHLEVBQUUsQ0FBQyxHQUFHLEVBQUUsQ0FBQztJQUMzQixPQUFPLEVBQUUsRUFBRSxFQUFFLElBQUksQ0FBQyxHQUFHLENBQUMsRUFBRSxFQUFFLEVBQUUsQ0FBQyxFQUFFLEVBQUUsRUFBRSxJQUFJLENBQUMsR0FBRyxDQUFDLEVBQUUsRUFBRSxFQUFFLENBQUMsRUFBRSxFQUFFLEVBQUUsSUFBSSxDQUFDLEdBQUcsQ0FBQyxFQUFFLEVBQUUsRUFBRSxDQUFDLEVBQUUsRUFBRSxFQUFFLElBQUksQ0FBQyxHQUFHLENBQUMsRUFBRSxFQUFFLEVBQUUsQ0FBQyxFQUFFLENBQUM7QUFDcEcsQ0FBQztBQUVEOzs7Ozs7Ozs7R0FTRztBQUNILE1BQU0sVUFBVSxXQUFXLENBQ3pCLElBQWMsRUFDZCxLQUFhLEVBQ2IsTUFBbUMsRUFDbkMsTUFBNkIsRUFDN0IsS0FBSyxHQUFHLFFBQVE7SUFFaEIsTUFBTSxJQUFJLEdBQUcsTUFBTSxDQUFDLEtBQUssQ0FBQyxFQUFFLFFBQVEsQ0FBQztJQUNyQyxJQUFJLENBQUMsQ0FBQyxJQUFJLEdBQUcsQ0FBQyxDQUFDO1FBQUUsT0FBTyxFQUFFLENBQUM7SUFDM0IsSUFBSSxFQUFFLEVBQUUsRUFBRSxFQUFFLEVBQUUsR0FBRyxJQUFJLENBQUM7SUFDdEIsMEZBQTBGO0lBQzFGLElBQUksR0FBRyxHQUFHLElBQUksQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLEVBQUUsR0FBRyxJQUFJLENBQUMsR0FBRyxDQUFDLENBQUM7SUFDeEMsSUFBSSxHQUFHLEdBQUcsSUFBSSxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsRUFBRSxHQUFHLElBQUksQ0FBQyxHQUFHLENBQUMsQ0FBQztJQUN4QyxJQUFJLE1BQU0sRUFBRSxDQUFDO1FBQ1gsRUFBRSxHQUFHLElBQUksQ0FBQyxHQUFHLENBQUMsRUFBRSxFQUFFLE1BQU0sQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDO1FBQzdCLEVBQUUsR0FBRyxJQUFJLENBQUMsR0FBRyxDQUFDLEVBQUUsRUFBRSxNQUFNLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQztRQUM3QixJQUFJLElBQUksQ0FBQyxHQUFHLENBQUMsSUFBSSxDQUFDLEVBQUUsRUFBRSxNQUFNLENBQUMsQ0FBQyxDQUFDLENBQUMsR0FBRyxFQUFFLElBQUksSUFBSSxDQUFDLEdBQUcsQ0FBQyxJQUFJLENBQUMsRUFBRSxFQUFFLE1BQU0sQ0FBQyxDQUFDLENBQUMsQ0FBQyxHQUFHLEVBQUU7WUFBRSxPQUFPLEVBQUUsQ0FBQztRQUN0RixHQUFHLEdBQUcsSUFBSSxDQUFDLEdBQUcsQ0FBQyxHQUFHLEVBQUUsSUFBSSxDQUFDLEtBQUssQ0FBQyxNQUFNLENBQUMsQ0FBQyxDQUFDLEdBQUcsSUFBSSxDQUFDLENBQUMsQ0FBQztRQUNsRCxHQUFHLEdBQUcsSUFBSSxDQUFDLEdBQUcsQ0FBQyxHQUFHLEVBQUUsSUFBSSxDQUFDLEtBQUssQ0FBQyxNQUFNLENBQUMsQ0FBQyxDQUFDLEdBQUcsSUFBSSxDQUFDLENBQUMsQ0FBQztJQUNwRCxDQUFDO0lBQ0QsTUFBTSxHQUFHLEdBQUcsSUFBSSxDQUFDLEtBQUssQ0FBQyxFQUFFLEdBQUcsSUFBSSxDQUFDLENBQUM7SUFDbEMsTUFBTSxHQUFHLEdBQUcsSUFBSSxDQUFDLEtBQUssQ0FBQyxFQUFFLEdBQUcsSUFBSSxDQUFDLENBQUM7SUFDbEMsTUFBTSxFQUFFLEdBQUcsQ0FBQyxJQUFJLENBQUMsRUFBRSxHQUFHLElBQUksQ0FBQyxFQUFFLENBQUMsR0FBRyxDQUFDLEdBQUcsSUFBSSxDQUFDO0lBQzFDLE1BQU0sRUFBRSxHQUFHLENBQUMsSUFBSSxDQUFDLEVBQUUsR0FBRyxJQUFJLENBQUMsRUFBRSxDQUFDLEdBQUcsQ0FBQyxHQUFHLElBQUksQ0FBQztJQUMxQyxNQUFNLEdBQUcsR0FBYyxFQUFFLENBQUM7SUFDMUIsS0FBSyxJQUFJLEVBQUUsR0FBRyxHQUFHLEVBQUUsRUFBRSxJQUFJLEdBQUcsRUFBRSxFQUFFLEVBQUUsRUFBRSxDQUFDO1FBQ25DLEtBQUssSUFBSSxFQUFFLEdBQUcsR0FBRyxFQUFFLEVBQUUsSUFBSSxHQUFHLEVBQUUsRUFBRSxFQUFFO1lBQUUsR0FBRyxDQUFDLElBQUksQ0FBQyxFQUFFLEtBQUssRUFBRSxFQUFFLEVBQUUsRUFBRSxFQUFFLENBQUMsQ0FBQztJQUNsRSxDQUFDO0lBQ0QsR0FBRyxDQUFDLElBQUksQ0FDTixDQUFDLENBQUMsRUFBRSxDQUFDLEVBQUUsRUFBRSxDQUFDLENBQUMsQ0FBQyxDQUFDLEVBQUUsR0FBRyxHQUFHLEdBQUcsRUFBRSxDQUFDLElBQUksQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDLEVBQUUsR0FBRyxHQUFHLEdBQUcsRUFBRSxDQUFDLElBQUksQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDLENBQUMsRUFBRSxHQUFHLEdBQUcsR0FBRyxFQUFFLENBQUMsSUFBSSxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUMsRUFBRSxHQUFHLEdBQUcsR0FBRyxFQUFFLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FDOUcsQ0FBQztJQUNGLE9BQU8sR0FBRyxDQUFDLE1BQU0sR0FBRyxLQUFLLENBQUMsQ0FBQyxDQUFDLEdBQUcsQ0FBQyxLQUFLLENBQUMsQ0FBQyxFQUFFLEtBQUssQ0FBQyxDQUFDLENBQUMsQ0FBQyxHQUFHLENBQUM7QUFDeEQsQ0FBQztBQUVELDJFQUEyRTtBQUMzRSxNQUFNLFVBQVUsZUFBZSxDQUM3QixNQUFpQyxFQUNqQyxJQUFjLEVBQ2QsS0FBYSxFQUNiLE1BQW1DLEVBQ25DLE1BQTZCLEVBQzdCLEtBQUssR0FBRyxRQUFRO0lBRWhCLE1BQU0sQ0FBQyxFQUFFLEVBQUUsRUFBRSxDQUFDLEdBQUcsTUFBTSxDQUFDO0lBQ3hCLE1BQU0sT0FBTyxHQUFHLEVBQUUsRUFBRSxFQUFFLElBQUksQ0FBQyxFQUFFLEdBQUcsRUFBRSxFQUFFLEVBQUUsRUFBRSxJQUFJLENBQUMsRUFBRSxHQUFHLEVBQUUsRUFBRSxFQUFFLEVBQUUsSUFBSSxDQUFDLEVBQUUsR0FBRyxFQUFFLEVBQUUsRUFBRSxFQUFFLElBQUksQ0FBQyxFQUFFLEdBQUcsRUFBRSxFQUFFLENBQUM7SUFDM0YsTUFBTSxDQUFDLEdBQXlCLE1BQU0sQ0FBQyxDQUFDLENBQUMsQ0FBQyxNQUFNLENBQUMsQ0FBQyxDQUFDLEdBQUcsRUFBRSxFQUFFLE1BQU0sQ0FBQyxDQUFDLENBQUMsR0FBRyxFQUFFLEVBQUUsTUFBTSxDQUFDLENBQUMsQ0FBQyxHQUFHLEVBQUUsRUFBRSxNQUFNLENBQUMsQ0FBQyxDQUFDLEdBQUcsRUFBRSxDQUFDLENBQUMsQ0FBQyxDQUFDLElBQUksQ0FBQztJQUNqSCxPQUFPLFdBQVcsQ0FBQyxPQUFPLEVBQUUsS0FBSyxFQUFFLE1BQU0sRUFBRSxDQUFDLEVBQUUsS0FBSyxDQUFDLENBQUM7QUFDdkQsQ0FBQztBQUVELDJFQUEyRTtBQUMzRSxNQUFNLFVBQVUsV0FBVyxDQUFDLElBQWMsRUFBRSxNQUE2QjtJQUN2RSxNQUFNLEVBQUUsR0FBRyxNQUFNLENBQUMsQ0FBQyxDQUFDLElBQUksQ0FBQyxHQUFHLENBQUMsSUFBSSxDQUFDLEVBQUUsRUFBRSxNQUFNLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsSUFBSSxDQUFDLEVBQUUsQ0FBQztJQUMzRCxNQUFNLEVBQUUsR0FBRyxNQUFNLENBQUMsQ0FBQyxDQUFDLElBQUksQ0FBQyxHQUFHLENBQUMsSUFBSSxDQUFDLEVBQUUsRUFBRSxNQUFNLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsSUFBSSxDQUFDLEVBQUUsQ0FBQztJQUMzRCxNQUFNLEVBQUUsR0FBRyxNQUFNLENBQUMsQ0FBQyxDQUFDLElBQUksQ0FBQyxHQUFHLENBQUMsSUFBSSxDQUFDLEVBQUUsRUFBRSxNQUFNLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsSUFBSSxDQUFDLEVBQUUsQ0FBQztJQUMzRCxNQUFNLEVBQUUsR0FBRyxNQUFNLENBQUMsQ0FBQyxDQUFDLElBQUksQ0FBQyxHQUFHLENBQUMsSUFBSSxDQUFDLEVBQUUsRUFBRSxNQUFNLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsSUFBSSxDQUFDLEVBQUUsQ0FBQztJQUMzRCxPQUFPLElBQUksQ0FBQyxHQUFHLENBQUMsQ0FBQyxFQUFFLEVBQUUsR0FBRyxFQUFFLENBQUMsR0FBRyxJQUFJLENBQUMsR0FBRyxDQUFDLENBQUMsRUFBRSxFQUFFLEdBQUcsRUFBRSxDQUFDLENBQUM7QUFDckQsQ0FBQztBQUVELHlGQUF5RjtBQUV6Rjs7O0dBR0c7QUFDSCxNQUFNLFVBQVUsbUJBQW1CLENBQUMsTUFBeUMsRUFBRSxRQUFRLEdBQUcsRUFBRTtJQUMxRixJQUFJLE9BQU8sTUFBTSxLQUFLLFFBQVE7UUFBRSxPQUFPLE1BQU0sR0FBRyxDQUFDLENBQUMsQ0FBQyxDQUFDLE1BQU0sR0FBRyxDQUFDLENBQUMsQ0FBQyxDQUFDLFFBQVEsQ0FBQztJQUMxRSxJQUFJLENBQUMsTUFBTSxFQUFFLE1BQU07UUFBRSxPQUFPLFFBQVEsQ0FBQztJQUNyQywrRUFBK0U7SUFDL0UsTUFBTSxNQUFNLEdBQUcsUUFBUSxDQUFDLE1BQU0sRUFBRSxHQUFHLEVBQUUsRUFBRSxNQUFNLEVBQUUsVUFBVSxFQUFFLFVBQVUsRUFBRSxJQUFJLEVBQUUsQ0FBQyxDQUFDO0lBQy9FLE9BQU8sTUFBTSxLQUFLLElBQUksQ0FBQyxDQUFDLENBQUMsUUFBUSxDQUFDLENBQUMsQ0FBQyxNQUFNLEdBQUcsQ0FBQyxDQUFDO0FBQ2pELENBQUM7QUFFRDs7Ozs7Ozs7OztHQVVHO0FBQ0gsTUFBTSxDQUFDLE1BQU0seUJBQXlCLEdBQUcsQ0FBQyxFQUFFLEVBQUUsRUFBRSxFQUFFLENBQUMsRUFBRSxRQUFRLENBQUMsQ0FBQztBQUUvRDs7O0dBR0c7QUFDSCxNQUFNLFVBQVUsZUFBZSxDQUFDLFNBQWlCLEVBQUUsWUFBb0IsRUFBRSxVQUFrQixFQUFFLE1BQU0sR0FBRyxDQUFDO0lBQ3JHLE1BQU0sTUFBTSxHQUFHLFNBQVMsR0FBRyxZQUFZLEdBQUcsTUFBTSxDQUFDO0lBQ2pELE1BQU0sS0FBSyxHQUFHLHlCQUF5QixDQUFDO0lBQ3hDLEtBQUssSUFBSSxDQUFDLEdBQUcsQ0FBQyxFQUFFLENBQUMsR0FBRyxVQUFVLEVBQUUsQ0FBQyxFQUFFLEVBQUUsQ0FBQztRQUNwQyxzRUFBc0U7UUFDdEUsTUFBTSxHQUFHLEdBQUcsS0FBSyxDQUFDLENBQUMsQ0FBQyxJQUFJLEtBQUssQ0FBQyxLQUFLLENBQUMsTUFBTSxHQUFHLENBQUMsQ0FBQyxHQUFHLENBQUMsSUFBSSxDQUFDLENBQUMsR0FBRyxLQUFLLENBQUMsTUFBTSxHQUFHLENBQUMsQ0FBQyxDQUFDO1FBQzlFLElBQUksTUFBTSxJQUFJLEdBQUc7WUFBRSxPQUFPLENBQUMsQ0FBQztJQUM5QixDQUFDO0lBQ0QsT0FBTyxDQUFDLENBQUMsQ0FBQztBQUNaLENBQUM7QUFFRDs7Ozs7R0FLRztBQUNILE1BQU0sVUFBVSxrQkFBa0IsQ0FDaEMsU0FBaUIsRUFDakIsTUFBbUMsRUFDbkMsWUFBWSxHQUFHLEdBQUc7SUFFbEIsSUFBSSxDQUFDLE1BQU0sQ0FBQyxNQUFNLElBQUksQ0FBQyxDQUFDLFNBQVMsR0FBRyxDQUFDLENBQUM7UUFBRSxPQUFPLENBQUMsQ0FBQztJQUNqRCxJQUFJLElBQUksR0FBRyxDQUFDLENBQUM7SUFDYixJQUFJLE9BQU8sR0FBRyxRQUFRLENBQUM7SUFDdkIsS0FBSyxJQUFJLENBQUMsR0FBRyxDQUFDLEVBQUUsQ0FBQyxHQUFHLE1BQU0sQ0FBQyxNQUFNLEVBQUUsQ0FBQyxFQUFFLEVBQUUsQ0FBQztRQUN2QyxNQUFNLEdBQUcsR0FBRyxJQUFJLENBQUMsR0FBRyxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsQ0FBQyxNQUFNLENBQUMsQ0FBQyxDQUFDLENBQUMsUUFBUSxHQUFHLFNBQVMsQ0FBQyxHQUFHLFlBQVksQ0FBQyxDQUFDLENBQUM7UUFDakYsSUFBSSxHQUFHLEdBQUcsT0FBTyxFQUFFLENBQUM7WUFDbEIsT0FBTyxHQUFHLEdBQUcsQ0FBQztZQUNkLElBQUksR0FBRyxDQUFDLENBQUM7UUFDWCxDQUFDO0lBQ0gsQ0FBQztJQUNELE9BQU8sSUFBSSxDQUFDO0FBQ2QsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbIi8qKlxuICogTGV2ZWwtb2YtZGV0YWlsIHBsYW5uaW5nIGZvciB0aWxlZCBzcGF0aWFsIGdlb21ldHJ5IOKAlCBjZWxsIG91dGxpbmVzIGFuZCB0cmFuc2NyaXB0cy5cbiAqXG4gKiBUaGUgcmVuZGVyZXIga25vd3MgaXRzIGNhbWVyYSAoYSB3b3JsZC1zcGFjZSBjZW50cmUsIGEgem9vbSBpbiBjYW52YXMgcGl4ZWxzIHBlciB3b3JsZFxuICogdW5pdCwgYSBjYW52YXMgc2l6ZSk7IGEgdGlsZWQgZGF0YXNldCBrbm93cyBpdHMgZ3JpZHMgKG9uZSBwZXIgbGV2ZWwsIGluIG9ic2VydmF0aW9uXG4gKiB1bml0cykuIFRoaXMgbW9kdWxlIGlzIHRoZSBicmlkZ2U6IHdoaWNoIGxldmVsIHRoZSB6b29tIGNhbGxzIGZvciBhbmQgd2hpY2ggdGlsZXMgYXJlIG9uXG4gKiBzY3JlZW4uIEV2ZXJ5dGhpbmcgaGVyZSBpcyBwdXJlLCBzbyB0aGUgcG9saWN5IOKAlCB0aGUgcGFydCB0aGF0IGRlY2lkZXMgd2hldGhlciB0aGUgdmlld1xuICogaXMgZmFzdCBhbmQgbGVnaWJsZSDigJQgaXMgdGVzdGFibGUgd2l0aG91dCBhIEdQVS5cbiAqXG4gKiBPYnNlcnZhdGlvbiB1bml0cyBtYXAgb250byB3b3JsZCB1bml0cyB0aHJvdWdoIHRoZSBkYXRhc2V0J3MgYGltYWdlUmVmYCBhZmZpbmVcbiAqIChgd29ybGQgPSBkYXRhIMK3IHNjYWxlICsgdHJhbnNsYXRlYCksIHNvIFwicGl4ZWxzIHBlciBvYnNlcnZhdGlvbiB1bml0XCIgaXNcbiAqIGB6b29tIMK3IHNjYWxlYC4gRm9yIGEgWGVuaXVtIGJ1bmRsZSB0aGUgZGF0YSB1bml0IGlzIHRoZSBtaWNyb24gYW5kIHRoZSB3b3JsZCB1bml0IHRoZVxuICogbW9ycGhvbG9neSBwaXhlbC5cbiAqL1xuXG5pbXBvcnQgeyB3b3JsZFZpZXdwb3J0IH0gZnJvbSAnbmFwYXJpLWpzJztcblxuaW1wb3J0IHR5cGUge1xuICBTcGF0aWFsQm91bmRzLFxuICBTcGF0aWFsRGF0YXNldCxcbiAgU3BhdGlhbEltYWdlUmVmLFxuICBTcGF0aWFsVGlsZUxldmVsLFxufSBmcm9tICcuLi9jb250cmFjdHMvc3BhdGlhbC1kYXRhc2V0LmNvbnRyYWN0JztcbmltcG9ydCB0eXBlIHsgU3BhdGlhbFZpZXdTdGF0ZSB9IGZyb20gJy4uL2NvbnRyYWN0cy9kaXNwbGF5LXR5cGVzJztcbmltcG9ydCB7IHF1YW50aWxlIH0gZnJvbSAnLi9zdGF0cyc7XG5cbi8qKiBBIHJlY3RhbmdsZSBpbiBvYnNlcnZhdGlvbiBjb29yZGluYXRlcy4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgRGF0YVJlY3Qge1xuICB4MDogbnVtYmVyO1xuICB5MDogbnVtYmVyO1xuICB4MTogbnVtYmVyO1xuICB5MTogbnVtYmVyO1xufVxuXG4vKiogVGlsZSBhZGRyZXNzLiAqL1xuZXhwb3J0IGludGVyZmFjZSBUaWxlS2V5IHtcbiAgbGV2ZWw6IG51bWJlcjtcbiAgZ3g6IG51bWJlcjtcbiAgZ3k6IG51bWJlcjtcbn1cblxuLy8g4pSA4pSAIFdoYXQgdGhlIHZpZXcgZHJhd3Mg4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSAXG5cbi8qKiBXaGV0aGVyIGNlbGwgb3V0bGluZXMgYXJlIGRyYXduOiB0aGUgdXNlcidzIGNob2ljZSwgZWxzZSBvbiB3aGVuIHRoZSBkYXRhc2V0IGhhcyBhbnkuICovXG5leHBvcnQgZnVuY3Rpb24gY2VsbHNTaG93bihcbiAgZGF0YXNldDogUGljazxTcGF0aWFsRGF0YXNldCwgJ3BvbHlnb25UaWxlcycgfCAncG9seWdvbnMnPiB8IG51bGwsXG4gIHZpZXc6IFBpY2s8U3BhdGlhbFZpZXdTdGF0ZSwgJ3Nob3dDZWxscyc+LFxuKTogYm9vbGVhbiB7XG4gIGNvbnN0IGF2YWlsYWJsZSA9ICEhKGRhdGFzZXQ/LnBvbHlnb25UaWxlcyB8fCBkYXRhc2V0Py5wb2x5Z29ucyk7XG4gIHJldHVybiBhdmFpbGFibGUgJiYgKHZpZXcuc2hvd0NlbGxzID8/IHRydWUpO1xufVxuXG4vKiogQSBjb2x1bW4gaG9sZGluZyBhIGhhbmQtY3VyYXRlZCBjZWxsLXR5cGUgYW5ub3RhdGlvbiwgYnkgbmFtaW5nIGNvbnZlbnRpb24uICovXG5leHBvcnQgZnVuY3Rpb24gaXNDdXJhdGVkQ29sdW1uKG5hbWU6IHN0cmluZyk6IGJvb2xlYW4ge1xuICByZXR1cm4gL2N1cmF0ZWQvaS50ZXN0KG5hbWUpO1xufVxuXG4vKipcbiAqIFRoZSBjYXRlZ29yaWNhbCBjb2x1bW4gdGhhdCBuYW1lcyBlYWNoIGNlbGwncyB0eXBlOiB0aGUgdmlldydzIGNob2ljZSB3aGVuIGl0IGlzIGFcbiAqIGNvbHVtbiBvZiB0aGlzIGRhdGFzZXQsIGVsc2UgdGhlIGZpcnN0IGNhdGVnb3JpY2FsIGNvbHVtbiB0aGF0IGlzIG5vdCBhIGN1cmF0ZWRcbiAqIGFubm90YXRpb24gKGEgcGlwZWxpbmUncyBjbHVzdGVyaW5nIGlzIHRoZSBkZWZhdWx0OyBjdXJhdGlvbiBpcyBvcHRlZCBpbnRvKSwgZWxzZVxuICogYW55IGNhdGVnb3JpY2FsIGNvbHVtbi5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGNlbGxUeXBlQ29sdW1uRm9yKFxuICBkYXRhc2V0OiBTcGF0aWFsRGF0YXNldCxcbiAgdmlldzogUGljazxTcGF0aWFsVmlld1N0YXRlLCAnY2VsbFR5cGVDb2x1bW4nPixcbik6IHN0cmluZyB8IG51bGwge1xuICBjb25zdCBjYXRlZ29yaWNhbCA9IGRhdGFzZXQuY29sdW1ucy5maWx0ZXIoKGMpID0+IGMua2luZCA9PT0gJ2NhdGVnb3JpY2FsJyk7XG4gIGlmICh2aWV3LmNlbGxUeXBlQ29sdW1uICYmIGNhdGVnb3JpY2FsLnNvbWUoKGMpID0+IGMubmFtZSA9PT0gdmlldy5jZWxsVHlwZUNvbHVtbikpIHtcbiAgICByZXR1cm4gdmlldy5jZWxsVHlwZUNvbHVtbjtcbiAgfVxuICByZXR1cm4gKGNhdGVnb3JpY2FsLmZpbmQoKGMpID0+ICFpc0N1cmF0ZWRDb2x1bW4oYy5uYW1lKSkgPz8gY2F0ZWdvcmljYWxbMF0pPy5uYW1lID8/IG51bGw7XG59XG5cbi8vIOKUgOKUgCBUaWxlcyBpbiB2aWV3IOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgFxuXG4vKiogQSBzdGFibGUgc3RyaW5nIGlkIGZvciBhIHRpbGUga2V5LCBgbGV2ZWwvZ3gvZ3lgIOKAlCB1c2FibGUgYXMgYSBNYXAga2V5LiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHRpbGVJZChrOiBUaWxlS2V5KTogc3RyaW5nIHtcbiAgcmV0dXJuIGAke2subGV2ZWx9LyR7ay5neH0vJHtrLmd5fWA7XG59XG5cbi8qKiBDYW52YXMgcGl4ZWxzIHBlciBvYnNlcnZhdGlvbiB1bml0IGFsb25nIHgsIGZvciBhIGNhbWVyYSB6b29tIGFuZCBhIGRhdGHihpJ3b3JsZCBhZmZpbmUuICovXG5leHBvcnQgZnVuY3Rpb24gcGl4ZWxzUGVyRGF0YVVuaXQoem9vbTogbnVtYmVyLCByZWY/OiBTcGF0aWFsSW1hZ2VSZWYgfCBudWxsKTogbnVtYmVyIHtcbiAgcmV0dXJuIHpvb20gKiBNYXRoLmFicyhyZWY/LnNjYWxlPy5bMF0gPz8gMSk7XG59XG5cbi8qKlxuICogVGhlIHBhcnQgb2Ygb2JzZXJ2YXRpb24gc3BhY2UgdGhlIGNhbWVyYSBzaG93cywgcGFkZGVkIGJ5IGBtYXJnaW5gIChhIGZyYWN0aW9uIG9mIHRoZVxuICogdmlld3BvcnQpIHNvIHRpbGVzIGp1c3Qgb2ZmIHNjcmVlbiBhcmUgYWxyZWFkeSB0aGVyZSB3aGVuIGEgcGFuIGJyaW5ncyB0aGVtIGluOiBuYXBhcmktanMnc1xuICogYHdvcmxkVmlld3BvcnRgLCBtYXBwZWQgYmFjayB0aHJvdWdoIHRoZSBpbnZlcnNlIG9mIHRoZSBkYXRh4oaSd29ybGQgYWZmaW5lLlxuICovXG5leHBvcnQgZnVuY3Rpb24gdmlzaWJsZURhdGFSZWN0KFxuICBjZW50ZXI6IHJlYWRvbmx5IFtudW1iZXIsIG51bWJlcl0sXG4gIHpvb206IG51bWJlcixcbiAgY2FudmFzVzogbnVtYmVyLFxuICBjYW52YXNIOiBudW1iZXIsXG4gIHJlZj86IFNwYXRpYWxJbWFnZVJlZiB8IG51bGwsXG4gIG1hcmdpbiA9IDAuMTUsXG4pOiBEYXRhUmVjdCB8IG51bGwge1xuICBpZiAoISh6b29tID4gMCkgfHwgIShjYW52YXNXID4gMCkgfHwgIShjYW52YXNIID4gMCkpIHJldHVybiBudWxsO1xuICBjb25zdCBzeCA9IHJlZj8uc2NhbGU/LlswXSA/PyAxO1xuICBjb25zdCBzeSA9IHJlZj8uc2NhbGU/LlsxXSA/PyAxO1xuICBjb25zdCB0eCA9IHJlZj8udHJhbnNsYXRlPy5bMF0gPz8gMDtcbiAgY29uc3QgdHkgPSByZWY/LnRyYW5zbGF0ZT8uWzFdID8/IDA7XG4gIC8vIFRoZSB3b3JsZCByZWN0IG9mIGEgY2FudmFzIGdyb3duIGJ5IHRoZSBtYXJnaW4gb24gZWFjaCBzaWRlIChuYXBhcmktanMncyB3b3JsZFZpZXdwb3J0KS5cbiAgY29uc3QgdiA9IHdvcmxkVmlld3BvcnQoY2VudGVyWzBdLCBjZW50ZXJbMV0sIHpvb20sIGNhbnZhc1cgKiAoMSArIDIgKiBtYXJnaW4pLCBjYW52YXNIICogKDEgKyAyICogbWFyZ2luKSk7XG4gIGNvbnN0IHd4MCA9IHYueDtcbiAgY29uc3Qgd3gxID0gdi54ICsgdi53aWR0aDtcbiAgY29uc3Qgd3kwID0gdi55O1xuICBjb25zdCB3eTEgPSB2LnkgKyB2LmhlaWdodDtcbiAgY29uc3QgYXggPSAod3gwIC0gdHgpIC8gc3g7XG4gIGNvbnN0IGJ4ID0gKHd4MSAtIHR4KSAvIHN4O1xuICBjb25zdCBheSA9ICh3eTAgLSB0eSkgLyBzeTtcbiAgY29uc3QgYnkgPSAod3kxIC0gdHkpIC8gc3k7XG4gIHJldHVybiB7IHgwOiBNYXRoLm1pbihheCwgYngpLCB5MDogTWF0aC5taW4oYXksIGJ5KSwgeDE6IE1hdGgubWF4KGF4LCBieCksIHkxOiBNYXRoLm1heChheSwgYnkpIH07XG59XG5cbi8qKlxuICogVGlsZXMgb2Ygb25lIGxldmVsIGludGVyc2VjdGluZyBgcmVjdGAsIGNsaXBwZWQgdG8gdGhlIGRhdGFzZXQncyBgYm91bmRzYCAoc28gem9vbWluZ1xuICogb3V0IG92ZXIgZW1wdHkgY2FudmFzIGRvZXMgbm90IGFzayBmb3IgdGlsZXMgdGhhdCBjYW5ub3QgZXhpc3QpLiBPcmRlcmVkIGZyb20gdGhlXG4gKiByZWN0YW5nbGUncyBjZW50cmUgb3V0d2FyZCwgc28gdGhlIG1pZGRsZSBvZiB0aGUgc2NyZWVuIGZpbGxzIGluIGZpcnN0LlxuICpcbiAqIFRpbGUgYGdgIGNvdmVycyBgW2fCt3MsIChnKzEpwrdzKWAuIFRoZSB2aWV3J3MgZmFyIGVkZ2UgaXMgb3BlbiDigJQgYSB0aWxlIHN0YXJ0aW5nIGV4YWN0bHlcbiAqIGF0IGByZWN0LngxYCBzaG93cyBub3RoaW5nIOKAlCBidXQgdGhlIGJvdW5kcycgZmFyIGVkZ2UgaXMgY2xvc2VkOiB0aGUgYm91bmRzIGFyZSB0aGVcbiAqIGV4dHJlbWUgb2JzZXJ2YXRpb25zJyBjb29yZGluYXRlcywgc28gb25lIHNpdHMgZXhhY3RseSBvbiBgYm91bmRzWzJdYCwgaW4gdGhlIHRpbGVcbiAqIHN0YXJ0aW5nIHRoZXJlLlxuICovXG5leHBvcnQgZnVuY3Rpb24gdGlsZXNJblJlY3QoXG4gIHJlY3Q6IERhdGFSZWN0LFxuICBsZXZlbDogbnVtYmVyLFxuICBsZXZlbHM6IHJlYWRvbmx5IFNwYXRpYWxUaWxlTGV2ZWxbXSxcbiAgYm91bmRzPzogU3BhdGlhbEJvdW5kcyB8IG51bGwsXG4gIGxpbWl0ID0gSW5maW5pdHksXG4pOiBUaWxlS2V5W10ge1xuICBjb25zdCBzaXplID0gbGV2ZWxzW2xldmVsXT8udGlsZVNpemU7XG4gIGlmICghKHNpemUgPiAwKSkgcmV0dXJuIFtdO1xuICBsZXQgeyB4MCwgeTAgfSA9IHJlY3Q7XG4gIC8vIExhc3QgdGlsZSBhbG9uZyBhbiBheGlzOiB0aGUgb25lIGJlZm9yZSB0aGUgb3BlbiB2aWV3IGVkZ2UsIGF0IG1vc3QgdGhlIGNsb3NlZCBib3VuZCdzLlxuICBsZXQgZ3gxID0gTWF0aC5jZWlsKHJlY3QueDEgLyBzaXplKSAtIDE7XG4gIGxldCBneTEgPSBNYXRoLmNlaWwocmVjdC55MSAvIHNpemUpIC0gMTtcbiAgaWYgKGJvdW5kcykge1xuICAgIHgwID0gTWF0aC5tYXgoeDAsIGJvdW5kc1swXSk7XG4gICAgeTAgPSBNYXRoLm1heCh5MCwgYm91bmRzWzFdKTtcbiAgICBpZiAoTWF0aC5taW4ocmVjdC54MSwgYm91bmRzWzJdKSA8IHgwIHx8IE1hdGgubWluKHJlY3QueTEsIGJvdW5kc1szXSkgPCB5MCkgcmV0dXJuIFtdO1xuICAgIGd4MSA9IE1hdGgubWluKGd4MSwgTWF0aC5mbG9vcihib3VuZHNbMl0gLyBzaXplKSk7XG4gICAgZ3kxID0gTWF0aC5taW4oZ3kxLCBNYXRoLmZsb29yKGJvdW5kc1szXSAvIHNpemUpKTtcbiAgfVxuICBjb25zdCBneDAgPSBNYXRoLmZsb29yKHgwIC8gc2l6ZSk7XG4gIGNvbnN0IGd5MCA9IE1hdGguZmxvb3IoeTAgLyBzaXplKTtcbiAgY29uc3QgY3ggPSAocmVjdC54MCArIHJlY3QueDEpIC8gMiAvIHNpemU7XG4gIGNvbnN0IGN5ID0gKHJlY3QueTAgKyByZWN0LnkxKSAvIDIgLyBzaXplO1xuICBjb25zdCBvdXQ6IFRpbGVLZXlbXSA9IFtdO1xuICBmb3IgKGxldCBneSA9IGd5MDsgZ3kgPD0gZ3kxOyBneSsrKSB7XG4gICAgZm9yIChsZXQgZ3ggPSBneDA7IGd4IDw9IGd4MTsgZ3grKykgb3V0LnB1c2goeyBsZXZlbCwgZ3gsIGd5IH0pO1xuICB9XG4gIG91dC5zb3J0KFxuICAgIChhLCBiKSA9PiAoYS5neCArIDAuNSAtIGN4KSAqKiAyICsgKGEuZ3kgKyAwLjUgLSBjeSkgKiogMiAtICgoYi5neCArIDAuNSAtIGN4KSAqKiAyICsgKGIuZ3kgKyAwLjUgLSBjeSkgKiogMiksXG4gICk7XG4gIHJldHVybiBvdXQubGVuZ3RoID4gbGltaXQgPyBvdXQuc2xpY2UoMCwgbGltaXQpIDogb3V0O1xufVxuXG4vKioge0BsaW5rIHRpbGVzSW5SZWN0fSBmb3IgYSBncmlkIHdob3NlIHRpbGUgKDAsIDApIHN0YXJ0cyBhdCBgb3JpZ2luYC4gKi9cbmV4cG9ydCBmdW5jdGlvbiB0aWxlc0luUmVjdEZyb20oXG4gIG9yaWdpbjogcmVhZG9ubHkgW251bWJlciwgbnVtYmVyXSxcbiAgcmVjdDogRGF0YVJlY3QsXG4gIGxldmVsOiBudW1iZXIsXG4gIGxldmVsczogcmVhZG9ubHkgU3BhdGlhbFRpbGVMZXZlbFtdLFxuICBib3VuZHM/OiBTcGF0aWFsQm91bmRzIHwgbnVsbCxcbiAgbGltaXQgPSBJbmZpbml0eSxcbik6IFRpbGVLZXlbXSB7XG4gIGNvbnN0IFtveCwgb3ldID0gb3JpZ2luO1xuICBjb25zdCBzaGlmdGVkID0geyB4MDogcmVjdC54MCAtIG94LCB5MDogcmVjdC55MCAtIG95LCB4MTogcmVjdC54MSAtIG94LCB5MTogcmVjdC55MSAtIG95IH07XG4gIGNvbnN0IGI6IFNwYXRpYWxCb3VuZHMgfCBudWxsID0gYm91bmRzID8gW2JvdW5kc1swXSAtIG94LCBib3VuZHNbMV0gLSBveSwgYm91bmRzWzJdIC0gb3gsIGJvdW5kc1szXSAtIG95XSA6IG51bGw7XG4gIHJldHVybiB0aWxlc0luUmVjdChzaGlmdGVkLCBsZXZlbCwgbGV2ZWxzLCBiLCBsaW1pdCk7XG59XG5cbi8qKiBBcmVhIG9mIGByZWN0YCBpbnNpZGUgYGJvdW5kc2AgKHRoZSB3aG9sZSByZWN0IHdoZW4gdGhlcmUgYXJlIG5vbmUpLiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHZpc2libGVBcmVhKHJlY3Q6IERhdGFSZWN0LCBib3VuZHM/OiBTcGF0aWFsQm91bmRzIHwgbnVsbCk6IG51bWJlciB7XG4gIGNvbnN0IHgwID0gYm91bmRzID8gTWF0aC5tYXgocmVjdC54MCwgYm91bmRzWzBdKSA6IHJlY3QueDA7XG4gIGNvbnN0IHkwID0gYm91bmRzID8gTWF0aC5tYXgocmVjdC55MCwgYm91bmRzWzFdKSA6IHJlY3QueTA7XG4gIGNvbnN0IHgxID0gYm91bmRzID8gTWF0aC5taW4ocmVjdC54MSwgYm91bmRzWzJdKSA6IHJlY3QueDE7XG4gIGNvbnN0IHkxID0gYm91bmRzID8gTWF0aC5taW4ocmVjdC55MSwgYm91bmRzWzNdKSA6IHJlY3QueTE7XG4gIHJldHVybiBNYXRoLm1heCgwLCB4MSAtIHgwKSAqIE1hdGgubWF4KDAsIHkxIC0geTApO1xufVxuXG4vLyDilIDilIAgTGV2ZWxzIOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgFxuXG4vKipcbiAqIFR5cGljYWwgY2VsbCBkaWFtZXRlciwgaW4gb2JzZXJ2YXRpb24gdW5pdHMsIHVzZWQgdG8ganVkZ2UgaG93IGxhcmdlIGNlbGxzIGFwcGVhci5cbiAqIERlcml2ZWQgZnJvbSB0aGUgcGVyLW9ic2VydmF0aW9uIHJhZGl1cyB3aGVuIHRoZXJlIGlzIG9uZTsgMTIgwrVtIG90aGVyd2lzZS5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHR5cGljYWxDZWxsRGlhbWV0ZXIocmFkaXVzOiBGbG9hdDMyQXJyYXkgfCBudW1iZXIgfCB1bmRlZmluZWQsIGZhbGxiYWNrID0gMTIpOiBudW1iZXIge1xuICBpZiAodHlwZW9mIHJhZGl1cyA9PT0gJ251bWJlcicpIHJldHVybiByYWRpdXMgPiAwID8gcmFkaXVzICogMiA6IGZhbGxiYWNrO1xuICBpZiAoIXJhZGl1cz8ubGVuZ3RoKSByZXR1cm4gZmFsbGJhY2s7XG4gIC8vIFRoZSBtZWRpYW4gb2YgYSBzYW1wbGUgaXMgcGxlbnR5IOKAlCB0aGlzIHNldHMgYSB0aHJlc2hvbGQsIG5vdCBhIG1lYXN1cmVtZW50LlxuICBjb25zdCBtZWRpYW4gPSBxdWFudGlsZShyYWRpdXMsIDAuNSwgeyBmaWx0ZXI6ICdwb3NpdGl2ZScsIHNhbXBsZVNpemU6IDIwNDggfSk7XG4gIHJldHVybiBtZWRpYW4gPT09IG51bGwgPyBmYWxsYmFjayA6IG1lZGlhbiAqIDI7XG59XG5cbi8qKlxuICogT24tc2NyZWVuIGNlbGwgZGlhbWV0ZXIgKHB4KSBhdCBvciBhYm92ZSB3aGljaCBlYWNoIHBvbHlnb24gbGV2ZWwgaXMgdXNlZC4gQSBsZXZlbFxuICogaGFsdmVzIHRoZSB2ZXJ0aWNlcyBvZiB0aGUgb25lIGJlbG93LCBzbyBlYWNoIHNob3VsZCB0YWtlIG92ZXIgd2hlbiB0aGUgY2VsbCBpcyBhYm91dFxuICogaGFsZiBhcyBsYXJnZSBvbiBzY3JlZW4uIEJlbG93IHRoZSBsYXN0IGZpbml0ZSB0aHJlc2hvbGQgb3V0bGluZXMgYXJlIG5vdCBkcmF3biBhdFxuICogYWxsIOKAlCBhIGNlbGwgYSBmZXcgcGl4ZWxzIHdpZGUgaXMgYSBkb3QsIGFuZCB0aGUgb2JzZXJ2YXRpb24gbWFya2VycyBhbHJlYWR5IGRyYXcgaXRcbiAqIGFzIG9uZS5cbiAqXG4gKiBYZW5pdW0ncyBmb3VydGggbGV2ZWwgKDMgdmVydGljZXMgcGVyIGNlbGwpIGlzIGRlbGliZXJhdGVseSBuZXZlciB1c2VkOiBzZWVuIG9uXG4gKiBzY3JlZW4gaXQgaXMgYSBmaWVsZCBvZiB0cmlhbmdsZXMsIHdoaWNoIHJlYWRzIGFzIGFuIGFydGVmYWN0IHJhdGhlciB0aGFuIGFzIGNlbGxzLlxuICogVGhlIGRvdHMgYmVsb3cgOCBweCBzYXkgdGhlIHNhbWUgdGhpbmcgbW9yZSBob25lc3RseS5cbiAqL1xuZXhwb3J0IGNvbnN0IFBPTFlHT05fTEVWRUxfTUlOX0NFTExfUFggPSBbMzYsIDE4LCA4LCBJbmZpbml0eV07XG5cbi8qKlxuICogV2hpY2ggcG9seWdvbiBsZXZlbCBzdWl0cyB0aGlzIHpvb20sIG9yIC0xIGZvciBcInRvbyBzbWFsbCB0byBvdXRsaW5lXCIuXG4gKiBgZGV0YWlsYCA+IDEgcHJlZmVycyBmaW5lciBsZXZlbHMgKHNoYXJwZXIsIHNsb3dlcik7IDwgMSBjb2Fyc2VyLlxuICovXG5leHBvcnQgZnVuY3Rpb24gcG9seWdvbkxldmVsRm9yKHB4UGVyVW5pdDogbnVtYmVyLCBjZWxsRGlhbWV0ZXI6IG51bWJlciwgbGV2ZWxDb3VudDogbnVtYmVyLCBkZXRhaWwgPSAxKTogbnVtYmVyIHtcbiAgY29uc3QgY2VsbFB4ID0gcHhQZXJVbml0ICogY2VsbERpYW1ldGVyICogZGV0YWlsO1xuICBjb25zdCB0YWJsZSA9IFBPTFlHT05fTEVWRUxfTUlOX0NFTExfUFg7XG4gIGZvciAobGV0IGwgPSAwOyBsIDwgbGV2ZWxDb3VudDsgbCsrKSB7XG4gICAgLy8gUGFzdCB0aGUgdGFibGUsIGtlZXAgaGFsdmluZzogZWFjaCBsZXZlbCBzdGlsbCBoYWx2ZXMgdGhlIHZlcnRpY2VzLlxuICAgIGNvbnN0IG1pbiA9IHRhYmxlW2xdID8/IHRhYmxlW3RhYmxlLmxlbmd0aCAtIDFdIC8gMiAqKiAobCAtIHRhYmxlLmxlbmd0aCArIDEpO1xuICAgIGlmIChjZWxsUHggPj0gbWluKSByZXR1cm4gbDtcbiAgfVxuICByZXR1cm4gLTE7XG59XG5cbi8qKlxuICogV2hpY2ggdHJhbnNjcmlwdCBsZXZlbCBzdWl0cyB0aGlzIHpvb206IHRoZSBvbmUgd2hvc2UgdGlsZXMgY29tZSBvdXQgY2xvc2VzdCB0b1xuICogYHRhcmdldFRpbGVQeGAgb24gc2NyZWVuLiBDb2Fyc2VyIGxldmVscyBhZ2dyZWdhdGUgbW9yZSwgc28gdGhpcyBrZWVwcyB0aGUgbnVtYmVyIG9mXG4gKiBtYXJrZXJzIHBlciBzY3JlZW4gcm91Z2hseSBjb25zdGFudCBob3dldmVyIGZhciBvdXQgdGhlIGNhbWVyYSBpcyDigJQgdGhlIHByb3BlcnR5IHRoYXRcbiAqIGtlZXBzIHRoZSB2aWV3IGZhc3QuXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiB0cmFuc2NyaXB0TGV2ZWxGb3IoXG4gIHB4UGVyVW5pdDogbnVtYmVyLFxuICBsZXZlbHM6IHJlYWRvbmx5IFNwYXRpYWxUaWxlTGV2ZWxbXSxcbiAgdGFyZ2V0VGlsZVB4ID0gNTEyLFxuKTogbnVtYmVyIHtcbiAgaWYgKCFsZXZlbHMubGVuZ3RoIHx8ICEocHhQZXJVbml0ID4gMCkpIHJldHVybiAwO1xuICBsZXQgYmVzdCA9IDA7XG4gIGxldCBiZXN0RXJyID0gSW5maW5pdHk7XG4gIGZvciAobGV0IGwgPSAwOyBsIDwgbGV2ZWxzLmxlbmd0aDsgbCsrKSB7XG4gICAgY29uc3QgZXJyID0gTWF0aC5hYnMoTWF0aC5sb2cyKChsZXZlbHNbbF0udGlsZVNpemUgKiBweFBlclVuaXQpIC8gdGFyZ2V0VGlsZVB4KSk7XG4gICAgaWYgKGVyciA8IGJlc3RFcnIpIHtcbiAgICAgIGJlc3RFcnIgPSBlcnI7XG4gICAgICBiZXN0ID0gbDtcbiAgICB9XG4gIH1cbiAgcmV0dXJuIGJlc3Q7XG59XG4iXX0=
|
|
@@ -0,0 +1,200 @@
|
|
|
1
|
+
import { firstValueFrom } from 'rxjs';
|
|
2
|
+
import { isSpatialOmics3d } from '../contracts/plot-type';
|
|
3
|
+
import { isCategoricalColumn } from '../contracts/spatial-dataset.contract';
|
|
4
|
+
import { resolveCategoryColors } from './spatial-encoding';
|
|
5
|
+
import { sectionsOf } from './spatial-sections';
|
|
6
|
+
import { observationsInSlice, volumeImageRef } from './spatial-volume-image';
|
|
7
|
+
import { emptySelection, selectByCategory, selectByIndices, selectInRegions, selectInRegionsProjected, } from './spatial-selection';
|
|
8
|
+
/**
|
|
9
|
+
* The spatial-omics controls (`ISpatialControls`) over a host's `SPATIAL_DATA_PORT`.
|
|
10
|
+
*
|
|
11
|
+
* Backend-neutral: the view state lives in the shared `VisualizerStore` (like the
|
|
12
|
+
* colormap) and the selection in the `SpatialSelectionStore`, so the controls keep
|
|
13
|
+
* working across a plot-type switch and a host can drive them before any backend has
|
|
14
|
+
* mounted. Owns its mirror of the port's dataset — dropping a stale selection and an
|
|
15
|
+
* unsatisfiable colour source when the dataset changes — and the subscription behind
|
|
16
|
+
* it, released by {@link dispose} (review CORE-30).
|
|
17
|
+
*/
|
|
18
|
+
export class SpatialControlsFacade {
|
|
19
|
+
constructor(port, ctx) {
|
|
20
|
+
this.port = port;
|
|
21
|
+
this.ctx = ctx;
|
|
22
|
+
/** Latest dataset, mirrored so `selectFromRegions()` can answer synchronously — it
|
|
23
|
+
* runs from a button click and must not await a round-trip. */
|
|
24
|
+
this.dataset = null;
|
|
25
|
+
// Mirror the dataset (and drop a stale selection when it changes — the masks are
|
|
26
|
+
// index-based, so they are meaningless against different observations).
|
|
27
|
+
this.sub = port.getDataset$().subscribe((dataset) => {
|
|
28
|
+
const changed = dataset?.id !== this.dataset?.id;
|
|
29
|
+
this.dataset = dataset;
|
|
30
|
+
if (!changed)
|
|
31
|
+
return;
|
|
32
|
+
ctx.selectionStore.set(emptySelection(dataset?.observations.count ?? 0));
|
|
33
|
+
// A colour source the new dataset cannot satisfy would leave the map flat while
|
|
34
|
+
// the panel and the charts kept naming the old column — so drop it, and only it:
|
|
35
|
+
// point size, opacity and the rest are the user's preferences.
|
|
36
|
+
const by = ctx.store.currentSpatialView().colorBy;
|
|
37
|
+
if (by && !canColorBy(dataset, by))
|
|
38
|
+
ctx.store.setSpatialView({ colorBy: null });
|
|
39
|
+
});
|
|
40
|
+
this.controls = this.build();
|
|
41
|
+
}
|
|
42
|
+
/** Release the port subscription (the router's injector is being destroyed). */
|
|
43
|
+
dispose() {
|
|
44
|
+
this.sub.unsubscribe();
|
|
45
|
+
}
|
|
46
|
+
build() {
|
|
47
|
+
const port = this.port;
|
|
48
|
+
return {
|
|
49
|
+
getDataset$: () => port.getDataset$(),
|
|
50
|
+
getViewState$: () => this.ctx.store.getSpatialView$(),
|
|
51
|
+
viewState: () => this.ctx.store.currentSpatialView(),
|
|
52
|
+
setViewState: (partial) => this.ctx.store.setSpatialView(partial),
|
|
53
|
+
// The hint SEEDS the toggle when the source changes, and nothing consults it
|
|
54
|
+
// afterwards. It used to be ORed in at render time, which meant an unchecked
|
|
55
|
+
// box could not turn log scaling off for a hinted column — and the linked
|
|
56
|
+
// chart, which reads `logScale` alone, disagreed with the map about what it
|
|
57
|
+
// was showing. One authority, set once per source.
|
|
58
|
+
colorByColumn: (name) => {
|
|
59
|
+
const meta = this.dataset?.columns.find((c) => c.name === name);
|
|
60
|
+
const hint = meta?.kind === 'continuous' ? !!meta.logScaleHint : false;
|
|
61
|
+
this.ctx.store.setSpatialView({ colorBy: { kind: 'column', name }, logScale: hint });
|
|
62
|
+
},
|
|
63
|
+
colorByFeature: (name) => this.ctx.store.setSpatialView({
|
|
64
|
+
colorBy: { kind: 'feature', name },
|
|
65
|
+
logScale: !!this.dataset?.features?.logScaleHint,
|
|
66
|
+
}),
|
|
67
|
+
clearColorBy: () => this.ctx.store.setSpatialView({ colorBy: null }),
|
|
68
|
+
searchFeatures: async (query, limit = 50) => {
|
|
69
|
+
// Prefer the port's search (a 31k-gene dataset does not ship its names);
|
|
70
|
+
// otherwise filter whatever the manifest inlined.
|
|
71
|
+
if (port.searchFeatures)
|
|
72
|
+
return port.searchFeatures(query, limit);
|
|
73
|
+
const dataset = await firstValueFrom(port.getDataset$());
|
|
74
|
+
const names = dataset?.features?.names ?? [];
|
|
75
|
+
const q = query.toLowerCase();
|
|
76
|
+
return names.filter((n) => n.toLowerCase().includes(q)).slice(0, limit);
|
|
77
|
+
},
|
|
78
|
+
...(port.importGroups
|
|
79
|
+
? {
|
|
80
|
+
importGroups: (label, table) => port.importGroups(label, table),
|
|
81
|
+
}
|
|
82
|
+
: {}),
|
|
83
|
+
...(port.getTranscriptCounts
|
|
84
|
+
? {
|
|
85
|
+
transcriptCounts: (genes) => port.getTranscriptCounts(genes),
|
|
86
|
+
}
|
|
87
|
+
: {}),
|
|
88
|
+
...(port.getMarkerGenes
|
|
89
|
+
? {
|
|
90
|
+
markerGenes: (column, perGroup) => port.getMarkerGenes(column, perGroup),
|
|
91
|
+
}
|
|
92
|
+
: {}),
|
|
93
|
+
getTranscriptEstimate$: () => this.ctx.napari.transcriptEstimate$.asObservable(),
|
|
94
|
+
getGeneCountsInView$: () => this.ctx.napari.geneCountsInView$.asObservable(),
|
|
95
|
+
getDensityStats$: () => this.ctx.napari.densityStats$.asObservable(),
|
|
96
|
+
categoryColors: async (name) => {
|
|
97
|
+
const column = await port.getColumn(name);
|
|
98
|
+
if (!isCategoricalColumn(column)) {
|
|
99
|
+
throw new Error(`[spatial] column "${name}" is continuous — it has no categories`);
|
|
100
|
+
}
|
|
101
|
+
// Resolved by the SAME function the renderer uses, so a legend swatch
|
|
102
|
+
// can never disagree with the colour on screen.
|
|
103
|
+
return resolveCategoryColors(column.meta);
|
|
104
|
+
},
|
|
105
|
+
continuousValues: async (source) => {
|
|
106
|
+
if (source.kind === 'feature')
|
|
107
|
+
return port.getFeatureVector(source.name);
|
|
108
|
+
const column = await port.getColumn(source.name);
|
|
109
|
+
if (isCategoricalColumn(column)) {
|
|
110
|
+
throw new Error(`[spatial] column "${source.name}" is categorical — it has no values to chart`);
|
|
111
|
+
}
|
|
112
|
+
return column.values;
|
|
113
|
+
},
|
|
114
|
+
categoricalView: async (name) => {
|
|
115
|
+
const column = await port.getColumn(name);
|
|
116
|
+
if (!isCategoricalColumn(column)) {
|
|
117
|
+
throw new Error(`[spatial] column "${name}" is continuous — it has no categories`);
|
|
118
|
+
}
|
|
119
|
+
return {
|
|
120
|
+
name,
|
|
121
|
+
categories: column.meta.categories,
|
|
122
|
+
colors: resolveCategoryColors(column.meta),
|
|
123
|
+
codes: column.codes,
|
|
124
|
+
};
|
|
125
|
+
},
|
|
126
|
+
// Spread rather than always defined: `getEmbedding` is optional on both the port
|
|
127
|
+
// and this facade, and a panel checks for its presence to decide whether the view
|
|
128
|
+
// is offered at all. Defining it as a function that rejects would make an
|
|
129
|
+
// embedding-less source look like a broken one.
|
|
130
|
+
...(port.getEmbedding ? { getEmbedding: (name) => port.getEmbedding(name) } : {}),
|
|
131
|
+
categoricalColumns: () => (this.dataset?.columns ?? []).filter((c) => c.kind === 'categorical').map((c) => c.name),
|
|
132
|
+
// Memoized on the observations object, so the renderer's own lookup and
|
|
133
|
+
// this one are the same single scan of up to 3.7M z values.
|
|
134
|
+
sampledSections: () => {
|
|
135
|
+
const obs = this.dataset?.observations;
|
|
136
|
+
return obs ? sectionsOf(obs) : null;
|
|
137
|
+
},
|
|
138
|
+
getSelection$: () => this.ctx.selectionStore.getSelection$(),
|
|
139
|
+
selectFromRegions: () => {
|
|
140
|
+
const dataset = this.dataset;
|
|
141
|
+
if (!dataset)
|
|
142
|
+
return 0;
|
|
143
|
+
const regions = this.ctx.regionStore.getRegions();
|
|
144
|
+
// The union of every drawn region — so every ROI tool the library
|
|
145
|
+
// already has doubles as a spatial selection tool.
|
|
146
|
+
//
|
|
147
|
+
// In the 3D cloud there is no data-space affine to push a drawn shape
|
|
148
|
+
// through, so the observations are projected to canvas pixels by the
|
|
149
|
+
// renderer (which owns the camera) and tested in screen space instead.
|
|
150
|
+
// Falls back to the 2D path whenever the cloud is not mounted.
|
|
151
|
+
const projected = isSpatialOmics3d(this.ctx.plotType())
|
|
152
|
+
? this.ctx.napari.getSpatialScreenProjection(dataset.observations)
|
|
153
|
+
: null;
|
|
154
|
+
// In the 2D view of a volume-backed dataset the shape was drawn over ONE
|
|
155
|
+
// section, in the volume's pixel grid: it selects the cells of that
|
|
156
|
+
// section, not the whole depth of brain standing behind them.
|
|
157
|
+
const volume = !dataset.imageRef ? dataset.volume : undefined;
|
|
158
|
+
const selection = projected
|
|
159
|
+
? selectInRegionsProjected(projected, dataset.observations.count, regions)
|
|
160
|
+
: selectInRegions(dataset.observations, volume ? volumeImageRef(volume, dataset.micronsPerUnit) : dataset.imageRef, regions, volume ? observationsInSlice(dataset.observations, volume, this.ctx.zIndex()) : undefined);
|
|
161
|
+
this.ctx.selectionStore.set(selection);
|
|
162
|
+
return selection.count;
|
|
163
|
+
},
|
|
164
|
+
selectCategory: async (column, categoryIndex) => {
|
|
165
|
+
const loaded = await port.getColumn(column);
|
|
166
|
+
if (!isCategoricalColumn(loaded)) {
|
|
167
|
+
throw new Error(`[spatial] column "${column}" is continuous — it has no categories`);
|
|
168
|
+
}
|
|
169
|
+
const selection = selectByCategory(loaded.codes, categoryIndex);
|
|
170
|
+
this.ctx.selectionStore.set(selection);
|
|
171
|
+
return selection.count;
|
|
172
|
+
},
|
|
173
|
+
selectIndices: (indices) => {
|
|
174
|
+
const count = this.dataset?.observations.count ?? 0;
|
|
175
|
+
if (count === 0)
|
|
176
|
+
return 0;
|
|
177
|
+
const selection = selectByIndices(indices, count);
|
|
178
|
+
this.ctx.selectionStore.set(selection);
|
|
179
|
+
return selection.count;
|
|
180
|
+
},
|
|
181
|
+
clearSelection: () => this.ctx.selectionStore.clear(),
|
|
182
|
+
};
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
/**
|
|
186
|
+
* Whether `dataset` can answer this colour source. A column is checkable against the
|
|
187
|
+
* declared list. A gene is checkable only when the dataset inlines its feature names —
|
|
188
|
+
* a dataset too wide to inline them (typeahead-only) keeps the source, and a name that
|
|
189
|
+
* turns out not to exist surfaces as the chart's "could not be charted" rather than as
|
|
190
|
+
* a silent reset.
|
|
191
|
+
*/
|
|
192
|
+
function canColorBy(dataset, by) {
|
|
193
|
+
if (!dataset)
|
|
194
|
+
return false;
|
|
195
|
+
if (by.kind === 'column')
|
|
196
|
+
return dataset.columns.some((c) => c.name === by.name);
|
|
197
|
+
const names = dataset.features?.names;
|
|
198
|
+
return !!dataset.features && (!names || names.includes(by.name));
|
|
199
|
+
}
|
|
200
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic3BhdGlhbC1jb250cm9scy5mYWNhZGUuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi9zcmMvbGliL3NwYXRpYWwvc3BhdGlhbC1jb250cm9scy5mYWNhZGUudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUE0QixjQUFjLEVBQUUsTUFBTSxNQUFNLENBQUM7QUFFaEUsT0FBTyxFQUFZLGdCQUFnQixFQUFFLE1BQU0sd0JBQXdCLENBQUM7QUFHcEUsT0FBTyxFQUF1QyxtQkFBbUIsRUFBRSxNQUFNLHVDQUF1QyxDQUFDO0FBS2pILE9BQU8sRUFBRSxxQkFBcUIsRUFBRSxNQUFNLG9CQUFvQixDQUFDO0FBQzNELE9BQU8sRUFBRSxVQUFVLEVBQUUsTUFBTSxvQkFBb0IsQ0FBQztBQUNoRCxPQUFPLEVBQUUsbUJBQW1CLEVBQUUsY0FBYyxFQUFFLE1BQU0sd0JBQXdCLENBQUM7QUFDN0UsT0FBTyxFQUNMLGNBQWMsRUFDZCxnQkFBZ0IsRUFDaEIsZUFBZSxFQUNmLGVBQWUsRUFDZix3QkFBd0IsR0FDekIsTUFBTSxxQkFBcUIsQ0FBQztBQXVCN0I7Ozs7Ozs7OztHQVNHO0FBQ0gsTUFBTSxPQUFPLHFCQUFxQjtJQVFoQyxZQUNtQixJQUFxQixFQUNyQixHQUEyQjtRQUQzQixTQUFJLEdBQUosSUFBSSxDQUFpQjtRQUNyQixRQUFHLEdBQUgsR0FBRyxDQUF3QjtRQVA5Qzt3RUFDZ0U7UUFDeEQsWUFBTyxHQUEwQixJQUFJLENBQUM7UUFPNUMsaUZBQWlGO1FBQ2pGLHdFQUF3RTtRQUN4RSxJQUFJLENBQUMsR0FBRyxHQUFHLElBQUksQ0FBQyxXQUFXLEVBQUUsQ0FBQyxTQUFTLENBQUMsQ0FBQyxPQUFPLEVBQUUsRUFBRTtZQUNsRCxNQUFNLE9BQU8sR0FBRyxPQUFPLEVBQUUsRUFBRSxLQUFLLElBQUksQ0FBQyxPQUFPLEVBQUUsRUFBRSxDQUFDO1lBQ2pELElBQUksQ0FBQyxPQUFPLEdBQUcsT0FBTyxDQUFD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LGVBQWUsQ0FBQyxPQUFPLEVBQUUsS0FBSyxDQUFDLENBQUM7Z0JBQ2xELElBQUksQ0FBQyxHQUFHLENBQUMsY0FBYyxDQUFDLEdBQUcsQ0FBQyxTQUFTLENBQUMsQ0FBQztnQkFDdkMsT0FBTyxTQUFTLENBQUMsS0FBSyxDQUFDO1lBQ3pCLENBQUM7WUFFRCxjQUFjLEVBQUUsR0FBRyxFQUFFLENBQUMsSUFBSSxDQUFDLEdBQUcsQ0FBQyxjQUFjLENBQUMsS0FBSyxFQUFFO1NBQ3RELENBQUM7SUFDSixDQUFDO0NBQ0Y7QUFFRDs7Ozs7O0dBTUc7QUFDSCxTQUFTLFVBQVUsQ0FBQyxPQUE4QixFQUFFLEVBQWtCO0lBQ3BFLElBQUksQ0FBQyxPQUFPO1FBQUUsT0FBTyxLQUFLLENBQUM7SUFDM0IsSUFBSSxFQUFFLENBQUMsSUFBSSxLQUFLLFFBQVE7UUFBRSxPQUFPLE9BQU8sQ0FBQyxPQUFPLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQyxFQUFFLEVBQUUsQ0FBQyxDQUFDLENBQUMsSUFBSSxLQUFLLEVBQUUsQ0FBQyxJQUFJLENBQUMsQ0FBQztJQUNqRixNQUFNLEtBQUssR0FBRyxPQUFPLENBQUMsUUFBUSxFQUFFLEtBQUssQ0FBQztJQUN0QyxPQUFPLENBQUMsQ0FBQyxPQUFPLENBQUMsUUFBUSxJQUFJLENBQUMsQ0FBQyxLQUFLLElBQUksS0FBSyxDQUFDLFFBQVEsQ0FBQyxFQUFFLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQztBQUNuRSxDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgT2JzZXJ2YWJsZSwgU3Vic2NyaXB0aW9uLCBmaXJzdFZhbHVlRnJvbSB9IGZyb20gJ3J4anMnO1xuXG5pbXBvcnQgeyBQbG90VHlwZSwgaXNTcGF0aWFsT21pY3MzZCB9IGZyb20gJy4uL2NvbnRyYWN0cy9wbG90LXR5cGUnO1xuaW1wb3J0IHsgU3BhdGlhbERhdGFQb3J0IH0gZnJvbSAnLi4vY29udHJhY3RzL3BvcnRzL3NwYXRpYWwtZGF0YS5wb3J0JztcbmltcG9ydCB7IFNwYXRpYWxDb2xvckJ5IH0gZnJvbSAnLi4vY29udHJhY3RzL2Rpc3BsYXktdHlwZXMnO1xuaW1wb3J0IHsgU3BhdGlhbERhdGFzZXQsIFNwYXRpYWxPYnNlcnZhdGlvbnMsIGlzQ2F0ZWdvcmljYWxDb2x1bW4gfSBmcm9tICcuLi9jb250cmFjdHMvc3BhdGlhbC1kYXRhc2V0LmNvbnRyYWN0JztcbmltcG9ydCB7IElTcGF0aWFsQ29udHJvbHMgfSBmcm9tICcuLi9jb250cmFjdHMvdmlzdWFsaXplci5jb250cmFjdCc7XG5pbXBvcnQgeyBSZWdpb25TdG9yZSB9IGZyb20gJy4uL3N0b3JlL3JlZ2lvbi1zdG9yZS5zZXJ2aWNlJztcbmltcG9ydCB7IFNwYXRpYWxTZWxlY3Rpb25TdG9yZSB9IGZyb20gJy4uL3N0b3JlL3NwYXRpYWwtc2VsZWN0aW9uLnNlcnZpY2UnO1xuaW1wb3J0IHsgVmlzdWFsaXplclN0b3JlIH0gZnJvbSAnLi4vc3RvcmUvdmlzdWFsaXplci1zdG9yZS5zZXJ2aWNlJztcbmltcG9ydCB7IHJlc29sdmVDYXRlZ29yeUNvbG9ycyB9IGZyb20gJy4vc3BhdGlhbC1lbmNvZGluZyc7XG5pbXBvcnQgeyBzZWN0aW9uc09mIH0gZnJvbSAnLi9zcGF0aWFsLXNlY3Rpb25zJztcbmltcG9ydCB7IG9ic2VydmF0aW9uc0luU2xpY2UsIHZvbHVtZUltYWdlUmVmIH0gZnJvbSAnLi9zcGF0aWFsLXZvbHVtZS1pbWFnZSc7XG5pbXBvcnQge1xuICBlbXB0eVNlbGVjdGlvbixcbiAgc2VsZWN0QnlDYXRlZ29yeSxcbiAgc2VsZWN0QnlJbmRpY2VzLFxuICBzZWxlY3RJblJlZ2lvbnMsXG4gIHNlbGVjdEluUmVnaW9uc1Byb2plY3RlZCxcbn0gZnJvbSAnLi9zcGF0aWFsLXNlbGVjdGlvbic7XG5cbi8qKiBUaGUgcmVuZGVyZXItc2lkZSBzcGF0aWFsIHJlYWRvdXRzIHRoZSBjb250cm9scyBzdXJmYWNlICh0aGUgbmFwYXJpLWpzIGJhY2tlbmQpLiAqL1xuZXhwb3J0IGludGVyZmFjZSBTcGF0aWFsUmVuZGVyZXJGZWVkcyB7XG4gIHJlYWRvbmx5IHRyYW5zY3JpcHRFc3RpbWF0ZSQ6IHsgYXNPYnNlcnZhYmxlKCk6IE9ic2VydmFibGU8eyBwb2ludHM6IG51bWJlcjsgbWF4OiBudW1iZXIgfSB8IG51bGw+IH07XG4gIHJlYWRvbmx5IGdlbmVDb3VudHNJblZpZXckOiB7IGFzT2JzZXJ2YWJsZSgpOiBPYnNlcnZhYmxlPFJlY29yZDxzdHJpbmcsIG51bWJlcj4gfCBudWxsPiB9O1xuICByZWFkb25seSBkZW5zaXR5U3RhdHMkOiB7IGFzT2JzZXJ2YWJsZSgpOiBPYnNlcnZhYmxlPHsgbG86IG51bWJlcjsgaGk6IG51bWJlcjsgbWF4OiBudW1iZXIgfSB8IG51bGw+IH07XG4gIC8qKiBPYnNlcnZhdGlvbnMgcHJvamVjdGVkIHRvIGNhbnZhcyBwaXhlbHMgYnkgdGhlIDNEIGNhbWVyYSwgb3IgbnVsbCB3aGVuIHRoZSBjbG91ZCBpcyBub3QgbW91bnRlZC4gKi9cbiAgZ2V0U3BhdGlhbFNjcmVlblByb2plY3Rpb24ob2JzOiBTcGF0aWFsT2JzZXJ2YXRpb25zKTogRmxvYXQzMkFycmF5IHwgbnVsbDtcbn1cblxuLyoqIFdoYXQgdGhlIGZhY2FkZSB3b3JrcyBvdmVyOiB0aGUgc2hhcmVkIHN0b3JlcywgdGhlIHJlbmRlcmVyIGZlZWRzIGFuZCB0aGUgcm91dGVyJ3MgdmlldyBzdGF0ZS4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgU3BhdGlhbENvbnRyb2xzQ29udGV4dCB7XG4gIHJlYWRvbmx5IHN0b3JlOiBWaXN1YWxpemVyU3RvcmU7XG4gIHJlYWRvbmx5IHJlZ2lvblN0b3JlOiBSZWdpb25TdG9yZTtcbiAgcmVhZG9ubHkgc2VsZWN0aW9uU3RvcmU6IFNwYXRpYWxTZWxlY3Rpb25TdG9yZTtcbiAgcmVhZG9ubHkgbmFwYXJpOiBTcGF0aWFsUmVuZGVyZXJGZWVkcztcbiAgLyoqIFRoZSBwbG90IHR5cGUgb24gc2NyZWVuICh0aGUgM0QgY2xvdWQgc2VsZWN0cyBpbiBzY3JlZW4gc3BhY2UpLiAqL1xuICBwbG90VHlwZSgpOiBQbG90VHlwZTtcbiAgLyoqIFRoZSBkaXNwbGF5ZWQgc2xpY2UgKGEgdm9sdW1lLWJhY2tlZCBkYXRhc2V0IHNlbGVjdHMgd2l0aGluIG9uZSBzZWN0aW9uKS4gKi9cbiAgekluZGV4KCk6IG51bWJlcjtcbn1cblxuLyoqXG4gKiBUaGUgc3BhdGlhbC1vbWljcyBjb250cm9scyAoYElTcGF0aWFsQ29udHJvbHNgKSBvdmVyIGEgaG9zdCdzIGBTUEFUSUFMX0RBVEFfUE9SVGAuXG4gKlxuICogQmFja2VuZC1uZXV0cmFsOiB0aGUgdmlldyBzdGF0ZSBsaXZlcyBpbiB0aGUgc2hhcmVkIGBWaXN1YWxpemVyU3RvcmVgIChsaWtlIHRoZVxuICogY29sb3JtYXApIGFuZCB0aGUgc2VsZWN0aW9uIGluIHRoZSBgU3BhdGlhbFNlbGVjdGlvblN0b3JlYCwgc28gdGhlIGNvbnRyb2xzIGtlZXBcbiAqIHdvcmtpbmcgYWNyb3NzIGEgcGxvdC10eXBlIHN3aXRjaCBhbmQgYSBob3N0IGNhbiBkcml2ZSB0aGVtIGJlZm9yZSBhbnkgYmFja2VuZCBoYXNcbiAqIG1vdW50ZWQuIE93bnMgaXRzIG1pcnJvciBvZiB0aGUgcG9ydCdzIGRhdGFzZXQg4oCUIGRyb3BwaW5nIGEgc3RhbGUgc2VsZWN0aW9uIGFuZCBhblxuICogdW5zYXRpc2ZpYWJsZSBjb2xvdXIgc291cmNlIHdoZW4gdGhlIGRhdGFzZXQgY2hhbmdlcyDigJQgYW5kIHRoZSBzdWJzY3JpcHRpb24gYmVoaW5kXG4gKiBpdCwgcmVsZWFzZWQgYnkge0BsaW5rIGRpc3Bvc2V9IChyZXZpZXcgQ09SRS0zMCkuXG4gKi9cbmV4cG9ydCBjbGFzcyBTcGF0aWFsQ29udHJvbHNGYWNhZGUge1xuICAvKiogVGhlIGNvbnRyb2xzOyBvbmUgb2JqZWN0IGZvciB0aGUgZmFjYWRlJ3MgbGlmZSwgc28gY29uc3VtZXJzIGNhbiBob2xkIGl0LiAqL1xuICByZWFkb25seSBjb250cm9sczogSVNwYXRpYWxDb250cm9scztcbiAgLyoqIExhdGVzdCBkYXRhc2V0LCBtaXJyb3JlZCBzbyBgc2VsZWN0RnJvbVJlZ2lvbnMoKWAgY2FuIGFuc3dlciBzeW5jaHJvbm91c2x5IOKAlCBpdFxuICAgKiAgcnVucyBmcm9tIGEgYnV0dG9uIGNsaWNrIGFuZCBtdXN0IG5vdCBhd2FpdCBhIHJvdW5kLXRyaXAuICovXG4gIHByaXZhdGUgZGF0YXNldDogU3BhdGlhbERhdGFzZXQgfCBudWxsID0gbnVsbDtcbiAgcHJpdmF0ZSByZWFkb25seSBzdWI6IFN1YnNjcmlwdGlvbjtcblxuICBjb25zdHJ1Y3RvcihcbiAgICBwcml2YXRlIHJlYWRvbmx5IHBvcnQ6IFNwYXRpYWxEYXRhUG9ydCxcbiAgICBwcml2YXRlIHJlYWRvbmx5IGN0eDogU3BhdGlhbENvbnRyb2xzQ29udGV4dCxcbiAgKSB7XG4gICAgLy8gTWlycm9yIHRoZSBkYXRhc2V0IChhbmQgZHJvcCBhIHN0YWxlIHNlbGVjdGlvbiB3aGVuIGl0IGNoYW5nZXMg4oCUIHRoZSBtYXNrcyBhcmVcbiAgICAvLyBpbmRleC1iYXNlZCwgc28gdGhleSBhcmUgbWVhbmluZ2xlc3MgYWdhaW5zdCBkaWZmZXJlbnQgb2JzZXJ2YXRpb25zKS5cbiAgICB0aGlzLnN1YiA9IHBvcnQuZ2V0RGF0YXNldCQoKS5zdWJzY3JpYmUoKGRhdGFzZXQpID0+IHtcbiAgICAgIGNvbnN0IGNoYW5nZWQgPSBkYXRhc2V0Py5pZCAhPT0gdGhpcy5kYXRhc2V0Py5pZDtcbiAgICAgIHRoaXMuZGF0YXNldCA9IGRhdGFzZXQ7XG4gICAgICBpZiAoIWNoYW5nZWQpIHJldHVybjtcbiAgICAgIGN0eC5zZWxlY3Rpb25TdG9yZS5zZXQoZW1wdHlTZWxlY3Rpb24oZGF0YXNldD8ub2JzZXJ2YXRpb25zLmNvdW50ID8/IDApKTtcbiAgICAgIC8vIEEgY29sb3VyIHNvdXJjZSB0aGUgbmV3IGRhdGFzZXQgY2Fubm90IHNhdGlzZnkgd291bGQgbGVhdmUgdGhlIG1hcCBmbGF0IHdoaWxlXG4gICAgICAvLyB0aGUgcGFuZWwgYW5kIHRoZSBjaGFydHMga2VwdCBuYW1pbmcgdGhlIG9sZCBjb2x1bW4g4oCUIHNvIGRyb3AgaXQsIGFuZCBvbmx5IGl0OlxuICAgICAgLy8gcG9pbnQgc2l6ZSwgb3BhY2l0eSBhbmQgdGhlIHJlc3QgYXJlIHRoZSB1c2VyJ3MgcHJlZmVyZW5jZXMuXG4gICAgICBjb25zdCBieSA9IGN0eC5zdG9yZS5jdXJyZW50U3BhdGlhbFZpZXcoKS5jb2xvckJ5O1xuICAgICAgaWYgKGJ5ICYmICFjYW5Db2xvckJ5KGRhdGFzZXQsIGJ5KSkgY3R4LnN0b3JlLnNldFNwYXRpYWxWaWV3KHsgY29sb3JCeTogbnVsbCB9KTtcbiAgICB9KTtcbiAgICB0aGlzLmNvbnRyb2xzID0gdGhpcy5idWlsZCgpO1xuICB9XG5cbiAgLyoqIFJlbGVhc2UgdGhlIHBvcnQgc3Vic2NyaXB0aW9uICh0aGUgcm91dGVyJ3MgaW5qZWN0b3IgaXMgYmVpbmcgZGVzdHJveWVkKS4gKi9cbiAgZGlzcG9zZSgpOiB2b2lkIHtcbiAgICB0aGlzLnN1Yi51bnN1YnNjcmliZSgpO1xuICB9XG5cbiAgcHJpdmF0ZSBidWlsZCgpOiBJU3BhdGlhbENvbnRyb2xzIHtcbiAgICBjb25zdCBwb3J0ID0gdGhpcy5wb3J0O1xuICAgIHJldHVybiB7XG4gICAgICBnZXREYXRhc2V0JDogKCkgPT4gcG9ydC5nZXREYXRhc2V0JCgpLFxuICAgICAgZ2V0Vmlld1N0YXRlJDogKCkgPT4gdGhpcy5jdHguc3RvcmUuZ2V0U3BhdGlhbFZpZXckKCksXG4gICAgICB2aWV3U3RhdGU6ICgpID0+IHRoaXMuY3R4LnN0b3JlLmN1cnJlbnRTcGF0aWFsVmlldygpLFxuICAgICAgc2V0Vmlld1N0YXRlOiAocGFydGlhbCkgPT4gdGhpcy5jdHguc3RvcmUuc2V0U3BhdGlhbFZpZXcocGFydGlhbCksXG4gICAgICAvLyBUaGUgaGludCBTRUVEUyB0aGUgdG9nZ2xlIHdoZW4gdGhlIHNvdXJjZSBjaGFuZ2VzLCBhbmQgbm90aGluZyBjb25zdWx0cyBpdFxuICAgICAgLy8gYWZ0ZXJ3YXJkcy4gSXQgdXNlZCB0byBiZSBPUmVkIGluIGF0IHJlbmRlciB0aW1lLCB3aGljaCBtZWFudCBhbiB1bmNoZWNrZWRcbiAgICAgIC8vIGJveCBjb3VsZCBub3QgdHVybiBsb2cgc2NhbGluZyBvZmYgZm9yIGEgaGludGVkIGNvbHVtbiDigJQgYW5kIHRoZSBsaW5rZWRcbiAgICAgIC8vIGNoYXJ0LCB3aGljaCByZWFkcyBgbG9nU2NhbGVgIGFsb25lLCBkaXNhZ3JlZWQgd2l0aCB0aGUgbWFwIGFib3V0IHdoYXQgaXRcbiAgICAgIC8vIHdhcyBzaG93aW5nLiBPbmUgYXV0aG9yaXR5LCBzZXQgb25jZSBwZXIgc291cmNlLlxuICAgICAgY29sb3JCeUNvbHVtbjogKG5hbWU6IHN0cmluZykgPT4ge1xuICAgICAgICBjb25zdCBtZXRhID0gdGhpcy5kYXRhc2V0Py5jb2x1bW5zLmZpbmQoKGMpID0+IGMubmFtZSA9PT0gbmFtZSk7XG4gICAgICAgIGNvbnN0IGhpbnQgPSBtZXRhPy5raW5kID09PSAnY29udGludW91cycgPyAhIW1ldGEubG9nU2NhbGVIaW50IDogZmFsc2U7XG4gICAgICAgIHRoaXMuY3R4LnN0b3JlLnNldFNwYXRpYWxWaWV3KHsgY29sb3JCeTogeyBraW5kOiAnY29sdW1uJywgbmFtZSB9LCBsb2dTY2FsZTogaGludCB9KTtcbiAgICAgIH0sXG4gICAgICBjb2xvckJ5RmVhdHVyZTogKG5hbWU6IHN0cmluZykgPT5cbiAgICAgICAgdGhpcy5jdHguc3RvcmUuc2V0U3BhdGlhbFZpZXcoe1xuICAgICAgICAgIGNvbG9yQnk6IHsga2luZDogJ2ZlYXR1cmUnLCBuYW1lIH0sXG4gICAgICAgICAgbG9nU2NhbGU6ICEhdGhpcy5kYXRhc2V0Py5mZWF0dXJlcz8ubG9nU2NhbGVIaW50LFxuICAgICAgICB9KSxcbiAgICAgIGNsZWFyQ29sb3JCeTogKCkgPT4gdGhpcy5jdHguc3RvcmUuc2V0U3BhdGlhbFZpZXcoeyBjb2xvckJ5OiBudWxsIH0pLFxuICAgICAgc2VhcmNoRmVhdHVyZXM6IGFzeW5jIChxdWVyeTogc3RyaW5nLCBsaW1pdCA9IDUwKSA9PiB7XG4gICAgICAgIC8vIFByZWZlciB0aGUgcG9ydCdzIHNlYXJjaCAoYSAzMWstZ2VuZSBkYXRhc2V0IGRvZXMgbm90IHNoaXAgaXRzIG5hbWVzKTtcbiAgICAgICAgLy8gb3RoZXJ3aXNlIGZpbHRlciB3aGF0ZXZlciB0aGUgbWFuaWZlc3QgaW5saW5lZC5cbiAgICAgICAgaWYgKHBvcnQuc2VhcmNoRmVhdHVyZXMpIHJldHVybiBwb3J0LnNlYXJjaEZlYXR1cmVzKHF1ZXJ5LCBsaW1pdCk7XG4gICAgICAgIGNvbnN0IGRhdGFzZXQgPSBhd2FpdCBmaXJzdFZhbHVlRnJvbShwb3J0LmdldERhdGFzZXQkKCkpO1xuICAgICAgICBjb25zdCBuYW1lcyA9IGRhdGFzZXQ/LmZlYXR1cmVzPy5uYW1lcyA/PyBbXTtcbiAgICAgICAgY29uc3QgcSA9IHF1ZXJ5LnRvTG93ZXJDYXNlKCk7XG4gICAgICAgIHJldHVybiBuYW1lcy5maWx0ZXIoKG4pID0+IG4udG9Mb3dlckNhc2UoKS5pbmNsdWRlcyhxKSkuc2xpY2UoMCwgbGltaXQpO1xuICAgICAgfSxcbiAgICAgIC4uLihwb3J0LmltcG9ydEdyb3Vwc1xuICAgICAgICA/IHtcbiAgICAgICAgICAgIGltcG9ydEdyb3VwczogKGxhYmVsOiBzdHJpbmcsIHRhYmxlOiBzdHJpbmcpID0+IHBvcnQuaW1wb3J0R3JvdXBzIShsYWJlbCwgdGFibGUpLFxuICAgICAgICAgIH1cbiAgICAgICAgOiB7fSksXG4gICAgICAuLi4ocG9ydC5nZXRUcmFuc2NyaXB0Q291bnRzXG4gICAgICAgID8ge1xuICAgICAgICAgICAgdHJhbnNjcmlwdENvdW50czogKGdlbmVzOiBzdHJpbmdbXSkgPT4gcG9ydC5nZXRUcmFuc2NyaXB0Q291bnRzIShnZW5lcyksXG4gICAgICAgICAgfVxuICAgICAgICA6IHt9KSxcbiAgICAgIC4uLihwb3J0LmdldE1hcmtlckdlbmVzXG4gICAgICAgID8ge1xuICAgICAgICAgICAgbWFya2VyR2VuZXM6IChjb2x1bW46IHN0cmluZywgcGVyR3JvdXA/OiBudW1iZXIpID0+IHBvcnQuZ2V0TWFya2VyR2VuZXMhKGNvbHVtbiwgcGVyR3JvdXApLFxuICAgICAgICAgIH1cbiAgICAgICAgOiB7fSksXG4gICAgICBnZXRUcmFuc2NyaXB0RXN0aW1hdGUkOiAoKSA9PiB0aGlzLmN0eC5uYXBhcmkudHJhbnNjcmlwdEVzdGltYXRlJC5hc09ic2VydmFibGUoKSxcbiAgICAgIGdldEdlbmVDb3VudHNJblZpZXckOiAoKSA9PiB0aGlzLmN0eC5uYXBhcmkuZ2VuZUNvdW50c0luVmlldyQuYXNPYnNlcnZhYmxlKCksXG4gICAgICBnZXREZW5zaXR5U3RhdHMkOiAoKSA9PiB0aGlzLmN0eC5uYXBhcmkuZGVuc2l0eVN0YXRzJC5hc09ic2VydmFibGUoKSxcbiAgICAgIGNhdGVnb3J5Q29sb3JzOiBhc3luYyAobmFtZTogc3RyaW5nKSA9PiB7XG4gICAgICAgIGNvbnN0IGNvbHVtbiA9IGF3YWl0IHBvcnQuZ2V0Q29sdW1uKG5hbWUpO1xuICAgICAgICBpZiAoIWlzQ2F0ZWdvcmljYWxDb2x1bW4oY29sdW1uKSkge1xuICAgICAgICAgIHRocm93IG5ldyBFcnJvcihgW3NwYXRpYWxdIGNvbHVtbiBcIiR7bmFtZX1cIiBpcyBjb250aW51b3VzIOKAlCBpdCBoYXMgbm8gY2F0ZWdvcmllc2ApO1xuICAgICAgICB9XG4gICAgICAgIC8vIFJlc29sdmVkIGJ5IHRoZSBTQU1FIGZ1bmN0aW9uIHRoZSByZW5kZXJlciB1c2VzLCBzbyBhIGxlZ2VuZCBzd2F0Y2hcbiAgICAgICAgLy8gY2FuIG5ldmVyIGRpc2FncmVlIHdpdGggdGhlIGNvbG91ciBvbiBzY3JlZW4uXG4gICAgICAgIHJldHVybiByZXNvbHZlQ2F0ZWdvcnlDb2xvcnMoY29sdW1uLm1ldGEpO1xuICAgICAgfSxcblxuICAgICAgY29udGludW91c1ZhbHVlczogYXN5bmMgKHNvdXJjZSkgPT4ge1xuICAgICAgICBpZiAoc291cmNlLmtpbmQgPT09ICdmZWF0dXJlJykgcmV0dXJuIHBvcnQuZ2V0RmVhdHVyZVZlY3Rvcihzb3VyY2UubmFtZSk7XG4gICAgICAgIGNvbnN0IGNvbHVtbiA9IGF3YWl0IHBvcnQuZ2V0Q29sdW1uKHNvdXJjZS5uYW1lKTtcbiAgICAgICAgaWYgKGlzQ2F0ZWdvcmljYWxDb2x1bW4oY29sdW1uKSkge1xuICAgICAgICAgIHRocm93IG5ldyBFcnJvcihgW3NwYXRpYWxdIGNvbHVtbiBcIiR7c291cmNlLm5hbWV9XCIgaXMgY2F0ZWdvcmljYWwg4oCUIGl0IGhhcyBubyB2YWx1ZXMgdG8gY2hhcnRgKTtcbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gY29sdW1uLnZhbHVlcztcbiAgICAgIH0sXG5cbiAgICAgIGNhdGVnb3JpY2FsVmlldzogYXN5bmMgKG5hbWU6IHN0cmluZykgPT4ge1xuICAgICAgICBjb25zdCBjb2x1bW4gPSBhd2FpdCBwb3J0LmdldENvbHVtbihuYW1lKTtcbiAgICAgICAgaWYgKCFpc0NhdGVnb3JpY2FsQ29sdW1uKGNvbHVtbikpIHtcbiAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoYFtzcGF0aWFsXSBjb2x1bW4gXCIke25hbWV9XCIgaXMgY29udGludW91cyDigJQgaXQgaGFzIG5vIGNhdGVnb3JpZXNgKTtcbiAgICAgICAgfVxuICAgICAgICByZXR1cm4ge1xuICAgICAgICAgIG5hbWUsXG4gICAgICAgICAgY2F0ZWdvcmllczogY29sdW1uLm1ldGEuY2F0ZWdvcmllcyxcbiAgICAgICAgICBjb2xvcnM6IHJlc29sdmVDYXRlZ29yeUNvbG9ycyhjb2x1bW4ubWV0YSksXG4gICAgICAgICAgY29kZXM6IGNvbHVtbi5jb2RlcyxcbiAgICAgICAgfTtcbiAgICAgIH0sXG5cbiAgICAgIC8vIFNwcmVhZCByYXRoZXIgdGhhbiBhbHdheXMgZGVmaW5lZDogYGdldEVtYmVkZGluZ2AgaXMgb3B0aW9uYWwgb24gYm90aCB0aGUgcG9ydFxuICAgICAgLy8gYW5kIHRoaXMgZmFjYWRlLCBhbmQgYSBwYW5lbCBjaGVja3MgZm9yIGl0cyBwcmVzZW5jZSB0byBkZWNpZGUgd2hldGhlciB0aGUgdmlld1xuICAgICAgLy8gaXMgb2ZmZXJlZCBhdCBhbGwuIERlZmluaW5nIGl0IGFzIGEgZnVuY3Rpb24gdGhhdCByZWplY3RzIHdvdWxkIG1ha2UgYW5cbiAgICAgIC8vIGVtYmVkZGluZy1sZXNzIHNvdXJjZSBsb29rIGxpa2UgYSBicm9rZW4gb25lLlxuICAgICAgLi4uKHBvcnQuZ2V0RW1iZWRkaW5nID8geyBnZXRFbWJlZGRpbmc6IChuYW1lOiBzdHJpbmcpID0+IHBvcnQuZ2V0RW1iZWRkaW5nIShuYW1lKSB9IDoge30pLFxuXG4gICAgICBjYXRlZ29yaWNhbENvbHVtbnM6ICgpID0+XG4gICAgICAgICh0aGlzLmRhdGFzZXQ/LmNvbHVtbnMgPz8gW10pLmZpbHRlcigoYykgPT4gYy5raW5kID09PSAnY2F0ZWdvcmljYWwnKS5tYXAoKGMpID0+IGMubmFtZSksXG5cbiAgICAgIC8vIE1lbW9pemVkIG9uIHRoZSBvYnNlcnZhdGlvbnMgb2JqZWN0LCBzbyB0aGUgcmVuZGVyZXIncyBvd24gbG9va3VwIGFuZFxuICAgICAgLy8gdGhpcyBvbmUgYXJlIHRoZSBzYW1lIHNpbmdsZSBzY2FuIG9mIHVwIHRvIDMuN00geiB2YWx1ZXMuXG4gICAgICBzYW1wbGVkU2VjdGlvbnM6ICgpID0+IHtcbiAgICAgICAgY29uc3Qgb2JzID0gdGhpcy5kYXRhc2V0Py5vYnNlcnZhdGlvbnM7XG4gICAgICAgIHJldHVybiBvYnMgPyBzZWN0aW9uc09mKG9icykgOiBudWxsO1xuICAgICAgfSxcblxuICAgICAgZ2V0U2VsZWN0aW9uJDogKCkgPT4gdGhpcy5jdHguc2VsZWN0aW9uU3RvcmUuZ2V0U2VsZWN0aW9uJCgpLFxuXG4gICAgICBzZWxlY3RGcm9tUmVnaW9uczogKCkgPT4ge1xuICAgICAgICBjb25zdCBkYXRhc2V0ID0gdGhpcy5kYXRhc2V0O1xuICAgICAgICBpZiAoIWRhdGFzZXQpIHJldHVybiAwO1xuICAgICAgICBjb25zdCByZWdpb25zID0gdGhpcy5jdHgucmVnaW9uU3RvcmUuZ2V0UmVnaW9ucygpO1xuICAgICAgICAvLyBUaGUgdW5pb24gb2YgZXZlcnkgZHJhd24gcmVnaW9uIOKAlCBzbyBldmVyeSBST0kgdG9vbCB0aGUgbGlicmFyeVxuICAgICAgICAvLyBhbHJlYWR5IGhhcyBkb3VibGVzIGFzIGEgc3BhdGlhbCBzZWxlY3Rpb24gdG9vbC5cbiAgICAgICAgLy9cbiAgICAgICAgLy8gSW4gdGhlIDNEIGNsb3VkIHRoZXJlIGlzIG5vIGRhdGEtc3BhY2UgYWZmaW5lIHRvIHB1c2ggYSBkcmF3biBzaGFwZVxuICAgICAgICAvLyB0aHJvdWdoLCBzbyB0aGUgb2JzZXJ2YXRpb25zIGFyZSBwcm9qZWN0ZWQgdG8gY2FudmFzIHBpeGVscyBieSB0aGVcbiAgICAgICAgLy8gcmVuZGVyZXIgKHdoaWNoIG93bnMgdGhlIGNhbWVyYSkgYW5kIHRlc3RlZCBpbiBzY3JlZW4gc3BhY2UgaW5zdGVhZC5cbiAgICAgICAgLy8gRmFsbHMgYmFjayB0byB0aGUgMkQgcGF0aCB3aGVuZXZlciB0aGUgY2xvdWQgaXMgbm90IG1vdW50ZWQuXG4gICAgICAgIGNvbnN0IHByb2plY3RlZCA9IGlzU3BhdGlhbE9taWNzM2QodGhpcy5jdHgucGxvdFR5cGUoKSlcbiAgICAgICAgICA/IHRoaXMuY3R4Lm5hcGFyaS5nZXRTcGF0aWFsU2NyZWVuUHJvamVjdGlvbihkYXRhc2V0Lm9ic2VydmF0aW9ucylcbiAgICAgICAgICA6IG51bGw7XG4gICAgICAgIC8vIEluIHRoZSAyRCB2aWV3IG9mIGEgdm9sdW1lLWJhY2tlZCBkYXRhc2V0IHRoZSBzaGFwZSB3YXMgZHJhd24gb3ZlciBPTkVcbiAgICAgICAgLy8gc2VjdGlvbiwgaW4gdGhlIHZvbHVtZSdzIHBpeGVsIGdyaWQ6IGl0IHNlbGVjdHMgdGhlIGNlbGxzIG9mIHRoYXRcbiAgICAgICAgLy8gc2VjdGlvbiwgbm90IHRoZSB3aG9sZSBkZXB0aCBvZiBicmFpbiBzdGFuZGluZyBiZWhpbmQgdGhlbS5cbiAgICAgICAgY29uc3Qgdm9sdW1lID0gIWRhdGFzZXQuaW1hZ2VSZWYgPyBkYXRhc2V0LnZvbHVtZSA6IHVuZGVmaW5lZDtcbiAgICAgICAgY29uc3Qgc2VsZWN0aW9uID0gcHJvamVjdGVkXG4gICAgICAgICAgPyBzZWxlY3RJblJlZ2lvbnNQcm9qZWN0ZWQocHJvamVjdGVkLCBkYXRhc2V0Lm9ic2VydmF0aW9ucy5jb3VudCwgcmVnaW9ucylcbiAgICAgICAgICA6IHNlbGVjdEluUmVnaW9ucyhcbiAgICAgICAgICAgICAgZGF0YXNldC5vYnNlcnZhdGlvbnMsXG4gICAgICAgICAgICAgIHZvbHVtZSA/IHZvbHVtZUltYWdlUmVmKHZvbHVtZSwgZGF0YXNldC5taWNyb25zUGVyVW5pdCkgOiBkYXRhc2V0LmltYWdlUmVmLFxuICAgICAgICAgICAgICByZWdpb25zLFxuICAgICAgICAgICAgICB2b2x1bWUgPyBvYnNlcnZhdGlvbnNJblNsaWNlKGRhdGFzZXQub2JzZXJ2YXRpb25zLCB2b2x1bWUsIHRoaXMuY3R4LnpJbmRleCgpKSA6IHVuZGVmaW5lZCxcbiAgICAgICAgICAgICk7XG4gICAgICAgIHRoaXMuY3R4LnNlbGVjdGlvblN0b3JlLnNldChzZWxlY3Rpb24pO1xuICAgICAgICByZXR1cm4gc2VsZWN0aW9uLmNvdW50O1xuICAgICAgfSxcblxuICAgICAgc2VsZWN0Q2F0ZWdvcnk6IGFzeW5jIChjb2x1bW46IHN0cmluZywgY2F0ZWdvcnlJbmRleDogbnVtYmVyKSA9PiB7XG4gICAgICAgIGNvbnN0IGxvYWRlZCA9IGF3YWl0IHBvcnQuZ2V0Q29sdW1uKGNvbHVtbik7XG4gICAgICAgIGlmICghaXNDYXRlZ29yaWNhbENvbHVtbihsb2FkZWQpKSB7XG4gICAgICAgICAgdGhyb3cgbmV3IEVycm9yKGBbc3BhdGlhbF0gY29sdW1uIFwiJHtjb2x1bW59XCIgaXMgY29udGludW91cyDigJQgaXQgaGFzIG5vIGNhdGVnb3JpZXNgKTtcbiAgICAgICAgfVxuICAgICAgICBjb25zdCBzZWxlY3Rpb24gPSBzZWxlY3RCeUNhdGVnb3J5KGxvYWRlZC5jb2RlcywgY2F0ZWdvcnlJbmRleCk7XG4gICAgICAgIHRoaXMuY3R4LnNlbGVjdGlvblN0b3JlLnNldChzZWxlY3Rpb24pO1xuICAgICAgICByZXR1cm4gc2VsZWN0aW9uLmNvdW50O1xuICAgICAgfSxcblxuICAgICAgc2VsZWN0SW5kaWNlczogKGluZGljZXM6IEl0ZXJhYmxlPG51bWJlcj4pID0+IHtcbiAgICAgICAgY29uc3QgY291bnQgPSB0aGlzLmRhdGFzZXQ/Lm9ic2VydmF0aW9ucy5jb3VudCA/PyAwO1xuICAgICAgICBpZiAoY291bnQgPT09IDApIHJldHVybiAwO1xuICAgICAgICBjb25zdCBzZWxlY3Rpb24gPSBzZWxlY3RCeUluZGljZXMoaW5kaWNlcywgY291bnQpO1xuICAgICAgICB0aGlzLmN0eC5zZWxlY3Rpb25TdG9yZS5zZXQoc2VsZWN0aW9uKTtcbiAgICAgICAgcmV0dXJuIHNlbGVjdGlvbi5jb3VudDtcbiAgICAgIH0sXG5cbiAgICAgIGNsZWFyU2VsZWN0aW9uOiAoKSA9PiB0aGlzLmN0eC5zZWxlY3Rpb25TdG9yZS5jbGVhcigpLFxuICAgIH07XG4gIH1cbn1cblxuLyoqXG4gKiBXaGV0aGVyIGBkYXRhc2V0YCBjYW4gYW5zd2VyIHRoaXMgY29sb3VyIHNvdXJjZS4gQSBjb2x1bW4gaXMgY2hlY2thYmxlIGFnYWluc3QgdGhlXG4gKiBkZWNsYXJlZCBsaXN0LiBBIGdlbmUgaXMgY2hlY2thYmxlIG9ubHkgd2hlbiB0aGUgZGF0YXNldCBpbmxpbmVzIGl0cyBmZWF0dXJlIG5hbWVzIOKAlFxuICogYSBkYXRhc2V0IHRvbyB3aWRlIHRvIGlubGluZSB0aGVtICh0eXBlYWhlYWQtb25seSkga2VlcHMgdGhlIHNvdXJjZSwgYW5kIGEgbmFtZSB0aGF0XG4gKiB0dXJucyBvdXQgbm90IHRvIGV4aXN0IHN1cmZhY2VzIGFzIHRoZSBjaGFydCdzIFwiY291bGQgbm90IGJlIGNoYXJ0ZWRcIiByYXRoZXIgdGhhbiBhc1xuICogYSBzaWxlbnQgcmVzZXQuXG4gKi9cbmZ1bmN0aW9uIGNhbkNvbG9yQnkoZGF0YXNldDogU3BhdGlhbERhdGFzZXQgfCBudWxsLCBieTogU3BhdGlhbENvbG9yQnkpOiBib29sZWFuIHtcbiAgaWYgKCFkYXRhc2V0KSByZXR1cm4gZmFsc2U7XG4gIGlmIChieS5raW5kID09PSAnY29sdW1uJykgcmV0dXJuIGRhdGFzZXQuY29sdW1ucy5zb21lKChjKSA9PiBjLm5hbWUgPT09IGJ5Lm5hbWUpO1xuICBjb25zdCBuYW1lcyA9IGRhdGFzZXQuZmVhdHVyZXM/Lm5hbWVzO1xuICByZXR1cm4gISFkYXRhc2V0LmZlYXR1cmVzICYmICghbmFtZXMgfHwgbmFtZXMuaW5jbHVkZXMoYnkubmFtZSkpO1xufVxuIl19
|