@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.
Files changed (525) hide show
  1. package/README.md +201 -460
  2. package/esm2022/index.mjs +28 -15
  3. package/esm2022/lib/channel-histogram/channel-histogram.component.mjs +163 -91
  4. package/esm2022/lib/contracts/capabilities.contract.mjs +4 -3
  5. package/esm2022/lib/contracts/cell-segmenter.contract.mjs +1 -1
  6. package/esm2022/lib/contracts/channel-histogram-api.contract.mjs +5 -1
  7. package/esm2022/lib/contracts/color.mjs +60 -0
  8. package/esm2022/lib/contracts/colormap-lut.mjs +213 -57
  9. package/esm2022/lib/contracts/coordinate-transform.contract.mjs +1 -1
  10. package/esm2022/lib/contracts/display-types.mjs +11 -1
  11. package/esm2022/lib/contracts/instance-segmenter.contract.mjs +1 -1
  12. package/esm2022/lib/contracts/intensity.mjs +48 -5
  13. package/esm2022/lib/contracts/plot-type-contribution.contract.mjs +1 -1
  14. package/esm2022/lib/contracts/plot-type.mjs +134 -17
  15. package/esm2022/lib/contracts/ports/image-state.port.mjs +4 -1
  16. package/esm2022/lib/contracts/ports/preferences.port.mjs +5 -1
  17. package/esm2022/lib/contracts/ports/region-io.port.mjs +2 -1
  18. package/esm2022/lib/contracts/ports/spatial-data.port.mjs +5 -1
  19. package/esm2022/lib/contracts/ports/tile-access.port.mjs +2 -1
  20. package/esm2022/lib/contracts/region-editor-api.contract.mjs +1 -1
  21. package/esm2022/lib/contracts/region-overlay.contract.mjs +1 -1
  22. package/esm2022/lib/contracts/sam.contract.mjs +1 -1
  23. package/esm2022/lib/contracts/semantic-segmenter.contract.mjs +1 -1
  24. package/esm2022/lib/contracts/spatial-dataset.contract.mjs +3 -1
  25. package/esm2022/lib/contracts/toolbar-tool.contract.mjs +6 -4
  26. package/esm2022/lib/contracts/visualizer.contract.mjs +1 -1
  27. package/esm2022/lib/contracts/viz-config.mjs +2 -1
  28. package/esm2022/lib/geometry/contour.mjs +63 -0
  29. package/esm2022/lib/geometry/raster.mjs +98 -0
  30. package/esm2022/lib/geometry/ring.mjs +201 -0
  31. package/esm2022/lib/hex-color-picker/hex-color-picker.component.mjs +202 -102
  32. package/esm2022/lib/implementations/base-store-visualizer.mjs +201 -48
  33. package/esm2022/lib/implementations/napari-js/napari-axes-gizmo.mjs +65 -0
  34. package/esm2022/lib/implementations/napari-js/napari-display-state.mjs +136 -0
  35. package/esm2022/lib/implementations/napari-js/napari-helpers.mjs +199 -0
  36. package/esm2022/lib/implementations/napari-js/napari-image-2d-scene.mjs +602 -0
  37. package/esm2022/lib/implementations/napari-js/napari-loading-badge.mjs +3 -4
  38. package/esm2022/lib/implementations/napari-js/napari-loading-state.mjs +66 -0
  39. package/esm2022/lib/implementations/napari-js/napari-region-overlay.mjs +157 -591
  40. package/esm2022/lib/implementations/napari-js/napari-scene.mjs +2 -0
  41. package/esm2022/lib/implementations/napari-js/napari-spatial-2d-scene.mjs +614 -0
  42. package/esm2022/lib/implementations/napari-js/napari-spatial-3d-scene.mjs +769 -0
  43. package/esm2022/lib/implementations/napari-js/napari-spatial-encoding.mjs +199 -0
  44. package/esm2022/lib/implementations/napari-js/napari-spatial-hover.mjs +263 -0
  45. package/esm2022/lib/implementations/napari-js/napari-spatial-scene.mjs +159 -0
  46. package/esm2022/lib/implementations/napari-js/napari-spatial-tiles.mjs +106 -1408
  47. package/esm2022/lib/implementations/napari-js/napari-spatial-tooltip.mjs +2 -2
  48. package/esm2022/lib/implementations/napari-js/napari-surface-scene.mjs +271 -0
  49. package/esm2022/lib/implementations/napari-js/napari-tile-client.mjs +562 -0
  50. package/esm2022/lib/implementations/napari-js/napari-tool-bridge.mjs +344 -0
  51. package/esm2022/lib/implementations/napari-js/napari-visualizer.service.mjs +361 -4184
  52. package/esm2022/lib/implementations/napari-js/napari-volume-scene.mjs +439 -0
  53. package/esm2022/lib/implementations/napari-js/napari-volume-z-handle.mjs +6 -6
  54. package/esm2022/lib/implementations/napari-js/region-overlay/overlay-projection.mjs +96 -0
  55. package/esm2022/lib/implementations/napari-js/region-overlay/region-edit.mjs +35 -0
  56. package/esm2022/lib/implementations/napari-js/region-overlay/region-svg-renderer.mjs +182 -0
  57. package/esm2022/lib/implementations/napari-js/spatial-tiles/categorical-lookup.mjs +30 -0
  58. package/esm2022/lib/implementations/napari-js/spatial-tiles/cell-layers.mjs +274 -0
  59. package/esm2022/lib/implementations/napari-js/spatial-tiles/density-layer.mjs +144 -0
  60. package/esm2022/lib/implementations/napari-js/spatial-tiles/layer-groups.mjs +165 -0
  61. package/esm2022/lib/implementations/napari-js/spatial-tiles/plan-context.mjs +78 -0
  62. package/esm2022/lib/implementations/napari-js/spatial-tiles/transcript-hover.mjs +182 -0
  63. package/esm2022/lib/implementations/napari-js/spatial-tiles/transcript-jobs.mjs +369 -0
  64. package/esm2022/lib/implementations/napari-js/spatial-tiles/transcript-layers.mjs +306 -0
  65. package/esm2022/lib/implementations/osd/display-pipeline.mjs +102 -40
  66. package/esm2022/lib/implementations/osd/histogram-sampler.mjs +56 -31
  67. package/esm2022/lib/implementations/osd/openseadragon-viewer-options.mjs +128 -0
  68. package/esm2022/lib/implementations/osd/openseadragon-visualizer.service.mjs +333 -1685
  69. package/esm2022/lib/implementations/osd/osd-coordinate-transform.mjs +1 -1
  70. package/esm2022/lib/implementations/osd/osd-coords.mjs +5 -6
  71. package/esm2022/lib/implementations/osd/osd-export.mjs +122 -0
  72. package/esm2022/lib/implementations/osd/osd-lib.mjs +15 -1
  73. package/esm2022/lib/implementations/osd/osd-navigator-chrome.mjs +205 -0
  74. package/esm2022/lib/implementations/osd/osd-pixel-readback.mjs +68 -0
  75. package/esm2022/lib/implementations/osd/osd-region-overlay-draw.mjs +153 -0
  76. package/esm2022/lib/implementations/osd/osd-region-overlay.mjs +185 -718
  77. package/esm2022/lib/implementations/osd/osd-scale-bar.mjs +52 -60
  78. package/esm2022/lib/implementations/osd/osd-tile-source.mjs +105 -0
  79. package/esm2022/lib/implementations/osd/osd-viewer-like.mjs +2 -0
  80. package/esm2022/lib/implementations/osd/osd-viewer-mount.mjs +44 -0
  81. package/esm2022/lib/implementations/osd/osd-viewport.mjs +184 -0
  82. package/esm2022/lib/implementations/osd/osd-zoom.mjs +7 -1
  83. package/esm2022/lib/implementations/osd/simple-source.mjs +395 -0
  84. package/esm2022/lib/implementations/osd/slice-cache.mjs +53 -48
  85. package/esm2022/lib/implementations/osd/tile-client.mjs +32 -11
  86. package/esm2022/lib/implementations/osd/tile-recolor.mjs +330 -0
  87. package/esm2022/lib/implementations/plotly/omics-trace-builders.mjs +161 -73
  88. package/esm2022/lib/implementations/plotly/plotly-coordinate-transform.mjs +1 -1
  89. package/esm2022/lib/implementations/plotly/plotly-image-loader.mjs +112 -0
  90. package/esm2022/lib/implementations/plotly/plotly-image-recolor.mjs +178 -0
  91. package/esm2022/lib/implementations/plotly/plotly-intensity-inset.mjs +33 -0
  92. package/esm2022/lib/implementations/plotly/plotly-isosurface-controls.mjs +83 -0
  93. package/esm2022/lib/implementations/plotly/plotly-layouts.mjs +121 -0
  94. package/esm2022/lib/implementations/plotly/plotly-readback.mjs +117 -0
  95. package/esm2022/lib/implementations/plotly/plotly-region-overlay.mjs +19 -10
  96. package/esm2022/lib/implementations/plotly/plotly-shape-projection.mjs +223 -0
  97. package/esm2022/lib/implementations/plotly/plotly-trace-builders.mjs +79 -19
  98. package/esm2022/lib/implementations/plotly/plotly-zoom-controller.mjs +223 -0
  99. package/esm2022/lib/implementations/plotly/plotly.service.mjs +439 -1655
  100. package/esm2022/lib/implementations/region-centroids.mjs +47 -0
  101. package/esm2022/lib/implementations/simple-slice-access.service.mjs +22 -12
  102. package/esm2022/lib/implementations/spatial-data-http/spatial-data-http.service.mjs +172 -92
  103. package/esm2022/lib/implementations/spatial-data-http/spatial-wire.mjs +103 -22
  104. package/esm2022/lib/implementations/tile-server/index.mjs +6 -0
  105. package/esm2022/lib/implementations/tile-server/native-histogram.mjs +30 -0
  106. package/esm2022/lib/implementations/tile-server/poll-descriptor.mjs +65 -0
  107. package/esm2022/lib/implementations/tile-server/tile-protocol.mjs +42 -0
  108. package/esm2022/lib/implementations/tile-server/transport.mjs +135 -0
  109. package/esm2022/lib/intensity/intensity-profile.mjs +107 -0
  110. package/esm2022/lib/intensity/intensity-profile.service.mjs +223 -0
  111. package/esm2022/lib/intensity-inset/intensity-inset.component.mjs +133 -0
  112. package/esm2022/lib/models/bezier.mjs +1 -11
  113. package/esm2022/lib/models/class-preset.mjs +41 -3
  114. package/esm2022/lib/models/geometry.mjs +27 -164
  115. package/esm2022/lib/models/polygon-edit.mjs +254 -0
  116. package/esm2022/lib/models/polygon-factory.mjs +118 -0
  117. package/esm2022/lib/models/region-clone.mjs +68 -0
  118. package/esm2022/lib/models/region-geojson.mjs +373 -0
  119. package/esm2022/lib/models/region.mjs +34 -33
  120. package/esm2022/lib/models/shape.mjs +18 -16
  121. package/esm2022/lib/plot-mode/contribution-host.mjs +297 -0
  122. package/esm2022/lib/plot-mode/plot-mode-controller.mjs +9 -6
  123. package/esm2022/lib/plot-mode/plot-type-menu.mjs +85 -0
  124. package/esm2022/lib/plot-mode/tool-params-model.mjs +87 -0
  125. package/esm2022/lib/plot.utilities.mjs +296 -473
  126. package/esm2022/lib/processing/image-crop.mjs +1 -1
  127. package/esm2022/lib/processing/processing-image.mjs +28 -15
  128. package/esm2022/lib/provide-visualization.mjs +40 -14
  129. package/esm2022/lib/region-editor/classes-panel/classes-panel.component.mjs +99 -0
  130. package/esm2022/lib/region-editor/file-stem.mjs +13 -0
  131. package/esm2022/lib/region-editor/manage-classes-dialog/manage-classes-dialog.component.mjs +118 -0
  132. package/esm2022/lib/region-editor/mask-export.service.mjs +98 -0
  133. package/esm2022/lib/region-editor/mask-raster.mjs +11 -5
  134. package/esm2022/lib/region-editor/region-color-dialog/region-color-dialog.component.mjs +56 -0
  135. package/esm2022/lib/region-editor/region-editor-help/region-editor-help.component.mjs +28 -0
  136. package/esm2022/lib/region-editor/region-editor.component.mjs +402 -651
  137. package/esm2022/lib/region-editor/region-metrics.mjs +68 -0
  138. package/esm2022/lib/region-editor/region-persistence.service.mjs +134 -0
  139. package/esm2022/lib/region-editor/region-table/region-table.component.mjs +153 -0
  140. package/esm2022/lib/region-editor/save-mask-dialog/save-mask-dialog.component.mjs +91 -0
  141. package/esm2022/lib/region-editor/save-regions-dialog/save-regions-dialog.component.mjs +92 -0
  142. package/esm2022/lib/region-ops.service.mjs +28 -70
  143. package/esm2022/lib/region-overlay/region-geometry.mjs +360 -0
  144. package/esm2022/lib/region-overlay/region-hit-test.mjs +103 -0
  145. package/esm2022/lib/region-overlay/svg-region-renderer.mjs +228 -0
  146. package/esm2022/lib/render-orchestrator.mjs +14 -11
  147. package/esm2022/lib/render-session.mjs +207 -0
  148. package/esm2022/lib/routing-visualizer.service.mjs +459 -411
  149. package/esm2022/lib/spatial/density-raster.mjs +14 -0
  150. package/esm2022/lib/spatial/embedding-compute-coordinator.mjs +239 -0
  151. package/esm2022/lib/spatial/embedding-compute.mjs +43 -10
  152. package/esm2022/lib/spatial/gene-search.mjs +1 -1
  153. package/esm2022/lib/spatial/glyphs.mjs +97 -0
  154. package/esm2022/lib/spatial/lod.mjs +187 -0
  155. package/esm2022/lib/spatial/spatial-controls.facade.mjs +200 -0
  156. package/esm2022/lib/spatial/spatial-density.mjs +25 -16
  157. package/esm2022/lib/spatial/spatial-encoding.mjs +26 -82
  158. package/esm2022/lib/spatial/spatial-expression.mjs +43 -42
  159. package/esm2022/lib/spatial/spatial-framing.mjs +1 -1
  160. package/esm2022/lib/spatial/spatial-heatmap.mjs +6 -3
  161. package/esm2022/lib/spatial/spatial-hover.mjs +5 -33
  162. package/esm2022/lib/spatial/spatial-panel-model.mjs +282 -0
  163. package/esm2022/lib/spatial/spatial-sections.mjs +1 -1
  164. package/esm2022/lib/spatial/spatial-selection.mjs +33 -46
  165. package/esm2022/lib/spatial/spatial-tile-merge.mjs +219 -0
  166. package/esm2022/lib/spatial/spatial-tiles.mjs +12 -648
  167. package/esm2022/lib/spatial/spatial-volume-image.mjs +2 -4
  168. package/esm2022/lib/spatial/stats.mjs +71 -0
  169. package/esm2022/lib/spatial/transcript-grouping.mjs +307 -0
  170. package/esm2022/lib/spatial-controls/spatial-cells-panel/spatial-cells-panel.component.mjs +150 -0
  171. package/esm2022/lib/spatial-controls/spatial-charts/chart-data-model.mjs +309 -0
  172. package/esm2022/lib/spatial-controls/spatial-charts/chart-help.mjs +145 -0
  173. package/esm2022/lib/spatial-controls/spatial-charts/plotly-chart-host.mjs +158 -0
  174. package/esm2022/lib/spatial-controls/spatial-charts/spatial-chart-window/spatial-chart-window.component.mjs +47 -0
  175. package/esm2022/lib/spatial-controls/spatial-charts/spatial-charts.component.mjs +297 -802
  176. package/esm2022/lib/spatial-controls/spatial-charts/spatial-embedding-controls/spatial-embedding-controls.component.mjs +89 -0
  177. package/esm2022/lib/spatial-controls/spatial-charts/spatial-heatmap-controls/spatial-heatmap-controls.component.mjs +52 -0
  178. package/esm2022/lib/spatial-controls/spatial-controls.component.mjs +143 -1238
  179. package/esm2022/lib/spatial-controls/spatial-gene-picker.mjs +153 -0
  180. package/esm2022/lib/spatial-controls/spatial-gene-tree/spatial-gene-tree.component.mjs +241 -0
  181. package/esm2022/lib/spatial-controls/spatial-groups-panel/spatial-groups-panel.component.mjs +193 -0
  182. package/esm2022/lib/spatial-controls/spatial-key/spatial-key.component.mjs +132 -0
  183. package/esm2022/lib/spatial-controls/spatial-key/spatial-key.model.mjs +67 -0
  184. package/esm2022/lib/spatial-controls/spatial-marker-genes-form/spatial-marker-genes-form.component.mjs +147 -0
  185. package/esm2022/lib/spatial-controls/spatial-observations-panel/spatial-observations-panel.component.mjs +300 -0
  186. package/esm2022/lib/spatial-controls/spatial-transcripts-panel/spatial-transcripts-panel.component.mjs +370 -0
  187. package/esm2022/lib/store/class-color.util.mjs +46 -3
  188. package/esm2022/lib/store/region-history.mjs +146 -0
  189. package/esm2022/lib/store/region-scope-cache.mjs +140 -0
  190. package/esm2022/lib/store/region-selection.mjs +82 -0
  191. package/esm2022/lib/store/region-store.service.mjs +279 -675
  192. package/esm2022/lib/store/spatial-selection.service.mjs +2 -2
  193. package/esm2022/lib/store/visualizer-store.service.mjs +49 -71
  194. package/esm2022/lib/toast-outlets.mjs +5 -4
  195. package/esm2022/lib/toolbar/brush/brush-tool.service.mjs +92 -434
  196. package/esm2022/lib/toolbar/canvas-tools.mjs +20 -0
  197. package/esm2022/lib/toolbar/crop/slide-crop.mjs +26 -42
  198. package/esm2022/lib/toolbar/plot-type-selector/plot-type-selector.component.mjs +85 -0
  199. package/esm2022/lib/toolbar/region-tools/region-tool-buttons.mjs +74 -0
  200. package/esm2022/lib/toolbar/region-tools/region-tools.component.mjs +114 -0
  201. package/esm2022/lib/toolbar/segmentation/cell-segment-tool.service.mjs +74 -78
  202. package/esm2022/lib/toolbar/segmentation/cellpose-segmenter.service.mjs +50 -8
  203. package/esm2022/lib/toolbar/segmentation/onnx-sam-session.mjs +61 -42
  204. package/esm2022/lib/toolbar/segmentation/pending-calls.mjs +47 -0
  205. package/esm2022/lib/toolbar/segmentation/sam-model-registry.mjs +12 -4
  206. package/esm2022/lib/toolbar/segmentation/sam-onnx-core.mjs +70 -14
  207. package/esm2022/lib/toolbar/segmentation/sam-point-tool.service.mjs +135 -172
  208. package/esm2022/lib/toolbar/segmentation/sam-prompt.mjs +9 -90
  209. package/esm2022/lib/toolbar/segmentation/sam-session.service.mjs +183 -0
  210. package/esm2022/lib/toolbar/segmentation/sam-tool.service.mjs +95 -150
  211. package/esm2022/lib/toolbar/segmentation/segmentation-commit.mjs +12 -0
  212. package/esm2022/lib/toolbar/segmentation/segmentation-runner.mjs +108 -0
  213. package/esm2022/lib/toolbar/segmentation-tools/segmentation-tools.component.mjs +155 -0
  214. package/esm2022/lib/toolbar/stack-controls/stack-controls.component.mjs +81 -0
  215. package/esm2022/lib/toolbar/tool-kit/async-tool-status.mjs +37 -0
  216. package/esm2022/lib/toolbar/tool-kit/canvas-tool-manager.mjs +63 -0
  217. package/esm2022/lib/toolbar/tool-kit/canvas-tool.mjs +2 -0
  218. package/esm2022/lib/toolbar/tool-kit/frame-pixels.mjs +108 -0
  219. package/esm2022/lib/toolbar/tool-kit/mask-stroke-editor.mjs +306 -0
  220. package/esm2022/lib/toolbar/tool-kit/matrix-frame.mjs +61 -0
  221. package/esm2022/lib/toolbar/tool-kit/tool-overlay.mjs +140 -0
  222. package/esm2022/lib/toolbar/tool-kit/undo-gesture.mjs +24 -0
  223. package/esm2022/lib/toolbar/tool-slider/tool-slider.component.mjs +63 -0
  224. package/esm2022/lib/toolbar/toolbar-help-dialog/toolbar-help-dialog.component.mjs +50 -0
  225. package/esm2022/lib/toolbar/toolbar.component.mjs +68 -117
  226. package/esm2022/lib/toolbar/vertex-eraser/vertex-eraser-tool.service.mjs +93 -115
  227. package/esm2022/lib/toolbar/view-controls/view-controls.component.mjs +107 -0
  228. package/esm2022/lib/toolbar/wand/wand-region-grow.mjs +321 -0
  229. package/esm2022/lib/toolbar/wand/wand-tool.service.mjs +121 -416
  230. package/esm2022/lib/toolbar/wand/wand.service.mjs +30 -894
  231. package/esm2022/lib/toolbar/zoom-to-box/zoom-to-box-tool.service.mjs +48 -90
  232. package/esm2022/lib/util/mark-for-check.mjs +17 -0
  233. package/esm2022/lib/util/supersede.mjs +56 -0
  234. package/esm2022/lib/visualization.module.mjs +39 -141
  235. package/esm2022/lib/visualizer/floating-drag.directive.mjs +58 -0
  236. package/esm2022/lib/visualizer/region-actions.mjs +149 -0
  237. package/esm2022/lib/visualizer/region-load.mjs +60 -0
  238. package/esm2022/lib/visualizer/spatial-dataset-binder.mjs +163 -0
  239. package/esm2022/lib/visualizer/tool-modes.mjs +113 -0
  240. package/esm2022/lib/visualizer/viewer-shortcuts.mjs +167 -0
  241. package/esm2022/lib/visualizer/visualizer-context-menu.mjs +119 -0
  242. package/esm2022/lib/visualizer.component.mjs +480 -1902
  243. package/esm2022/lib/workers/spatial-math-ops.mjs +43 -0
  244. package/esm2022/lib/workers/spatial-math-worker.mjs +10 -0
  245. package/esm2022/lib/workers/spatial-math.mjs +190 -0
  246. package/fesm2022/jax-data-science-sci-image-visualizer-jax-data-science-sci-image-visualizer-Csxlnq7I.mjs +41083 -0
  247. package/fesm2022/jax-data-science-sci-image-visualizer-jax-data-science-sci-image-visualizer-Csxlnq7I.mjs.map +1 -0
  248. package/fesm2022/jax-data-science-sci-image-visualizer-onnx-sam-session-Bkujqg7m.mjs +238 -0
  249. package/fesm2022/jax-data-science-sci-image-visualizer-onnx-sam-session-Bkujqg7m.mjs.map +1 -0
  250. package/fesm2022/jax-data-science-sci-image-visualizer-spatial-math-worker-BzVFFqGS.mjs +12 -0
  251. package/fesm2022/jax-data-science-sci-image-visualizer-spatial-math-worker-BzVFFqGS.mjs.map +1 -0
  252. package/fesm2022/jax-data-science-sci-image-visualizer.mjs +41 -34430
  253. package/fesm2022/jax-data-science-sci-image-visualizer.mjs.map +1 -1
  254. package/fesm2022/mask.worker.js +36 -917
  255. package/fesm2022/onnx-sam.worker.js +52 -16
  256. package/fesm2022/spatial-math.worker.js +471 -0
  257. package/fesm2022/tsne.worker.js +32 -15
  258. package/index.d.ts +13 -10
  259. package/lib/channel-histogram/channel-histogram.component.d.ts +53 -43
  260. package/lib/contracts/capabilities.contract.d.ts +4 -2
  261. package/lib/contracts/cell-segmenter.contract.d.ts +1 -0
  262. package/lib/contracts/channel-histogram-api.contract.d.ts +4 -0
  263. package/lib/contracts/color.d.ts +27 -0
  264. package/lib/contracts/colormap-lut.d.ts +19 -4
  265. package/lib/contracts/coordinate-transform.contract.d.ts +3 -3
  266. package/lib/contracts/display-types.d.ts +21 -0
  267. package/lib/contracts/instance-segmenter.contract.d.ts +5 -0
  268. package/lib/contracts/intensity.d.ts +13 -2
  269. package/lib/contracts/plot-type.d.ts +3 -1
  270. package/lib/contracts/ports/image-state.port.d.ts +6 -2
  271. package/lib/contracts/ports/preferences.port.d.ts +4 -0
  272. package/lib/contracts/ports/region-io.port.d.ts +1 -0
  273. package/lib/contracts/ports/spatial-data.port.d.ts +4 -10
  274. package/lib/contracts/ports/tile-access.port.d.ts +1 -0
  275. package/lib/contracts/region-editor-api.contract.d.ts +1 -1
  276. package/lib/contracts/region-overlay.contract.d.ts +5 -0
  277. package/lib/contracts/sam.contract.d.ts +7 -0
  278. package/lib/contracts/semantic-segmenter.contract.d.ts +6 -0
  279. package/lib/contracts/spatial-dataset.contract.d.ts +19 -6
  280. package/lib/contracts/toolbar-tool.contract.d.ts +1 -0
  281. package/lib/contracts/visualizer.contract.d.ts +221 -54
  282. package/lib/contracts/viz-config.d.ts +1 -0
  283. package/lib/geometry/contour.d.ts +24 -0
  284. package/lib/geometry/raster.d.ts +42 -0
  285. package/lib/geometry/ring.d.ts +67 -0
  286. package/lib/hex-color-picker/hex-color-picker.component.d.ts +61 -27
  287. package/lib/implementations/base-store-visualizer.d.ts +61 -15
  288. package/lib/implementations/napari-js/napari-axes-gizmo.d.ts +36 -0
  289. package/lib/implementations/napari-js/napari-display-state.d.ts +76 -0
  290. package/lib/implementations/napari-js/napari-helpers.d.ts +129 -0
  291. package/lib/implementations/napari-js/napari-image-2d-scene.d.ts +162 -0
  292. package/lib/implementations/napari-js/napari-loading-badge.d.ts +0 -1
  293. package/lib/implementations/napari-js/napari-loading-state.d.ts +30 -0
  294. package/lib/implementations/napari-js/napari-region-overlay.d.ts +62 -70
  295. package/lib/implementations/napari-js/napari-scene.d.ts +93 -0
  296. package/lib/implementations/napari-js/napari-spatial-2d-scene.d.ts +163 -0
  297. package/lib/implementations/napari-js/napari-spatial-3d-scene.d.ts +212 -0
  298. package/lib/implementations/napari-js/napari-spatial-encoding.d.ts +114 -0
  299. package/lib/implementations/napari-js/napari-spatial-hover.d.ts +89 -0
  300. package/lib/implementations/napari-js/napari-spatial-scene.d.ts +118 -0
  301. package/lib/implementations/napari-js/napari-spatial-tiles.d.ts +56 -263
  302. package/lib/implementations/napari-js/napari-spatial-tooltip.d.ts +1 -1
  303. package/lib/implementations/napari-js/napari-surface-scene.d.ts +76 -0
  304. package/lib/implementations/napari-js/napari-tile-client.d.ts +214 -0
  305. package/lib/implementations/napari-js/napari-tool-bridge.d.ts +179 -0
  306. package/lib/implementations/napari-js/napari-visualizer.service.d.ts +121 -878
  307. package/lib/implementations/napari-js/napari-volume-scene.d.ts +104 -0
  308. package/lib/implementations/napari-js/napari-volume-z-handle.d.ts +8 -12
  309. package/lib/implementations/napari-js/region-overlay/overlay-projection.d.ts +59 -0
  310. package/lib/implementations/napari-js/region-overlay/region-edit.d.ts +15 -0
  311. package/lib/implementations/napari-js/region-overlay/region-svg-renderer.d.ts +54 -0
  312. package/lib/implementations/napari-js/spatial-tiles/categorical-lookup.d.ts +26 -0
  313. package/lib/implementations/napari-js/spatial-tiles/cell-layers.d.ts +70 -0
  314. package/lib/implementations/napari-js/spatial-tiles/density-layer.d.ts +61 -0
  315. package/lib/implementations/napari-js/spatial-tiles/layer-groups.d.ts +67 -0
  316. package/lib/implementations/napari-js/spatial-tiles/plan-context.d.ts +38 -0
  317. package/lib/implementations/napari-js/spatial-tiles/transcript-hover.d.ts +71 -0
  318. package/lib/implementations/napari-js/spatial-tiles/transcript-jobs.d.ts +105 -0
  319. package/lib/implementations/napari-js/spatial-tiles/transcript-layers.d.ts +56 -0
  320. package/lib/implementations/osd/display-pipeline.d.ts +38 -9
  321. package/lib/implementations/osd/histogram-sampler.d.ts +22 -12
  322. package/lib/implementations/osd/openseadragon-viewer-options.d.ts +35 -0
  323. package/lib/implementations/osd/openseadragon-visualizer.service.d.ts +78 -354
  324. package/lib/implementations/osd/osd-coordinate-transform.d.ts +2 -1
  325. package/lib/implementations/osd/osd-coords.d.ts +6 -4
  326. package/lib/implementations/osd/osd-export.d.ts +36 -0
  327. package/lib/implementations/osd/osd-lib.d.ts +7 -0
  328. package/lib/implementations/osd/osd-navigator-chrome.d.ts +69 -0
  329. package/lib/implementations/osd/osd-pixel-readback.d.ts +22 -0
  330. package/lib/implementations/osd/osd-region-overlay-draw.d.ts +37 -0
  331. package/lib/implementations/osd/osd-region-overlay.d.ts +36 -48
  332. package/lib/implementations/osd/osd-scale-bar.d.ts +8 -6
  333. package/lib/implementations/osd/osd-tile-source.d.ts +49 -0
  334. package/lib/implementations/osd/osd-viewer-like.d.ts +100 -0
  335. package/lib/implementations/osd/osd-viewer-mount.d.ts +14 -0
  336. package/lib/implementations/osd/osd-viewport.d.ts +77 -0
  337. package/lib/implementations/osd/osd-zoom.d.ts +6 -0
  338. package/lib/implementations/osd/simple-source.d.ts +161 -0
  339. package/lib/implementations/osd/slice-cache.d.ts +12 -3
  340. package/lib/implementations/osd/tile-client.d.ts +11 -14
  341. package/lib/implementations/osd/tile-recolor.d.ts +141 -0
  342. package/lib/implementations/plotly/omics-trace-builders.d.ts +32 -20
  343. package/lib/implementations/plotly/plotly-image-loader.d.ts +49 -0
  344. package/lib/implementations/plotly/plotly-image-recolor.d.ts +75 -0
  345. package/lib/implementations/plotly/plotly-intensity-inset.d.ts +8 -0
  346. package/lib/implementations/plotly/plotly-isosurface-controls.d.ts +38 -0
  347. package/lib/implementations/plotly/plotly-layouts.d.ts +188 -0
  348. package/lib/implementations/plotly/plotly-readback.d.ts +41 -0
  349. package/lib/implementations/plotly/plotly-region-overlay.d.ts +2 -2
  350. package/lib/implementations/plotly/plotly-shape-projection.d.ts +92 -0
  351. package/lib/implementations/plotly/plotly-trace-builders.d.ts +23 -12
  352. package/lib/implementations/plotly/plotly-zoom-controller.d.ts +86 -0
  353. package/lib/implementations/plotly/plotly.service.d.ts +136 -401
  354. package/lib/implementations/region-centroids.d.ts +14 -0
  355. package/lib/implementations/simple-slice-access.service.d.ts +7 -4
  356. package/lib/implementations/spatial-data-http/spatial-data-http.service.d.ts +42 -18
  357. package/lib/implementations/spatial-data-http/spatial-wire.d.ts +34 -9
  358. package/lib/implementations/tile-server/index.d.ts +5 -0
  359. package/lib/implementations/tile-server/native-histogram.d.ts +25 -0
  360. package/lib/implementations/tile-server/poll-descriptor.d.ts +39 -0
  361. package/lib/implementations/tile-server/tile-protocol.d.ts +80 -0
  362. package/lib/implementations/tile-server/transport.d.ts +62 -0
  363. package/lib/intensity/intensity-profile.d.ts +66 -0
  364. package/lib/intensity/intensity-profile.service.d.ts +108 -0
  365. package/lib/intensity-inset/intensity-inset.component.d.ts +58 -0
  366. package/lib/models/bezier.d.ts +0 -5
  367. package/lib/models/class-preset.d.ts +18 -0
  368. package/lib/models/geometry.d.ts +14 -48
  369. package/lib/models/polygon-edit.d.ts +72 -0
  370. package/lib/models/polygon-factory.d.ts +40 -0
  371. package/lib/models/region-clone.d.ts +20 -0
  372. package/lib/models/region-geojson.d.ts +17 -0
  373. package/lib/models/region.d.ts +40 -4
  374. package/lib/models/shape.d.ts +8 -0
  375. package/lib/plot-mode/contribution-host.d.ts +125 -0
  376. package/lib/plot-mode/plot-type-menu.d.ts +60 -0
  377. package/lib/plot-mode/tool-params-model.d.ts +49 -0
  378. package/lib/plot.utilities.d.ts +19 -30
  379. package/lib/processing/processing-image.d.ts +5 -2
  380. package/lib/provide-visualization.d.ts +19 -2
  381. package/lib/region-editor/classes-panel/classes-panel.component.d.ts +56 -0
  382. package/lib/region-editor/file-stem.d.ts +7 -0
  383. package/lib/region-editor/manage-classes-dialog/manage-classes-dialog.component.d.ts +45 -0
  384. package/lib/region-editor/mask-export.service.d.ts +54 -0
  385. package/lib/region-editor/mask-raster.d.ts +2 -8
  386. package/lib/region-editor/region-color-dialog/region-color-dialog.component.d.ts +29 -0
  387. package/lib/region-editor/region-editor-help/region-editor-help.component.d.ts +11 -0
  388. package/lib/region-editor/region-editor.component.d.ts +166 -199
  389. package/lib/region-editor/region-metrics.d.ts +26 -0
  390. package/lib/region-editor/region-persistence.service.d.ts +69 -0
  391. package/lib/region-editor/region-table/region-table.component.d.ts +83 -0
  392. package/lib/region-editor/save-mask-dialog/save-mask-dialog.component.d.ts +36 -0
  393. package/lib/region-editor/save-regions-dialog/save-regions-dialog.component.d.ts +37 -0
  394. package/lib/region-ops.service.d.ts +1 -7
  395. package/lib/region-overlay/region-geometry.d.ts +157 -0
  396. package/lib/region-overlay/region-hit-test.d.ts +38 -0
  397. package/lib/region-overlay/svg-region-renderer.d.ts +110 -0
  398. package/lib/render-orchestrator.d.ts +6 -2
  399. package/lib/render-session.d.ts +75 -0
  400. package/lib/routing-visualizer.service.d.ts +110 -58
  401. package/lib/spatial/density-raster.d.ts +6 -0
  402. package/lib/spatial/embedding-compute-coordinator.d.ts +123 -0
  403. package/lib/spatial/embedding-compute.d.ts +21 -2
  404. package/lib/spatial/glyphs.d.ts +16 -0
  405. package/lib/spatial/lod.d.ts +94 -0
  406. package/lib/spatial/spatial-controls.facade.d.ts +64 -0
  407. package/lib/spatial/spatial-density.d.ts +15 -5
  408. package/lib/spatial/spatial-encoding.d.ts +11 -44
  409. package/lib/spatial/spatial-expression.d.ts +40 -22
  410. package/lib/spatial/spatial-framing.d.ts +1 -0
  411. package/lib/spatial/spatial-heatmap.d.ts +2 -0
  412. package/lib/spatial/spatial-hover.d.ts +4 -16
  413. package/lib/spatial/spatial-panel-model.d.ts +135 -0
  414. package/lib/spatial/spatial-selection.d.ts +21 -26
  415. package/lib/spatial/spatial-tile-merge.d.ts +41 -0
  416. package/lib/spatial/spatial-tiles.d.ts +9 -256
  417. package/lib/spatial/stats.d.ts +38 -0
  418. package/lib/spatial/transcript-grouping.d.ts +119 -0
  419. package/lib/spatial-controls/spatial-cells-panel/spatial-cells-panel.component.d.ts +64 -0
  420. package/lib/spatial-controls/spatial-charts/chart-data-model.d.ts +153 -0
  421. package/lib/spatial-controls/spatial-charts/chart-help.d.ts +69 -0
  422. package/lib/spatial-controls/spatial-charts/plotly-chart-host.d.ts +98 -0
  423. package/lib/spatial-controls/spatial-charts/spatial-chart-window/spatial-chart-window.component.d.ts +26 -0
  424. package/lib/spatial-controls/spatial-charts/spatial-charts.component.d.ts +101 -260
  425. package/lib/spatial-controls/spatial-charts/spatial-embedding-controls/spatial-embedding-controls.component.d.ts +43 -0
  426. package/lib/spatial-controls/spatial-charts/spatial-heatmap-controls/spatial-heatmap-controls.component.d.ts +27 -0
  427. package/lib/spatial-controls/spatial-controls.component.d.ts +68 -448
  428. package/lib/spatial-controls/spatial-gene-picker.d.ts +86 -0
  429. package/lib/spatial-controls/spatial-gene-tree/spatial-gene-tree.component.d.ts +102 -0
  430. package/lib/spatial-controls/spatial-groups-panel/spatial-groups-panel.component.d.ts +72 -0
  431. package/lib/spatial-controls/spatial-key/spatial-key.component.d.ts +66 -0
  432. package/lib/spatial-controls/spatial-key/spatial-key.model.d.ts +33 -0
  433. package/lib/spatial-controls/spatial-marker-genes-form/spatial-marker-genes-form.component.d.ts +64 -0
  434. package/lib/spatial-controls/spatial-observations-panel/spatial-observations-panel.component.d.ts +117 -0
  435. package/lib/spatial-controls/spatial-transcripts-panel/spatial-transcripts-panel.component.d.ts +142 -0
  436. package/lib/store/class-color.util.d.ts +35 -1
  437. package/lib/store/region-history.d.ts +66 -0
  438. package/lib/store/region-scope-cache.d.ts +63 -0
  439. package/lib/store/region-selection.d.ts +36 -0
  440. package/lib/store/region-store.service.d.ts +104 -112
  441. package/lib/store/visualizer-store.service.d.ts +22 -33
  442. package/lib/toast-outlets.d.ts +4 -3
  443. package/lib/toolbar/brush/brush-tool.service.d.ts +31 -98
  444. package/lib/toolbar/canvas-tools.d.ts +20 -0
  445. package/lib/toolbar/crop/slide-crop.d.ts +10 -4
  446. package/lib/toolbar/plot-type-selector/plot-type-selector.component.d.ts +38 -0
  447. package/lib/toolbar/region-tools/region-tool-buttons.d.ts +21 -0
  448. package/lib/toolbar/region-tools/region-tools.component.d.ts +60 -0
  449. package/lib/toolbar/segmentation/cell-segment-tool.service.d.ts +10 -14
  450. package/lib/toolbar/segmentation/cellpose-segmenter.service.d.ts +12 -2
  451. package/lib/toolbar/segmentation/onnx-sam-session.d.ts +22 -3
  452. package/lib/toolbar/segmentation/pending-calls.d.ts +31 -0
  453. package/lib/toolbar/segmentation/sam-model-registry.d.ts +9 -3
  454. package/lib/toolbar/segmentation/sam-onnx-core.d.ts +18 -5
  455. package/lib/toolbar/segmentation/sam-point-tool.service.d.ts +46 -32
  456. package/lib/toolbar/segmentation/sam-prompt.d.ts +7 -31
  457. package/lib/toolbar/segmentation/sam-session.service.d.ts +74 -0
  458. package/lib/toolbar/segmentation/sam-tool.service.d.ts +23 -30
  459. package/lib/toolbar/segmentation/segmentation-commit.d.ts +8 -0
  460. package/lib/toolbar/segmentation/segmentation-runner.d.ts +52 -0
  461. package/lib/toolbar/segmentation-tools/segmentation-tools.component.d.ts +87 -0
  462. package/lib/toolbar/stack-controls/stack-controls.component.d.ts +40 -0
  463. package/lib/toolbar/tool-kit/async-tool-status.d.ts +21 -0
  464. package/lib/toolbar/tool-kit/canvas-tool-manager.d.ts +36 -0
  465. package/lib/toolbar/tool-kit/canvas-tool.d.ts +86 -0
  466. package/lib/toolbar/tool-kit/frame-pixels.d.ts +45 -0
  467. package/lib/toolbar/tool-kit/mask-stroke-editor.d.ts +125 -0
  468. package/lib/toolbar/tool-kit/matrix-frame.d.ts +40 -0
  469. package/lib/toolbar/tool-kit/tool-overlay.d.ts +60 -0
  470. package/lib/toolbar/tool-kit/undo-gesture.d.ts +17 -0
  471. package/lib/toolbar/tool-slider/tool-slider.component.d.ts +33 -0
  472. package/lib/toolbar/toolbar-help-dialog/toolbar-help-dialog.component.d.ts +24 -0
  473. package/lib/toolbar/toolbar.component.d.ts +47 -83
  474. package/lib/toolbar/vertex-eraser/vertex-eraser-tool.service.d.ts +33 -40
  475. package/lib/toolbar/view-controls/view-controls.component.d.ts +54 -0
  476. package/lib/toolbar/wand/wand-region-grow.d.ts +49 -0
  477. package/lib/toolbar/wand/wand-tool.service.d.ts +39 -124
  478. package/lib/toolbar/wand/wand.service.d.ts +22 -116
  479. package/lib/toolbar/zoom-to-box/zoom-to-box-tool.service.d.ts +17 -37
  480. package/lib/util/mark-for-check.d.ts +11 -0
  481. package/lib/util/supersede.d.ts +53 -0
  482. package/lib/visualization.module.d.ts +18 -39
  483. package/lib/visualizer/floating-drag.directive.d.ts +30 -0
  484. package/lib/visualizer/region-actions.d.ts +54 -0
  485. package/lib/visualizer/region-load.d.ts +27 -0
  486. package/lib/visualizer/spatial-dataset-binder.d.ts +74 -0
  487. package/lib/visualizer/tool-modes.d.ts +49 -0
  488. package/lib/visualizer/viewer-shortcuts.d.ts +71 -0
  489. package/lib/visualizer/visualizer-context-menu.d.ts +55 -0
  490. package/lib/visualizer.component.d.ts +201 -447
  491. package/lib/workers/spatial-math-ops.d.ts +65 -0
  492. package/lib/workers/spatial-math-worker.d.ts +7 -0
  493. package/lib/workers/spatial-math.d.ts +74 -0
  494. package/package.json +12 -3
  495. package/src/lib/styles/_viz-icons-rules.scss +73 -0
  496. package/src/lib/styles/viz-icons.scss +14 -0
  497. package/esm2022/lib/implementations/napari-js/napari-axes-labels.mjs +0 -97
  498. package/esm2022/lib/implementations/napari-js/napari-navigator.mjs +0 -195
  499. package/esm2022/lib/implementations/napari-js/napari-scale-bar.mjs +0 -92
  500. package/fesm2022/jax-data-science-sci-image-visualizer-onnx-sam-session-BwP-A11m.mjs +0 -329
  501. package/fesm2022/jax-data-science-sci-image-visualizer-onnx-sam-session-BwP-A11m.mjs.map +0 -1
  502. package/lib/implementations/napari-js/napari-axes-labels.d.ts +0 -49
  503. package/lib/implementations/napari-js/napari-navigator.d.ts +0 -72
  504. package/lib/implementations/napari-js/napari-scale-bar.d.ts +0 -35
  505. package/src/lib/assets/cell-detection.svg +0 -37
  506. package/src/lib/assets/click.svg +0 -1
  507. package/src/lib/assets/colormap-luts.json +0 -1
  508. package/src/lib/assets/edit-selection-white.svg +0 -47
  509. package/src/lib/assets/icons/colormap-earth.png +0 -0
  510. package/src/lib/assets/icons/colormap-placeholder.png +0 -0
  511. package/src/lib/assets/icons/colormap-pubu.png +0 -0
  512. package/src/lib/assets/interactive-segmentation-cursor.svg +0 -1
  513. package/src/lib/assets/picture-segmentation.svg +0 -43
  514. package/src/lib/assets/test/download-379.svg +0 -1
  515. package/src/lib/assets/test/download-98.svg +0 -1
  516. package/src/lib/assets/test/json-1.svg +0 -1
  517. package/src/lib/assets/test/load-53.svg +0 -1
  518. package/src/lib/assets/test/mask-44.svg +0 -1
  519. package/src/lib/assets/test/mask-download-44.svg +0 -15
  520. package/src/lib/assets/test/mask-save-44.svg +0 -11
  521. package/src/lib/assets/test/overlay-1.svg +0 -1
  522. package/src/lib/assets/test/overlay-4.svg +0 -1
  523. package/src/lib/assets/test/region-26.svg +0 -1
  524. package/src/lib/assets/test/save-56.svg +0 -1
  525. package/src/lib/assets/test/upload-43.svg +0 -1
