matterviz 0.3.7 → 0.4.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 (324) hide show
  1. package/dist/Icon.svelte +7 -4
  2. package/dist/MillerIndexInput.svelte +1 -1
  3. package/dist/api/optimade.js +32 -26
  4. package/dist/app.css +0 -3
  5. package/dist/brillouin/BrillouinZone.svelte +8 -3
  6. package/dist/brillouin/BrillouinZone.svelte.d.ts +2 -1
  7. package/dist/brillouin/BrillouinZoneScene.svelte +52 -6
  8. package/dist/brillouin/BrillouinZoneScene.svelte.d.ts +1 -0
  9. package/dist/brillouin/BrillouinZoneTooltip.svelte +16 -25
  10. package/dist/brillouin/compute.js +10 -14
  11. package/dist/chempot-diagram/ChemPotDiagram.svelte +14 -13
  12. package/dist/chempot-diagram/ChemPotDiagram2D.svelte +12 -15
  13. package/dist/chempot-diagram/ChemPotDiagram3D.svelte +8 -10
  14. package/dist/chempot-diagram/async-compute.svelte.js +3 -1
  15. package/dist/chempot-diagram/chempot-worker.js +2 -1
  16. package/dist/chempot-diagram/compute.d.ts +1 -1
  17. package/dist/chempot-diagram/compute.js +17 -19
  18. package/dist/colors/index.js +6 -5
  19. package/dist/composition/FormulaFilter.svelte +12 -6
  20. package/dist/composition/PieChart.svelte +6 -5
  21. package/dist/composition/chem-sys.d.ts +8 -0
  22. package/dist/composition/chem-sys.js +85 -0
  23. package/dist/composition/format.js +4 -2
  24. package/dist/composition/index.d.ts +1 -0
  25. package/dist/composition/index.js +1 -0
  26. package/dist/composition/parse.js +25 -13
  27. package/dist/convex-hull/ConvexHull2D.svelte +12 -10
  28. package/dist/convex-hull/ConvexHull3D.svelte +5 -5
  29. package/dist/convex-hull/ConvexHull4D.svelte +5 -9
  30. package/dist/convex-hull/ConvexHullStats.svelte +12 -12
  31. package/dist/convex-hull/GasPressureControls.svelte +4 -4
  32. package/dist/convex-hull/TemperatureSlider.svelte +2 -2
  33. package/dist/convex-hull/demo-temperature.d.ts +1 -1
  34. package/dist/convex-hull/demo-temperature.js +20 -22
  35. package/dist/convex-hull/gas-thermodynamics.d.ts +2 -2
  36. package/dist/convex-hull/gas-thermodynamics.js +22 -30
  37. package/dist/convex-hull/helpers.d.ts +3 -0
  38. package/dist/convex-hull/helpers.js +17 -9
  39. package/dist/convex-hull/index.d.ts +1 -1
  40. package/dist/convex-hull/thermodynamics.js +83 -78
  41. package/dist/convex-hull/types.d.ts +1 -1
  42. package/dist/coordination/CoordinationBarPlot.svelte +23 -23
  43. package/dist/coordination/CoordinationBarPlot.svelte.d.ts +1 -1
  44. package/dist/element/ElementTile.svelte.d.ts +1 -1
  45. package/dist/fermi-surface/FermiSlice.svelte +13 -5
  46. package/dist/fermi-surface/FermiSurface.svelte +11 -5
  47. package/dist/fermi-surface/FermiSurface.svelte.d.ts +1 -1
  48. package/dist/fermi-surface/FermiSurfaceControls.svelte +1 -1
  49. package/dist/fermi-surface/FermiSurfaceScene.svelte +3 -0
  50. package/dist/fermi-surface/FermiSurfaceTooltip.svelte +8 -34
  51. package/dist/fermi-surface/compute.js +59 -59
  52. package/dist/fermi-surface/export.js +3 -2
  53. package/dist/fermi-surface/parse.js +7 -4
  54. package/dist/fermi-surface/types.d.ts +1 -0
  55. package/dist/heatmap-matrix/HeatmapMatrix.svelte +23 -21
  56. package/dist/heatmap-matrix/index.js +1 -1
  57. package/dist/io/decompress.js +4 -2
  58. package/dist/io/export.d.ts +4 -4
  59. package/dist/io/export.js +47 -25
  60. package/dist/io/fetch.js +5 -1
  61. package/dist/io/file-drop.d.ts +1 -1
  62. package/dist/io/file-drop.js +35 -36
  63. package/dist/io/url-drop.js +64 -33
  64. package/dist/isosurface/parse.js +6 -7
  65. package/dist/isosurface/slice.js +5 -4
  66. package/dist/isosurface/types.js +1 -1
  67. package/dist/keyboard.d.ts +3 -0
  68. package/dist/keyboard.js +23 -0
  69. package/dist/labels.d.ts +1 -1
  70. package/dist/labels.js +8 -7
  71. package/dist/layout/PropertyFilter.svelte +3 -2
  72. package/dist/layout/SettingsSection.svelte +1 -1
  73. package/dist/layout/json-tree/JsonNode.svelte +1 -1
  74. package/dist/layout/json-tree/JsonTree.svelte +2 -2
  75. package/dist/layout/json-tree/utils.js +5 -4
  76. package/dist/marching-cubes.js +8 -13
  77. package/dist/math.d.ts +5 -1
  78. package/dist/math.js +24 -9
  79. package/dist/overlays/DraggablePane.svelte +4 -4
  80. package/dist/periodic-table/PeriodicTable.svelte +20 -9
  81. package/dist/periodic-table/PropertySelect.svelte +1 -0
  82. package/dist/phase-diagram/IsobaricBinaryPhaseDiagram.svelte +9 -3
  83. package/dist/phase-diagram/IsobaricBinaryPhaseDiagram.svelte.d.ts +1 -1
  84. package/dist/phase-diagram/PhaseDiagramControls.svelte.d.ts +1 -1
  85. package/dist/phase-diagram/PhaseDiagramEditorPane.svelte +2 -1
  86. package/dist/phase-diagram/PhaseDiagramTooltip.svelte +1 -1
  87. package/dist/phase-diagram/build-diagram.js +2 -2
  88. package/dist/phase-diagram/parse.js +6 -5
  89. package/dist/phase-diagram/types.d.ts +1 -1
  90. package/dist/phase-diagram/utils.d.ts +3 -3
  91. package/dist/phase-diagram/utils.js +8 -12
  92. package/dist/plot/{BarPlot.svelte → bar/BarPlot.svelte} +229 -587
  93. package/dist/plot/{BarPlot.svelte.d.ts → bar/BarPlot.svelte.d.ts} +5 -5
  94. package/dist/plot/{BarPlotControls.svelte → bar/BarPlotControls.svelte} +6 -5
  95. package/dist/plot/{BarPlotControls.svelte.d.ts → bar/BarPlotControls.svelte.d.ts} +3 -3
  96. package/dist/plot/{SpacegroupBarPlot.svelte → bar/SpacegroupBarPlot.svelte} +6 -6
  97. package/dist/plot/{SpacegroupBarPlot.svelte.d.ts → bar/SpacegroupBarPlot.svelte.d.ts} +1 -1
  98. package/dist/plot/bar/data.d.ts +40 -0
  99. package/dist/plot/bar/data.js +154 -0
  100. package/dist/plot/bar/geometry.d.ts +39 -0
  101. package/dist/plot/bar/geometry.js +60 -0
  102. package/dist/plot/bar/index.d.ts +3 -0
  103. package/dist/plot/bar/index.js +3 -0
  104. package/dist/plot/box/BoxPlot.svelte +1462 -0
  105. package/dist/plot/box/BoxPlot.svelte.d.ts +94 -0
  106. package/dist/plot/box/BoxPlotControls.svelte +109 -0
  107. package/dist/plot/box/BoxPlotControls.svelte.d.ts +19 -0
  108. package/dist/plot/box/Violin.svelte +14 -0
  109. package/dist/plot/box/Violin.svelte.d.ts +70 -0
  110. package/dist/plot/box/box-plot.d.ts +55 -0
  111. package/dist/plot/box/box-plot.js +126 -0
  112. package/dist/plot/box/index.d.ts +5 -0
  113. package/dist/plot/box/index.js +5 -0
  114. package/dist/plot/box/kde.d.ts +16 -0
  115. package/dist/plot/box/kde.js +160 -0
  116. package/dist/plot/box/quantile.d.ts +3 -0
  117. package/dist/plot/box/quantile.js +53 -0
  118. package/dist/plot/{auto-place.js → core/auto-place.js} +2 -2
  119. package/dist/plot/core/axis-utils.d.ts +46 -0
  120. package/dist/plot/core/axis-utils.js +110 -0
  121. package/dist/plot/{AxisLabel.svelte → core/components/AxisLabel.svelte} +2 -2
  122. package/dist/plot/{AxisLabel.svelte.d.ts → core/components/AxisLabel.svelte.d.ts} +1 -1
  123. package/dist/plot/{ColorBar.svelte → core/components/ColorBar.svelte} +36 -33
  124. package/dist/plot/{ColorBar.svelte.d.ts → core/components/ColorBar.svelte.d.ts} +2 -2
  125. package/dist/plot/{ColorScaleSelect.svelte → core/components/ColorScaleSelect.svelte} +4 -3
  126. package/dist/plot/{ColorScaleSelect.svelte.d.ts → core/components/ColorScaleSelect.svelte.d.ts} +2 -2
  127. package/dist/plot/core/components/ControlPane.svelte +46 -0
  128. package/dist/plot/core/components/ControlPane.svelte.d.ts +13 -0
  129. package/dist/plot/{FillArea.svelte → core/components/FillArea.svelte} +17 -6
  130. package/dist/plot/{FillArea.svelte.d.ts → core/components/FillArea.svelte.d.ts} +1 -1
  131. package/dist/plot/{InteractiveAxisLabel.svelte → core/components/InteractiveAxisLabel.svelte} +3 -3
  132. package/dist/plot/{InteractiveAxisLabel.svelte.d.ts → core/components/InteractiveAxisLabel.svelte.d.ts} +2 -2
  133. package/dist/plot/{Line.svelte → core/components/Line.svelte} +30 -13
  134. package/dist/plot/{PlotAxis.svelte → core/components/PlotAxis.svelte} +7 -5
  135. package/dist/plot/{PlotAxis.svelte.d.ts → core/components/PlotAxis.svelte.d.ts} +3 -2
  136. package/dist/plot/{PlotControls.svelte → core/components/PlotControls.svelte} +17 -29
  137. package/dist/plot/core/components/PlotControls.svelte.d.ts +4 -0
  138. package/dist/plot/{PlotLegend.svelte → core/components/PlotLegend.svelte} +21 -10
  139. package/dist/plot/{PlotLegend.svelte.d.ts → core/components/PlotLegend.svelte.d.ts} +3 -2
  140. package/dist/plot/{PlotTooltip.svelte → core/components/PlotTooltip.svelte} +17 -1
  141. package/dist/plot/{PlotTooltip.svelte.d.ts → core/components/PlotTooltip.svelte.d.ts} +8 -0
  142. package/dist/plot/{PortalSelect.svelte → core/components/PortalSelect.svelte} +11 -7
  143. package/dist/plot/{ReferenceLine.svelte → core/components/ReferenceLine.svelte} +3 -3
  144. package/dist/plot/{ReferenceLine.svelte.d.ts → core/components/ReferenceLine.svelte.d.ts} +1 -1
  145. package/dist/plot/{ReferenceLine3D.svelte → core/components/ReferenceLine3D.svelte} +4 -4
  146. package/dist/plot/{ReferenceLine3D.svelte.d.ts → core/components/ReferenceLine3D.svelte.d.ts} +2 -2
  147. package/dist/plot/{ReferencePlane.svelte → core/components/ReferencePlane.svelte} +7 -7
  148. package/dist/plot/{ReferencePlane.svelte.d.ts → core/components/ReferencePlane.svelte.d.ts} +2 -2
  149. package/dist/plot/{ZeroLines.svelte → core/components/ZeroLines.svelte} +3 -3
  150. package/dist/plot/{ZeroLines.svelte.d.ts → core/components/ZeroLines.svelte.d.ts} +3 -3
  151. package/dist/plot/{ZoomRect.svelte → core/components/ZoomRect.svelte} +1 -1
  152. package/dist/plot/{ZoomRect.svelte.d.ts → core/components/ZoomRect.svelte.d.ts} +1 -1
  153. package/dist/plot/core/components/index.d.ts +17 -0
  154. package/dist/plot/core/components/index.js +17 -0
  155. package/dist/plot/{data-cleaning.d.ts → core/data-cleaning.d.ts} +71 -1
  156. package/dist/plot/{data-cleaning.js → core/data-cleaning.js} +3 -5
  157. package/dist/plot/{data-transform.d.ts → core/data-transform.d.ts} +2 -2
  158. package/dist/plot/{data-transform.js → core/data-transform.js} +3 -3
  159. package/dist/plot/core/fill-utils.d.ts +33 -0
  160. package/dist/plot/core/fill-utils.js +388 -0
  161. package/dist/plot/{hover-lock.svelte.js → core/hover-lock.svelte.js} +5 -6
  162. package/dist/plot/core/index.d.ts +10 -0
  163. package/dist/plot/core/index.js +11 -0
  164. package/dist/plot/core/interactions.d.ts +35 -0
  165. package/dist/plot/core/interactions.js +195 -0
  166. package/dist/plot/{layout.d.ts → core/layout.d.ts} +1 -0
  167. package/dist/plot/{layout.js → core/layout.js} +16 -8
  168. package/dist/plot/{reference-line.d.ts → core/reference-line.d.ts} +1 -1
  169. package/dist/plot/{reference-line.js → core/reference-line.js} +23 -36
  170. package/dist/plot/{scales.d.ts → core/scales.d.ts} +2 -2
  171. package/dist/plot/{scales.js → core/scales.js} +84 -85
  172. package/dist/plot/core/svg.d.ts +2 -0
  173. package/dist/plot/core/svg.js +41 -0
  174. package/dist/plot/{types.d.ts → core/types.d.ts} +19 -79
  175. package/dist/plot/{types.js → core/types.js} +1 -1
  176. package/dist/plot/{utils → core/utils}/label-placement.d.ts +2 -2
  177. package/dist/plot/core/utils/series-visibility.d.ts +26 -0
  178. package/dist/plot/{utils → core/utils}/series-visibility.js +29 -2
  179. package/dist/plot/core/utils.d.ts +11 -0
  180. package/dist/plot/core/utils.js +27 -0
  181. package/dist/plot/{Histogram.svelte → histogram/Histogram.svelte} +154 -294
  182. package/dist/plot/{Histogram.svelte.d.ts → histogram/Histogram.svelte.d.ts} +2 -2
  183. package/dist/plot/{HistogramControls.svelte → histogram/HistogramControls.svelte} +6 -6
  184. package/dist/plot/{HistogramControls.svelte.d.ts → histogram/HistogramControls.svelte.d.ts} +4 -4
  185. package/dist/plot/histogram/index.d.ts +2 -0
  186. package/dist/plot/histogram/index.js +2 -0
  187. package/dist/plot/index.d.ts +8 -41
  188. package/dist/plot/index.js +10 -39
  189. package/dist/plot/sankey/Sankey.svelte +700 -0
  190. package/dist/plot/sankey/Sankey.svelte.d.ts +74 -0
  191. package/dist/plot/sankey/SankeyControls.svelte +98 -0
  192. package/dist/plot/sankey/SankeyControls.svelte.d.ts +19 -0
  193. package/dist/plot/sankey/index.d.ts +4 -0
  194. package/dist/plot/sankey/index.js +3 -0
  195. package/dist/plot/sankey/sankey-types.d.ts +42 -0
  196. package/dist/plot/sankey/sankey-types.js +4 -0
  197. package/dist/plot/sankey/sankey.d.ts +52 -0
  198. package/dist/plot/sankey/sankey.js +187 -0
  199. package/dist/plot/{BinnedScatterPlot.svelte → scatter/BinnedScatterPlot.svelte} +61 -59
  200. package/dist/plot/{BinnedScatterPlot.svelte.d.ts → scatter/BinnedScatterPlot.svelte.d.ts} +4 -4
  201. package/dist/plot/{ElementScatter.svelte → scatter/ElementScatter.svelte} +6 -6
  202. package/dist/plot/{ElementScatter.svelte.d.ts → scatter/ElementScatter.svelte.d.ts} +2 -2
  203. package/dist/plot/{ScatterPlot.svelte → scatter/ScatterPlot.svelte} +221 -642
  204. package/dist/plot/{ScatterPlot.svelte.d.ts → scatter/ScatterPlot.svelte.d.ts} +7 -7
  205. package/dist/plot/{ScatterPlotControls.svelte → scatter/ScatterPlotControls.svelte} +6 -5
  206. package/dist/plot/{ScatterPlotControls.svelte.d.ts → scatter/ScatterPlotControls.svelte.d.ts} +1 -1
  207. package/dist/plot/{ScatterPoint.svelte → scatter/ScatterPoint.svelte} +7 -7
  208. package/dist/plot/{ScatterPoint.svelte.d.ts → scatter/ScatterPoint.svelte.d.ts} +3 -3
  209. package/dist/plot/{adaptive-density.d.ts → scatter/adaptive-density.d.ts} +14 -4
  210. package/dist/plot/{adaptive-density.js → scatter/adaptive-density.js} +46 -20
  211. package/dist/plot/{binned-scatter-types.d.ts → scatter/binned-scatter-types.d.ts} +3 -3
  212. package/dist/plot/scatter/index.d.ts +7 -0
  213. package/dist/plot/scatter/index.js +5 -0
  214. package/dist/plot/scatter/scatter-data.d.ts +19 -0
  215. package/dist/plot/scatter/scatter-data.js +212 -0
  216. package/dist/plot/{ScatterPlot3D.svelte → scatter-3d/ScatterPlot3D.svelte} +12 -10
  217. package/dist/plot/{ScatterPlot3D.svelte.d.ts → scatter-3d/ScatterPlot3D.svelte.d.ts} +7 -7
  218. package/dist/plot/{ScatterPlot3DControls.svelte → scatter-3d/ScatterPlot3DControls.svelte} +5 -4
  219. package/dist/plot/{ScatterPlot3DControls.svelte.d.ts → scatter-3d/ScatterPlot3DControls.svelte.d.ts} +2 -2
  220. package/dist/plot/{ScatterPlot3DScene.svelte → scatter-3d/ScatterPlot3DScene.svelte} +11 -11
  221. package/dist/plot/{ScatterPlot3DScene.svelte.d.ts → scatter-3d/ScatterPlot3DScene.svelte.d.ts} +3 -3
  222. package/dist/plot/{Surface3D.svelte → scatter-3d/Surface3D.svelte} +1 -1
  223. package/dist/plot/{Surface3D.svelte.d.ts → scatter-3d/Surface3D.svelte.d.ts} +1 -1
  224. package/dist/plot/scatter-3d/index.d.ts +4 -0
  225. package/dist/plot/scatter-3d/index.js +4 -0
  226. package/dist/plot/sunburst/Sunburst.svelte +1045 -0
  227. package/dist/plot/sunburst/Sunburst.svelte.d.ts +96 -0
  228. package/dist/plot/sunburst/SunburstControls.svelte +200 -0
  229. package/dist/plot/sunburst/SunburstControls.svelte.d.ts +26 -0
  230. package/dist/plot/sunburst/index.d.ts +4 -0
  231. package/dist/plot/sunburst/index.js +4 -0
  232. package/dist/plot/sunburst/render.d.ts +34 -0
  233. package/dist/plot/sunburst/render.js +122 -0
  234. package/dist/plot/sunburst/sunburst.d.ts +62 -0
  235. package/dist/plot/sunburst/sunburst.js +266 -0
  236. package/dist/rdf/RdfPlot.svelte +2 -1
  237. package/dist/rdf/calc-rdf.js +11 -24
  238. package/dist/sanitize.js +1 -1
  239. package/dist/settings.d.ts +65 -1
  240. package/dist/settings.js +262 -0
  241. package/dist/spectral/Bands.svelte +39 -29
  242. package/dist/spectral/Bands.svelte.d.ts +3 -4
  243. package/dist/spectral/BandsAndDos.svelte +1 -1
  244. package/dist/spectral/BrillouinBandsDos.svelte +39 -27
  245. package/dist/spectral/Dos.svelte +10 -19
  246. package/dist/spectral/Dos.svelte.d.ts +2 -2
  247. package/dist/spectral/helpers.d.ts +3 -1
  248. package/dist/spectral/helpers.js +95 -29
  249. package/dist/structure/AtomLegend.svelte +8 -9
  250. package/dist/structure/CellSelect.svelte +1 -2
  251. package/dist/structure/Cylinder.svelte +12 -8
  252. package/dist/structure/Cylinder.svelte.d.ts +4 -1
  253. package/dist/structure/Structure.svelte +78 -72
  254. package/dist/structure/Structure.svelte.d.ts +1 -1
  255. package/dist/structure/StructureInfoPane.svelte +5 -6
  256. package/dist/structure/StructureScene.svelte +11 -10
  257. package/dist/structure/atom-properties.js +6 -6
  258. package/dist/structure/bond-order-perception.js +1 -1
  259. package/dist/structure/bonding.d.ts +1 -0
  260. package/dist/structure/bonding.js +43 -15
  261. package/dist/structure/export.js +27 -23
  262. package/dist/structure/index.d.ts +2 -4
  263. package/dist/structure/index.js +1 -3
  264. package/dist/structure/label-placement.js +4 -4
  265. package/dist/structure/measure.d.ts +3 -2
  266. package/dist/structure/measure.js +6 -5
  267. package/dist/structure/parse.js +121 -103
  268. package/dist/structure/pbc.js +4 -0
  269. package/dist/symmetry/SymmetryStats.svelte +2 -2
  270. package/dist/symmetry/index.d.ts +1 -1
  271. package/dist/symmetry/index.js +22 -24
  272. package/dist/symmetry/spacegroups.d.ts +7 -0
  273. package/dist/symmetry/spacegroups.js +48 -13
  274. package/dist/table/HeatmapTable.svelte +63 -11
  275. package/dist/table/HeatmapTable.svelte.d.ts +1 -1
  276. package/dist/table/index.d.ts +1 -3
  277. package/dist/table/index.js +1 -1
  278. package/dist/theme/index.js +8 -8
  279. package/dist/tooltip/KCoords.svelte +45 -0
  280. package/dist/tooltip/KCoords.svelte.d.ts +8 -0
  281. package/dist/tooltip/index.d.ts +1 -0
  282. package/dist/tooltip/index.js +1 -0
  283. package/dist/trajectory/Trajectory.svelte +66 -40
  284. package/dist/trajectory/Trajectory.svelte.d.ts +2 -1
  285. package/dist/trajectory/TrajectoryExportPane.svelte +2 -1
  286. package/dist/trajectory/TrajectoryInfoPane.svelte +2 -1
  287. package/dist/trajectory/format-detect.d.ts +1 -0
  288. package/dist/trajectory/format-detect.js +25 -11
  289. package/dist/trajectory/frame-reader.js +17 -50
  290. package/dist/trajectory/helpers.js +1 -1
  291. package/dist/trajectory/index.js +1 -1
  292. package/dist/trajectory/parse/hdf5.js +1 -1
  293. package/dist/trajectory/parse/index.js +14 -6
  294. package/dist/trajectory/parse/vasp.js +36 -17
  295. package/dist/trajectory/parse/xyz.d.ts +24 -0
  296. package/dist/trajectory/parse/xyz.js +102 -89
  297. package/dist/trajectory/plotting.d.ts +1 -1
  298. package/dist/trajectory/plotting.js +15 -15
  299. package/dist/utils.d.ts +1 -0
  300. package/dist/utils.js +6 -4
  301. package/dist/xrd/XrdPlot.svelte +2 -1
  302. package/dist/xrd/calc-xrd.js +15 -12
  303. package/dist/xrd/parse.js +2 -2
  304. package/package.json +22 -18
  305. package/dist/plot/PlotControls.svelte.d.ts +0 -4
  306. package/dist/plot/axis-utils.d.ts +0 -19
  307. package/dist/plot/axis-utils.js +0 -78
  308. package/dist/plot/defaults.d.ts +0 -19
  309. package/dist/plot/defaults.js +0 -9
  310. package/dist/plot/fill-utils.d.ts +0 -46
  311. package/dist/plot/fill-utils.js +0 -322
  312. package/dist/plot/interactions.d.ts +0 -12
  313. package/dist/plot/interactions.js +0 -101
  314. package/dist/plot/svg.d.ts +0 -1
  315. package/dist/plot/svg.js +0 -11
  316. package/dist/plot/utils/series-visibility.d.ts +0 -15
  317. package/dist/plot/utils.d.ts +0 -1
  318. package/dist/plot/utils.js +0 -14
  319. /package/dist/plot/{auto-place.d.ts → core/auto-place.d.ts} +0 -0
  320. /package/dist/plot/{Line.svelte.d.ts → core/components/Line.svelte.d.ts} +0 -0
  321. /package/dist/plot/{PortalSelect.svelte.d.ts → core/components/PortalSelect.svelte.d.ts} +0 -0
  322. /package/dist/plot/{hover-lock.svelte.d.ts → core/hover-lock.svelte.d.ts} +0 -0
  323. /package/dist/plot/{utils → core/utils}/label-placement.js +0 -0
  324. /package/dist/plot/{binned-scatter-types.js → scatter/binned-scatter-types.js} +0 -0
