matterviz 0.4.1 → 0.4.2

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 (395) hide show
  1. package/dist/EmptyState.svelte +10 -4
  2. package/dist/FilePicker.svelte +12 -14
  3. package/dist/Icon.svelte +7 -4
  4. package/dist/MillerIndexInput.svelte +2 -2
  5. package/dist/app.css +53 -0
  6. package/dist/brillouin/BrillouinZone.svelte +75 -85
  7. package/dist/brillouin/BrillouinZone.svelte.d.ts +5 -7
  8. package/dist/brillouin/BrillouinZoneControls.svelte +3 -6
  9. package/dist/brillouin/BrillouinZoneExportPane.svelte +18 -14
  10. package/dist/brillouin/BrillouinZoneInfoPane.svelte +6 -10
  11. package/dist/brillouin/BrillouinZoneScene.svelte +26 -39
  12. package/dist/brillouin/BrillouinZoneScene.svelte.d.ts +1 -1
  13. package/dist/chempot-diagram/ChemPotDiagram.svelte +33 -38
  14. package/dist/chempot-diagram/ChemPotDiagram2D.svelte +62 -74
  15. package/dist/chempot-diagram/ChemPotDiagram2D.svelte.d.ts +1 -1
  16. package/dist/chempot-diagram/ChemPotDiagram3D.svelte +511 -547
  17. package/dist/chempot-diagram/ChemPotDiagram3D.svelte.d.ts +1 -1
  18. package/dist/chempot-diagram/async-compute.svelte.js +1 -1
  19. package/dist/chempot-diagram/controls-state.svelte.js +1 -1
  20. package/dist/colors/index.d.ts +0 -4
  21. package/dist/colors/index.js +19 -20
  22. package/dist/composition/BarChart.svelte +37 -31
  23. package/dist/composition/BubbleChart.svelte +17 -17
  24. package/dist/composition/Composition.svelte +7 -11
  25. package/dist/composition/Formula.svelte +18 -25
  26. package/dist/composition/FormulaFilter.svelte +92 -95
  27. package/dist/composition/PieChart.svelte +55 -41
  28. package/dist/composition/format.js +1 -1
  29. package/dist/composition/index.d.ts +2 -0
  30. package/dist/composition/index.js +14 -0
  31. package/dist/composition/parse.d.ts +2 -2
  32. package/dist/composition/parse.js +11 -10
  33. package/dist/constants.js +11 -9
  34. package/dist/convex-hull/ConvexHull.svelte +12 -15
  35. package/dist/convex-hull/ConvexHull.svelte.d.ts +1 -1
  36. package/dist/convex-hull/ConvexHull2D.svelte +93 -92
  37. package/dist/convex-hull/ConvexHull2D.svelte.d.ts +1 -1
  38. package/dist/convex-hull/ConvexHull3D.svelte +109 -140
  39. package/dist/convex-hull/ConvexHull3D.svelte.d.ts +1 -1
  40. package/dist/convex-hull/ConvexHull4D.svelte +75 -94
  41. package/dist/convex-hull/ConvexHull4D.svelte.d.ts +1 -1
  42. package/dist/convex-hull/ConvexHullChrome.svelte +36 -40
  43. package/dist/convex-hull/ConvexHullControls.svelte +46 -48
  44. package/dist/convex-hull/ConvexHullStats.svelte +193 -195
  45. package/dist/convex-hull/ConvexHullTooltip.svelte +5 -12
  46. package/dist/convex-hull/GasPressureControls.svelte +5 -12
  47. package/dist/convex-hull/StructurePopup.svelte +17 -21
  48. package/dist/convex-hull/StructurePopup.svelte.d.ts +2 -0
  49. package/dist/convex-hull/TemperatureSlider.svelte +4 -10
  50. package/dist/convex-hull/canvas-interactions.svelte.js +2 -1
  51. package/dist/convex-hull/helpers.d.ts +8 -10
  52. package/dist/convex-hull/helpers.js +36 -36
  53. package/dist/convex-hull/hull-state.svelte.d.ts +1 -1
  54. package/dist/convex-hull/thermodynamics.js +18 -17
  55. package/dist/coordination/CoordinationBarPlot.svelte +38 -33
  56. package/dist/coordination/CoordinationBarPlot.svelte.d.ts +1 -1
  57. package/dist/coordination/calc-coordination.d.ts +1 -1
  58. package/dist/coordination/calc-coordination.js +28 -25
  59. package/dist/element/BohrAtom.svelte +5 -8
  60. package/dist/element/ElementHeading.svelte +4 -1
  61. package/dist/element/ElementPhoto.svelte +11 -9
  62. package/dist/element/ElementStats.svelte +12 -10
  63. package/dist/element/ElementTile.svelte +24 -29
  64. package/dist/element/Nucleus.svelte +4 -2
  65. package/dist/element/data.d.ts +1 -2
  66. package/dist/element/helpers.d.ts +4 -0
  67. package/dist/element/helpers.js +18 -0
  68. package/dist/element/index.d.ts +1 -4
  69. package/dist/element/index.js +3 -18
  70. package/dist/feedback/DragOverlay.svelte +5 -5
  71. package/dist/feedback/DragOverlay.svelte.d.ts +2 -2
  72. package/dist/feedback/StatusMessage.svelte +7 -4
  73. package/dist/fermi-surface/FermiSlice.svelte +21 -18
  74. package/dist/fermi-surface/FermiSurface.svelte +14 -22
  75. package/dist/fermi-surface/FermiSurface.svelte.d.ts +5 -7
  76. package/dist/fermi-surface/FermiSurfaceControls.svelte +6 -20
  77. package/dist/fermi-surface/FermiSurfaceControls.svelte.d.ts +1 -1
  78. package/dist/fermi-surface/FermiSurfaceScene.svelte +37 -64
  79. package/dist/fermi-surface/FermiSurfaceScene.svelte.d.ts +1 -1
  80. package/dist/fermi-surface/FermiSurfaceTooltip.svelte +9 -6
  81. package/dist/fermi-surface/compute.js +3 -3
  82. package/dist/fermi-surface/parse.js +22 -24
  83. package/dist/heatmap-matrix/HeatmapMatrix.svelte +109 -148
  84. package/dist/heatmap-matrix/HeatmapMatrix.svelte.d.ts +2 -2
  85. package/dist/heatmap-matrix/HeatmapMatrixControls.svelte +9 -7
  86. package/dist/heatmap-matrix/HeatmapMatrixControls.svelte.d.ts +1 -1
  87. package/dist/heatmap-matrix/index.d.ts +5 -0
  88. package/dist/icons.d.ts +4 -0
  89. package/dist/icons.js +4 -0
  90. package/dist/io/ExportPane.svelte +10 -6
  91. package/dist/io/decompress.d.ts +2 -1
  92. package/dist/io/decompress.js +22 -35
  93. package/dist/io/export.d.ts +4 -0
  94. package/dist/io/export.js +5 -1
  95. package/dist/io/fetch.d.ts +0 -3
  96. package/dist/io/fetch.js +0 -11
  97. package/dist/io/index.d.ts +0 -1
  98. package/dist/io/index.js +2 -9
  99. package/dist/io/is-binary.d.ts +9 -0
  100. package/dist/io/is-binary.js +45 -1
  101. package/dist/io/url-drop.js +13 -25
  102. package/dist/isosurface/Isosurface.svelte +17 -23
  103. package/dist/isosurface/IsosurfaceControls.svelte +37 -42
  104. package/dist/isosurface/parse-vaspwave.d.ts +3 -0
  105. package/dist/isosurface/parse-vaspwave.js +138 -0
  106. package/dist/isosurface/parse.js +6 -6
  107. package/dist/labels.d.ts +6 -2
  108. package/dist/labels.js +43 -13
  109. package/dist/layout/FullscreenButton.svelte +2 -1
  110. package/dist/layout/FullscreenToggle.svelte +10 -4
  111. package/dist/layout/InfoCard.svelte +7 -18
  112. package/dist/layout/InfoTag.svelte +1 -3
  113. package/dist/layout/NumberRangeInput.svelte +46 -0
  114. package/dist/layout/NumberRangeInput.svelte.d.ts +12 -0
  115. package/dist/layout/PropertyFilter.svelte +2 -6
  116. package/dist/layout/SettingsSection.svelte +21 -17
  117. package/dist/layout/SubpageGrid.svelte +3 -1
  118. package/dist/layout/ViewerChrome.svelte +9 -10
  119. package/dist/layout/ViewerChrome.svelte.d.ts +2 -1
  120. package/dist/layout/fullscreen.js +3 -5
  121. package/dist/layout/fullscreen.svelte.js +1 -2
  122. package/dist/layout/index.d.ts +1 -0
  123. package/dist/layout/index.js +1 -0
  124. package/dist/layout/json-tree/JsonNode.svelte +8 -11
  125. package/dist/layout/json-tree/JsonTree.svelte +53 -77
  126. package/dist/layout/json-tree/JsonValue.svelte +7 -15
  127. package/dist/layout/json-tree/utils.js +14 -23
  128. package/dist/math.d.ts +2 -0
  129. package/dist/math.js +19 -0
  130. package/dist/overlays/ContextMenu.svelte +4 -2
  131. package/dist/overlays/CopyButton.svelte +11 -5
  132. package/dist/overlays/DragControlTab.svelte +6 -1
  133. package/dist/overlays/DraggablePane.svelte +81 -26
  134. package/dist/overlays/DraggablePane.svelte.d.ts +1 -0
  135. package/dist/overlays/GlassChip.svelte +30 -0
  136. package/dist/overlays/GlassChip.svelte.d.ts +8 -0
  137. package/dist/overlays/InfoPaneCards.svelte +11 -23
  138. package/dist/overlays/index.d.ts +7 -0
  139. package/dist/overlays/index.js +26 -0
  140. package/dist/overlays/portal.d.ts +2 -0
  141. package/dist/overlays/portal.js +14 -0
  142. package/dist/periodic-table/PeriodicTable.svelte +113 -145
  143. package/dist/periodic-table/PeriodicTable.svelte.d.ts +5 -3
  144. package/dist/periodic-table/PeriodicTableControls.svelte +11 -63
  145. package/dist/periodic-table/TableInset.svelte +9 -4
  146. package/dist/phase-diagram/IsobaricBinaryPhaseDiagram.svelte +50 -71
  147. package/dist/phase-diagram/IsobaricBinaryPhaseDiagram.svelte.d.ts +6 -8
  148. package/dist/phase-diagram/PhaseDiagramControls.svelte +70 -94
  149. package/dist/phase-diagram/PhaseDiagramControls.svelte.d.ts +1 -1
  150. package/dist/phase-diagram/PhaseDiagramEditorPane.svelte +2 -1
  151. package/dist/phase-diagram/PhaseDiagramExportPane.svelte +12 -12
  152. package/dist/phase-diagram/PhaseDiagramTooltip.svelte +54 -58
  153. package/dist/phase-diagram/TdbInfoPanel.svelte +21 -15
  154. package/dist/phase-diagram/build-diagram.js +3 -3
  155. package/dist/phase-diagram/diagram-input.d.ts +1 -2
  156. package/dist/phase-diagram/parse.js +15 -15
  157. package/dist/phase-diagram/svg-to-diagram.js +21 -15
  158. package/dist/phase-diagram/utils.js +2 -3
  159. package/dist/plot/bar/BarPlot.svelte +430 -391
  160. package/dist/plot/bar/BarPlot.svelte.d.ts +2 -0
  161. package/dist/plot/bar/BarPlotControls.svelte +1 -3
  162. package/dist/plot/bar/BarPlotControls.svelte.d.ts +4 -6
  163. package/dist/plot/bar/SpacegroupBarPlot.svelte +29 -36
  164. package/dist/plot/bar/data.d.ts +5 -4
  165. package/dist/plot/bar/data.js +2 -1
  166. package/dist/plot/box/BoxPlot.svelte +301 -209
  167. package/dist/plot/box/BoxPlot.svelte.d.ts +2 -0
  168. package/dist/plot/box/Violin.svelte.d.ts +1 -0
  169. package/dist/plot/box/box-plot.js +1 -1
  170. package/dist/plot/core/auto-place.js +1 -1
  171. package/dist/plot/core/axis-utils.d.ts +12 -7
  172. package/dist/plot/core/axis-utils.js +48 -48
  173. package/dist/plot/core/components/AxisLabel.svelte +82 -20
  174. package/dist/plot/core/components/AxisLabel.svelte.d.ts +1 -0
  175. package/dist/plot/core/components/ColorBar.svelte +101 -106
  176. package/dist/plot/core/components/ColorScaleSelect.svelte +1 -1
  177. package/dist/plot/core/components/FillArea.svelte +10 -17
  178. package/dist/plot/core/components/HierarchyControls.svelte +249 -0
  179. package/dist/plot/{sunburst/SunburstControls.svelte.d.ts → core/components/HierarchyControls.svelte.d.ts} +12 -8
  180. package/dist/plot/core/components/InteractiveAxisLabel.svelte +1 -1
  181. package/dist/plot/core/components/InteractiveAxisLabel.svelte.d.ts +1 -1
  182. package/dist/plot/core/components/Line.svelte +18 -9
  183. package/dist/plot/core/components/Line.svelte.d.ts +2 -0
  184. package/dist/plot/core/components/PlotAxis.svelte +40 -17
  185. package/dist/plot/core/components/PlotControls.svelte +65 -41
  186. package/dist/plot/core/components/PlotLegend.svelte +31 -35
  187. package/dist/plot/core/components/PlotMarginals.svelte +616 -0
  188. package/dist/plot/core/components/PlotMarginals.svelte.d.ts +15 -0
  189. package/dist/plot/core/components/PlotTooltip.svelte +1 -1
  190. package/dist/plot/core/components/PortalSelect.svelte +4 -8
  191. package/dist/plot/core/components/ReferenceLine.svelte +27 -24
  192. package/dist/plot/core/components/ReferenceLine3D.svelte +54 -57
  193. package/dist/plot/core/components/ReferencePlane.svelte +7 -8
  194. package/dist/plot/core/components/ZeroLines.svelte +4 -8
  195. package/dist/plot/core/components/ZoomRect.svelte +1 -2
  196. package/dist/plot/core/components/index.d.ts +1 -0
  197. package/dist/plot/core/components/index.js +1 -0
  198. package/dist/plot/core/data-cleaning-signal.d.ts +46 -0
  199. package/dist/plot/core/data-cleaning-signal.js +467 -0
  200. package/dist/plot/core/data-cleaning.d.ts +2 -42
  201. package/dist/plot/core/data-cleaning.js +27 -474
  202. package/dist/plot/core/data-transform.js +9 -5
  203. package/dist/plot/core/fill-utils.d.ts +3 -1
  204. package/dist/plot/core/fill-utils.js +28 -6
  205. package/dist/plot/core/index.d.ts +1 -0
  206. package/dist/plot/core/index.js +1 -0
  207. package/dist/plot/core/interactions.js +0 -2
  208. package/dist/plot/core/layout.d.ts +3 -1
  209. package/dist/plot/core/layout.js +22 -13
  210. package/dist/plot/core/marginals.d.ts +170 -0
  211. package/dist/plot/core/marginals.js +436 -0
  212. package/dist/plot/core/reference-line.js +1 -1
  213. package/dist/plot/core/scales.d.ts +23 -0
  214. package/dist/plot/core/scales.js +39 -13
  215. package/dist/plot/core/types/fills.d.ts +101 -0
  216. package/dist/plot/core/types/fills.js +15 -0
  217. package/dist/plot/core/types/plot-3d.d.ts +87 -0
  218. package/dist/plot/core/types/plot-3d.js +4 -0
  219. package/dist/plot/core/types/reference-lines.d.ts +140 -0
  220. package/dist/plot/core/types/reference-lines.js +9 -0
  221. package/dist/plot/core/types.d.ts +29 -324
  222. package/dist/plot/core/types.js +23 -20
  223. package/dist/plot/core/utils/hierarchy-chart.d.ts +51 -0
  224. package/dist/plot/core/utils/hierarchy-chart.js +179 -0
  225. package/dist/plot/core/utils/hierarchy-labels.d.ts +20 -0
  226. package/dist/plot/core/utils/hierarchy-labels.js +99 -0
  227. package/dist/plot/core/utils/label-placement.js +2 -2
  228. package/dist/plot/histogram/Histogram.svelte +304 -325
  229. package/dist/plot/histogram/Histogram.svelte.d.ts +7 -7
  230. package/dist/plot/histogram/HistogramControls.svelte +30 -28
  231. package/dist/plot/histogram/histogram.d.ts +31 -0
  232. package/dist/plot/histogram/histogram.js +70 -0
  233. package/dist/plot/histogram/index.d.ts +1 -0
  234. package/dist/plot/histogram/index.js +1 -0
  235. package/dist/plot/index.d.ts +1 -0
  236. package/dist/plot/index.js +1 -0
  237. package/dist/plot/sankey/Sankey.svelte +78 -69
  238. package/dist/plot/sankey/Sankey.svelte.d.ts +2 -2
  239. package/dist/plot/sankey/SankeyControls.svelte +22 -16
  240. package/dist/plot/scatter/BinnedScatterPlot.svelte +263 -109
  241. package/dist/plot/scatter/BinnedScatterPlot.svelte.d.ts +7 -0
  242. package/dist/plot/scatter/ElementScatter.svelte +4 -1
  243. package/dist/plot/scatter/ScatterPlot.svelte +477 -385
  244. package/dist/plot/scatter/ScatterPlot.svelte.d.ts +2 -0
  245. package/dist/plot/scatter/ScatterPlotControls.svelte +18 -19
  246. package/dist/plot/scatter/ScatterPlotControls.svelte.d.ts +1 -1
  247. package/dist/plot/scatter/ScatterPoint.svelte +16 -9
  248. package/dist/plot/scatter/binned-scatter-types.d.ts +3 -2
  249. package/dist/plot/scatter/binned-scatter-types.js +6 -1
  250. package/dist/plot/scatter/scatter-data.d.ts +1 -1
  251. package/dist/plot/scatter/scatter-data.js +8 -7
  252. package/dist/plot/scatter-3d/ScatterPlot3D.svelte +25 -34
  253. package/dist/plot/scatter-3d/ScatterPlot3D.svelte.d.ts +2 -2
  254. package/dist/plot/scatter-3d/ScatterPlot3DControls.svelte +8 -5
  255. package/dist/plot/scatter-3d/ScatterPlot3DScene.svelte +113 -116
  256. package/dist/plot/scatter-3d/ScatterPlot3DScene.svelte.d.ts +2 -2
  257. package/dist/plot/scatter-3d/Surface3D.svelte +4 -13
  258. package/dist/plot/sunburst/Sunburst.svelte +251 -329
  259. package/dist/plot/sunburst/Sunburst.svelte.d.ts +2 -2
  260. package/dist/plot/sunburst/index.d.ts +1 -1
  261. package/dist/plot/sunburst/index.js +2 -1
  262. package/dist/plot/sunburst/render.d.ts +2 -2
  263. package/dist/plot/sunburst/render.js +47 -22
  264. package/dist/plot/sunburst/sunburst.d.ts +5 -1
  265. package/dist/plot/sunburst/sunburst.js +10 -3
  266. package/dist/plot/treemap/Treemap.svelte +907 -0
  267. package/dist/plot/treemap/Treemap.svelte.d.ts +84 -0
  268. package/dist/plot/treemap/index.d.ts +3 -0
  269. package/dist/plot/treemap/index.js +4 -0
  270. package/dist/plot/treemap/treemap.d.ts +26 -0
  271. package/dist/plot/treemap/treemap.js +99 -0
  272. package/dist/rdf/RdfPlot.svelte +22 -26
  273. package/dist/rdf/RdfPlot.svelte.d.ts +1 -1
  274. package/dist/rdf/calc-rdf.js +4 -8
  275. package/dist/sanitize.js +1 -1
  276. package/dist/scene/bind-renderer.svelte.js +14 -6
  277. package/dist/settings.d.ts +19 -9
  278. package/dist/settings.js +77 -50
  279. package/dist/spectral/Bands.svelte +223 -230
  280. package/dist/spectral/BandsAndDos.svelte +11 -9
  281. package/dist/spectral/BrillouinBandsDos.svelte +19 -27
  282. package/dist/spectral/Dos.svelte +70 -73
  283. package/dist/spectral/helpers.d.ts +3 -3
  284. package/dist/spectral/helpers.js +25 -35
  285. package/dist/state.svelte.js +5 -18
  286. package/dist/structure/Arrow.svelte +5 -18
  287. package/dist/structure/ArrowInstances.svelte +160 -0
  288. package/dist/structure/ArrowInstances.svelte.d.ts +16 -0
  289. package/dist/structure/AtomLegend.svelte +115 -75
  290. package/dist/structure/AtomLegend.svelte.d.ts +1 -1
  291. package/dist/structure/Bond.svelte +31 -23
  292. package/dist/structure/CanvasTooltip.svelte +15 -3
  293. package/dist/structure/CellSelect.svelte +11 -26
  294. package/dist/structure/Cylinder.svelte +24 -40
  295. package/dist/structure/InstancedAtoms.svelte +114 -0
  296. package/dist/structure/InstancedAtoms.svelte.d.ts +15 -0
  297. package/dist/structure/Lattice.svelte +85 -149
  298. package/dist/structure/SiteLabels.svelte +122 -0
  299. package/dist/structure/SiteLabels.svelte.d.ts +18 -0
  300. package/dist/structure/Structure.svelte +473 -419
  301. package/dist/structure/Structure.svelte.d.ts +4 -2
  302. package/dist/structure/StructureCarousel.svelte +630 -0
  303. package/dist/structure/StructureCarousel.svelte.d.ts +19 -0
  304. package/dist/structure/StructureControls.svelte +157 -399
  305. package/dist/structure/StructureControls.svelte.d.ts +1 -1
  306. package/dist/structure/StructureExportPane.svelte +17 -21
  307. package/dist/structure/StructureInfoPane.svelte +72 -66
  308. package/dist/structure/StructureInfoPane.svelte.d.ts +1 -1
  309. package/dist/structure/StructureScene.svelte +467 -476
  310. package/dist/structure/StructureScene.svelte.d.ts +3 -1
  311. package/dist/structure/StructureViewport.svelte +386 -0
  312. package/dist/structure/StructureViewport.svelte.d.ts +63 -0
  313. package/dist/structure/atom-label-placement.d.ts +16 -12
  314. package/dist/structure/atom-label-placement.js +70 -37
  315. package/dist/structure/atom-properties.d.ts +2 -0
  316. package/dist/structure/atom-properties.js +104 -38
  317. package/dist/structure/bonding.d.ts +10 -3
  318. package/dist/structure/bonding.js +84 -28
  319. package/dist/structure/edit-history.d.ts +6 -0
  320. package/dist/structure/edit-history.js +27 -0
  321. package/dist/structure/export.d.ts +1 -0
  322. package/dist/structure/export.js +39 -31
  323. package/dist/structure/format-detect.d.ts +1 -0
  324. package/dist/structure/format-detect.js +22 -0
  325. package/dist/structure/geometry.d.ts +9 -0
  326. package/dist/structure/geometry.js +27 -0
  327. package/dist/structure/index.d.ts +16 -1
  328. package/dist/structure/index.js +13 -2
  329. package/dist/structure/measure.d.ts +1 -1
  330. package/dist/structure/measure.js +6 -12
  331. package/dist/structure/parse.d.ts +2 -1
  332. package/dist/structure/parse.js +243 -222
  333. package/dist/structure/partial-occupancy.js +4 -2
  334. package/dist/structure/pbc.js +78 -98
  335. package/dist/structure/polyhedra.d.ts +0 -1
  336. package/dist/structure/polyhedra.js +3 -18
  337. package/dist/structure/supercell.d.ts +1 -2
  338. package/dist/structure/supercell.js +7 -13
  339. package/dist/symmetry/SymmetryElements.svelte +11 -15
  340. package/dist/symmetry/SymmetryStats.svelte +56 -68
  341. package/dist/symmetry/WyckoffTable.svelte +5 -24
  342. package/dist/symmetry/cell-transform.js +1 -0
  343. package/dist/symmetry/index.d.ts +1 -0
  344. package/dist/symmetry/index.js +8 -2
  345. package/dist/symmetry/spacegroups.js +3 -2
  346. package/dist/table/HeatmapTable.svelte +1102 -365
  347. package/dist/table/HeatmapTable.svelte.d.ts +12 -2
  348. package/dist/table/ToggleMenu.svelte +5 -12
  349. package/dist/table/index.d.ts +21 -6
  350. package/dist/table/index.js +34 -21
  351. package/dist/theme/ThemeControl.svelte +16 -8
  352. package/dist/theme/index.d.ts +1 -5
  353. package/dist/theme/index.js +4 -10
  354. package/dist/theme/themes.mjs +14 -7
  355. package/dist/tooltip/KCoords.svelte +4 -1
  356. package/dist/tooltip/TooltipContent.svelte +2 -5
  357. package/dist/trajectory/Trajectory.svelte +515 -308
  358. package/dist/trajectory/Trajectory.svelte.d.ts +1 -1
  359. package/dist/trajectory/TrajectoryError.svelte +11 -8
  360. package/dist/trajectory/TrajectoryExportPane.svelte +14 -31
  361. package/dist/trajectory/TrajectoryInfoPane.svelte +85 -97
  362. package/dist/trajectory/extract.js +56 -34
  363. package/dist/trajectory/format-detect.js +11 -9
  364. package/dist/trajectory/frame-reader.d.ts +2 -0
  365. package/dist/trajectory/frame-reader.js +33 -29
  366. package/dist/trajectory/helpers.d.ts +2 -0
  367. package/dist/trajectory/helpers.js +18 -7
  368. package/dist/trajectory/index.d.ts +1 -0
  369. package/dist/trajectory/index.js +3 -0
  370. package/dist/trajectory/parse/h5-utils.d.ts +13 -0
  371. package/dist/trajectory/parse/h5-utils.js +109 -0
  372. package/dist/trajectory/parse/hdf5.d.ts +1 -1
  373. package/dist/trajectory/parse/hdf5.js +116 -106
  374. package/dist/trajectory/parse/index.d.ts +2 -3
  375. package/dist/trajectory/parse/index.js +17 -20
  376. package/dist/trajectory/parse/lammps.js +8 -12
  377. package/dist/trajectory/parse/vasp.js +10 -7
  378. package/dist/trajectory/parse/vaspout-electronic.d.ts +13 -0
  379. package/dist/trajectory/parse/vaspout-electronic.js +207 -0
  380. package/dist/trajectory/parse/vaspout-h5.d.ts +5 -0
  381. package/dist/trajectory/parse/vaspout-h5.js +284 -0
  382. package/dist/trajectory/parse/xyz.js +11 -7
  383. package/dist/trajectory/plotting.d.ts +8 -9
  384. package/dist/trajectory/plotting.js +99 -27
  385. package/dist/utils.d.ts +3 -0
  386. package/dist/utils.js +7 -0
  387. package/dist/xrd/XrdPlot.svelte +47 -61
  388. package/dist/xrd/broadening.js +2 -1
  389. package/dist/xrd/calc-xrd.js +2 -4
  390. package/dist/xrd/parse.d.ts +0 -1
  391. package/dist/xrd/parse.js +56 -73
  392. package/package.json +61 -33
  393. package/dist/api/mp.d.ts +0 -6
  394. package/dist/api/mp.js +0 -22
  395. package/dist/plot/sunburst/SunburstControls.svelte +0 -200