@@ -0,0 +1,145 @@
1
+ /** What a continuous value can be drawn as. */
2
+ export const CONTINUOUS_KINDS = [
3
+ { label: 'Histogram', value: 'histogram' },
4
+ { label: 'Violin', value: 'violin' },
5
+ { label: 'Box', value: 'box' },
6
+ ];
7
+ /** What a categorical column can be drawn as: a category code is a label, not a magnitude,
8
+ * so a histogram of it would be meaningless — what it has is a frequency distribution. */
9
+ export const CATEGORICAL_KINDS = [{ label: 'Counts', value: 'counts' }];
10
+ /** Available whatever the map is coloured by: the heatmap's subject is a GENE LIST crossed
11
+ * with a grouping, not the active colour source. */
12
+ export const ALWAYS_KINDS = [{ label: 'Heatmap', value: 'heatmap' }];
13
+ /**
14
+ * Offered only when the dataset publishes an embedding to draw. Labelled for what it is
15
+ * rather than for one instance of it: this view draws whatever embedding the dataset
16
+ * publishes — a UMAP, a PCA, a t-SNE — and calling the tab "UMAP" while it showed a PCA
17
+ * would be a lie the picker beneath it immediately contradicts.
18
+ */
19
+ export const EMBEDDING_KINDS = [{ label: 'Embedding', value: 'embedding' }];
20
+ /**
21
+ * The kinds the active subject can be drawn as. An embedding is a property of the DATASET,
22
+ * not of the colour source, so it is offered whenever one is published and never
23
+ * otherwise — a tab that draws nothing is worse than an absent one.
24
+ */
25
+ export function chartKindOptions(categorical, hasEmbeddings) {
26
+ return [
27
+ ...(categorical ? CATEGORICAL_KINDS : CONTINUOUS_KINDS),
28
+ ...ALWAYS_KINDS,
29
+ ...(hasEmbeddings ? EMBEDDING_KINDS : []),
30
+ ];
31
+ }
32
+ /**
33
+ * What the chart on screen actually shows, and what it cannot be read for.
34
+ *
35
+ * Shown on hover from a `?` beside the tabs. Each of these plots answers a different
36
+ * question and two of them are routinely over-read — a UMAP's distances and a heatmap's
37
+ * unscaled colours — so the caveat is part of the explanation rather than a footnote.
38
+ *
39
+ * HTML, because the tooltip renders with `[escape]="false"`: a paragraph and a caveat read
40
+ * as two thoughts, and a single run-on line is skipped rather than read.
41
+ */
42
+ export function kindHelp(kind, embedding) {
43
+ switch (kind) {
44
+ case 'counts':
45
+ return ('<b>Counts</b> — how many observations fall in each category of the column ' +
46
+ 'the map is coloured by, largest first.<br><br>A category code is a label, not ' +
47
+ 'a magnitude, so a frequency is the only distribution it has: there is no ' +
48
+ 'histogram of a cell type.');
49
+ case 'histogram':
50
+ return ('<b>Histogram</b> — how the active value is distributed over all ' +
51
+ 'observations.<br><br>With a selection, it is overlaid on the full ' +
52
+ 'distribution rather than replacing it, so you can see where the selected ' +
53
+ 'cells sit within the whole.');
54
+ case 'violin':
55
+ return ("<b>Violin</b> — the active value's distribution within each category of " +
56
+ 'the grouping column, drawn as a smoothed density.<br><br>Shows shape a box ' +
57
+ 'plot hides: two groups with the same median can be one peak or two.');
58
+ case 'box':
59
+ return ('<b>Box</b> — median, quartiles and range of the active value within each ' +
60
+ 'category of the grouping column.<br><br>Compact and comparable across many ' +
61
+ 'groups, at the cost of hiding whether a group is bimodal.');
62
+ case 'heatmap':
63
+ return ('<b>Heatmap</b> — mean expression of each picked gene within each group: ' +
64
+ 'genes down, groups across.<br><br>Each gene is <b>z-scored across the ' +
65
+ 'groups</b> by default, so a colour says "above or below this gene\'s own ' +
66
+ 'average", not "highly expressed". Without that one loud gene saturates the ' +
67
+ 'scale and the rest of the panel reads as blank. Turning it off compares ' +
68
+ 'genes on their raw scale instead.');
69
+ case 'embedding':
70
+ return embeddingHelp(embedding);
71
+ default:
72
+ return '';
73
+ }
74
+ }
75
+ /**
76
+ * What the embedding on screen is, and how far its geometry can be trusted.
77
+ *
78
+ * Per METHOD, because that is the part people get wrong: a PCA's axes are ordered and
79
+ * measurable while a UMAP's are neither, and the same picture read the two ways supports
80
+ * opposite conclusions.
81
+ */
82
+ export function embeddingHelp(embedding) {
83
+ const shared = '<br><br>Every cell is in all views at once: lasso a group here and ' +
84
+ 'those cells light up on the tissue, because both read the same selection.';
85
+ const name = (embedding?.label ?? embedding?.name ?? '').toLowerCase();
86
+ if (name.includes('pca')) {
87
+ return ('<b>PCA</b> — a <b>linear</b> projection onto the directions of greatest ' +
88
+ 'variance, in order.<br><br>Alone among these, its axes mean something ' +
89
+ 'measurable: each reports the share of total variance it explains, which is why ' +
90
+ 'the labels carry a percentage. Distances are real, and a low percentage tells ' +
91
+ 'you the picture is a thin slice of the variation.' +
92
+ shared);
93
+ }
94
+ if (name.includes('t-sne') || name.includes('tsne')) {
95
+ return ('<b>t-SNE</b> — cells placed so that close neighbours in expression stay ' +
96
+ 'close.<br><br>Stricter about local neighbourhoods than UMAP and less ' +
97
+ 'trustworthy about anything global: it tends to spread clusters into ' +
98
+ 'evenly-sized islands whose sizes and separations mean little. Read which cells ' +
99
+ 'group together, not how far apart the groups are.' +
100
+ shared);
101
+ }
102
+ return ('<b>UMAP</b> — cells placed so that close neighbours in expression stay ' +
103
+ 'close.<br><br>The axes are arbitrary: unordered, unitless, and reproducible only ' +
104
+ 'up to a rotation, which is why they carry no percentage. Read which cells group ' +
105
+ 'together and which groups touch; do not read the distance between distant ' +
106
+ 'clusters, or the direction of an axis.' +
107
+ shared);
108
+ }
109
+ /** What the embedding view is showing, said plainly. */
110
+ export function embeddingNote(meta, coloured, selectionCount) {
111
+ if (!meta)
112
+ return 'This dataset publishes no embedding.';
113
+ // A derived embedding says so, and says HOW when the parameters are known: a t-SNE or
114
+ // UMAP at different settings is a different picture of the same cells, so "computed
115
+ // here" alone leaves a reader unable to reproduce or compare it.
116
+ const derived = meta.derived
117
+ ? ` Computed here${meta.params ? ` (${meta.params})` : ''}, not published with the dataset.`
118
+ : '';
119
+ const colour = coloured
120
+ ? ' Coloured to match the map.'
121
+ : ' Colour the map by a categorical column to colour these points.';
122
+ const sel = selectionCount > 0 ? ` ${selectionCount.toLocaleString()} selected are highlighted.` : '';
123
+ return `${meta.label ?? meta.name}.${colour}${sel}${derived}`;
124
+ }
125
+ /** What the heatmap is currently showing, said plainly. */
126
+ export function heatmapNote(s) {
127
+ if (s.geneCount === 0)
128
+ return 'Pick one or more genes for the rows.';
129
+ const perCell = s.selectionCount > 0 && s.selectionCount <= s.cellColumns;
130
+ if (perCell) {
131
+ return (`One column per selected cell (${s.selectionCount}). ` +
132
+ 'Mean expression per cell, so the columns are cells rather than classes.');
133
+ }
134
+ const scope = s.selectionCount > 0 ? 'the selected cells' : 'all cells';
135
+ const scaled = s.zScore
136
+ ? " Each gene is z-scored across the columns, so the colour is above or below that gene's own average."
137
+ : ' Raw means, so a highly-expressed gene dominates the scale.';
138
+ // Saying so matters: without it the panel looks like the whole column.
139
+ const capped = s.hidden > 0
140
+ ? ` Showing the ${s.maxColumns} strongest of ${s.maxColumns + s.hidden}, ` +
141
+ 'ranked by the largest value any picked gene reaches.'
142
+ : '';
143
+ return `Mean expression of each gene within each ${s.groupBy ?? 'group'}, over ${scope}.${scaled}${capped}`;
144
+ }
145
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2hhcnQtaGVscC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uLy4uL3NyYy9saWIvc3BhdGlhbC1jb250cm9scy9zcGF0aWFsLWNoYXJ0cy9jaGFydC1oZWxwLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQWVBLCtDQUErQztBQUMvQyxNQUFNLENBQUMsTUFBTSxnQkFBZ0IsR0FBK0I7SUFDMUQsRUFBRSxLQUFLLEVBQUUsV0FBVyxFQUFFLEtBQUssRUFBRSxXQUFXLEVBQUU7SUFDMUMsRUFBRSxLQUFLLEVBQUUsUUFBUSxFQUFFLEtBQUssRUFBRSxRQUFRLEVBQUU7SUFDcEMsRUFBRSxLQUFLLEVBQUUsS0FBSyxFQUFFLEtBQUssRUFBRSxLQUFLLEVBQUU7Q0FDL0IsQ0FBQztBQUVGOzJGQUMyRjtBQUMzRixNQUFNLENBQUMsTUFBTSxpQkFBaUIsR0FBK0IsQ0FBQyxFQUFFLEtBQUssRUFBRSxRQUFRLEVBQUUsS0FBSyxFQUFFLFFBQVEsRUFBRSxDQUFDLENBQUM7QUFFcEc7cURBQ3FEO0FBQ3JELE1BQU0sQ0FBQyxNQUFNLFlBQVksR0FBK0IsQ0FBQyxFQUFFLEtBQUssRUFBRSxTQUFTLEVBQUUsS0FBSyxFQUFFLFNBQVMsRUFBRSxDQUFDLENBQUM7QUFFakc7Ozs7O0dBS0c7QUFDSCxNQUFNLENBQUMsTUFBTSxlQUFlLEdBQStCLENBQUMsRUFBRSxLQUFLLEVBQUUsV0FBVyxFQUFFLEtBQUssRUFBRSxXQUFXLEVBQUUsQ0FBQyxDQUFDO0FBRXhHOzs7O0dBSUc7QUFDSCxNQUFNLFVBQVUsZ0JBQWdCLENBQUMsV0FBb0IsRUFBRSxhQUFzQjtJQUMzRSxPQUFPO1FBQ0wsR0FBRyxDQUFDLFdBQVcsQ0FBQyxDQUFDLENBQUMsaUJBQWlCLENBQUMsQ0FBQyxDQUFDLGdCQUFnQixDQUFDO1FBQ3ZELEdBQUcsWUFBWTtRQUNmLEdBQUcsQ0FBQyxhQUFhLENBQUMsQ0FBQyxDQUFDLGVBQWUsQ0FBQyxDQUFDLENBQUMsRUFBRSxD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ZGluZ01ldGEgfSBmcm9tICcuLi8uLi9jb250cmFjdHMvc3BhdGlhbC1kYXRhc2V0LmNvbnRyYWN0JztcbmltcG9ydCB0eXBlIHsgT21pY3NDaGFydEtpbmQgfSBmcm9tICcuLi8uLi9pbXBsZW1lbnRhdGlvbnMvcGxvdGx5L29taWNzLXRyYWNlLWJ1aWxkZXJzJztcblxuLyoqXG4gKiBUaGUgc3BhdGlhbCBjaGFydHMnIGtpbmQgY2F0YWxvZ3VlIGFuZCB0aGUgcHJvc2UgdGhhdCBleHBsYWlucyBlYWNoIGNoYXJ0OiBwdXJlXG4gKiBmdW5jdGlvbnMgb2Ygd2hhdCBpcyBjaGFydGVkLCBzbyBub25lIG9mIHRoZSB+MTUwIGxpbmVzIG9mIHRleHQgc2l0IGluIHRoZSBjb21wb25lbnQgYW5kXG4gKiBlYWNoIHNlbnRlbmNlIGlzIHRlc3RhYmxlIG9uIGl0cyBvd24uXG4gKi9cblxuLyoqIEEgY2hhcnQga2luZCBhcyB0aGUga2luZCBwaWNrZXIgb2ZmZXJzIGl0LiAqL1xuZXhwb3J0IGludGVyZmFjZSBDaGFydEtpbmRPcHRpb24ge1xuICBsYWJlbDogc3RyaW5nO1xuICB2YWx1ZTogT21pY3NDaGFydEtpbmQ7XG59XG5cbi8qKiBXaGF0IGEgY29udGludW91cyB2YWx1ZSBjYW4gYmUgZHJhd24gYXMuICovXG5leHBvcnQgY29uc3QgQ09OVElOVU9VU19LSU5EUzogcmVhZG9ubHkgQ2hhcnRLaW5kT3B0aW9uW10gPSBbXG4gIHsgbGFiZWw6ICdIaXN0b2dyYW0nLCB2YWx1ZTogJ2hpc3RvZ3JhbScgfSxcbiAgeyBsYWJlbDogJ1Zpb2xpbicsIHZhbHVlOiAndmlvbGluJyB9LFxuICB7IGxhYmVsOiAnQm94JywgdmFsdWU6ICdib3gnIH0sXG5dO1xuXG4vKiogV2hhdCBhIGNhdGVnb3JpY2FsIGNvbHVtbiBjYW4gYmUgZHJhd24gYXM6IGEgY2F0ZWdvcnkgY29kZSBpcyBhIGxhYmVsLCBub3QgYSBtYWduaXR1ZGUsXG4gKiAgc28gYSBoaXN0b2dyYW0gb2YgaXQgd291bGQgYmUgbWVhbmluZ2xlc3Mg4oCUIHdoYXQgaXQgaGFzIGlzIGEgZnJlcXVlbmN5IGRpc3RyaWJ1dGlvbi4gKi9cbmV4cG9ydCBjb25zdCBDQVRFR09SSUNBTF9LSU5EUzogcmVhZG9ubHkgQ2hhcnRLaW5kT3B0aW9uW10gPSBbeyBsYWJlbDogJ0NvdW50cycsIHZhbHVlOiAnY291bnRzJyB9XTtcblxuLyoqIEF2YWlsYWJsZSB3aGF0ZXZlciB0aGUgbWFwIGlzIGNvbG91cmVkIGJ5OiB0aGUgaGVhdG1hcCdzIHN1YmplY3QgaXMgYSBHRU5FIExJU1QgY3Jvc3NlZFxuICogIHdpdGggYSBncm91cGluZywgbm90IHRoZSBhY3RpdmUgY29sb3VyIHNvdXJjZS4gKi9cbmV4cG9ydCBjb25zdCBBTFdBWVNfS0lORFM6IHJlYWRvbmx5IENoYXJ0S2luZE9wdGlvbltdID0gW3sgbGFiZWw6ICdIZWF0bWFwJywgdmFsdWU6ICdoZWF0bWFwJyB9XTtcblxuLyoqXG4gKiBPZmZlcmVkIG9ubHkgd2hlbiB0aGUgZGF0YXNldCBwdWJsaXNoZXMgYW4gZW1iZWRkaW5nIHRvIGRyYXcuIExhYmVsbGVkIGZvciB3aGF0IGl0IGlzXG4gKiByYXRoZXIgdGhhbiBmb3Igb25lIGluc3RhbmNlIG9mIGl0OiB0aGlzIHZpZXcgZHJhd3Mgd2hhdGV2ZXIgZW1iZWRkaW5nIHRoZSBkYXRhc2V0XG4gKiBwdWJsaXNoZXMg4oCUIGEgVU1BUCwgYSBQQ0EsIGEgdC1TTkUg4oCUIGFuZCBjYWxsaW5nIHRoZSB0YWIgXCJVTUFQXCIgd2hpbGUgaXQgc2hvd2VkIGEgUENBXG4gKiB3b3VsZCBiZSBhIGxpZSB0aGUgcGlja2VyIGJlbmVhdGggaXQgaW1tZWRpYXRlbHkgY29udHJhZGljdHMuXG4gKi9cbmV4cG9ydCBjb25zdCBFTUJFRERJTkdfS0lORFM6IHJlYWRvbmx5IENoYXJ0S2luZE9wdGlvbltdID0gW3sgbGFiZWw6ICdFbWJlZGRpbmcnLCB2YWx1ZTogJ2VtYmVkZGluZycgfV07XG5cbi8qKlxuICogVGhlIGtpbmRzIHRoZSBhY3RpdmUgc3ViamVjdCBjYW4gYmUgZHJhd24gYXMuIEFuIGVtYmVkZGluZyBpcyBhIHByb3BlcnR5IG9mIHRoZSBEQVRBU0VULFxuICogbm90IG9mIHRoZSBjb2xvdXIgc291cmNlLCBzbyBpdCBpcyBvZmZlcmVkIHdoZW5ldmVyIG9uZSBpcyBwdWJsaXNoZWQgYW5kIG5ldmVyXG4gKiBvdGhlcndpc2Ug4oCUIGEgdGFiIHRoYXQgZHJhd3Mgbm90aGluZyBpcyB3b3JzZSB0aGFuIGFuIGFic2VudCBvbmUuXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBjaGFydEtpbmRPcHRpb25zKGNhdGVnb3JpY2FsOiBib29sZWFuLCBoYXNFbWJlZGRpbmdzOiBib29sZWFuKTogQ2hhcnRLaW5kT3B0aW9uW10ge1xuICByZXR1cm4gW1xuICAgIC4uLihjYXRlZ29yaWNhbCA/IENBVEVHT1JJQ0FMX0tJTkRTIDogQ09OVElOVU9VU19LSU5EUyksXG4gICAgLi4uQUxXQVlTX0tJTkRTLFxuICAgIC4uLihoYXNFbWJlZGRpbmdzID8gRU1CRURESU5HX0tJTkRTIDogW10pLFxuICBdO1xufVxuXG4vKipcbiAqIFdoYXQgdGhlIGNoYXJ0IG9uIHNjcmVlbiBhY3R1YWxseSBzaG93cywgYW5kIHdoYXQgaXQgY2Fubm90IGJlIHJlYWQgZm9yLlxuICpcbiAqIFNob3duIG9uIGhvdmVyIGZyb20gYSBgP2AgYmVzaWRlIHRoZSB0YWJzLiBFYWNoIG9mIHRoZXNlIHBsb3RzIGFuc3dlcnMgYSBkaWZmZXJlbnRcbiAqIHF1ZXN0aW9uIGFuZCB0d28gb2YgdGhlbSBhcmUgcm91dGluZWx5IG92ZXItcmVhZCDigJQgYSBVTUFQJ3MgZGlzdGFuY2VzIGFuZCBhIGhlYXRtYXAnc1xuICogdW5zY2FsZWQgY29sb3VycyDigJQgc28gdGhlIGNhdmVhdCBpcyBwYXJ0IG9mIHRoZSBleHBsYW5hdGlvbiByYXRoZXIgdGhhbiBhIGZvb3Rub3RlLlxuICpcbiAqIEhUTUwsIGJlY2F1c2UgdGhlIHRvb2x0aXAgcmVuZGVycyB3aXRoIGBbZXNjYXBlXT1cImZhbHNlXCJgOiBhIHBhcmFncmFwaCBhbmQgYSBjYXZlYXQgcmVhZFxuICogYXMgdHdvIHRob3VnaHRzLCBhbmQgYSBzaW5nbGUgcnVuLW9uIGxpbmUgaXMgc2tpcHBlZCByYXRoZXIgdGhhbiByZWFkLlxuICovXG5leHBvcnQgZnVuY3Rpb24ga2luZEhlbHAoXG4gIGtpbmQ6IE9taWNzQ2hhcnRLaW5kLFxuICBlbWJlZGRpbmc6IFBpY2s8U3BhdGlhbEVtYmVkZGluZ01ldGEsICduYW1lJyB8ICdsYWJlbCc+IHwgbnVsbCxcbik6IHN0cmluZyB7XG4gIHN3aXRjaCAoa2luZCkge1xuICAgIGNhc2UgJ2NvdW50cyc6XG4gICAgICByZXR1cm4gKFxuICAgICAgICAnPGI+Q291bnRzPC9iPiDigJQgaG93IG1hbnkgb2JzZXJ2YXRpb25zIGZhbGwgaW4gZWFjaCBjYXRlZ29yeSBvZiB0aGUgY29sdW1uICcgK1xuICAgICAgICAndGhlIG1hcCBpcyBjb2xvdXJlZCBieSwgbGFyZ2VzdCBmaXJzdC48YnI+PGJyPkEgY2F0ZWdvcnkgY29kZSBpcyBhIGxhYmVsLCBub3QgJyArXG4gICAgICAgICdhIG1hZ25pdHVkZSwgc28gYSBmcmVxdWVuY3kgaXMgdGhlIG9ubHkgZGlzdHJpYnV0aW9uIGl0IGhhczogdGhlcmUgaXMgbm8gJyArXG4gICAgICAgICdoaXN0b2dyYW0gb2YgYSBjZWxsIHR5cGUuJ1xuICAgICAgKTtcbiAgICBjYXNlICdoaXN0b2dyYW0nOlxuICAgICAgcmV0dXJuIChcbiAgICAgICAgJzxiPkhpc3RvZ3JhbTwvYj4g4oCUIGhvdyB0aGUgYWN0aXZlIHZhbHVlIGlzIGRpc3RyaWJ1dGVkIG92ZXIgYWxsICcgK1xuICAgICAgICAnb2JzZXJ2YXRpb25zLjxicj48YnI+V2l0aCBhIHNlbGVjdGlvbiwgaXQgaXMgb3ZlcmxhaWQgb24gdGhlIGZ1bGwgJyArXG4gICAgICAgICdkaXN0cmlidXRpb24gcmF0aGVyIHRoYW4gcmVwbGFjaW5nIGl0LCBzbyB5b3UgY2FuIHNlZSB3aGVyZSB0aGUgc2VsZWN0ZWQgJyArXG4gICAgICAgICdjZWxscyBzaXQgd2l0aGluIHRoZSB3aG9sZS4nXG4gICAgICApO1xuICAgIGNhc2UgJ3Zpb2xpbic6XG4gICAgICByZXR1cm4gKFxuICAgICAgICBcIjxiPlZpb2xpbjwvYj4g4oCUIHRoZSBhY3RpdmUgdmFsdWUncyBkaXN0cmlidXRpb24gd2l0aGluIGVhY2ggY2F0ZWdvcnkgb2YgXCIgK1xuICAgICAgICAndGhlIGdyb3VwaW5nIGNvbHVtbiwgZHJhd24gYXMgYSBzbW9vdGhlZCBkZW5zaXR5Ljxicj48YnI+U2hvd3Mgc2hhcGUgYSBib3ggJyArXG4gICAgICAgICdwbG90IGhpZGVzOiB0d28gZ3JvdXBzIHdpdGggdGhlIHNhbWUgbWVkaWFuIGNhbiBiZSBvbmUgcGVhayBvciB0d28uJ1xuICAgICAgKTtcbiAgICBjYXNlICdib3gnOlxuICAgICAgcmV0dXJuIChcbiAgICAgICAgJzxiPkJveDwvYj4g4oCUIG1lZGlhbiwgcXVhcnRpbGVzIGFuZCByYW5nZSBvZiB0aGUgYWN0aXZlIHZhbHVlIHdpdGhpbiBlYWNoICcgK1xuICAgICAgICAnY2F0ZWdvcnkgb2YgdGhlIGdyb3VwaW5nIGNvbHVtbi48YnI+PGJyPkNvbXBhY3QgYW5kIGNvbXBhcmFibGUgYWNyb3NzIG1hbnkgJyArXG4gICAgICAgICdncm91cHMsIGF0IHRoZSBjb3N0IG9mIGhpZGluZyB3aGV0aGVyIGEgZ3JvdXAgaXMgYmltb2RhbC4nXG4gICAgICApO1xuICAgIGNhc2UgJ2hlYXRtYXAnOlxuICAgICAgcmV0dXJuIChcbiAgICAgICAgJzxiPkhlYXRtYXA8L2I+IOKAlCBtZWFuIGV4cHJlc3Npb24gb2YgZWFjaCBwaWNrZWQgZ2VuZSB3aXRoaW4gZWFjaCBncm91cDogJyArXG4gICAgICAgICdnZW5lcyBkb3duLCBncm91cHMgYWNyb3NzLjxicj48YnI+RWFjaCBnZW5lIGlzIDxiPnotc2NvcmVkIGFjcm9zcyB0aGUgJyArXG4gICAgICAgICdncm91cHM8L2I+IGJ5IGRlZmF1bHQsIHNvIGEgY29sb3VyIHNheXMgXCJhYm92ZSBvciBiZWxvdyB0aGlzIGdlbmVcXCdzIG93biAnICtcbiAgICAgICAgJ2F2ZXJhZ2VcIiwgbm90IFwiaGlnaGx5IGV4cHJlc3NlZFwiLiBXaXRob3V0IHRoYXQgb25lIGxvdWQgZ2VuZSBzYXR1cmF0ZXMgdGhlICcgK1xuICAgICAgICAnc2NhbGUgYW5kIHRoZSByZXN0IG9mIHRoZSBwYW5lbCByZWFkcyBhcyBibGFuay4gVHVybmluZyBpdCBvZmYgY29tcGFyZXMgJyArXG4gICAgICAgICdnZW5lcyBvbiB0aGVpciByYXcgc2NhbGUgaW5zdGVhZC4nXG4gICAgICApO1xuICAgIGNhc2UgJ2VtYmVkZGluZyc6XG4gICAgICByZXR1cm4gZW1iZWRkaW5nSGVscChlbWJlZGRpbmcpO1xuICAgIGRlZmF1bHQ6XG4gICAgICByZXR1cm4gJyc7XG4gIH1cbn1cblxuLyoqXG4gKiBXaGF0IHRoZSBlbWJlZGRpbmcgb24gc2NyZWVuIGlzLCBhbmQgaG93IGZhciBpdHMgZ2VvbWV0cnkgY2FuIGJlIHRydXN0ZWQuXG4gKlxuICogUGVyIE1FVEhPRCwgYmVjYXVzZSB0aGF0IGlzIHRoZSBwYXJ0IHBlb3BsZSBnZXQgd3Jvbmc6IGEgUENBJ3MgYXhlcyBhcmUgb3JkZXJlZCBhbmRcbiAqIG1lYXN1cmFibGUgd2hpbGUgYSBVTUFQJ3MgYXJlIG5laXRoZXIsIGFuZCB0aGUgc2FtZSBwaWN0dXJlIHJlYWQgdGhlIHR3byB3YXlzIHN1cHBvcnRzXG4gKiBvcHBvc2l0ZSBjb25jbHVzaW9ucy5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGVtYmVkZGluZ0hlbHAoZW1iZWRkaW5nOiBQaWNrPFNwYXRpYWxFbWJlZGRpbmdNZXRhLCAnbmFtZScgfCAnbGFiZWwnPiB8IG51bGwpOiBzdHJpbmcge1xuICBjb25zdCBzaGFyZWQgPVxuICAgICc8YnI+PGJyPkV2ZXJ5IGNlbGwgaXMgaW4gYWxsIHZpZXdzIGF0IG9uY2U6IGxhc3NvIGEgZ3JvdXAgaGVyZSBhbmQgJyArXG4gICAgJ3Rob3NlIGNlbGxzIGxpZ2h0IHVwIG9uIHRoZSB0aXNzdWUsIGJlY2F1c2UgYm90aCByZWFkIHRoZSBzYW1lIHNlbGVjdGlvbi4nO1xuICBjb25zdCBuYW1lID0gKGVtYmVkZGluZz8ubGFiZWwgPz8gZW1iZWRkaW5nPy5uYW1lID8/ICcnKS50b0xvd2VyQ2FzZSgpO1xuICBpZiAobmFtZS5pbmNsdWRlcygncGNhJykpIHtcbiAgICByZXR1cm4gKFxuICAgICAgJzxiPlBDQTwvYj4g4oCUIGEgPGI+bGluZWFyPC9iPiBwcm9qZWN0aW9uIG9udG8gdGhlIGRpcmVjdGlvbnMgb2YgZ3JlYXRlc3QgJyArXG4gICAgICAndmFyaWFuY2UsIGluIG9yZGVyLjxicj48YnI+QWxvbmUgYW1vbmcgdGhlc2UsIGl0cyBheGVzIG1lYW4gc29tZXRoaW5nICcgK1xuICAgICAgJ21lYXN1cmFibGU6IGVhY2ggcmVwb3J0cyB0aGUgc2hhcmUgb2YgdG90YWwgdmFyaWFuY2UgaXQgZXhwbGFpbnMsIHdoaWNoIGlzIHdoeSAnICtcbiAgICAgICd0aGUgbGFiZWxzIGNhcnJ5IGEgcGVyY2VudGFnZS4gRGlzdGFuY2VzIGFyZSByZWFsLCBhbmQgYSBsb3cgcGVyY2VudGFnZSB0ZWxscyAnICtcbiAgICAgICd5b3UgdGhlIHBpY3R1cmUgaXMgYSB0aGluIHNsaWNlIG9mIHRoZSB2YXJpYXRpb24uJyArXG4gICAgICBzaGFyZWRcbiAgICApO1xuICB9XG4gIGlmIChuYW1lLmluY2x1ZGVzKCd0LXNuZScpIHx8IG5hbWUuaW5jbHVkZXMoJ3RzbmUnKSkge1xuICAgIHJldHVybiAoXG4gICAgICAnPGI+dC1TTkU8L2I+IOKAlCBjZWxscyBwbGFjZWQgc28gdGhhdCBjbG9zZSBuZWlnaGJvdXJzIGluIGV4cHJlc3Npb24gc3RheSAnICtcbiAgICAgICdjbG9zZS48YnI+PGJyPlN0cmljdGVyIGFib3V0IGxvY2FsIG5laWdoYm91cmhvb2RzIHRoYW4gVU1BUCBhbmQgbGVzcyAnICtcbiAgICAgICd0cnVzdHdvcnRoeSBhYm91dCBhbnl0aGluZyBnbG9iYWw6IGl0IHRlbmRzIHRvIHNwcmVhZCBjbHVzdGVycyBpbnRvICcgK1xuICAgICAgJ2V2ZW5seS1zaXplZCBpc2xhbmRzIHdob3NlIHNpemVzIGFuZCBzZXBhcmF0aW9ucyBtZWFuIGxpdHRsZS4gUmVhZCB3aGljaCBjZWxscyAnICtcbiAgICAgICdncm91cCB0b2dldGhlciwgbm90IGhvdyBmYXIgYXBhcnQgdGhlIGdyb3VwcyBhcmUuJyArXG4gICAgICBzaGFyZWRcbiAgICApO1xuICB9XG4gIHJldHVybiAoXG4gICAgJzxiPlVNQVA8L2I+IOKAlCBjZWxscyBwbGFjZWQgc28gdGhhdCBjbG9zZSBuZWlnaGJvdXJzIGluIGV4cHJlc3Npb24gc3RheSAnICtcbiAgICAnY2xvc2UuPGJyPjxicj5UaGUgYXhlcyBhcmUgYXJiaXRyYXJ5OiB1bm9yZGVyZWQsIHVuaXRsZXNzLCBhbmQgcmVwcm9kdWNpYmxlIG9ubHkgJyArXG4gICAgJ3VwIHRvIGEgcm90YXRpb24sIHdoaWNoIGlzIHdoeSB0aGV5IGNhcnJ5IG5vIHBlcmNlbnRhZ2UuIFJlYWQgd2hpY2ggY2VsbHMgZ3JvdXAgJyArXG4gICAgJ3RvZ2V0aGVyIGFuZCB3aGljaCBncm91cHMgdG91Y2g7IGRvIG5vdCByZWFkIHRoZSBkaXN0YW5jZSBiZXR3ZWVuIGRpc3RhbnQgJyArXG4gICAgJ2NsdXN0ZXJzLCBvciB0aGUgZGlyZWN0aW9uIG9mIGFuIGF4aXMuJyArXG4gICAgc2hhcmVkXG4gICk7XG59XG5cbi8qKiBXaGF0IHRoZSBlbWJlZGRpbmcgdmlldyBpcyBzaG93aW5nLCBzYWlkIHBsYWlubHkuICovXG5leHBvcnQgZnVuY3Rpb24gZW1iZWRkaW5nTm90ZShcbiAgbWV0YTogUGljazxTcGF0aWFsRW1iZWRkaW5nTWV0YSwgJ25hbWUnIHwgJ2xhYmVsJyB8ICdkZXJpdmVkJyB8ICdwYXJhbXMnPiB8IG51bGwsXG4gIGNvbG91cmVkOiBib29sZWFuLFxuICBzZWxlY3Rpb25Db3VudDogbnVtYmVyLFxuKTogc3RyaW5nIHtcbiAgaWYgKCFtZXRhKSByZXR1cm4gJ1RoaXMgZGF0YXNldCBwdWJsaXNoZXMgbm8gZW1iZWRkaW5nLic7XG4gIC8vIEEgZGVyaXZlZCBlbWJlZGRpbmcgc2F5cyBzbywgYW5kIHNheXMgSE9XIHdoZW4gdGhlIHBhcmFtZXRlcnMgYXJlIGtub3duOiBhIHQtU05FIG9yXG4gIC8vIFVNQVAgYXQgZGlmZmVyZW50IHNldHRpbmdzIGlzIGEgZGlmZmVyZW50IHBpY3R1cmUgb2YgdGhlIHNhbWUgY2VsbHMsIHNvIFwiY29tcHV0ZWRcbiAgLy8gaGVyZVwiIGFsb25lIGxlYXZlcyBhIHJlYWRlciB1bmFibGUgdG8gcmVwcm9kdWNlIG9yIGNvbXBhcmUgaXQuXG4gIGNvbnN0IGRlcml2ZWQgPSBtZXRhLmRlcml2ZWRcbiAgICA/IGAgQ29tcHV0ZWQgaGVyZSR7bWV0YS5wYXJhbXMgPyBgICgke21ldGEucGFyYW1zfSlgIDogJyd9LCBub3QgcHVibGlzaGVkIHdpdGggdGhlIGRhdGFzZXQuYFxuICAgIDogJyc7XG4gIGNvbnN0IGNvbG91ciA9IGNvbG91cmVkXG4gICAgPyAnIENvbG91cmVkIHRvIG1hdGNoIHRoZSBtYXAuJ1xuICAgIDogJyBDb2xvdXIgdGhlIG1hcCBieSBhIGNhdGVnb3JpY2FsIGNvbHVtbiB0byBjb2xvdXIgdGhlc2UgcG9pbnRzLic7XG4gIGNvbnN0IHNlbCA9IHNlbGVjdGlvbkNvdW50ID4gMCA/IGAgJHtzZWxlY3Rpb25Db3VudC50b0xvY2FsZVN0cmluZygpfSBzZWxlY3RlZCBhcmUgaGlnaGxpZ2h0ZWQuYCA6ICcnO1xuICByZXR1cm4gYCR7bWV0YS5sYWJlbCA/PyBtZXRhLm5hbWV9LiR7Y29sb3VyfSR7c2VsfSR7ZGVyaXZlZH1gO1xufVxuXG4vKiogV2hhdCB0aGUgaGVhdG1hcCBpcyBzaG93aW5nLCBhcyB7QGxpbmsgaGVhdG1hcE5vdGV9IHNheXMgaXQuICovXG5leHBvcnQgaW50ZXJmYWNlIEhlYXRtYXBOb3RlU3RhdGUge1xuICBnZW5lQ291bnQ6IG51bWJlcjtcbiAgc2VsZWN0aW9uQ291bnQ6IG51bWJlcjtcbiAgelNjb3JlOiBib29sZWFuO1xuICAvKiogQ29sdW1ucyB0aGUgY2FwIGRyb3BwZWQgZnJvbSB0aGUgbGFzdCByZW5kZXIuICovXG4gIGhpZGRlbjogbnVtYmVyO1xuICBncm91cEJ5OiBzdHJpbmcgfCBudWxsO1xuICAvKiogVGhlIGdyb3VwZWQgdmlldydzIGNvbHVtbiBjYXAuICovXG4gIG1heENvbHVtbnM6IG51bWJlcjtcbiAgLyoqIFVwIHRvIHRoaXMgbWFueSBzZWxlY3RlZCBjZWxscywgZWFjaCBpcyBpdHMgb3duIGNvbHVtbi4gKi9cbiAgY2VsbENvbHVtbnM6IG51bWJlcjtcbn1cblxuLyoqIFdoYXQgdGhlIGhlYXRtYXAgaXMgY3VycmVudGx5IHNob3dpbmcsIHNhaWQgcGxhaW5seS4gKi9cbmV4cG9ydCBmdW5jdGlvbiBoZWF0bWFwTm90ZShzOiBIZWF0bWFwTm90ZVN0YXRlKTogc3RyaW5nIHtcbiAgaWYgKHMuZ2VuZUNvdW50ID09PSAwKSByZXR1cm4gJ1BpY2sgb25lIG9yIG1vcmUgZ2VuZXMgZm9yIHRoZSByb3dzLic7XG4gIGNvbnN0IHBlckNlbGwgPSBzLnNlbGVjdGlvbkNvdW50ID4gMCAmJiBzLnNlbGVjdGlvbkNvdW50IDw9IHMuY2VsbENvbHVtbnM7XG4gIGlmIChwZXJDZWxsKSB7XG4gICAgcmV0dXJuIChcbiAgICAgIGBPbmUgY29sdW1uIHBlciBzZWxlY3RlZCBjZWxsICgke3Muc2VsZWN0aW9uQ291bnR9KS4gYCArXG4gICAgICAnTWVhbiBleHByZXNzaW9uIHBlciBjZWxsLCBzbyB0aGUgY29sdW1ucyBhcmUgY2VsbHMgcmF0aGVyIHRoYW4gY2xhc3Nlcy4nXG4gICAgKTtcbiAgfVxuICBjb25zdCBzY29wZSA9IHMuc2VsZWN0aW9uQ291bnQgPiAwID8gJ3RoZSBzZWxlY3RlZCBjZWxscycgOiAnYWxsIGNlbGxzJztcbiAgY29uc3Qgc2NhbGVkID0gcy56U2NvcmVcbiAgICA/IFwiIEVhY2ggZ2VuZSBpcyB6LXNjb3JlZCBhY3Jvc3MgdGhlIGNvbHVtbnMsIHNvIHRoZSBjb2xvdXIgaXMgYWJvdmUgb3IgYmVsb3cgdGhhdCBnZW5lJ3Mgb3duIGF2ZXJhZ2UuXCJcbiAgICA6ICcgUmF3IG1lYW5zLCBzbyBhIGhpZ2hseS1leHByZXNzZWQgZ2VuZSBkb21pbmF0ZXMgdGhlIHNjYWxlLic7XG4gIC8vIFNheWluZyBzbyBtYXR0ZXJzOiB3aXRob3V0IGl0IHRoZSBwYW5lbCBsb29rcyBsaWtlIHRoZSB3aG9sZSBjb2x1bW4uXG4gIGNvbnN0IGNhcHBlZCA9XG4gICAgcy5oaWRkZW4gPiAwXG4gICAgICA/IGAgU2hvd2luZyB0aGUgJHtzLm1heENvbHVtbnN9IHN0cm9uZ2VzdCBvZiAke3MubWF4Q29sdW1ucyArIHMuaGlkZGVufSwgYCArXG4gICAgICAgICdyYW5rZWQgYnkgdGhlIGxhcmdlc3QgdmFsdWUgYW55IHBpY2tlZCBnZW5lIHJlYWNoZXMuJ1xuICAgICAgOiAnJztcbiAgcmV0dXJuIGBNZWFuIGV4cHJlc3Npb24gb2YgZWFjaCBnZW5lIHdpdGhpbiBlYWNoICR7cy5ncm91cEJ5ID8/ICdncm91cCd9LCBvdmVyICR7c2NvcGV9LiR7c2NhbGVkfSR7Y2FwcGVkfWA7XG59XG4iXX0=
@@ -0,0 +1,158 @@
1
+ import * as Plotly from 'plotly.js-dist-min';
2
+ /** Plotly config: a static-ish analysis chart, not an editable figure. */
3
+ export const CHART_CONFIG = {
4
+ displaylogo: false,
5
+ responsive: true,
6
+ modeBarButtonsToRemove: ['lasso2d', 'select2d', 'autoScale2d'],
7
+ };
8
+ /**
9
+ * Config for the embedding, which unlike the distributions is a plot you SELECT in.
10
+ *
11
+ * The lasso and box-select are kept — drawing round a cluster is how a population gets
12
+ * picked out of a UMAP — and the wheel zooms, because exploring an embedding means zooming
13
+ * into a cluster and reaching for a toolbar button to do it breaks that.
14
+ */
15
+ export const EMBEDDING_CONFIG = {
16
+ displaylogo: false,
17
+ responsive: true,
18
+ scrollZoom: true,
19
+ modeBarButtonsToRemove: ['autoScale2d'],
20
+ };
21
+ /**
22
+ * Plotly I/O for the spatial charts, keyed by the id of the div drawn into: drawing,
23
+ * purging, re-fitting to the container, binding a selection, and reading back the view
24
+ * the user has set up. The only place the charts import Plotly.
25
+ *
26
+ * Remembers whether the last drawn layout fixed its own height, because re-fitting depends
27
+ * on it (see {@link refit}).
28
+ */
29
+ export class PlotlyChartHost {
30
+ constructor() {
31
+ /**
32
+ * The height the drawn layout asked for, or null where it autosizes. The counts and
33
+ * heatmap layouts size their height to their content — one band per bar, per gene row —
34
+ * while the distribution kinds want to fill whatever height they are given.
35
+ */
36
+ this.drawnHeight = null;
37
+ }
38
+ /** Whether the plot on screen fixed its own height. */
39
+ get hasFixedHeight() {
40
+ return this.drawnHeight !== null;
41
+ }
42
+ /**
43
+ * Draw into `div`, remembering whether this layout fixed its own height.
44
+ *
45
+ * The layout builders return `unknown` on purpose — they keep Plotly's layout types out
46
+ * of the pure module — so the height is read back by narrowing rather than declared.
47
+ * `height` is Plotly's own key, not ours.
48
+ */
49
+ async draw(div, traces, layout, config = CHART_CONFIG) {
50
+ const height = layout?.height;
51
+ this.drawnHeight = typeof height === 'number' ? height : null;
52
+ await Plotly.react(div, traces, layout, config);
53
+ }
54
+ /** Purge `div`, freeing its plot (and WebGL context); a div with no plot is fine. */
55
+ purge(div) {
56
+ try {
57
+ Plotly.purge(div);
58
+ }
59
+ catch {
60
+ // Nothing plotted there, or the div is already gone.
61
+ }
62
+ }
63
+ /**
64
+ * Re-fit whatever is plotted in `div` to its container.
65
+ *
66
+ * Plotly does not notice a container resize on its own — its `responsive` option listens
67
+ * for WINDOW resizes only. And `autosize` takes BOTH dimensions from the container, which
68
+ * is right only where the layout did not fix its own height. Measured: autosizing a layout
69
+ * with an explicit height of 500 replaced it with the container's 400. The counts and
70
+ * heatmap layouts size themselves to their row count, so for them the width is set ALONE
71
+ * and the height left to stand.
72
+ */
73
+ refit(div) {
74
+ const el = document.getElementById(div);
75
+ if (!el)
76
+ return;
77
+ const width = Math.round(el.clientWidth);
78
+ // Zero while the section is collapsed or the dialog is closed; relaying out to a zero
79
+ // box makes Plotly compute a layout it does not recover from.
80
+ if (width <= 0)
81
+ return;
82
+ try {
83
+ Plotly.relayout(el, this.drawnHeight === null ? { autosize: true } : { width });
84
+ }
85
+ catch {
86
+ // Nothing plotted yet.
87
+ }
88
+ }
89
+ /**
90
+ * Turn a lasso or box selection in `div` into observation indices.
91
+ *
92
+ * Bound after each draw, and the previous listeners removed first: `Plotly.react`
93
+ * preserves handlers, so re-binding without removing would fire the selection once per
94
+ * redraw the plot had ever had.
95
+ */
96
+ bindSelection(div, handlers) {
97
+ const el = document.getElementById(div);
98
+ if (!el?.on)
99
+ return;
100
+ el.removeAllListeners?.('plotly_selected');
101
+ el.removeAllListeners?.('plotly_deselect');
102
+ el.on('plotly_selected', (ev) => {
103
+ // A lasso that selects nothing arrives as an event with no points; it is a clear,
104
+ // which is what dragging an empty patch looks like it should do.
105
+ const points = ev?.points ?? [];
106
+ const indices = [];
107
+ for (const p of points) {
108
+ // The observation index rides on `customdata` — see `buildEmbeddingTraces`. A
109
+ // point's index within its trace is not the observation once the points are split
110
+ // by category, so this is the only correct source.
111
+ const id = p.customdata;
112
+ if (typeof id === 'number')
113
+ indices.push(id);
114
+ }
115
+ if (indices.length === 0)
116
+ handlers.deselected();
117
+ else
118
+ handlers.selected(indices);
119
+ });
120
+ el.on('plotly_deselect', () => handlers.deselected());
121
+ }
122
+ /**
123
+ * Drop the selection handlers from a div another chart is about to use.
124
+ *
125
+ * `plotly_deselect` fires on a plain click in ANY Plotly chart, so handlers left bound
126
+ * for an embedding would make the first click on a bar clear the map's selection.
127
+ */
128
+ unbindSelection(div) {
129
+ const el = document.getElementById(div);
130
+ if (!el?.removeAllListeners)
131
+ return;
132
+ el.removeAllListeners('plotly_selected');
133
+ el.removeAllListeners('plotly_deselect');
134
+ }
135
+ /**
136
+ * The view the user has set up on the live plot in `div`, to carry across a redraw.
137
+ *
138
+ * `Plotly.react` resets a 3D scene camera and any zoomed 2D range unless the layout
139
+ * carries them, so selecting a category or recolouring would throw away an orientation
140
+ * that took work to find. Null where nothing is drawn yet, or a 2D plot is not zoomed:
141
+ * passing an autoranged range back would freeze the axes and stop the plot re-fitting
142
+ * when the data changes.
143
+ */
144
+ liveView(div) {
145
+ const el = document.getElementById(div);
146
+ const full = el?._fullLayout;
147
+ if (!full)
148
+ return null;
149
+ if (full.scene?.camera)
150
+ return { camera: full.scene.camera };
151
+ const zoomed = full.xaxis?.autorange === false && full.yaxis?.autorange === false;
152
+ if (zoomed && full.xaxis?.range && full.yaxis?.range) {
153
+ return { ranges: { x: full.xaxis.range, y: full.yaxis.range } };
154
+ }
155
+ return null;
156
+ }
157
+ }
158
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicGxvdGx5LWNoYXJ0LWhvc3QuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi9zcmMvbGliL3NwYXRpYWwtY29udHJvbHMvc3BhdGlhbC1jaGFydHMvcGxvdGx5LWNoYXJ0LWhvc3QudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxLQUFLLE1BQU0sTUFBTSxvQkFBb0IsQ0FBQztBQUU3QywwRUFBMEU7QUFDMUUsTUFBTSxDQUFDLE1BQU0sWUFBWSxHQUFHO0lBQzFCLFdBQVcsRUFBRSxLQUFLO0lBQ2xCLFVBQVUsRUFBRSxJQUFJO0lBQ2hCLHNCQUFzQixFQUFFLENBQUMsU0FBUyxFQUFFLFVBQVUsRUFBRSxhQUFhLENBQUM7Q0FDL0QsQ0FBQztBQUVGOzs7Ozs7R0FNRztBQUNILE1BQU0sQ0FBQyxNQUFNLGdCQUFnQixHQUFHO0lBQzlCLFdBQVcsRUFBRSxLQUFLO0lBQ2xCLFVBQVUsRUFBRSxJQUFJO0lBQ2hCLFVBQVUsRUFBRSxJQUFJO0lBQ2hCLHNCQUFzQixFQUFFLENBQUMsYUFBYSxDQUFDO0NBQ3hDLENBQUM7QUFnQkY7Ozs7Ozs7R0FPRztBQUNILE1BQU0sT0FBTyxlQUFlO0lBQTVCO1FBQ0U7Ozs7V0FJRztRQUNLLGdCQUFXLEdBQWtCLElBQUksQ0FBQztJQTRINUMsQ0FBQztJQTFIQyx1REFBdUQ7SUFDdkQsSUFBSSxjQUFjO1FBQ2hCLE9BQU8sSUFBSSxDQUFDLFdBQVcsS0FBSyxJQUFJLENBQUM7SUFDbkMsQ0FBQztJQUVEOzs7Ozs7T0FNRztJQUNILEtBQUssQ0FBQyxJQUFJLENBQUMsR0FBVyxFQUFFLE1BQWUsRUFBRSxNQUFlLEVBQUUsU0FBa0IsWUFBWTtRQUN0RixNQUFNLE1BQU0sR0FBSSxNQUFzQyxFQUFFLE1BQU0sQ0FBQztRQUMvRCxJQUFJLENBQUMsV0FBVyxHQUFHLE9BQU8sTUFBTSxLQUFLLFFBQVEsQ0FBQyxDQUFDLENBQUMsTUFBTSxDQUFDLENBQUMsQ0FBQyxJQUFJLENB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SUFDSCxRQUFRLENBQUMsR0FBVztRQUNsQixNQUFNLEVBQUUsR0FBRyxRQUFRLENBQUMsY0FBYyxDQUFDLEdBQUcsQ0FBQyxDQUFDO1FBQ3hDLE1BQU0sSUFBSSxHQUNSLEVBT0QsRUFBRSxXQUFXLENBQUM7UUFDZixJQUFJLENBQUMsSUFBSTtZQUFFLE9BQU8sSUFBSSxDQUFDO1FBQ3ZCLElBQUksSUFBSSxDQUFDLEtBQUssRUFBRSxNQUFNO1lBQUUsT0FBTyxFQUFFLE1BQU0sRUFBRSxJQUFJLENBQUMsS0FBSyxDQUFDLE1BQU0sRUFBRSxDQUFDO1FBQzdELE1BQU0sTUFBTSxHQUFHLElBQUksQ0FBQyxLQUFLLEVBQUUsU0FBUyxLQUFLLEtBQUssSUFBSSxJQUFJLENBQUMsS0FBSyxFQUFFLFNBQVMsS0FBSyxLQUFLLENBQUM7UUFDbEYsSUFBSSxNQUFNLElBQUksSUFBSSxDQUFDLEtBQUssRUFBRSxLQUFLLElBQUksSUFBSSxDQUFDLEtBQUssRUFBRSxLQUFLLEVBQUUsQ0FBQztZQUNyRCxPQUFPLEVBQUUsTUFBTSxFQUFFLEVBQUUsQ0FBQyxFQUFFLElBQUksQ0FBQyxLQUFLLENBQUMsS0FBSyxFQUFFLENBQUMsRUFBRSxJQUFJLENBQUMsS0FBSyxDQUFDLEtBQUssRUFBRSxFQUFFLENBQUM7UUFDbEUsQ0FBQztRQUNELE9BQU8sSUFBSSxDQUFDO0lBQ2QsQ0FBQztDQUNGIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0ICogYXMgUGxvdGx5IGZyb20gJ3Bsb3RseS5qcy1kaXN0LW1pbic7XG5cbi8qKiBQbG90bHkgY29uZmlnOiBhIHN0YXRpYy1pc2ggYW5hbHlzaXMgY2hhcnQsIG5vdCBhbiBlZGl0YWJsZSBmaWd1cmUuICovXG5leHBvcnQgY29uc3QgQ0hBUlRfQ09ORklHID0ge1xuICBkaXNwbGF5bG9nbzogZmFsc2UsXG4gIHJlc3BvbnNpdmU6IHRydWUsXG4gIG1vZGVCYXJCdXR0b25zVG9SZW1vdmU6IFsnbGFzc28yZCcsICdzZWxlY3QyZCcsICdhdXRvU2NhbGUyZCddLFxufTtcblxuLyoqXG4gKiBDb25maWcgZm9yIHRoZSBlbWJlZGRpbmcsIHdoaWNoIHVubGlrZSB0aGUgZGlzdHJpYnV0aW9ucyBpcyBhIHBsb3QgeW91IFNFTEVDVCBpbi5cbiAqXG4gKiBUaGUgbGFzc28gYW5kIGJveC1zZWxlY3QgYXJlIGtlcHQg4oCUIGRyYXdpbmcgcm91bmQgYSBjbHVzdGVyIGlzIGhvdyBhIHBvcHVsYXRpb24gZ2V0c1xuICogcGlja2VkIG91dCBvZiBhIFVNQVAg4oCUIGFuZCB0aGUgd2hlZWwgem9vbXMsIGJlY2F1c2UgZXhwbG9yaW5nIGFuIGVtYmVkZGluZyBtZWFucyB6b29taW5nXG4gKiBpbnRvIGEgY2x1c3RlciBhbmQgcmVhY2hpbmcgZm9yIGEgdG9vbGJhciBidXR0b24gdG8gZG8gaXQgYnJlYWtzIHRoYXQuXG4gKi9cbmV4cG9ydCBjb25zdCBFTUJFRERJTkdfQ09ORklHID0ge1xuICBkaXNwbGF5bG9nbzogZmFsc2UsXG4gIHJlc3BvbnNpdmU6IHRydWUsXG4gIHNjcm9sbFpvb206IHRydWUsXG4gIG1vZGVCYXJCdXR0b25zVG9SZW1vdmU6IFsnYXV0b1NjYWxlMmQnXSxcbn07XG5cbi8qKiBXaGF0IGEgbGFzc28gb3IgYm94IHNlbGVjdGlvbiBpbiBhIHBsb3QgcmVwb3J0cy4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgUGxvdFNlbGVjdGlvbkhhbmRsZXJzIHtcbiAgLyoqIFRoZSBvYnNlcnZhdGlvbiBpbmRpY2VzIHNlbGVjdGVkIChlbXB0eSBmb3IgYSBzZWxlY3Rpb24gdGhhdCBjYXVnaHQgbm90aGluZykuICovXG4gIHNlbGVjdGVkKGluZGljZXM6IG51bWJlcltdKTogdm9pZDtcbiAgLyoqIFRoZSBtb2RlYmFyJ3MgZGVzZWxlY3QsIG9yIGEgcGxhaW4gY2xpY2sgb24gZW1wdHkgc3BhY2UuICovXG4gIGRlc2VsZWN0ZWQoKTogdm9pZDtcbn1cblxuLyoqIFRoZSB2aWV3IHRoZSB1c2VyIGhhcyBzZXQgdXAgb24gYSBsaXZlIHBsb3Q6IGEgM0QgY2FtZXJhLCBvciBhIHpvb21lZCAyRCByYW5nZS4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgTGl2ZVBsb3RWaWV3IHtcbiAgY2FtZXJhPzogdW5rbm93bjtcbiAgcmFuZ2VzPzogeyB4OiB1bmtub3duOyB5OiB1bmtub3duIH07XG59XG5cbi8qKlxuICogUGxvdGx5IEkvTyBmb3IgdGhlIHNwYXRpYWwgY2hhcnRzLCBrZXllZCBieSB0aGUgaWQgb2YgdGhlIGRpdiBkcmF3biBpbnRvOiBkcmF3aW5nLFxuICogcHVyZ2luZywgcmUtZml0dGluZyB0byB0aGUgY29udGFpbmVyLCBiaW5kaW5nIGEgc2VsZWN0aW9uLCBhbmQgcmVhZGluZyBiYWNrIHRoZSB2aWV3XG4gKiB0aGUgdXNlciBoYXMgc2V0IHVwLiBUaGUgb25seSBwbGFjZSB0aGUgY2hhcnRzIGltcG9ydCBQbG90bHkuXG4gKlxuICogUmVtZW1iZXJzIHdoZXRoZXIgdGhlIGxhc3QgZHJhd24gbGF5b3V0IGZpeGVkIGl0cyBvd24gaGVpZ2h0LCBiZWNhdXNlIHJlLWZpdHRpbmcgZGVwZW5kc1xuICogb24gaXQgKHNlZSB7QGxpbmsgcmVmaXR9KS5cbiAqL1xuZXhwb3J0IGNsYXNzIFBsb3RseUNoYXJ0SG9zdCB7XG4gIC8qKlxuICAgKiBUaGUgaGVpZ2h0IHRoZSBkcmF3biBsYXlvdXQgYXNrZWQgZm9yLCBvciBudWxsIHdoZXJlIGl0IGF1dG9zaXplcy4gVGhlIGNvdW50cyBhbmRcbiAgICogaGVhdG1hcCBsYXlvdXRzIHNpemUgdGhlaXIgaGVpZ2h0IHRvIHRoZWlyIGNvbnRlbnQg4oCUIG9uZSBiYW5kIHBlciBiYXIsIHBlciBnZW5lIHJvdyDigJRcbiAgICogd2hpbGUgdGhlIGRpc3RyaWJ1dGlvbiBraW5kcyB3YW50IHRvIGZpbGwgd2hhdGV2ZXIgaGVpZ2h0IHRoZXkgYXJlIGdpdmVuLlxuICAgKi9cbiAgcHJpdmF0ZSBkcmF3bkhlaWdodDogbnVtYmVyIHwgbnVsbCA9IG51bGw7XG5cbiAgLyoqIFdoZXRoZXIgdGhlIHBsb3Qgb24gc2NyZWVuIGZpeGVkIGl0cyBvd24gaGVpZ2h0LiAqL1xuICBnZXQgaGFzRml4ZWRIZWlnaHQoKTogYm9vbGVhbiB7XG4gICAgcmV0dXJuIHRoaXMuZHJhd25IZWlnaHQgIT09IG51bGw7XG4gIH1cblxuICAvKipcbiAgICogRHJhdyBpbnRvIGBkaXZgLCByZW1lbWJlcmluZyB3aGV0aGVyIHRoaXMgbGF5b3V0IGZpeGVkIGl0cyBvd24gaGVpZ2h0LlxuICAgKlxuICAgKiBUaGUgbGF5b3V0IGJ1aWxkZXJzIHJldHVybiBgdW5rbm93bmAgb24gcHVycG9zZSDigJQgdGhleSBrZWVwIFBsb3RseSdzIGxheW91dCB0eXBlcyBvdXRcbiAgICogb2YgdGhlIHB1cmUgbW9kdWxlIOKAlCBzbyB0aGUgaGVpZ2h0IGlzIHJlYWQgYmFjayBieSBuYXJyb3dpbmcgcmF0aGVyIHRoYW4gZGVjbGFyZWQuXG4gICAqIGBoZWlnaHRgIGlzIFBsb3RseSdzIG93biBrZXksIG5vdCBvdXJzLlxuICAgKi9cbiAgYXN5bmMgZHJhdyhkaXY6IHN0cmluZywgdHJhY2VzOiB1bmtub3duLCBsYXlvdXQ6IHVua25vd24sIGNvbmZpZzogdW5rbm93biA9IENIQVJUX0NPTkZJRyk6IFByb21pc2U8dm9pZD4ge1xuICAgIGNvbnN0IGhlaWdodCA9IChsYXlvdXQgYXMgeyBoZWlnaHQ/OiB1bmtub3duIH0gfCBudWxsKT8uaGVpZ2h0O1xuICAgIHRoaXMuZHJhd25IZWlnaHQgPSB0eXBlb2YgaGVpZ2h0ID09PSAnbnVtYmVyJyA/IGhlaWdodCA6IG51bGw7XG4gICAgYXdhaXQgUGxvdGx5LnJlYWN0KGRpdiwgdHJhY2VzIGFzIG5ldmVyLCBsYXlvdXQgYXMgbmV2ZXIsIGNvbmZpZyBhcyBuZXZlcik7XG4gIH1cblxuICAvKiogUHVyZ2UgYGRpdmAsIGZyZWVpbmcgaXRzIHBsb3QgKGFuZCBXZWJHTCBjb250ZXh0KTsgYSBkaXYgd2l0aCBubyBwbG90IGlzIGZpbmUuICovXG4gIHB1cmdlKGRpdjogc3RyaW5nKTogdm9pZCB7XG4gICAgdHJ5IHtcbiAgICAgIFBsb3RseS5wdXJnZShkaXYpO1xuICAgIH0gY2F0Y2gge1xuICAgICAgLy8gTm90aGluZyBwbG90dGVkIHRoZXJlLCBvciB0aGUgZGl2IGlzIGFscmVhZHkgZ29uZS5cbiAgICB9XG4gIH1cblxuICAvKipcbiAgICogUmUtZml0IHdoYXRldmVyIGlzIHBsb3R0ZWQgaW4gYGRpdmAgdG8gaXRzIGNvbnRhaW5lci5cbiAgICpcbiAgICogUGxvdGx5IGRvZXMgbm90IG5vdGljZSBhIGNvbnRhaW5lciByZXNpemUgb24gaXRzIG93biDigJQgaXRzIGByZXNwb25zaXZlYCBvcHRpb24gbGlzdGVuc1xuICAgKiBmb3IgV0lORE9XIHJlc2l6ZXMgb25seS4gQW5kIGBhdXRvc2l6ZWAgdGFrZXMgQk9USCBkaW1lbnNpb25zIGZyb20gdGhlIGNvbnRhaW5lciwgd2hpY2hcbiAgICogaXMgcmlnaHQgb25seSB3aGVyZSB0aGUgbGF5b3V0IGRpZCBub3QgZml4IGl0cyBvd24gaGVpZ2h0LiBNZWFzdXJlZDogYXV0b3NpemluZyBhIGxheW91dFxuICAgKiB3aXRoIGFuIGV4cGxpY2l0IGhlaWdodCBvZiA1MDAgcmVwbGFjZWQgaXQgd2l0aCB0aGUgY29udGFpbmVyJ3MgNDAwLiBUaGUgY291bnRzIGFuZFxuICAgKiBoZWF0bWFwIGxheW91dHMgc2l6ZSB0aGVtc2VsdmVzIHRvIHRoZWlyIHJvdyBjb3VudCwgc28gZm9yIHRoZW0gdGhlIHdpZHRoIGlzIHNldCBBTE9ORVxuICAgKiBhbmQgdGhlIGhlaWdodCBsZWZ0IHRvIHN0YW5kLlxuICAgKi9cbiAgcmVmaXQoZGl2OiBzdHJpbmcpOiB2b2lkIHtcbiAgICBjb25zdCBlbCA9IGRvY3VtZW50LmdldEVsZW1lbnRCeUlkKGRpdik7XG4gICAgaWYgKCFlbCkgcmV0dXJuO1xuICAgIGNvbnN0IHdpZHRoID0gTWF0aC5yb3VuZChlbC5jbGllbnRXaWR0aCk7XG4gICAgLy8gWmVybyB3aGlsZSB0aGUgc2VjdGlvbiBpcyBjb2xsYXBzZWQgb3IgdGhlIGRpYWxvZyBpcyBjbG9zZWQ7IHJlbGF5aW5nIG91dCB0byBhIHplcm9cbiAgICAvLyBib3ggbWFrZXMgUGxvdGx5IGNvbXB1dGUgYSBsYXlvdXQgaXQgZG9lcyBub3QgcmVjb3ZlciBmcm9tLlxuICAgIGlmICh3aWR0aCA8PSAwKSByZXR1cm47XG4gICAgdHJ5IHtcbiAgICAgIFBsb3RseS5yZWxheW91dChlbCwgdGhpcy5kcmF3bkhlaWdodCA9PT0gbnVsbCA/IHsgYXV0b3NpemU6IHRydWUgfSA6IHsgd2lkdGggfSk7XG4gICAgfSBjYXRjaCB7XG4gICAgICAvLyBOb3RoaW5nIHBsb3R0ZWQgeWV0LlxuICAgIH1cbiAgfVxuXG4gIC8qKlxuICAgKiBUdXJuIGEgbGFzc28gb3IgYm94IHNlbGVjdGlvbiBpbiBgZGl2YCBpbnRvIG9ic2VydmF0aW9uIGluZGljZXMuXG4gICAqXG4gICAqIEJvdW5kIGFmdGVyIGVhY2ggZHJhdywgYW5kIHRoZSBwcmV2aW91cyBsaXN0ZW5lcnMgcmVtb3ZlZCBmaXJzdDogYFBsb3RseS5yZWFjdGBcbiAgICogcHJlc2VydmVzIGhhbmRsZXJzLCBzbyByZS1iaW5kaW5nIHdpdGhvdXQgcmVtb3Zpbmcgd291bGQgZmlyZSB0aGUgc2VsZWN0aW9uIG9uY2UgcGVyXG4gICAqIHJlZHJhdyB0aGUgcGxvdCBoYWQgZXZlciBoYWQuXG4gICAqL1xuICBiaW5kU2VsZWN0aW9uKGRpdjogc3RyaW5nLCBoYW5kbGVyczogUGxvdFNlbGVjdGlvbkhhbmRsZXJzKTogdm9pZCB7XG4gICAgY29uc3QgZWwgPSBkb2N1bWVudC5nZXRFbGVtZW50QnlJZChkaXYpIGFzIFBsb3RseS5QbG90bHlIVE1MRWxlbWVudCB8IG51bGw7XG4gICAgaWYgKCFlbD8ub24pIHJldHVybjtcbiAgICBlbC5yZW1vdmVBbGxMaXN0ZW5lcnM/LigncGxvdGx5X3NlbGVjdGVkJyk7XG4gICAgZWwucmVtb3ZlQWxsTGlzdGVuZXJzPy4oJ3Bsb3RseV9kZXNlbGVjdCcpO1xuICAgIGVsLm9uKCdwbG90bHlfc2VsZWN0ZWQnLCAoZXYpID0+IHtcbiAgICAgIC8vIEEgbGFzc28gdGhhdCBzZWxlY3RzIG5vdGhpbmcgYXJyaXZlcyBhcyBhbiBldmVudCB3aXRoIG5vIHBvaW50czsgaXQgaXMgYSBjbGVhcixcbiAgICAgIC8vIHdoaWNoIGlzIHdoYXQgZHJhZ2dpbmcgYW4gZW1wdHkgcGF0Y2ggbG9va3MgbGlrZSBpdCBzaG91bGQgZG8uXG4gICAgICBjb25zdCBwb2ludHMgPSAoZXYgYXMgeyBwb2ludHM/OiByZWFkb25seSB1bmtub3duW10gfSB8IHVuZGVmaW5lZCk/LnBvaW50cyA/PyBbXTtcbiAgICAgIGNvbnN0IGluZGljZXM6IG51bWJlcltdID0gW107XG4gICAgICBmb3IgKGNvbnN0IHAgb2YgcG9pbnRzKSB7XG4gICAgICAgIC8vIFRoZSBvYnNlcnZhdGlvbiBpbmRleCByaWRlcyBvbiBgY3VzdG9tZGF0YWAg4oCUIHNlZSBgYnVpbGRFbWJlZGRpbmdUcmFjZXNgLiBBXG4gICAgICAgIC8vIHBvaW50J3MgaW5kZXggd2l0aGluIGl0cyB0cmFjZSBpcyBub3QgdGhlIG9ic2VydmF0aW9uIG9uY2UgdGhlIHBvaW50cyBhcmUgc3BsaXRcbiAgICAgICAgLy8gYnkgY2F0ZWdvcnksIHNvIHRoaXMgaXMgdGhlIG9ubHkgY29ycmVjdCBzb3VyY2UuXG4gICAgICAgIGNvbnN0IGlkID0gKHAgYXMgeyBjdXN0b21kYXRhPzogdW5rbm93biB9KS5jdXN0b21kYXRhO1xuICAgICAgICBpZiAodHlwZW9mIGlkID09PSAnbnVtYmVyJykgaW5kaWNlcy5wdXNoKGlkKTtcbiAgICAgIH1cbiAgICAgIGlmIChpbmRpY2VzLmxlbmd0aCA9PT0gMCkgaGFuZGxlcnMuZGVzZWxlY3RlZCgpO1xuICAgICAgZWxzZSBoYW5kbGVycy5zZWxlY3RlZChpbmRpY2VzKTtcbiAgICB9KTtcbiAgICBlbC5vbigncGxvdGx5X2Rlc2VsZWN0JywgKCkgPT4gaGFuZGxlcnMuZGVzZWxlY3RlZCgpKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBEcm9wIHRoZSBzZWxlY3Rpb24gaGFuZGxlcnMgZnJvbSBhIGRpdiBhbm90aGVyIGNoYXJ0IGlzIGFib3V0IHRvIHVzZS5cbiAgICpcbiAgICogYHBsb3RseV9kZXNlbGVjdGAgZmlyZXMgb24gYSBwbGFpbiBjbGljayBpbiBBTlkgUGxvdGx5IGNoYXJ0LCBzbyBoYW5kbGVycyBsZWZ0IGJvdW5kXG4gICAqIGZvciBhbiBlbWJlZGRpbmcgd291bGQgbWFrZSB0aGUgZmlyc3QgY2xpY2sgb24gYSBiYXIgY2xlYXIgdGhlIG1hcCdzIHNlbGVjdGlvbi5cbiAgICovXG4gIHVuYmluZFNlbGVjdGlvbihkaXY6IHN0cmluZyk6IHZvaWQge1xuICAgIGNvbnN0IGVsID0gZG9jdW1lbnQuZ2V0RWxlbWVudEJ5SWQoZGl2KSBhcyBQbG90bHkuUGxvdGx5SFRNTEVsZW1lbnQgfCBudWxsO1xuICAgIGlmICghZWw/LnJlbW92ZUFsbExpc3RlbmVycykgcmV0dXJuO1xuICAgIGVsLnJlbW92ZUFsbExpc3RlbmVycygncGxvdGx5X3NlbGVjdGVkJyk7XG4gICAgZWwucmVtb3ZlQWxsTGlzdGVuZXJzKCdwbG90bHlfZGVzZWxlY3QnKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBUaGUgdmlldyB0aGUgdXNlciBoYXMgc2V0IHVwIG9uIHRoZSBsaXZlIHBsb3QgaW4gYGRpdmAsIHRvIGNhcnJ5IGFjcm9zcyBhIHJlZHJhdy5cbiAgICpcbiAgICogYFBsb3RseS5yZWFjdGAgcmVzZXRzIGEgM0Qgc2NlbmUgY2FtZXJhIGFuZCBhbnkgem9vbWVkIDJEIHJhbmdlIHVubGVzcyB0aGUgbGF5b3V0XG4gICAqIGNhcnJpZXMgdGhlbSwgc28gc2VsZWN0aW5nIGEgY2F0ZWdvcnkgb3IgcmVjb2xvdXJpbmcgd291bGQgdGhyb3cgYXdheSBhbiBvcmllbnRhdGlvblxuICAgKiB0aGF0IHRvb2sgd29yayB0byBmaW5kLiBOdWxsIHdoZXJlIG5vdGhpbmcgaXMgZHJhd24geWV0LCBvciBhIDJEIHBsb3QgaXMgbm90IHpvb21lZDpcbiAgICogcGFzc2luZyBhbiBhdXRvcmFuZ2VkIHJhbmdlIGJhY2sgd291bGQgZnJlZXplIHRoZSBheGVzIGFuZCBzdG9wIHRoZSBwbG90IHJlLWZpdHRpbmdcbiAgICogd2hlbiB0aGUgZGF0YSBjaGFuZ2VzLlxuICAgKi9cbiAgbGl2ZVZpZXcoZGl2OiBzdHJpbmcpOiBMaXZlUGxvdFZpZXcgfCBudWxsIHtcbiAgICBjb25zdCBlbCA9IGRvY3VtZW50LmdldEVsZW1lbnRCeUlkKGRpdik7XG4gICAgY29uc3QgZnVsbCA9IChcbiAgICAgIGVsIGFzIHtcbiAgICAgICAgX2Z1bGxMYXlvdXQ/OiB7XG4gICAgICAgICAgc2NlbmU/OiB7IGNhbWVyYT86IHVua25vd24gfTtcbiAgICAgICAgICB4YXhpcz86IHsgcmFuZ2U/OiB1bmtub3duOyBhdXRvcmFuZ2U/OiBib29sZWFuIH07XG4gICAgICAgICAgeWF4aXM/OiB7IHJhbmdlPzogdW5rbm93bjsgYXV0b3JhbmdlPzogYm9vbGVhbiB9O1xuICAgICAgICB9O1xuICAgICAgfSB8IG51bGxcbiAgICApPy5fZnVsbExheW91dDtcbiAgICBpZiAoIWZ1bGwpIHJldHVybiBudWxsO1xuICAgIGlmIChmdWxsLnNjZW5lPy5jYW1lcmEpIHJldHVybiB7IGNhbWVyYTogZnVsbC5zY2VuZS5jYW1lcmEgfTtcbiAgICBjb25zdCB6b29tZWQgPSBmdWxsLnhheGlzPy5hdXRvcmFuZ2UgPT09IGZhbHNlICYmIGZ1bGwueWF4aXM/LmF1dG9yYW5nZSA9PT0gZmFsc2U7XG4gICAgaWYgKHpvb21lZCAmJiBmdWxsLnhheGlzPy5yYW5nZSAmJiBmdWxsLnlheGlzPy5yYW5nZSkge1xuICAgICAgcmV0dXJuIHsgcmFuZ2VzOiB7IHg6IGZ1bGwueGF4aXMucmFuZ2UsIHk6IGZ1bGwueWF4aXMucmFuZ2UgfSB9O1xuICAgIH1cbiAgICByZXR1cm4gbnVsbDtcbiAgfVxufVxuIl19
@@ -0,0 +1,47 @@
1
+ import { ChangeDetectionStrategy, Component, EventEmitter, Input, Output } from '@angular/core';
2
+ import { DialogModule } from 'primeng/dialog';
3
+ import * as i0 from "@angular/core";
4
+ import * as i1 from "primeng/dialog";
5
+ /**
6
+ * The detached chart window: a non-modal, draggable, resizable dialog beside the
7
+ * spatial-omics dialog, holding the plot div (by {@link divId}) and whatever is projected
8
+ * under it (the chart's hints).
9
+ *
10
+ * Presentational: the charts panel draws into the div, and decides what closing,
11
+ * showing and resizing the window mean.
12
+ */
13
+ export class SpatialChartWindowComponent {
14
+ constructor() {
15
+ /** The window's header — what it is showing. */
16
+ this.title = '';
17
+ /** The id of the div the chart is drawn into. */
18
+ this.divId = '';
19
+ /** Whether the drawn layout fixed its own height (and so the window scrolls). */
20
+ this.fixedHeight = false;
21
+ /** The window was closed: put the chart back. */
22
+ this.closed = new EventEmitter();
23
+ /** The window is up and its div exists: the chart can be drawn into it. */
24
+ this.shown = new EventEmitter();
25
+ /** The window was resized: re-fit the chart. */
26
+ this.resizeEnd = new EventEmitter();
27
+ }
28
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.9", ngImport: i0, type: SpatialChartWindowComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
29
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "17.3.9", type: SpatialChartWindowComponent, isStandalone: true, selector: "spatial-chart-window", inputs: { title: "title", divId: "divId", fixedHeight: "fixedHeight" }, outputs: { closed: "closed", shown: "shown", resizeEnd: "resizeEnd" }, ngImport: i0, template: "<!-- The detached chart. Its own non-modal, draggable, resizable window so it can be put\n beside the spatial-omics dialog. `appendTo=\"body\"` keeps it out of the dialog's\n stacking context, or it would be clipped by the panel it is meant to sit next to. -->\n<p-dialog\n [header]=\"title\"\n [visible]=\"true\"\n (visibleChange)=\"closed.emit()\"\n [modal]=\"false\"\n [resizable]=\"true\"\n [draggable]=\"true\"\n position=\"right\"\n appendTo=\"body\"\n (onShow)=\"shown.emit()\"\n (onResizeEnd)=\"resizeEnd.emit()\"\n [style]=\"{ width: '34rem', height: '30rem' }\"\n [contentStyle]=\"{\n display: 'flex',\n flexDirection: 'column',\n gap: '0.25rem',\n padding: '0.4rem 0.6rem 0.5rem',\n flex: '1 1 auto',\n minHeight: '0',\n overflow: 'auto',\n }\"\n styleClass=\"spatial-detached-dialog\"\n>\n <div [id]=\"divId\" class=\"sx-detached-plot\" [class.sx-plot-fixed]=\"fixedHeight\"></div>\n <ng-content></ng-content>\n</p-dialog>\n", styles: [".sx-detached-plot{flex:1;width:100%;min-height:0;overflow:hidden}.sx-detached-plot.sx-plot-fixed{flex:0 0 auto;min-height:auto;overflow:visible}\n"], dependencies: [{ kind: "ngmodule", type: DialogModule }, { kind: "component", type: i1.Dialog, selector: "p-dialog", inputs: ["header", "draggable", "resizable", "positionLeft", "positionTop", "contentStyle", "contentStyleClass", "modal", "closeOnEscape", "dismissableMask", "rtl", "closable", "responsive", "appendTo", "breakpoints", "styleClass", "maskStyleClass", "maskStyle", "showHeader", "breakpoint", "blockScroll", "autoZIndex", "baseZIndex", "minX", "minY", "focusOnShow", "maximizable", "keepInViewport", "focusTrap", "transitionOptions", "closeIcon", "closeAriaLabel", "closeTabindex", "minimizeIcon", "maximizeIcon", "visible", "style", "position"], outputs: ["onShow", "onHide", "visibleChange", "onResizeInit", "onResizeEnd", "onDragEnd", "onMaximize"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
30
+ }
31
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.9", ngImport: i0, type: SpatialChartWindowComponent, decorators: [{
32
+ type: Component,
33
+ args: [{ selector: 'spatial-chart-window', standalone: true, imports: [DialogModule], changeDetection: ChangeDetectionStrategy.OnPush, template: "<!-- The detached chart. Its own non-modal, draggable, resizable window so it can be put\n beside the spatial-omics dialog. `appendTo=\"body\"` keeps it out of the dialog's\n stacking context, or it would be clipped by the panel it is meant to sit next to. -->\n<p-dialog\n [header]=\"title\"\n [visible]=\"true\"\n (visibleChange)=\"closed.emit()\"\n [modal]=\"false\"\n [resizable]=\"true\"\n [draggable]=\"true\"\n position=\"right\"\n appendTo=\"body\"\n (onShow)=\"shown.emit()\"\n (onResizeEnd)=\"resizeEnd.emit()\"\n [style]=\"{ width: '34rem', height: '30rem' }\"\n [contentStyle]=\"{\n display: 'flex',\n flexDirection: 'column',\n gap: '0.25rem',\n padding: '0.4rem 0.6rem 0.5rem',\n flex: '1 1 auto',\n minHeight: '0',\n overflow: 'auto',\n }\"\n styleClass=\"spatial-detached-dialog\"\n>\n <div [id]=\"divId\" class=\"sx-detached-plot\" [class.sx-plot-fixed]=\"fixedHeight\"></div>\n <ng-content></ng-content>\n</p-dialog>\n", styles: [".sx-detached-plot{flex:1;width:100%;min-height:0;overflow:hidden}.sx-detached-plot.sx-plot-fixed{flex:0 0 auto;min-height:auto;overflow:visible}\n"] }]
34
+ }], propDecorators: { title: [{
35
+ type: Input
36
+ }], divId: [{
37
+ type: Input
38
+ }], fixedHeight: [{
39
+ type: Input
40
+ }], closed: [{
41
+ type: Output
42
+ }], shown: [{
43
+ type: Output
44
+ }], resizeEnd: [{
45
+ type: Output
46
+ }] } });
47
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic3BhdGlhbC1jaGFydC13aW5kb3cuY29tcG9uZW50LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vLi4vLi4vc3JjL2xpYi9zcGF0aWFsLWNvbnRyb2xzL3NwYXRpYWwtY2hhcnRzL3NwYXRpYWwtY2hhcnQtd2luZG93L3NwYXRpYWwtY2hhcnQtd2luZG93LmNvbXBvbmVudC50cyIsIi4uLy4uLy4uLy4uLy4uLy4uL3NyYy9saWIvc3BhdGlhbC1jb250cm9scy9zcGF0aWFsLWNoYXJ0cy9zcGF0aWFsLWNoYXJ0LXdpbmRvdy9zcGF0aWFsLWNoYXJ0LXdpbmRvdy5jb21wb25lbnQuaHRtbCJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQUUsdUJBQXVCLEVBQUUsU0FBUyxFQUFFLFlBQVksRUFBRSxLQUFLLEVBQUUsTUFBTSxFQUFFLE1BQU0sZUFBZSxDQUFDO0FBQ2hHLE9BQU8sRUFBRSxZQUFZLEVBQUUsTUFBTSxnQkFBZ0IsQ0FBQzs7O0FBRTlDOzs7Ozs7O0dBT0c7QUFTSCxNQUFNLE9BQU8sMkJBQTJCO0lBUnhDO1FBU0UsZ0RBQWdEO1FBQ3ZDLFVBQUssR0FBRyxFQUFFLENBQUM7UUFDcEIsaURBQWlEO1FBQ3hDLFVBQUssR0FBRyxFQUFFLENBQUM7UUFDcEIsaUZBQWlGO1FBQ3hFLGdCQUFXLEdBQUcsS0FBSyxDQUFDO1FBQzdCLGlEQUFpRDtRQUM5QixXQUFNLEdBQUcsSUFBSSxZQUFZLEVBQVEsQ0FBQztRQUNyRCwyRUFBMkU7UUFDeEQsVUFBSyxHQUFHLElBQUksWUFBWSxFQUFRLENBQUM7UUFDcEQsZ0RBQWdEO1FBQzdCLGNBQVMsR0FBRyxJQUFJLFlBQVksRUFBUSxDQUFDO0tBQ3pEOzhHQWJZLDJCQUEyQjtrR0FBM0IsMkJBQTJCLCtOQ25CeEMsdTlCQTZCQSwyTURmWSxZQUFZOzsyRkFLWCwyQkFBMkI7a0JBUnZDLFNBQVM7K0JBQ0Usc0JBQXNCLGNBQ3BCLElBQUksV0FDUCxDQUFDLFlBQVksQ0FBQyxtQkFHTix1QkFBdUIsQ0FBQyxNQUFNOzhCQUl0QyxLQUFLO3NCQUFiLEtBQUs7Z0JBRUcsS0FBSztzQkFBYixLQUFLO2dCQUVHLFdBQVc7c0JBQW5CLEtBQUs7Z0JBRWEsTUFBTTtzQkFBeEIsTUFBTTtnQkFFWSxLQUFLO3NCQUF2QixNQUFNO2dCQUVZLFNBQVM7c0JBQTNCLE1BQU0iLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBDaGFuZ2VEZXRlY3Rpb25TdHJhdGVneSwgQ29tcG9uZW50LCBFdmVudEVtaXR0ZXIsIElucHV0LCBPdXRwdXQgfSBmcm9tICdAYW5ndWxhci9jb3JlJztcbmltcG9ydCB7IERpYWxvZ01vZHVsZSB9IGZyb20gJ3ByaW1lbmcvZGlhbG9nJztcblxuLyoqXG4gKiBUaGUgZGV0YWNoZWQgY2hhcnQgd2luZG93OiBhIG5vbi1tb2RhbCwgZHJhZ2dhYmxlLCByZXNpemFibGUgZGlhbG9nIGJlc2lkZSB0aGVcbiAqIHNwYXRpYWwtb21pY3MgZGlhbG9nLCBob2xkaW5nIHRoZSBwbG90IGRpdiAoYnkge0BsaW5rIGRpdklkfSkgYW5kIHdoYXRldmVyIGlzIHByb2plY3RlZFxuICogdW5kZXIgaXQgKHRoZSBjaGFydCdzIGhpbnRzKS5cbiAqXG4gKiBQcmVzZW50YXRpb25hbDogdGhlIGNoYXJ0cyBwYW5lbCBkcmF3cyBpbnRvIHRoZSBkaXYsIGFuZCBkZWNpZGVzIHdoYXQgY2xvc2luZyxcbiAqIHNob3dpbmcgYW5kIHJlc2l6aW5nIHRoZSB3aW5kb3cgbWVhbi5cbiAqL1xuQENvbXBvbmVudCh7XG4gIHNlbGVjdG9yOiAnc3BhdGlhbC1jaGFydC13aW5kb3cnLFxuICBzdGFuZGFsb25lOiB0cnVlLFxuICBpbXBvcnRzOiBbRGlhbG9nTW9kdWxlXSxcbiAgdGVtcGxhdGVVcmw6ICcuL3NwYXRpYWwtY2hhcnQtd2luZG93LmNvbXBvbmVudC5odG1sJyxcbiAgc3R5bGVVcmxzOiBbJy4vc3BhdGlhbC1jaGFydC13aW5kb3cuY29tcG9uZW50LnNjc3MnXSxcbiAgY2hhbmdlRGV0ZWN0aW9uOiBDaGFuZ2VEZXRlY3Rpb25TdHJhdGVneS5PblB1c2gsXG59KVxuZXhwb3J0IGNsYXNzIFNwYXRpYWxDaGFydFdpbmRvd0NvbXBvbmVudCB7XG4gIC8qKiBUaGUgd2luZG93J3MgaGVhZGVyIOKAlCB3aGF0IGl0IGlzIHNob3dpbmcuICovXG4gIEBJbnB1dCgpIHRpdGxlID0gJyc7XG4gIC8qKiBUaGUgaWQgb2YgdGhlIGRpdiB0aGUgY2hhcnQgaXMgZHJhd24gaW50by4gKi9cbiAgQElucHV0KCkgZGl2SWQgPSAnJztcbiAgLyoqIFdoZXRoZXIgdGhlIGRyYXduIGxheW91dCBmaXhlZCBpdHMgb3duIGhlaWdodCAoYW5kIHNvIHRoZSB3aW5kb3cgc2Nyb2xscykuICovXG4gIEBJbnB1dCgpIGZpeGVkSGVpZ2h0ID0gZmFsc2U7XG4gIC8qKiBUaGUgd2luZG93IHdhcyBjbG9zZWQ6IHB1dCB0aGUgY2hhcnQgYmFjay4gKi9cbiAgQE91dHB1dCgpIHJlYWRvbmx5IGNsb3NlZCA9IG5ldyBFdmVudEVtaXR0ZXI8dm9pZD4oKTtcbiAgLyoqIFRoZSB3aW5kb3cgaXMgdXAgYW5kIGl0cyBkaXYgZXhpc3RzOiB0aGUgY2hhcnQgY2FuIGJlIGRyYXduIGludG8gaXQuICovXG4gIEBPdXRwdXQoKSByZWFkb25seSBzaG93biA9IG5ldyBFdmVudEVtaXR0ZXI8dm9pZD4oKTtcbiAgLyoqIFRoZSB3aW5kb3cgd2FzIHJlc2l6ZWQ6IHJlLWZpdCB0aGUgY2hhcnQuICovXG4gIEBPdXRwdXQoKSByZWFkb25seSByZXNpemVFbmQgPSBuZXcgRXZlbnRFbWl0dGVyPHZvaWQ+KCk7XG59XG4iLCI8IS0tIFRoZSBkZXRhY2hlZCBjaGFydC4gSXRzIG93biBub24tbW9kYWwsIGRyYWdnYWJsZSwgcmVzaXphYmxlIHdpbmRvdyBzbyBpdCBjYW4gYmUgcHV0XG4gICAgIGJlc2lkZSB0aGUgc3BhdGlhbC1vbWljcyBkaWFsb2cuIGBhcHBlbmRUbz1cImJvZHlcImAga2VlcHMgaXQgb3V0IG9mIHRoZSBkaWFsb2cnc1xuICAgICBzdGFja2luZyBjb250ZXh0LCBvciBpdCB3b3VsZCBiZSBjbGlwcGVkIGJ5IHRoZSBwYW5lbCBpdCBpcyBtZWFudCB0byBzaXQgbmV4dCB0by4gLS0+XG48cC1kaWFsb2dcbiAgW2hlYWRlcl09XCJ0aXRsZVwiXG4gIFt2aXNpYmxlXT1cInRydWVcIlxuICAodmlzaWJsZUNoYW5nZSk9XCJjbG9zZWQuZW1pdCgpXCJcbiAgW21vZGFsXT1cImZhbHNlXCJcbiAgW3Jlc2l6YWJsZV09XCJ0cnVlXCJcbiAgW2RyYWdnYWJsZV09XCJ0cnVlXCJcbiAgcG9zaXRpb249XCJyaWdodFwiXG4gIGFwcGVuZFRvPVwiYm9keVwiXG4gIChvblNob3cpPVwic2hvd24uZW1pdCgpXCJcbiAgKG9uUmVzaXplRW5kKT1cInJlc2l6ZUVuZC5lbWl0KClcIlxuICBbc3R5bGVdPVwieyB3aWR0aDogJzM0cmVtJywgaGVpZ2h0OiAnMzByZW0nIH1cIlxuICBbY29udGVudFN0eWxlXT1cIntcbiAgICBkaXNwbGF5OiAnZmxleCcsXG4gICAgZmxleERpcmVjdGlvbjogJ2NvbHVtbicsXG4gICAgZ2FwOiAnMC4yNXJlbScsXG4gICAgcGFkZGluZzogJzAuNHJlbSAwLjZyZW0gMC41cmVtJyxcbiAgICBmbGV4OiAnMSAxIGF1dG8nLFxuICAgIG1pbkhlaWdodDogJzAnLFxuICAgIG92ZXJmbG93OiAnYXV0bycsXG4gIH1cIlxuICBzdHlsZUNsYXNzPVwic3BhdGlhbC1kZXRhY2hlZC1kaWFsb2dcIlxuPlxuICA8ZGl2IFtpZF09XCJkaXZJZFwiIGNsYXNzPVwic3gtZGV0YWNoZWQtcGxvdFwiIFtjbGFzcy5zeC1wbG90LWZpeGVkXT1cImZpeGVkSGVpZ2h0XCI+PC9kaXY+XG4gIDxuZy1jb250ZW50PjwvbmctY29udGVudD5cbjwvcC1kaWFsb2c+XG4iXX0=