@@ -0,0 +1,700 @@
1
+ <script
2
+ lang="ts"
3
+ generics="Metadata extends Record<string, unknown> = Record<string, unknown>"
4
+ >
5
+ import { format_value } from '../../labels'
6
+ import { FullscreenToggle, set_fullscreen_bg } from '../../layout'
7
+ import type {
8
+ BasePlotProps,
9
+ LegendConfig,
10
+ LegendItem,
11
+ SankeyData,
12
+ SankeyHandlerProps,
13
+ SankeyLinkColorMode,
14
+ SankeyLinkHandlerProps,
15
+ SankeyNodeAlign,
16
+ SankeyNodeHandlerProps,
17
+ SankeyOrientation,
18
+ } from '..'
19
+ import { DEFAULT_SERIES_COLORS, PlotLegend, PlotTooltip, SankeyControls } from '..'
20
+ import { closest_data_idx } from '../core/interactions'
21
+ import { compute_element_placement, constrain_tooltip_position, filter_padding } from '../core/layout'
22
+ import type { Sides } from '../core/layout'
23
+ import {
24
+ compute_sankey_layout,
25
+ type PositionedLink,
26
+ type PositionedNode,
27
+ } from './sankey'
28
+ import { unique_id } from '../core/utils'
29
+ import { DEFAULTS } from '../../settings'
30
+ import { type Snippet, untrack } from 'svelte'
31
+ import type { HTMLAttributes } from 'svelte/elements'
32
+ import { SvelteSet } from 'svelte/reactivity'
33
+
34
+ const DEFAULT_PADDING: Required<Sides> = { t: 20, b: 20, l: 10, r: 10 }
35
+
36
+ let {
37
+ data = $bindable({ nodes: [], links: [] }),
38
+ orientation = $bindable(DEFAULTS.sankey.orientation),
39
+ node_width = $bindable(DEFAULTS.sankey.node_width),
40
+ node_padding = $bindable(DEFAULTS.sankey.node_padding),
41
+ node_align = $bindable(DEFAULTS.sankey.node_align),
42
+ iterations = DEFAULTS.sankey.iterations,
43
+ link_opacity = $bindable(DEFAULTS.sankey.link_opacity),
44
+ link_color_mode = `source`,
45
+ show_node_labels = $bindable(DEFAULTS.sankey.show_node_labels),
46
+ node_label,
47
+ value_format = `,`,
48
+ padding = DEFAULT_PADDING,
49
+ legend = {},
50
+ show_legend = false,
51
+ tooltip,
52
+ node_content,
53
+ link_content,
54
+ hovered = $bindable(false),
55
+ change = () => {},
56
+ on_node_click,
57
+ on_node_hover,
58
+ on_link_click,
59
+ on_link_hover,
60
+ show_controls = $bindable(true),
61
+ controls_open = $bindable(false),
62
+ controls_toggle_props,
63
+ controls_pane_props,
64
+ fullscreen = $bindable(false),
65
+ fullscreen_toggle = true,
66
+ children,
67
+ header_controls,
68
+ controls_extra,
69
+ ...rest
70
+ }: HTMLAttributes<HTMLDivElement> & Omit<BasePlotProps, `change`> & {
71
+ data?: SankeyData<Metadata>
72
+ orientation?: SankeyOrientation
73
+ node_width?: number
74
+ node_padding?: number
75
+ node_align?: SankeyNodeAlign
76
+ iterations?: number
77
+ link_opacity?: number
78
+ link_color_mode?: SankeyLinkColorMode
79
+ show_node_labels?: boolean
80
+ node_label?: (node: PositionedNode) => string
81
+ value_format?: string
82
+ padding?: Sides
83
+ legend?: LegendConfig | null
84
+ show_legend?: boolean
85
+ tooltip?: Snippet<[SankeyHandlerProps<Metadata>]>
86
+ // Fully replace the default node rect / link ribbon. NOTE: this also replaces the
87
+ // built-in hover/focus/click + tooltip wiring, so re-implement any interactivity
88
+ // you need inside the snippet.
89
+ node_content?: Snippet<[{ node: PositionedNode; color: string }]>
90
+ link_content?: Snippet<[{ link: PositionedLink; color: string }]>
91
+ change?: (data: SankeyHandlerProps<Metadata> | null) => void
92
+ on_node_click?: (
93
+ data: SankeyNodeHandlerProps<Metadata> & { event: MouseEvent | KeyboardEvent },
94
+ ) => void
95
+ on_node_hover?: (
96
+ data:
97
+ | (SankeyNodeHandlerProps<Metadata> & { event: MouseEvent | FocusEvent })
98
+ | null,
99
+ ) => void
100
+ on_link_click?: (
101
+ data: SankeyLinkHandlerProps<Metadata> & { event: MouseEvent | KeyboardEvent },
102
+ ) => void
103
+ on_link_hover?: (
104
+ data:
105
+ | (SankeyLinkHandlerProps<Metadata> & { event: MouseEvent | FocusEvent })
106
+ | null,
107
+ ) => void
108
+ header_controls?: Snippet<[{ height: number; width: number; fullscreen: boolean }]>
109
+ controls_extra?: Snippet<[{ orientation: SankeyOrientation }]>
110
+ } = $props()
111
+
112
+ let [width, height] = $state([0, 0])
113
+ let wrapper: HTMLDivElement | undefined = $state()
114
+ let svg_element: SVGSVGElement | null = $state(null)
115
+ let tooltip_el = $state<HTMLDivElement | undefined>()
116
+ // Unique per-instance prefix for gradient ids (collision-resistant, see unique_id)
117
+ const uid = unique_id(`sankey`)
118
+
119
+ let hovered_node = $state<number | null>(null)
120
+ let hovered_link = $state<number | null>(null)
121
+ let hover_info = $state<SankeyHandlerProps<Metadata> | null>(null)
122
+ let hover_pos = $state<{ x: number; y: number }>({ x: 0, y: 0 })
123
+ // Nodes muted via legend toggle (dimmed, not removed - keeps layout stable)
124
+ let muted_nodes = new SvelteSet<string | number>()
125
+
126
+ let pad = $derived(filter_padding(padding, DEFAULT_PADDING))
127
+ let inner_width = $derived(Math.max(0, width - pad.l - pad.r))
128
+ let inner_height = $derived(Math.max(0, height - pad.t - pad.b))
129
+
130
+ // Resolved node colors (per node_idx), explicit color or cycled palette
131
+ let node_colors = $derived(
132
+ data.nodes.map((node, idx) =>
133
+ node.color ?? DEFAULT_SERIES_COLORS[idx % DEFAULT_SERIES_COLORS.length]
134
+ ),
135
+ )
136
+
137
+ // Drop muted ids that no longer exist when data changes (untrack avoids a
138
+ // self-trigger loop from reading/writing muted_nodes in the same effect).
139
+ $effect(() => {
140
+ const valid = new Set(data.nodes.map((node, idx) => node.id ?? idx))
141
+ untrack(() => {
142
+ for (const id of muted_nodes) if (!valid.has(id)) muted_nodes.delete(id)
143
+ })
144
+ })
145
+
146
+ // Degrade to an empty layout (instead of crashing the host page) when the graph
147
+ // is invalid, e.g. contains a cycle. The thrown error is surfaced via console.error.
148
+ let layout = $derived.by(() => {
149
+ try {
150
+ return compute_sankey_layout(data, {
151
+ width: inner_width,
152
+ height: inner_height,
153
+ node_width,
154
+ node_padding,
155
+ node_align,
156
+ orientation,
157
+ iterations,
158
+ })
159
+ } catch (err) {
160
+ console.error(err)
161
+ return { nodes: [], links: [] }
162
+ }
163
+ })
164
+
165
+ // node_idx -> positioned node (array order is preserved by d3-sankey, but map is safer)
166
+ let node_by_idx = $derived(
167
+ new Map(layout.nodes.map((node) => [node.node_idx, node])),
168
+ )
169
+
170
+ const node_id_at = (node_idx: number): string | number =>
171
+ node_by_idx.get(node_idx)?.id ?? node_idx
172
+
173
+ // Node box center in container (pad-offset) pixel space, for tooltip + legend placement
174
+ const node_center = (node: PositionedNode): { x: number; y: number } => ({
175
+ x: pad.l + (node.x0 + node.x1) / 2,
176
+ y: pad.t + (node.y0 + node.y1) / 2,
177
+ })
178
+
179
+ // Resolve a link's ribbon color from explicit color or the active color mode
180
+ const link_color = (link: PositionedLink): string => {
181
+ if (link.color) return link.color
182
+ const src = node_colors[link.source.node_idx]
183
+ const tgt = node_colors[link.target.node_idx]
184
+ if (link_color_mode === `target`) return tgt
185
+ if (link_color_mode === `gradient`) return `url(#${uid}-grad-${link.link_idx})`
186
+ if (link_color_mode === `static`) return `var(--sankey-link-color, #888)`
187
+ return src
188
+ }
189
+
190
+ // Set of node/link indices to keep fully opaque given the current hover target
191
+ let active = $derived.by(() => {
192
+ if (hovered_node != null) {
193
+ const node = node_by_idx.get(hovered_node)
194
+ if (!node) return null
195
+ const link_set = new SvelteSet<number>()
196
+ const node_set = new SvelteSet<number>([hovered_node])
197
+ for (const link of [...(node.sourceLinks ?? []), ...(node.targetLinks ?? [])]) {
198
+ link_set.add((link as PositionedLink).link_idx)
199
+ node_set.add((link.source as PositionedNode).node_idx)
200
+ node_set.add((link.target as PositionedNode).node_idx)
201
+ }
202
+ return { links: link_set, nodes: node_set }
203
+ }
204
+ if (hovered_link != null) {
205
+ const link = layout.links[hovered_link]
206
+ if (!link) return null
207
+ return {
208
+ links: new SvelteSet([hovered_link]),
209
+ nodes: new SvelteSet([link.source.node_idx, link.target.node_idx]),
210
+ }
211
+ }
212
+ return null
213
+ })
214
+
215
+ const node_opacity = (node: PositionedNode): number => {
216
+ if (muted_nodes.has(node.id)) return 0.12
217
+ if (active && !active.nodes.has(node.node_idx)) return 0.3
218
+ return 1
219
+ }
220
+
221
+ const link_dim = (link: PositionedLink): boolean =>
222
+ muted_nodes.has(link.source.id) || muted_nodes.has(link.target.id)
223
+
224
+ const link_stroke_opacity = (link: PositionedLink): number => {
225
+ if (link_dim(link)) return link_opacity * 0.15
226
+ if (active) return active.links.has(link.link_idx) ? Math.min(1, link_opacity + 0.35) : link_opacity * 0.25
227
+ return link_opacity
228
+ }
229
+
230
+ const node_text = (node: PositionedNode): string =>
231
+ node_label?.(node) ?? node.label ?? `${node.id}`
232
+
233
+ function make_node_props(node: PositionedNode): SankeyNodeHandlerProps<Metadata> {
234
+ return {
235
+ type: `node`,
236
+ node_idx: node.node_idx,
237
+ id: node.id,
238
+ label: node.label,
239
+ value: node.value ?? 0,
240
+ color: node_colors[node.node_idx],
241
+ metadata: data.nodes[node.node_idx]?.metadata,
242
+ }
243
+ }
244
+
245
+ function make_link_props(link: PositionedLink): SankeyLinkHandlerProps<Metadata> {
246
+ return {
247
+ type: `link`,
248
+ link_idx: link.link_idx,
249
+ source_idx: link.source.node_idx,
250
+ target_idx: link.target.node_idx,
251
+ source_label: link.source.label,
252
+ target_label: link.target.label,
253
+ value: link.value,
254
+ color: link_color(link),
255
+ metadata: data.links[link.link_idx]?.metadata,
256
+ }
257
+ }
258
+
259
+ // Anchor the tooltip at the cursor (mouse hover) so it follows the pointer over wide nodes
260
+ // and long link ribbons; fall back to the element center on keyboard focus (no cursor).
261
+ function event_pos(event?: MouseEvent | FocusEvent): { x: number; y: number } | null {
262
+ if (event instanceof MouseEvent && svg_element) {
263
+ const rect = svg_element.getBoundingClientRect()
264
+ return { x: event.clientX - rect.left, y: event.clientY - rect.top }
265
+ }
266
+ return null
267
+ }
268
+
269
+ function set_node_hover(node: PositionedNode | null, event?: MouseEvent | FocusEvent) {
270
+ if (node) {
271
+ hovered = true
272
+ hovered_node = node.node_idx
273
+ hovered_link = null
274
+ hover_info = make_node_props(node)
275
+ hover_pos = event_pos(event) ?? node_center(node)
276
+ change(hover_info)
277
+ if (event) on_node_hover?.({ ...(hover_info as SankeyNodeHandlerProps<Metadata>), event })
278
+ } else {
279
+ hovered_node = null
280
+ hover_info = null
281
+ change(null)
282
+ on_node_hover?.(null)
283
+ }
284
+ }
285
+
286
+ function set_link_hover(link: PositionedLink | null, event?: MouseEvent | FocusEvent) {
287
+ if (link) {
288
+ hovered = true
289
+ hovered_link = link.link_idx
290
+ hovered_node = null
291
+ hover_info = make_link_props(link)
292
+ hover_pos = event_pos(event) ?? { x: pad.l + link.mid.x, y: pad.t + link.mid.y }
293
+ change(hover_info)
294
+ if (event) on_link_hover?.({ ...(hover_info as SankeyLinkHandlerProps<Metadata>), event })
295
+ } else {
296
+ hovered_link = null
297
+ hover_info = null
298
+ change(null)
299
+ on_link_hover?.(null)
300
+ }
301
+ }
302
+
303
+ const link_from_event = (event: Event): PositionedLink | null => {
304
+ const idx = closest_data_idx(event, `data-sankey-link-idx`, svg_element)
305
+ return idx == null ? null : layout.links[idx] ?? null
306
+ }
307
+
308
+ const node_from_event = (event: Event): PositionedNode | null => {
309
+ const idx = closest_data_idx(event, `data-sankey-node-idx`, svg_element)
310
+ return idx == null ? null : node_by_idx.get(idx) ?? null
311
+ }
312
+
313
+ function handle_link_hover_event(event: MouseEvent | FocusEvent) {
314
+ set_link_hover(link_from_event(event), event)
315
+ }
316
+
317
+ function handle_node_hover_event(event: MouseEvent | FocusEvent) {
318
+ set_node_hover(node_from_event(event), event)
319
+ }
320
+
321
+ function handle_link_click(event: MouseEvent | KeyboardEvent) {
322
+ const link = link_from_event(event)
323
+ if (link) on_link_click?.({ ...make_link_props(link), event })
324
+ }
325
+
326
+ function handle_node_click(event: MouseEvent | KeyboardEvent) {
327
+ const node = node_from_event(event)
328
+ if (node) on_node_click?.({ ...make_node_props(node), event })
329
+ }
330
+
331
+ function handle_link_keydown(event: KeyboardEvent) {
332
+ if (event.key !== `Enter` && event.key !== ` `) return
333
+ event.preventDefault()
334
+ handle_link_click(event)
335
+ }
336
+
337
+ function handle_node_keydown(event: KeyboardEvent) {
338
+ if (event.key !== `Enter` && event.key !== ` `) return
339
+ event.preventDefault()
340
+ handle_node_click(event)
341
+ }
342
+
343
+ // Legend: one item per node, toggling mutes (dims) rather than removing.
344
+ // Auto-place to avoid covering nodes (node box centers act as obstacle points).
345
+ let legend_element = $state<HTMLDivElement | undefined>()
346
+ let legend_placement = $derived.by(() => {
347
+ if (!show_legend || legend == null || data.nodes.length <= 1 || !width || !height) {
348
+ return null
349
+ }
350
+ return compute_element_placement({
351
+ plot_bounds: { x: pad.l, y: pad.t, width: inner_width, height: inner_height },
352
+ element: legend_element,
353
+ element_size: { width: 120, height: 60 },
354
+ axis_clearance: legend?.axis_clearance,
355
+ exclude_rects: [],
356
+ points: layout.nodes.map(node_center),
357
+ })
358
+ })
359
+ // Only nodes that survive the layout (orphans with no links are dropped, see
360
+ // compute_sankey_layout) - keeps the legend in sync with what's drawn.
361
+ let legend_data = $derived.by<LegendItem[]>(() =>
362
+ data.nodes
363
+ .map((node, idx) => ({ node, idx }))
364
+ .filter(({ idx }) => node_by_idx.has(idx))
365
+ .map(({ node, idx }) => ({
366
+ series_idx: idx,
367
+ label: node.label ?? `${node.id ?? idx}`,
368
+ visible: !muted_nodes.has(node.id ?? idx),
369
+ display_style: { symbol_type: `Square` as const, symbol_color: node_colors[idx] },
370
+ }))
371
+ )
372
+
373
+ function toggle_node(series_idx: number) {
374
+ const id = node_id_at(series_idx)
375
+ if (muted_nodes.has(id)) muted_nodes.delete(id)
376
+ else muted_nodes.add(id)
377
+ }
378
+
379
+ $effect(() => set_fullscreen_bg(wrapper, fullscreen, `--sankey-fullscreen-bg`))
380
+
381
+ // Node label placement: horizontal -> beside node; vertical -> above node
382
+ function label_attrs(node: PositionedNode) {
383
+ if (orientation === `vertical`) {
384
+ return {
385
+ x: (node.x0 + node.x1) / 2,
386
+ y: node.y0 - 4,
387
+ anchor: `middle` as const,
388
+ baseline: `auto` as const,
389
+ }
390
+ }
391
+ const left_half = (node.x0 + node.x1) / 2 < inner_width / 2
392
+ return {
393
+ x: left_half ? node.x1 + 6 : node.x0 - 6,
394
+ y: (node.y0 + node.y1) / 2,
395
+ anchor: (left_half ? `start` : `end`) as `start` | `end`,
396
+ baseline: `middle` as const,
397
+ }
398
+ }
399
+ </script>
400
+
401
+ <svelte:window
402
+ onkeydown={(evt) => {
403
+ if (evt.key === `Escape` && fullscreen) {
404
+ evt.preventDefault()
405
+ fullscreen = false
406
+ }
407
+ }}
408
+ />
409
+
410
+ <div
411
+ bind:this={wrapper}
412
+ bind:clientWidth={width}
413
+ bind:clientHeight={height}
414
+ {...rest}
415
+ class="sankey {rest.class ?? ``}"
416
+ class:fullscreen
417
+ >
418
+ {#if width && height}
419
+ <div class="header-controls">
420
+ {@render header_controls?.({ height, width, fullscreen })}
421
+ {#if fullscreen_toggle}
422
+ <FullscreenToggle bind:fullscreen />
423
+ {/if}
424
+ </div>
425
+ <!-- svelte-ignore a11y_no_noninteractive_tabindex -->
426
+ <svg
427
+ bind:this={svg_element}
428
+ role="application"
429
+ aria-label={rest[`aria-label`] ?? `Sankey diagram`}
430
+ onmouseleave={() => {
431
+ hovered = false
432
+ set_node_hover(null)
433
+ set_link_hover(null)
434
+ }}
435
+ >
436
+ {#if link_color_mode === `gradient`}
437
+ <defs>
438
+ {#each layout.links as link (link.link_idx)}
439
+ {@const src_color = node_colors[link.source.node_idx]}
440
+ {@const tgt_color = node_colors[link.target.node_idx]}
441
+ {@const vertical = orientation === `vertical`}
442
+ <linearGradient
443
+ id="{uid}-grad-{link.link_idx}"
444
+ gradientUnits="userSpaceOnUse"
445
+ x1={vertical ? link.mid.x : link.source.x1}
446
+ y1={vertical ? link.source.y1 : link.mid.y}
447
+ x2={vertical ? link.mid.x : link.target.x0}
448
+ y2={vertical ? link.target.y0 : link.mid.y}
449
+ >
450
+ <stop offset="0%" stop-color={src_color} />
451
+ <stop offset="100%" stop-color={tgt_color} />
452
+ </linearGradient>
453
+ {/each}
454
+ </defs>
455
+ {/if}
456
+
457
+ <g transform="translate({pad.l}, {pad.t})">
458
+ <!-- Links -->
459
+ <!-- svelte-ignore a11y_no_static_element_interactions -->
460
+ <g
461
+ class="links"
462
+ fill="none"
463
+ onmousemove={handle_link_hover_event}
464
+ onmouseleave={() => set_link_hover(null)}
465
+ onfocusin={handle_link_hover_event}
466
+ onfocusout={() => set_link_hover(null)}
467
+ onclick={handle_link_click}
468
+ onkeydown={handle_link_keydown}
469
+ >
470
+ {#each layout.links as link (link.link_idx)}
471
+ {@const color = link_color(link)}
472
+ {#if link_content}
473
+ {@render link_content({ link, color })}
474
+ {:else}
475
+ <!-- svelte-ignore a11y_no_static_element_interactions -->
476
+ <path
477
+ d={link.path}
478
+ data-sankey-link-idx={link.link_idx}
479
+ stroke={color}
480
+ stroke-width={Math.max(1, link.width)}
481
+ stroke-opacity={link_stroke_opacity(link)}
482
+ role={on_link_click ? `button` : undefined}
483
+ tabindex={on_link_click ? 0 : undefined}
484
+ aria-label={on_link_click
485
+ ? `flow ${link.source.label} to ${link.target.label}: ${link.value}`
486
+ : undefined}
487
+ style:cursor={on_link_click ? `pointer` : `default`}
488
+ />
489
+ {/if}
490
+ {/each}
491
+ </g>
492
+
493
+ <!-- Nodes -->
494
+ <!-- svelte-ignore a11y_no_static_element_interactions -->
495
+ <g
496
+ class="nodes"
497
+ onmousemove={handle_node_hover_event}
498
+ onmouseleave={() => set_node_hover(null)}
499
+ onfocusin={handle_node_hover_event}
500
+ onfocusout={() => set_node_hover(null)}
501
+ onclick={handle_node_click}
502
+ onkeydown={handle_node_keydown}
503
+ >
504
+ {#each layout.nodes as node (node.node_idx)}
505
+ {@const color = node_colors[node.node_idx]}
506
+ <g class="node" style:opacity={node_opacity(node)}>
507
+ {#if node_content}
508
+ {@render node_content({ node, color })}
509
+ {:else}
510
+ <!-- svelte-ignore a11y_no_static_element_interactions -->
511
+ <rect
512
+ data-sankey-node-idx={node.node_idx}
513
+ x={node.x0}
514
+ y={node.y0}
515
+ width={Math.max(0, node.x1 - node.x0)}
516
+ height={Math.max(0, node.y1 - node.y0)}
517
+ fill={color}
518
+ stroke="var(--sankey-node-stroke, rgba(0, 0, 0, 0.5))"
519
+ stroke-width="0.5"
520
+ rx="1"
521
+ role={on_node_click ? `button` : undefined}
522
+ tabindex={on_node_click ? 0 : undefined}
523
+ aria-label={on_node_click ? `${node.label ?? node.id}: ${node.value}` : undefined}
524
+ style:cursor={on_node_click ? `pointer` : `default`}
525
+ />
526
+ {/if}
527
+ {#if show_node_labels}
528
+ {@const lbl = label_attrs(node)}
529
+ <text
530
+ class="node-label"
531
+ x={lbl.x}
532
+ y={lbl.y}
533
+ text-anchor={lbl.anchor}
534
+ dominant-baseline={lbl.baseline}
535
+ >{node_text(node)}</text>
536
+ {/if}
537
+ </g>
538
+ {/each}
539
+ </g>
540
+ </g>
541
+ </svg>
542
+ {/if}
543
+
544
+ {#if hover_info}
545
+ {@const tip = constrain_tooltip_position(
546
+ hover_pos.x,
547
+ hover_pos.y,
548
+ tooltip_el?.offsetWidth ?? 140,
549
+ tooltip_el?.offsetHeight ?? 44,
550
+ width,
551
+ height,
552
+ { offset_x: 10, offset_y: 5 },
553
+ )}
554
+ <!-- Solid chip bg (PlotTooltip auto-contrasts text). Links use the source node
555
+ color so gradient/static ribbons (url(...)/var(...)) still get a readable color. -->
556
+ {@const tip_bg = hover_info.type === `node`
557
+ ? hover_info.color
558
+ : node_colors[hover_info.source_idx] ?? `rgba(0, 0, 0, 0.7)`}
559
+ <PlotTooltip
560
+ x={tip.x}
561
+ y={tip.y}
562
+ offset={{ x: 0, y: 0 }}
563
+ bg_color={tip_bg}
564
+ bind:wrapper={tooltip_el}
565
+ >
566
+ {#if tooltip}
567
+ {@render tooltip(hover_info)}
568
+ {:else if hover_info.type === `node`}
569
+ <strong>{hover_info.label ?? hover_info.id}</strong>: {
570
+ format_value(hover_info.value, value_format)
571
+ }
572
+ {:else}
573
+ {hover_info.source_label ?? hover_info.source_idx} &rarr; {
574
+ hover_info.target_label ?? hover_info.target_idx
575
+ }: {format_value(hover_info.value, value_format)}
576
+ {/if}
577
+ </PlotTooltip>
578
+ {/if}
579
+
580
+ {#if show_legend && legend != null && data.nodes.length > 1}
581
+ {@const legend_left = legend_placement?.x ?? pad.l + 10}
582
+ {@const legend_top = legend_placement?.y ?? pad.t + 10}
583
+ <PlotLegend
584
+ bind:root_element={legend_element}
585
+ {...legend}
586
+ series_data={legend_data}
587
+ on_toggle={legend?.on_toggle ?? toggle_node}
588
+ on_item_hover={(item) =>
589
+ (hovered_node = item != null && item.series_idx >= 0 ? item.series_idx : null)}
590
+ style={`position: absolute; left: ${legend_left}px; top: ${legend_top}px; pointer-events: auto; ${
591
+ legend?.style ?? ``
592
+ }`}
593
+ />
594
+ {/if}
595
+
596
+ {#if show_controls}
597
+ <SankeyControls
598
+ toggle_props={{
599
+ ...controls_toggle_props,
600
+ style: `--ctrl-btn-right: var(--fullscreen-btn-offset, 30px); ${
601
+ controls_toggle_props?.style ?? ``
602
+ }`,
603
+ }}
604
+ pane_props={controls_pane_props}
605
+ bind:show_controls
606
+ bind:controls_open
607
+ bind:orientation
608
+ bind:node_width
609
+ bind:node_padding
610
+ bind:node_align
611
+ bind:link_opacity
612
+ bind:show_node_labels
613
+ >
614
+ {@render controls_extra?.({ orientation })}
615
+ </SankeyControls>
616
+ {/if}
617
+
618
+ {@render children?.({ height, width, fullscreen })}
619
+ </div>
620
+
621
+ <style>
622
+ .sankey {
623
+ position: relative;
624
+ width: var(--sankey-width, 100%);
625
+ height: var(--sankey-height, auto);
626
+ min-height: var(--sankey-min-height, 300px);
627
+ container-type: size;
628
+ z-index: var(--sankey-z-index, auto);
629
+ flex: var(--sankey-flex, 1);
630
+ display: var(--sankey-display, flex);
631
+ flex-direction: column;
632
+ background: var(--sankey-bg, var(--plot-bg));
633
+ border-radius: var(--sankey-border-radius, var(--border-radius, 3pt));
634
+ }
635
+ .sankey.fullscreen {
636
+ position: fixed;
637
+ top: 0;
638
+ left: 0;
639
+ width: 100vw !important;
640
+ height: 100vh !important;
641
+ z-index: var(--sankey-fullscreen-z-index, var(--z-index-overlay-nav, 100000001));
642
+ margin: 0;
643
+ border-radius: 0;
644
+ background: var(--sankey-fullscreen-bg, var(--sankey-bg, var(--plot-bg)));
645
+ max-height: none !important;
646
+ overflow: hidden;
647
+ /* border-top (not padding-top): bind:clientHeight includes padding but excludes
648
+ borders - padding made the chart overflow + clip its bottom 2em (x-axis title) */
649
+ border-top: var(--plot-fullscreen-padding-top, 2em) solid
650
+ var(--sankey-fullscreen-bg, var(--sankey-bg, var(--plot-bg, transparent)));
651
+ box-sizing: border-box;
652
+ }
653
+ .header-controls {
654
+ position: absolute;
655
+ top: var(--ctrl-btn-top, 5pt);
656
+ right: var(--fullscreen-btn-right, 4px);
657
+ z-index: var(--fullscreen-btn-z-index, 10);
658
+ display: flex;
659
+ align-items: center;
660
+ gap: 8px;
661
+ }
662
+ .header-controls :global(.fullscreen-toggle) {
663
+ position: static;
664
+ opacity: 1;
665
+ }
666
+ .sankey :global(.pane-toggle),
667
+ .sankey .header-controls {
668
+ opacity: 0;
669
+ transition: opacity 0.2s, background-color 0.2s;
670
+ }
671
+ .sankey:hover :global(.pane-toggle),
672
+ .sankey:hover .header-controls,
673
+ .sankey :global(.pane-toggle:focus-visible),
674
+ .sankey :global(.pane-toggle[aria-expanded='true']),
675
+ .sankey .header-controls:focus-within {
676
+ opacity: 1;
677
+ }
678
+ svg {
679
+ width: var(--sankey-svg-width, 100%);
680
+ height: var(--sankey-svg-height, 100%);
681
+ flex: var(--sankey-svg-flex, 1);
682
+ overflow: var(--sankey-svg-overflow, visible);
683
+ fill: var(--text-color);
684
+ font-size: var(--sankey-font-size, 11px);
685
+ }
686
+ .links path {
687
+ transition: stroke-opacity 0.15s ease;
688
+ }
689
+ .node {
690
+ transition: opacity 0.15s ease;
691
+ }
692
+ .node-label {
693
+ fill: var(--text-color);
694
+ pointer-events: none;
695
+ paint-order: stroke;
696
+ stroke: var(--sankey-label-halo, var(--plot-bg, white));
697
+ stroke-width: var(--sankey-label-halo-width, 3px);
698
+ stroke-linejoin: round;
699
+ }
700
+ </style>