@@ -0,0 +1,616 @@
1
+ <script lang="ts">
2
+ // Renders marginal-distribution strips on any side of a 2D plot. Used by every 2D plot:
3
+ // each passes its resolved `marginals`, a generic `series` adapter, the shared positional
4
+ // scales/ranges, and the inflated `pad`. This must be a direct child of the host <svg>
5
+ // (outside the plot clip group); each strip self-clips. See core/marginals.ts for the math.
6
+ import type { Vec2 } from '../../../math'
7
+ import type { Rect, Sides } from '../layout'
8
+ import type {
9
+ MarginalAxes,
10
+ MarginalAxisBinding,
11
+ MarginalCurve,
12
+ MarginalHover,
13
+ MarginalRenderContext,
14
+ MarginalSeriesCurve,
15
+ MarginalSeriesInput,
16
+ MarginalSide,
17
+ ResolvedMarginalConfig,
18
+ ResolvedMarginals,
19
+ ScaleFn,
20
+ } from '../marginals'
21
+ import {
22
+ MARGINAL_SIDES,
23
+ compute_marginal_curve,
24
+ curves_max,
25
+ default_axis_for_side,
26
+ default_marginal_label,
27
+ marginal_hit,
28
+ marginal_strip_rect,
29
+ marginal_value_format,
30
+ marginal_value_scale,
31
+ } from '../marginals'
32
+ import { line_curve_factory } from '../fill-utils'
33
+ import PlotTooltip from './PlotTooltip.svelte'
34
+ import { sanitize_html } from '../../../sanitize'
35
+ import { format_value } from '../../../labels'
36
+ import { ticks as d3_ticks } from 'd3-array'
37
+ import { area, curveMonotoneX, curveMonotoneY, line } from 'd3-shape'
38
+
39
+ let {
40
+ marginals,
41
+ series,
42
+ width,
43
+ height,
44
+ pad,
45
+ has_axis = { top: false, bottom: true, left: true, right: false },
46
+ axes,
47
+ id,
48
+ }: {
49
+ marginals: ResolvedMarginals
50
+ series: MarginalSeriesInput[]
51
+ width: number
52
+ height: number
53
+ pad: Required<Sides>
54
+ has_axis?: Record<MarginalSide, boolean>
55
+ axes: MarginalAxes
56
+ id: string // unique per host plot; used to scope each strip's clipPath
57
+ } = $props()
58
+
59
+ // The marginal datum under the pointer (set by the hit-rects, drives the tooltip below)
60
+ let hovered = $state<MarginalHover | null>(null)
61
+
62
+ // Map a pointer event on a strip hit-rect to a MarginalHover via the pure marginal_hit. The svg
63
+ // has no scaling viewBox, so wrapper px = svg user-space px = the coords PlotTooltip expects.
64
+ const on_marginal_move = (
65
+ event: PointerEvent,
66
+ ctx: MarginalRenderContext,
67
+ ): MarginalHover | null => {
68
+ const svg = (event.currentTarget as Element).closest(`svg`)
69
+ if (!svg) return null
70
+ const box = svg.getBoundingClientRect()
71
+ return marginal_hit(ctx, event.clientX - box.left, event.clientY - box.top)
72
+ }
73
+
74
+ // Keep strip pointer/mouse events off the host plot's own handlers (hover, pan, zoom)
75
+ const stop = (event: Event) => event.stopPropagation()
76
+
77
+ // A strip shows a hover tooltip unless opted out via hover:false or replaced by a custom snippet
78
+ const is_hoverable = (config: ResolvedMarginalConfig) =>
79
+ config.hover !== false && !config.snippet
80
+
81
+ // PlotMarginals renders inside the <svg>, which can't host an HTML tooltip. Relocate the tooltip
82
+ // div to be a sibling of the <svg> (in the positioned plot wrapper) so it positions in wrapper px
83
+ // and stacks above HTML overlays (legend, colorbar) — like each host plot's own PlotTooltip.
84
+ const portal_to_wrapper = (node: HTMLElement) => {
85
+ node.closest(`svg`)?.parentElement?.append(node)
86
+ return () => node.remove()
87
+ }
88
+
89
+ // Precompute tooltip content off the hot pointer path (recomputes only when `hovered` changes).
90
+ // `head_label`/`head_value` form the position row (bin range for bars, else a single position);
91
+ // `value` is the count/density/CDF row (null for rug, which has no value). A per-side
92
+ // `config.tooltip` snippet overrides this default content.
93
+ const tip = $derived.by(() => {
94
+ if (!hovered) return null
95
+ const {
96
+ kind,
97
+ config,
98
+ color,
99
+ format,
100
+ pos,
101
+ pos0,
102
+ pos1,
103
+ pos_label,
104
+ value,
105
+ label,
106
+ axis_title,
107
+ } = hovered
108
+ const bg_color = color.trim().toLowerCase() === `currentcolor` ? null : color
109
+ const pos_fmt = format || `.3~g`
110
+ // Position row = `<axis title>: <value>`. The title uses the host axis's markup convention
111
+ // (e.g. E<sub>hull</sub>), so it's sanitized HTML; the value/category portion stays literal
112
+ // text (matches how tick labels render, so a literal `<` in a bin label isn't mangled). `||`
113
+ // (not `??`) so an empty/whitespace axis title falls back to the generic `range`/`pos` label.
114
+ const head_label = sanitize_html(axis_title?.trim() || (kind === `bars` ? `range` : `pos`))
115
+ const head_value =
116
+ kind === `bars`
117
+ ? `${format_value(pos0 ?? pos, pos_fmt)}–${format_value(pos1 ?? pos, pos_fmt)}`
118
+ : (pos_label ?? format_value(pos, pos_fmt))
119
+ const value_row =
120
+ kind === `rug`
121
+ ? null
122
+ : `${default_marginal_label(config)}: ${format_value(value ?? 0, marginal_value_format(config))}`
123
+ return {
124
+ bg_color,
125
+ snippet: config.tooltip,
126
+ label,
127
+ head_label,
128
+ head_value,
129
+ value: value_row,
130
+ }
131
+ })
132
+
133
+ type RugMark = { x1: number; y1: number; x2: number; y2: number }
134
+ type LinePt = { pos: number; value: number }
135
+ type CurveRender = {
136
+ kind: MarginalCurve[`kind`]
137
+ fill: string
138
+ fill_opacity: number
139
+ stroke: string
140
+ stroke_width: number
141
+ opacity: number
142
+ bars: Rect[]
143
+ area_path: string
144
+ line_path: string
145
+ rug: RugMark[]
146
+ }
147
+ type ValueAxisRender = {
148
+ spine: { x1: number; y1: number; x2: number; y2: number }
149
+ ticks: { x: number; y: number; text: string }[]
150
+ anchor: string // text-anchor shared by all tick labels
151
+ baseline: string // dominant-baseline shared by all tick labels
152
+ title: { x: number; y: number; text: string; transform?: string }
153
+ }
154
+ type SideRender = {
155
+ side: MarginalSide
156
+ config: ResolvedMarginalConfig
157
+ rect: Rect
158
+ clip_id: string
159
+ ctx: MarginalRenderContext
160
+ curves: CurveRender[]
161
+ value_axis: ValueAxisRender | null
162
+ }
163
+
164
+ // The axis a marginal binds to (x2/y2 fall back to x1/y1), with scale_type defaulted to linear
165
+ const axis_props = (axis: MarginalAxisBinding) => {
166
+ const ax = axes[axis] ?? (axis === `x2` ? axes.x1 : axes.y1)
167
+ return { ...ax, scale_type: ax.scale_type ?? `linear` }
168
+ }
169
+
170
+ // Values a series contributes for a given side (x for top/bottom, y for left/right)
171
+ const series_values = (
172
+ srs: MarginalSeriesInput,
173
+ is_x: boolean,
174
+ ): { positions: ArrayLike<number>; weights: ArrayLike<number> | undefined } => ({
175
+ positions: (is_x ? srs.x : srs.y) ?? [],
176
+ weights: srs.weight,
177
+ })
178
+
179
+ // Flatten several series into one positions/weights pair (for `reduce` and merged per_series=false)
180
+ const merge_values = (
181
+ list: MarginalSeriesInput[],
182
+ is_x: boolean,
183
+ ): { positions: number[]; weights: number[] | undefined } => {
184
+ const positions: number[] = []
185
+ const weights: number[] = []
186
+ let has_weight = false
187
+ for (const srs of list) {
188
+ const { positions: pos, weights: wts } = series_values(srs, is_x)
189
+ for (let idx = 0; idx < pos.length; idx++) {
190
+ positions.push(pos[idx])
191
+ if (wts) {
192
+ has_weight = true
193
+ weights.push(wts[idx])
194
+ } else weights.push(1)
195
+ }
196
+ }
197
+ return { positions, weights: has_weight ? weights : undefined }
198
+ }
199
+
200
+ // Build the SVG primitives for one curve given the side's scales
201
+ const build_curve_render = (
202
+ curve: MarginalSeriesCurve,
203
+ side: MarginalSide,
204
+ is_x: boolean,
205
+ pos_scale: ScaleFn,
206
+ val_scale: ScaleFn,
207
+ baseline: number,
208
+ config: ResolvedMarginalConfig,
209
+ ): CurveRender => {
210
+ const color = config.color ?? curve.color
211
+ const fill = config.fill ?? color
212
+ const fill_opacity = config.fill_opacity ?? 0.6
213
+ const stroke = config.stroke ?? color
214
+ const { stroke_width, opacity } = config
215
+ const data = curve.curve
216
+ const base: CurveRender = {
217
+ kind: data.kind,
218
+ fill,
219
+ fill_opacity,
220
+ stroke,
221
+ stroke_width,
222
+ opacity,
223
+ bars: [],
224
+ area_path: ``,
225
+ line_path: ``,
226
+ rug: [],
227
+ }
228
+
229
+ if (data.kind === `bars`) {
230
+ base.stroke = config.stroke ?? `none` // histogram bars are fill-only unless a stroke is set
231
+ base.bars = data.bins
232
+ .filter((item) => item.value > 0)
233
+ .map((item) => {
234
+ // bar spans [pos0, pos1] on the positional axis and [baseline, value] on the value axis
235
+ const pos_min = Math.min(pos_scale(item.pos0), pos_scale(item.pos1))
236
+ const pos_len = Math.max(0, Math.abs(pos_scale(item.pos1) - pos_scale(item.pos0)))
237
+ const value_px = val_scale(item.value)
238
+ const val_min = Math.min(value_px, baseline)
239
+ const val_len = Math.abs(baseline - value_px)
240
+ return is_x
241
+ ? { x: pos_min, y: val_min, width: pos_len, height: val_len }
242
+ : { x: val_min, y: pos_min, width: val_len, height: pos_len }
243
+ })
244
+ // all four must be finite: a custom reduce/data bin with a non-finite edge/value would
245
+ // otherwise emit width/height="Infinity" (invalid SVG). mirrors marginal_hit's bar filter
246
+ .filter((bar) => [bar.x, bar.y, bar.width, bar.height].every(isFinite))
247
+ return base
248
+ }
249
+
250
+ if (data.kind === `line`) {
251
+ const raw_pts = data.points.filter((pt) => isFinite(pt.pos) && isFinite(pt.value))
252
+ if (raw_pts.length < 2) return base
253
+ // area fills (kde/cdf) read better lighter than histogram bars
254
+ base.fill_opacity = config.fill_opacity ?? 0.5
255
+ // For monotone, the monotonic axis is the position axis: x for top/bottom, y for left/right
256
+ const curve_name = config.curve ?? `monotone`
257
+ const curve_fn =
258
+ curve_name === `monotone`
259
+ ? is_x
260
+ ? curveMonotoneX
261
+ : curveMonotoneY
262
+ : line_curve_factory(curve_name)
263
+ // Position maps to x for top/bottom strips and to y for left/right strips; value is the
264
+ // cross-axis. The line generator is symmetric; the area differs only in which axis baselines.
265
+ const px = (pt: LinePt) => (is_x ? pos_scale(pt.pos) : val_scale(pt.value))
266
+ const py = (pt: LinePt) => (is_x ? val_scale(pt.value) : pos_scale(pt.pos))
267
+ // drop points whose scaled pixels are non-finite (degenerate/log scales) so the path stays
268
+ // valid — mirrors marginal_hit, which also skips non-finite scaled coords
269
+ const pts = raw_pts.filter((pt) => isFinite(px(pt)) && isFinite(py(pt)))
270
+ if (pts.length < 2) return base
271
+ const area_gen = is_x
272
+ ? area<LinePt>().x(px).y0(baseline).y1(py)
273
+ : area<LinePt>().y(py).x0(baseline).x1(px)
274
+ base.line_path = line<LinePt>().x(px).y(py).curve(curve_fn)(pts) ?? ``
275
+ base.area_path = area_gen.curve(curve_fn)(pts) ?? ``
276
+ return base
277
+ }
278
+
279
+ // rug: short ticks at each position, drawn from the plot-facing edge outward
280
+ const rug_len = Math.min(config.size, 10)
281
+ const dir = side === `top` || side === `left` ? -1 : 1
282
+ base.rug = data.positions
283
+ .map((p) => pos_scale(p))
284
+ .filter((px) => isFinite(px))
285
+ .map((px) =>
286
+ is_x
287
+ ? { x1: px, y1: baseline, x2: px, y2: baseline + dir * rug_len }
288
+ : { x1: baseline, y1: px, x2: baseline + dir * rug_len, y2: px },
289
+ )
290
+ // rug ticks are unfilled lines, so `opacity` (already config.opacity in base) controls them
291
+ return base
292
+ }
293
+
294
+ // Build the strip's value-axis (spine + a few value ticks + title), mirroring a regular axis:
295
+ // tick labels sit just OUTSIDE the spine (away from the strip's data) and the title sits beyond
296
+ // them. x-strips (top/bottom) read as a y-axis (vertical spine at the strip's left edge, labels
297
+ // to the left, rotated title); y-strips read as an x-axis (horizontal spine at the strip's bottom
298
+ // edge — which coincides with the host plot's x-axis baseline — labels below, title below them).
299
+ const build_value_axis = (
300
+ is_x: boolean,
301
+ rect: Rect,
302
+ val_scale: ScaleFn,
303
+ domain: Vec2,
304
+ config: ResolvedMarginalConfig,
305
+ ): ValueAxisRender => {
306
+ const fmt = marginal_value_format(config)
307
+ const title = default_marginal_label(config)
308
+ const [v0, v1] = [val_scale(domain[0]), val_scale(domain[1])] // spine ends in px
309
+ const gap = 6 // spine -> tick label
310
+ // value px + label per tick, minus non-finite and the baseline tick (v0, plot-facing edge):
311
+ // it's only `gap` px from the host plot's adjacent axis tick, so they'd overlap (e.g. a CDF
312
+ // `0%` over the plot's top y-tick). The spine still spans full range — zero edge implied.
313
+ const tick_px = d3_ticks(domain[0], domain[1], 3)
314
+ .map((value) => ({ vpx: val_scale(value), text: format_value(value, fmt) }))
315
+ .filter(({ vpx }) => isFinite(vpx) && Math.abs(vpx - v0) > 1)
316
+ if (is_x) {
317
+ // labels left of the spine (anchor end); title rotated beyond the widest label
318
+ const label_w = Math.max(0, ...tick_px.map(({ text }) => text.length)) * 6 // ~px at 0.65em
319
+ const ty = rect.y + rect.height / 2
320
+ const title_x = rect.x - gap - label_w - 10
321
+ return {
322
+ spine: { x1: rect.x, y1: v0, x2: rect.x, y2: v1 },
323
+ ticks: tick_px.map(({ vpx, text }) => ({ x: rect.x - gap, y: vpx, text })),
324
+ anchor: `end`,
325
+ baseline: `central`,
326
+ title: { x: title_x, y: ty, text: title, transform: `rotate(-90, ${title_x}, ${ty})` },
327
+ }
328
+ }
329
+ // value axis at the strip's BOTTOM edge (= host plot's x-axis baseline) so it reads as an
330
+ // extension of the main x-axis; labels hang below the spine, title below them
331
+ const axis_y = rect.y + rect.height
332
+ return {
333
+ spine: { x1: v0, y1: axis_y, x2: v1, y2: axis_y },
334
+ ticks: tick_px.map(({ vpx, text }) => ({ x: vpx, y: axis_y + gap, text })),
335
+ anchor: `middle`,
336
+ baseline: `hanging`,
337
+ title: { x: rect.x + rect.width / 2, y: axis_y + gap + 16, text: title },
338
+ }
339
+ }
340
+
341
+ // Compute the render model for every active side
342
+ const side_renders = $derived.by<SideRender[]>(() => {
343
+ if (!width || !height) return []
344
+ const visible = series.filter((srs) => srs.visible ?? true)
345
+ const out: SideRender[] = []
346
+
347
+ for (const side of MARGINAL_SIDES) {
348
+ const config = marginals[side]
349
+ if (!config) continue
350
+ const is_x = side === `top` || side === `bottom`
351
+ const axis = config.axis ?? default_axis_for_side(side)
352
+ const {
353
+ scale: pos_scale,
354
+ range: positional_range,
355
+ scale_type,
356
+ format,
357
+ tick_label,
358
+ label: axis_title,
359
+ } = axis_props(axis)
360
+ const rect = marginal_strip_rect(side, pad, width, height, config, has_axis[side])
361
+ if (rect.width <= 0 || rect.height <= 0) continue
362
+
363
+ const ctx_base = { config, side, positional_range, scale_type }
364
+
365
+ // Only summarize series that render on the axis this side binds to (a top/x1 marginal
366
+ // ignores x2 series; a right/y1 marginal ignores y2 series)
367
+ const axis_series = visible.filter((srs) =>
368
+ is_x ? (srs.x_axis ?? `x1`) === axis : (srs.y_axis ?? `y1`) === axis,
369
+ )
370
+ const merged_color = config.color ?? axis_series[0]?.color ?? `currentColor`
371
+ // One combined curve (for reduce / data / merged), colored once
372
+ const single = (curve: MarginalCurve): MarginalSeriesCurve[] => [
373
+ { series_idx: -1, color: merged_color, curve },
374
+ ]
375
+ const compute = (
376
+ pos: ArrayLike<number>,
377
+ wts: ArrayLike<number> | undefined,
378
+ ): MarginalCurve =>
379
+ compute_marginal_curve(pos, wts, config, positional_range, scale_type)
380
+
381
+ // Resolve which curves to draw (precedence: reduce > data > per-series > merged)
382
+ let curves: MarginalSeriesCurve[]
383
+ if (config.reduce) {
384
+ const { positions, weights } = merge_values(axis_series, is_x)
385
+ curves = single(config.reduce(positions, weights, ctx_base))
386
+ } else if (config.data) {
387
+ const values = typeof config.data === `function` ? config.data(ctx_base) : config.data
388
+ curves = single(compute(values, undefined))
389
+ } else if (config.per_series) {
390
+ curves = axis_series.map((srs, idx) => {
391
+ const { positions, weights } = series_values(srs, is_x)
392
+ return {
393
+ series_idx: idx,
394
+ color: srs.color,
395
+ label: srs.label,
396
+ curve: compute(positions, weights),
397
+ }
398
+ })
399
+ } else {
400
+ const { positions, weights } = merge_values(axis_series, is_x)
401
+ curves = single(compute(positions, weights))
402
+ }
403
+
404
+ // Shared per-side value scale so per-series curves are directly comparable. Auto-scale adds
405
+ // 5% headroom above the peak so the tallest curve's line stroke isn't clipped at the strip's
406
+ // far edge (the clip rect sits exactly at value=max). A pinned value_range is honored as-is.
407
+ const max = curves_max(curves.map((entry) => entry.curve))
408
+ const domain: Vec2 = config.value_range ?? [0, max * 1.05]
409
+ const { scale: val_scale, baseline } = marginal_value_scale(side, rect, domain)
410
+
411
+ const ctx: MarginalRenderContext = {
412
+ ...ctx_base,
413
+ rect,
414
+ positional_scale: pos_scale,
415
+ value_scale: val_scale,
416
+ baseline,
417
+ curves,
418
+ series: axis_series,
419
+ format,
420
+ tick_label,
421
+ axis_title,
422
+ }
423
+
424
+ out.push({
425
+ side,
426
+ config,
427
+ rect,
428
+ clip_id: `${id}-${side}`,
429
+ ctx,
430
+ // A snippet renders the strip itself, so skip building the built-in SVG primitives
431
+ curves: config.snippet
432
+ ? []
433
+ : curves.map((curve) =>
434
+ build_curve_render(curve, side, is_x, pos_scale, val_scale, baseline, config),
435
+ ),
436
+ // Value axis only when there's something to scale: a pinned value_range, or positive
437
+ // non-rug content (max > 0). This skips rug (no value), empty curves (degenerate [0,0]
438
+ // domain), and snippets (which draw their own).
439
+ value_axis:
440
+ config.value_axis && !config.snippet && (config.value_range != null || max > 0)
441
+ ? build_value_axis(is_x, rect, val_scale, domain, config)
442
+ : null,
443
+ })
444
+ }
445
+ return out
446
+ })
447
+ </script>
448
+
449
+ {#each side_renders as render (render.side)}
450
+ {@const { side, config, rect, clip_id, ctx, curves, value_axis } = render}
451
+ <defs>
452
+ <clipPath id={clip_id}>
453
+ <rect x={rect.x} y={rect.y} width={rect.width} height={rect.height} />
454
+ </clipPath>
455
+ </defs>
456
+ <g
457
+ class={[`marginal`, `marginal-${side}`, config.class]}
458
+ clip-path="url(#{clip_id})"
459
+ style={config.style}
460
+ >
461
+ {#if config.snippet}
462
+ {@render config.snippet(ctx)}
463
+ {:else}
464
+ {#each curves as curve, curve_idx (curve_idx)}
465
+ <!-- Discriminate on the actual curve kind so a custom `reduce`/`data` returning any
466
+ kind renders correctly (empty primitives simply render nothing) -->
467
+ {#if curve.kind === `bars`}
468
+ {#each curve.bars as bar, bar_idx (bar_idx)}
469
+ <rect
470
+ x={bar.x}
471
+ y={bar.y}
472
+ width={bar.width}
473
+ height={bar.height}
474
+ fill={curve.fill}
475
+ fill-opacity={curve.fill_opacity}
476
+ stroke={curve.stroke}
477
+ stroke-width={curve.stroke_width}
478
+ opacity={curve.opacity}
479
+ />
480
+ {/each}
481
+ {:else if curve.kind === `rug`}
482
+ {#each curve.rug as mark, mark_idx (mark_idx)}
483
+ <line
484
+ x1={mark.x1}
485
+ y1={mark.y1}
486
+ x2={mark.x2}
487
+ y2={mark.y2}
488
+ stroke={curve.stroke}
489
+ stroke-width={curve.stroke_width}
490
+ opacity={curve.opacity}
491
+ />
492
+ {/each}
493
+ {:else}
494
+ {#if curve.area_path}
495
+ <path
496
+ d={curve.area_path}
497
+ fill={curve.fill}
498
+ fill-opacity={curve.fill_opacity}
499
+ stroke="none"
500
+ opacity={curve.opacity}
501
+ />
502
+ {/if}
503
+ {#if curve.line_path}
504
+ <path
505
+ d={curve.line_path}
506
+ fill="none"
507
+ stroke={curve.stroke}
508
+ stroke-width={curve.stroke_width}
509
+ opacity={curve.opacity}
510
+ />
511
+ {/if}
512
+ {/if}
513
+ {/each}
514
+ {/if}
515
+ </g>
516
+ <!-- Value-axis (spine + ticks + title). Unclipped so the corner title isn't cut off. -->
517
+ {#if value_axis}
518
+ <g class={[`marginal-axis`, `marginal-axis-${side}`]}>
519
+ <line {...value_axis.spine} />
520
+ {#each value_axis.ticks as tick, tick_idx (tick_idx)}
521
+ <text
522
+ x={tick.x}
523
+ y={tick.y}
524
+ text-anchor={value_axis.anchor}
525
+ dominant-baseline={value_axis.baseline}>{tick.text}</text
526
+ >
527
+ {/each}
528
+ {#if value_axis.title.text}
529
+ <text
530
+ class="marginal-axis-title"
531
+ x={value_axis.title.x}
532
+ y={value_axis.title.y}
533
+ text-anchor="middle"
534
+ dominant-baseline="central"
535
+ transform={value_axis.title.transform}>{value_axis.title.text}</text
536
+ >
537
+ {/if}
538
+ </g>
539
+ {/if}
540
+ <!-- Transparent hit-rect for hover tooltips. Sits outside the pointer-events:none <g> (so it
541
+ opts back in) and only on built-in strips the user hasn't opted out of via hover:false.
542
+ stopPropagation keeps strip pointer/mouse moves from reaching the host plot's own
543
+ hover/pan-zoom handlers (avoids a double tooltip and accidental drag-from-strip). -->
544
+ {#if is_hoverable(config)}
545
+ <!-- svelte-ignore a11y_no_static_element_interactions -->
546
+ <rect
547
+ class={[`marginal-hit`, `marginal-hit-${side}`]}
548
+ x={rect.x}
549
+ y={rect.y}
550
+ width={rect.width}
551
+ height={rect.height}
552
+ fill="transparent"
553
+ style="pointer-events: all"
554
+ onpointermove={(event) => {
555
+ event.stopPropagation()
556
+ hovered = on_marginal_move(event, ctx)
557
+ }}
558
+ onpointerleave={() => (hovered = null)}
559
+ onmousemove={stop}
560
+ onpointerdown={stop}
561
+ onmousedown={stop}
562
+ />
563
+ {/if}
564
+ {/each}
565
+
566
+ <!-- Single shared hover tooltip for all strips. Rendered in a foreignObject HTML div that the
567
+ portal relocates to the plot wrapper (an svg can't host an HTML sibling), so it reuses the
568
+ same PlotTooltip, positioning, and z-index as each host plot's own tooltip. Only mounted when
569
+ some strip is actually hoverable (skips the empty portal on plots with no/snippet marginals). -->
570
+ {#if side_renders.some((render) => is_hoverable(render.config))}
571
+ <foreignObject width="0" height="0" style="overflow: visible">
572
+ <div
573
+ xmlns="http://www.w3.org/1999/xhtml"
574
+ style="display: contents"
575
+ {@attach portal_to_wrapper}
576
+ >
577
+ {#if hovered && tip}
578
+ <PlotTooltip
579
+ x={hovered.x}
580
+ y={hovered.y}
581
+ offset={{ x: 10, y: 5 }}
582
+ constrain_to={{ width, height }}
583
+ fallback_size={{ width: 120, height: 44 }}
584
+ bg_color={tip.bg_color}
585
+ >
586
+ {#if tip.snippet}
587
+ {@render tip.snippet(hovered)}
588
+ {:else}
589
+ <!-- contiguous (no source whitespace) so rows don't pick up stray leading spaces;
590
+ head_label is pre-sanitized @html so an axis title with markup renders, while the
591
+ value/category portion stays literal text -->
592
+ {#if tip.label}<strong>{tip.label}</strong><br />{/if}{@html tip.head_label}: {tip.head_value}{#if tip.value}<br
593
+ />{tip.value}{/if}
594
+ {/if}
595
+ </PlotTooltip>
596
+ {/if}
597
+ </div>
598
+ </foreignObject>
599
+ {/if}
600
+
601
+ <style>
602
+ .marginal,
603
+ .marginal-axis {
604
+ pointer-events: none;
605
+ }
606
+ .marginal-axis line {
607
+ stroke: var(--border-color, gray);
608
+ }
609
+ .marginal-axis text {
610
+ fill: var(--text-color);
611
+ font-size: var(--marginal-axis-font-size, 0.65em);
612
+ }
613
+ .marginal-axis-title {
614
+ font-size: var(--marginal-axis-title-font-size, 0.75em);
615
+ }
616
+ </style>
@@ -0,0 +1,15 @@
1
+ import type { Sides } from '../layout';
2
+ import type { MarginalAxes, MarginalSeriesInput, MarginalSide, ResolvedMarginals } from '../marginals';
3
+ type $$ComponentProps = {
4
+ marginals: ResolvedMarginals;
5
+ series: MarginalSeriesInput[];
6
+ width: number;
7
+ height: number;
8
+ pad: Required<Sides>;
9
+ has_axis?: Record<MarginalSide, boolean>;
10
+ axes: MarginalAxes;
11
+ id: string;
12
+ };
13
+ declare const PlotMarginals: import("svelte").Component<$$ComponentProps, {}, "">;
14
+ type PlotMarginals = ReturnType<typeof PlotMarginals>;
15
+ export default PlotMarginals;
@@ -63,7 +63,7 @@
63
63
 
64
64
  <div
65
65
  {...rest}
66
- class="plot-tooltip {rest.class ?? ``}"
66
+ class={[`plot-tooltip`, rest.class]}
67
67
  style:background-color={bg_color}
68
68
  style:color={text_color}
69
69
  {style}
@@ -14,9 +14,7 @@
14
14
  selected_key = $bindable(),
15
15
  on_select,
16
16
  disabled = false,
17
- format_option = (
18
- opt: Option,
19
- ) => (opt.unit ? `${opt.label} (${opt.unit})` : opt.label),
17
+ format_option = (opt: Option) => (opt.unit ? `${opt.label} (${opt.unit})` : opt.label),
20
18
  ...rest
21
19
  }: Omit<HTMLButtonAttributes, `onclick`> & {
22
20
  options: Option[]
@@ -59,11 +57,9 @@
59
57
  // Inline styles for portal elements (can't use scoped CSS for elements in document.body)
60
58
  const portal_styles = {
61
59
  container: `position: fixed; transform: translateX(-50%); z-index: 10000;`,
62
- ul:
63
- `margin: 0; padding: 0; list-style: none; background: var(--dropdown-bg, white); border: 1px solid var(--dropdown-border, #ccc); border-radius: 4px; box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15); min-width: max-content; max-height: 300px; overflow-y: auto; font-size: 14px;`,
60
+ ul: `margin: 0; padding: 0; list-style: none; background: var(--dropdown-bg, white); border: 1px solid var(--dropdown-border, #ccc); border-radius: 4px; box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15); min-width: max-content; max-height: 300px; overflow-y: auto; font-size: 14px;`,
64
61
  li: `margin: 0;`,
65
- btn:
66
- `display: block; width: 100%; padding: var(--dropdown-padding-v, 3px) var(--dropdown-padding-h, 10px); border: none; background: transparent; font: inherit; color: var(--dropdown-color, black); text-align: left; cursor: pointer; white-space: nowrap;`,
62
+ btn: `display: block; width: 100%; padding: var(--dropdown-padding-v, 3px) var(--dropdown-padding-h, 10px); border: none; background: transparent; font: inherit; color: var(--dropdown-color, black); text-align: left; cursor: pointer; white-space: nowrap;`,
67
63
  btn_selected: `font-weight: 500; background: rgba(0, 100, 200, 0.15);`,
68
64
  }
69
65
 
@@ -206,7 +202,7 @@
206
202
  aria-expanded={dropdown_open}
207
203
  aria-haspopup="listbox"
208
204
  {...rest}
209
- class="portal-select-trigger {rest.class ?? ``}"
205
+ class={[`portal-select-trigger`, rest.class]}
210
206
  >
211
207
  {@html sanitize_html(format_option(selected_option))}
212
208
  <span class="arrow">▾</span>