matterviz 0.3.6 → 0.3.7

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 (863) hide show
  1. package/dist/EmptyState.svelte.d.ts +9 -0
  2. package/dist/FilePicker.svelte +360 -0
  3. package/dist/FilePicker.svelte.d.ts +17 -0
  4. package/dist/Icon.svelte.d.ts +13 -0
  5. package/dist/MillerIndexInput.svelte +66 -0
  6. package/dist/MillerIndexInput.svelte.d.ts +7 -0
  7. package/dist/api/mp.d.ts +6 -0
  8. package/dist/api/mp.js +22 -0
  9. package/dist/api/optimade.d.ts +45 -0
  10. package/dist/api/optimade.js +135 -0
  11. package/dist/brillouin/BrillouinZone.svelte +549 -0
  12. package/dist/brillouin/BrillouinZone.svelte.d.ts +83 -0
  13. package/dist/brillouin/BrillouinZoneControls.svelte +144 -0
  14. package/dist/brillouin/BrillouinZoneControls.svelte.d.ts +17 -0
  15. package/dist/brillouin/BrillouinZoneExportPane.svelte +146 -0
  16. package/dist/brillouin/BrillouinZoneExportPane.svelte.d.ts +15 -0
  17. package/dist/brillouin/BrillouinZoneInfoPane.svelte +146 -0
  18. package/dist/brillouin/BrillouinZoneInfoPane.svelte.d.ts +13 -0
  19. package/dist/brillouin/BrillouinZoneScene.svelte +476 -0
  20. package/dist/brillouin/BrillouinZoneScene.svelte.d.ts +48 -0
  21. package/dist/brillouin/BrillouinZoneTooltip.svelte +92 -0
  22. package/dist/brillouin/BrillouinZoneTooltip.svelte.d.ts +8 -0
  23. package/dist/brillouin/compute.d.ts +17 -0
  24. package/dist/brillouin/compute.js +426 -0
  25. package/dist/brillouin/index.d.ts +8 -0
  26. package/dist/brillouin/index.js +7 -0
  27. package/dist/brillouin/types.d.ts +43 -0
  28. package/dist/brillouin/types.js +1 -0
  29. package/dist/chempot-diagram/ChemPotDiagram.svelte +327 -0
  30. package/dist/chempot-diagram/ChemPotDiagram.svelte.d.ts +13 -0
  31. package/dist/chempot-diagram/ChemPotDiagram2D.svelte +846 -0
  32. package/dist/chempot-diagram/ChemPotDiagram2D.svelte.d.ts +16 -0
  33. package/dist/chempot-diagram/ChemPotDiagram3D.svelte +3193 -0
  34. package/dist/chempot-diagram/ChemPotDiagram3D.svelte.d.ts +16 -0
  35. package/dist/chempot-diagram/ChemPotScene3D.svelte.d.ts +7 -0
  36. package/dist/chempot-diagram/async-compute.svelte.d.ts +3 -0
  37. package/dist/chempot-diagram/async-compute.svelte.js +78 -0
  38. package/dist/chempot-diagram/chempot-worker.d.ts +1 -0
  39. package/dist/chempot-diagram/chempot-worker.js +11 -0
  40. package/dist/chempot-diagram/color.d.ts +10 -0
  41. package/dist/chempot-diagram/color.js +32 -0
  42. package/dist/chempot-diagram/compute.d.ts +48 -0
  43. package/dist/chempot-diagram/compute.js +806 -0
  44. package/dist/chempot-diagram/index.d.ts +6 -0
  45. package/dist/chempot-diagram/index.js +6 -0
  46. package/dist/chempot-diagram/pointer.d.ts +16 -0
  47. package/dist/chempot-diagram/pointer.js +40 -0
  48. package/dist/chempot-diagram/temperature.d.ts +15 -0
  49. package/dist/chempot-diagram/temperature.js +34 -0
  50. package/dist/chempot-diagram/types.d.ts +81 -0
  51. package/dist/chempot-diagram/types.js +28 -0
  52. package/dist/colors/index.d.ts +47 -0
  53. package/dist/colors/index.js +203 -0
  54. package/dist/composition/BarChart.svelte +297 -0
  55. package/dist/composition/BarChart.svelte.d.ts +39 -0
  56. package/dist/composition/BubbleChart.svelte +218 -0
  57. package/dist/composition/BubbleChart.svelte.d.ts +28 -0
  58. package/dist/composition/Composition.svelte +165 -0
  59. package/dist/composition/Composition.svelte.d.ts +15 -0
  60. package/dist/composition/Formula.svelte +268 -0
  61. package/dist/composition/Formula.svelte.d.ts +19 -0
  62. package/dist/composition/FormulaFilter.svelte +1257 -0
  63. package/dist/composition/FormulaFilter.svelte.d.ts +51 -0
  64. package/dist/composition/PieChart.svelte +323 -0
  65. package/dist/composition/PieChart.svelte.d.ts +37 -0
  66. package/dist/composition/format.d.ts +15 -0
  67. package/dist/composition/format.js +109 -0
  68. package/dist/composition/index.d.ts +20 -0
  69. package/dist/composition/index.js +14 -0
  70. package/dist/composition/parse.d.ts +56 -0
  71. package/dist/composition/parse.js +474 -0
  72. package/dist/constants.d.ts +29 -0
  73. package/dist/constants.js +99 -0
  74. package/dist/controls.d.ts +14 -0
  75. package/dist/controls.js +30 -0
  76. package/dist/convex-hull/ConvexHull.svelte +157 -0
  77. package/dist/convex-hull/ConvexHull.svelte.d.ts +13 -0
  78. package/dist/convex-hull/ConvexHull2D.svelte +825 -0
  79. package/dist/convex-hull/ConvexHull2D.svelte.d.ts +11 -0
  80. package/dist/convex-hull/ConvexHull3D.svelte +1801 -0
  81. package/dist/convex-hull/ConvexHull3D.svelte.d.ts +8 -0
  82. package/dist/convex-hull/ConvexHull4D.svelte +1398 -0
  83. package/dist/convex-hull/ConvexHull4D.svelte.d.ts +8 -0
  84. package/dist/convex-hull/ConvexHullControls.svelte +535 -0
  85. package/dist/convex-hull/ConvexHullControls.svelte.d.ts +48 -0
  86. package/dist/convex-hull/ConvexHullInfoPane.svelte +125 -0
  87. package/dist/convex-hull/ConvexHullInfoPane.svelte.d.ts +20 -0
  88. package/dist/convex-hull/ConvexHullStats.svelte +929 -0
  89. package/dist/convex-hull/ConvexHullStats.svelte.d.ts +17 -0
  90. package/dist/convex-hull/ConvexHullTooltip.svelte +131 -0
  91. package/dist/convex-hull/ConvexHullTooltip.svelte.d.ts +33 -0
  92. package/dist/convex-hull/GasPressureControls.svelte +247 -0
  93. package/dist/convex-hull/GasPressureControls.svelte.d.ts +11 -0
  94. package/dist/convex-hull/StructurePopup.svelte +151 -0
  95. package/dist/convex-hull/StructurePopup.svelte.d.ts +18 -0
  96. package/dist/convex-hull/TemperatureSlider.svelte.d.ts +8 -0
  97. package/dist/convex-hull/barycentric-coords.d.ts +18 -0
  98. package/dist/convex-hull/barycentric-coords.js +182 -0
  99. package/dist/convex-hull/demo-temperature.d.ts +6 -0
  100. package/dist/convex-hull/demo-temperature.js +40 -0
  101. package/dist/convex-hull/gas-thermodynamics.d.ts +16 -0
  102. package/dist/convex-hull/gas-thermodynamics.js +314 -0
  103. package/dist/convex-hull/helpers.d.ts +114 -0
  104. package/dist/convex-hull/helpers.js +710 -0
  105. package/dist/convex-hull/index.d.ts +119 -0
  106. package/dist/convex-hull/index.js +58 -0
  107. package/dist/convex-hull/thermodynamics.d.ts +67 -0
  108. package/dist/convex-hull/thermodynamics.js +1752 -0
  109. package/dist/convex-hull/types.d.ts +162 -0
  110. package/dist/convex-hull/types.js +36 -0
  111. package/dist/coordination/CoordinationBarPlot.svelte +311 -0
  112. package/dist/coordination/CoordinationBarPlot.svelte.d.ts +30 -0
  113. package/dist/coordination/calc-coordination.d.ts +15 -0
  114. package/dist/coordination/calc-coordination.js +63 -0
  115. package/dist/coordination/index.d.ts +8 -0
  116. package/dist/coordination/index.js +7 -0
  117. package/dist/effects.svelte.d.ts +12 -0
  118. package/dist/effects.svelte.js +37 -0
  119. package/dist/element/BohrAtom.svelte.d.ts +20 -0
  120. package/dist/element/ElementHeading.svelte +26 -0
  121. package/dist/element/ElementHeading.svelte.d.ts +8 -0
  122. package/dist/element/ElementPhoto.svelte +57 -0
  123. package/dist/element/ElementPhoto.svelte.d.ts +9 -0
  124. package/dist/element/ElementStats.svelte +80 -0
  125. package/dist/element/ElementStats.svelte.d.ts +8 -0
  126. package/dist/element/ElementTile.svelte +484 -0
  127. package/dist/element/ElementTile.svelte.d.ts +29 -0
  128. package/dist/element/Nucleus.svelte.d.ts +17 -0
  129. package/dist/element/data.d.ts +2 -0
  130. package/dist/element/data.js +2 -0
  131. package/dist/element/index.d.ts +8 -0
  132. package/dist/element/index.js +7 -0
  133. package/dist/element/types.d.ts +57 -0
  134. package/dist/element/types.js +1 -0
  135. package/dist/feedback/ClickFeedback.svelte +58 -0
  136. package/dist/feedback/ClickFeedback.svelte.d.ts +12 -0
  137. package/dist/feedback/DragOverlay.svelte +42 -0
  138. package/dist/feedback/DragOverlay.svelte.d.ts +7 -0
  139. package/dist/feedback/Spinner.svelte.d.ts +7 -0
  140. package/dist/feedback/StatusMessage.svelte.d.ts +9 -0
  141. package/dist/feedback/index.d.ts +4 -0
  142. package/dist/feedback/index.js +4 -0
  143. package/dist/fermi-surface/FermiSlice.svelte +189 -0
  144. package/dist/fermi-surface/FermiSlice.svelte.d.ts +24 -0
  145. package/dist/fermi-surface/FermiSurface.svelte +600 -0
  146. package/dist/fermi-surface/FermiSurface.svelte.d.ts +83 -0
  147. package/dist/fermi-surface/FermiSurfaceControls.svelte +448 -0
  148. package/dist/fermi-surface/FermiSurfaceControls.svelte.d.ts +35 -0
  149. package/dist/fermi-surface/FermiSurfaceScene.svelte +794 -0
  150. package/dist/fermi-surface/FermiSurfaceScene.svelte.d.ts +50 -0
  151. package/dist/fermi-surface/FermiSurfaceTooltip.svelte +111 -0
  152. package/dist/fermi-surface/FermiSurfaceTooltip.svelte.d.ts +8 -0
  153. package/dist/fermi-surface/compute.d.ts +5 -0
  154. package/dist/fermi-surface/compute.js +538 -0
  155. package/dist/fermi-surface/constants.d.ts +9 -0
  156. package/dist/fermi-surface/constants.js +27 -0
  157. package/dist/fermi-surface/export.d.ts +5 -0
  158. package/dist/fermi-surface/export.js +50 -0
  159. package/dist/fermi-surface/index.d.ts +12 -0
  160. package/dist/fermi-surface/index.js +13 -0
  161. package/dist/fermi-surface/marching-cubes.d.ts +2 -0
  162. package/dist/fermi-surface/marching-cubes.js +2 -0
  163. package/dist/fermi-surface/parse.d.ts +2 -0
  164. package/dist/fermi-surface/parse.js +491 -0
  165. package/dist/fermi-surface/symmetry.d.ts +3 -0
  166. package/dist/fermi-surface/symmetry.js +46 -0
  167. package/dist/fermi-surface/types.d.ts +110 -0
  168. package/dist/fermi-surface/types.js +4 -0
  169. package/dist/heatmap-matrix/HeatmapMatrix.svelte +1545 -0
  170. package/dist/heatmap-matrix/HeatmapMatrix.svelte.d.ts +110 -0
  171. package/dist/heatmap-matrix/HeatmapMatrixControls.svelte +225 -0
  172. package/dist/heatmap-matrix/HeatmapMatrixControls.svelte.d.ts +30 -0
  173. package/dist/heatmap-matrix/index.d.ts +53 -0
  174. package/dist/heatmap-matrix/index.js +100 -0
  175. package/dist/heatmap-matrix/shared.d.ts +2 -0
  176. package/dist/heatmap-matrix/shared.js +4 -0
  177. package/dist/icons.d.ts +569 -0
  178. package/dist/icons.js +648 -0
  179. package/dist/index.d.ts +39 -0
  180. package/dist/index.js +39 -0
  181. package/dist/io/decompress.d.ts +11 -0
  182. package/dist/io/decompress.js +74 -0
  183. package/dist/io/export.d.ts +16 -0
  184. package/dist/io/export.js +316 -0
  185. package/dist/io/fetch.d.ts +5 -0
  186. package/dist/io/fetch.js +39 -0
  187. package/dist/io/file-drop.d.ts +7 -0
  188. package/dist/io/file-drop.js +43 -0
  189. package/dist/io/index.d.ts +7 -0
  190. package/dist/io/index.js +6 -0
  191. package/dist/io/is-binary.d.ts +1 -0
  192. package/dist/io/is-binary.js +20 -0
  193. package/dist/io/types.d.ts +8 -0
  194. package/dist/io/types.js +1 -0
  195. package/dist/io/url-drop.d.ts +2 -0
  196. package/dist/io/url-drop.js +123 -0
  197. package/dist/isosurface/Isosurface.svelte +285 -0
  198. package/dist/isosurface/Isosurface.svelte.d.ts +8 -0
  199. package/dist/isosurface/IsosurfaceControls.svelte +277 -0
  200. package/dist/isosurface/IsosurfaceControls.svelte.d.ts +9 -0
  201. package/dist/isosurface/index.d.ts +5 -0
  202. package/dist/isosurface/index.js +6 -0
  203. package/dist/isosurface/parse.d.ts +6 -0
  204. package/dist/isosurface/parse.js +553 -0
  205. package/dist/isosurface/slice.d.ts +11 -0
  206. package/dist/isosurface/slice.js +140 -0
  207. package/dist/isosurface/types.d.ts +56 -0
  208. package/dist/isosurface/types.js +227 -0
  209. package/dist/labels.d.ts +53 -0
  210. package/dist/labels.js +277 -0
  211. package/dist/layout/FullscreenToggle.svelte +50 -0
  212. package/dist/layout/FullscreenToggle.svelte.d.ts +7 -0
  213. package/dist/layout/InfoCard.svelte +120 -0
  214. package/dist/layout/InfoCard.svelte.d.ts +21 -0
  215. package/dist/layout/InfoTag.svelte +185 -0
  216. package/dist/layout/InfoTag.svelte.d.ts +19 -0
  217. package/dist/layout/PropertyFilter.svelte +246 -0
  218. package/dist/layout/PropertyFilter.svelte.d.ts +24 -0
  219. package/dist/layout/SettingsSection.svelte +148 -0
  220. package/dist/layout/SettingsSection.svelte.d.ts +17 -0
  221. package/dist/layout/SubpageGrid.svelte +82 -0
  222. package/dist/layout/SubpageGrid.svelte.d.ts +14 -0
  223. package/dist/layout/fullscreen.d.ts +9 -0
  224. package/dist/layout/fullscreen.js +53 -0
  225. package/dist/layout/index.d.ts +10 -0
  226. package/dist/layout/index.js +8 -0
  227. package/dist/layout/json-tree/JsonNode.svelte +548 -0
  228. package/dist/layout/json-tree/JsonNode.svelte.d.ts +11 -0
  229. package/dist/layout/json-tree/JsonTree.svelte +1230 -0
  230. package/dist/layout/json-tree/JsonTree.svelte.d.ts +6 -0
  231. package/dist/layout/json-tree/JsonValue.svelte.d.ts +9 -0
  232. package/dist/layout/json-tree/index.d.ts +3 -0
  233. package/dist/layout/json-tree/index.js +3 -0
  234. package/dist/layout/json-tree/types.d.ts +74 -0
  235. package/dist/layout/json-tree/types.js +2 -0
  236. package/dist/layout/json-tree/utils.d.ts +29 -0
  237. package/dist/layout/json-tree/utils.js +641 -0
  238. package/dist/marching-cubes.d.ts +14 -0
  239. package/dist/marching-cubes.js +540 -0
  240. package/dist/math.d.ts +101 -0
  241. package/dist/math.js +905 -0
  242. package/dist/overlays/ContextMenu.svelte +162 -0
  243. package/dist/overlays/ContextMenu.svelte.d.ts +25 -0
  244. package/dist/overlays/CopyButton.svelte +45 -0
  245. package/dist/overlays/CopyButton.svelte.d.ts +8 -0
  246. package/dist/overlays/DragControlTab.svelte +98 -0
  247. package/dist/overlays/DragControlTab.svelte.d.ts +8 -0
  248. package/dist/overlays/DraggablePane.svelte +487 -0
  249. package/dist/overlays/DraggablePane.svelte.d.ts +36 -0
  250. package/dist/overlays/InfoPaneCards.svelte +149 -0
  251. package/dist/overlays/InfoPaneCards.svelte.d.ts +22 -0
  252. package/dist/overlays/index.d.ts +3 -0
  253. package/dist/overlays/index.js +3 -0
  254. package/dist/periodic-table/PeriodicTable.svelte +469 -0
  255. package/dist/periodic-table/PeriodicTable.svelte.d.ts +55 -0
  256. package/dist/periodic-table/PeriodicTableControls.svelte +557 -0
  257. package/dist/periodic-table/PeriodicTableControls.svelte.d.ts +24 -0
  258. package/dist/periodic-table/PropertySelect.svelte +37 -0
  259. package/dist/periodic-table/PropertySelect.svelte.d.ts +13 -0
  260. package/dist/periodic-table/TableInset.svelte.d.ts +9 -0
  261. package/dist/periodic-table/index.d.ts +10 -0
  262. package/dist/periodic-table/index.js +4 -0
  263. package/dist/phase-diagram/IsobaricBinaryPhaseDiagram.svelte +1086 -0
  264. package/dist/phase-diagram/IsobaricBinaryPhaseDiagram.svelte.d.ts +44 -0
  265. package/dist/phase-diagram/PhaseDiagramControls.svelte +444 -0
  266. package/dist/phase-diagram/PhaseDiagramControls.svelte.d.ts +30 -0
  267. package/dist/phase-diagram/PhaseDiagramEditorPane.svelte +126 -0
  268. package/dist/phase-diagram/PhaseDiagramEditorPane.svelte.d.ts +15 -0
  269. package/dist/phase-diagram/PhaseDiagramExportPane.svelte +184 -0
  270. package/dist/phase-diagram/PhaseDiagramExportPane.svelte.d.ts +19 -0
  271. package/dist/phase-diagram/PhaseDiagramTooltip.svelte +391 -0
  272. package/dist/phase-diagram/PhaseDiagramTooltip.svelte.d.ts +16 -0
  273. package/dist/phase-diagram/TdbInfoPanel.svelte +203 -0
  274. package/dist/phase-diagram/TdbInfoPanel.svelte.d.ts +12 -0
  275. package/dist/phase-diagram/build-diagram.d.ts +11 -0
  276. package/dist/phase-diagram/build-diagram.js +160 -0
  277. package/dist/phase-diagram/colors.d.ts +35 -0
  278. package/dist/phase-diagram/colors.js +51 -0
  279. package/dist/phase-diagram/diagram-input.d.ts +29 -0
  280. package/dist/phase-diagram/diagram-input.js +3 -0
  281. package/dist/phase-diagram/index.d.ts +13 -0
  282. package/dist/phase-diagram/index.js +11 -0
  283. package/dist/phase-diagram/parse.d.ts +55 -0
  284. package/dist/phase-diagram/parse.js +272 -0
  285. package/dist/phase-diagram/svg-to-diagram.d.ts +2 -0
  286. package/dist/phase-diagram/svg-to-diagram.js +867 -0
  287. package/dist/phase-diagram/types.d.ts +93 -0
  288. package/dist/phase-diagram/types.js +1 -0
  289. package/dist/phase-diagram/utils.d.ts +118 -0
  290. package/dist/phase-diagram/utils.js +604 -0
  291. package/dist/plot/AxisLabel.svelte +51 -0
  292. package/dist/plot/AxisLabel.svelte.d.ts +16 -0
  293. package/dist/plot/BarPlot.svelte +2113 -0
  294. package/dist/plot/BarPlot.svelte.d.ts +84 -0
  295. package/dist/plot/BarPlotControls.svelte +66 -0
  296. package/dist/plot/BarPlotControls.svelte.d.ts +18 -0
  297. package/dist/plot/BinnedScatterPlot.svelte +1114 -0
  298. package/dist/plot/BinnedScatterPlot.svelte.d.ts +66 -0
  299. package/dist/plot/ColorBar.svelte +721 -0
  300. package/dist/plot/ColorBar.svelte.d.ts +31 -0
  301. package/dist/plot/ColorScaleSelect.svelte +54 -0
  302. package/dist/plot/ColorScaleSelect.svelte.d.ts +15 -0
  303. package/dist/plot/ElementScatter.svelte +63 -0
  304. package/dist/plot/ElementScatter.svelte.d.ts +14 -0
  305. package/dist/plot/FillArea.svelte.d.ts +21 -0
  306. package/dist/plot/Histogram.svelte +1558 -0
  307. package/dist/plot/Histogram.svelte.d.ts +50 -0
  308. package/dist/plot/HistogramControls.svelte +212 -0
  309. package/dist/plot/HistogramControls.svelte.d.ts +22 -0
  310. package/dist/plot/InteractiveAxisLabel.svelte +96 -0
  311. package/dist/plot/InteractiveAxisLabel.svelte.d.ts +14 -0
  312. package/dist/plot/Line.svelte +84 -0
  313. package/dist/plot/Line.svelte.d.ts +15 -0
  314. package/dist/plot/PlotAxis.svelte +169 -0
  315. package/dist/plot/PlotAxis.svelte.d.ts +24 -0
  316. package/dist/plot/PlotControls.svelte +537 -0
  317. package/dist/plot/PlotControls.svelte.d.ts +4 -0
  318. package/dist/plot/PlotLegend.svelte +569 -0
  319. package/dist/plot/PlotLegend.svelte.d.ts +29 -0
  320. package/dist/plot/PlotTooltip.svelte +67 -0
  321. package/dist/plot/PlotTooltip.svelte.d.ts +17 -0
  322. package/dist/plot/PortalSelect.svelte +253 -0
  323. package/dist/plot/PortalSelect.svelte.d.ts +16 -0
  324. package/dist/plot/ReferenceLine.svelte.d.ts +20 -0
  325. package/dist/plot/ReferenceLine3D.svelte +156 -0
  326. package/dist/plot/ReferenceLine3D.svelte.d.ts +14 -0
  327. package/dist/plot/ReferencePlane.svelte +175 -0
  328. package/dist/plot/ReferencePlane.svelte.d.ts +14 -0
  329. package/dist/plot/ScatterPlot.svelte +2778 -0
  330. package/dist/plot/ScatterPlot.svelte.d.ts +96 -0
  331. package/dist/plot/ScatterPlot3D.svelte +529 -0
  332. package/dist/plot/ScatterPlot3D.svelte.d.ts +95 -0
  333. package/dist/plot/ScatterPlot3DControls.svelte +437 -0
  334. package/dist/plot/ScatterPlot3DControls.svelte.d.ts +20 -0
  335. package/dist/plot/ScatterPlot3DScene.svelte +912 -0
  336. package/dist/plot/ScatterPlot3DScene.svelte.d.ts +74 -0
  337. package/dist/plot/ScatterPlotControls.svelte +306 -0
  338. package/dist/plot/ScatterPlotControls.svelte.d.ts +17 -0
  339. package/dist/plot/ScatterPoint.svelte +182 -0
  340. package/dist/plot/ScatterPoint.svelte.d.ts +22 -0
  341. package/dist/plot/SpacegroupBarPlot.svelte +293 -0
  342. package/dist/plot/SpacegroupBarPlot.svelte.d.ts +9 -0
  343. package/dist/plot/Surface3D.svelte +197 -0
  344. package/dist/plot/Surface3D.svelte.d.ts +13 -0
  345. package/dist/plot/ZeroLines.svelte +97 -0
  346. package/dist/plot/ZeroLines.svelte.d.ts +33 -0
  347. package/dist/plot/ZoomRect.svelte +23 -0
  348. package/dist/plot/ZoomRect.svelte.d.ts +8 -0
  349. package/dist/plot/adaptive-density.d.ts +69 -0
  350. package/dist/plot/adaptive-density.js +191 -0
  351. package/dist/plot/auto-place.d.ts +43 -0
  352. package/dist/plot/auto-place.js +122 -0
  353. package/dist/plot/axis-utils.d.ts +19 -0
  354. package/dist/plot/axis-utils.js +78 -0
  355. package/dist/plot/binned-scatter-types.d.ts +59 -0
  356. package/dist/plot/binned-scatter-types.js +1 -0
  357. package/dist/plot/data-cleaning.d.ts +37 -0
  358. package/dist/plot/data-cleaning.js +855 -0
  359. package/dist/plot/data-transform.d.ts +16 -0
  360. package/dist/plot/data-transform.js +45 -0
  361. package/dist/plot/defaults.d.ts +19 -0
  362. package/dist/plot/defaults.js +9 -0
  363. package/dist/plot/fill-utils.d.ts +46 -0
  364. package/dist/plot/fill-utils.js +322 -0
  365. package/dist/plot/hover-lock.svelte.d.ts +14 -0
  366. package/dist/plot/hover-lock.svelte.js +46 -0
  367. package/dist/plot/index.d.ts +41 -0
  368. package/dist/plot/index.js +39 -0
  369. package/dist/plot/interactions.d.ts +12 -0
  370. package/dist/plot/interactions.js +101 -0
  371. package/dist/plot/layout.d.ts +78 -0
  372. package/dist/plot/layout.js +273 -0
  373. package/dist/plot/reference-line.d.ts +60 -0
  374. package/dist/plot/reference-line.js +314 -0
  375. package/dist/plot/scales.d.ts +48 -0
  376. package/dist/plot/scales.js +481 -0
  377. package/dist/plot/svg.d.ts +1 -0
  378. package/dist/plot/svg.js +11 -0
  379. package/dist/plot/types.d.ts +831 -0
  380. package/dist/plot/types.js +99 -0
  381. package/dist/plot/utils/label-placement.d.ts +68 -0
  382. package/dist/plot/utils/label-placement.js +326 -0
  383. package/dist/plot/utils/series-visibility.d.ts +15 -0
  384. package/dist/plot/utils/series-visibility.js +85 -0
  385. package/dist/plot/utils.d.ts +1 -0
  386. package/dist/plot/utils.js +14 -0
  387. package/dist/rdf/RdfPlot.svelte +247 -0
  388. package/dist/rdf/RdfPlot.svelte.d.ts +27 -0
  389. package/dist/rdf/calc-rdf.d.ts +4 -0
  390. package/dist/rdf/calc-rdf.js +111 -0
  391. package/dist/rdf/index.d.ts +23 -0
  392. package/dist/rdf/index.js +2 -0
  393. package/dist/sanitize.d.ts +6 -0
  394. package/dist/sanitize.js +116 -0
  395. package/dist/settings.d.ts +255 -0
  396. package/dist/settings.js +1132 -0
  397. package/dist/spectral/Bands.svelte +1040 -0
  398. package/dist/spectral/Bands.svelte.d.ts +40 -0
  399. package/dist/spectral/BandsAndDos.svelte +134 -0
  400. package/dist/spectral/BandsAndDos.svelte.d.ts +18 -0
  401. package/dist/spectral/BrillouinBandsDos.svelte +252 -0
  402. package/dist/spectral/BrillouinBandsDos.svelte.d.ts +20 -0
  403. package/dist/spectral/Dos.svelte +697 -0
  404. package/dist/spectral/Dos.svelte.d.ts +29 -0
  405. package/dist/spectral/helpers.d.ts +119 -0
  406. package/dist/spectral/helpers.js +1032 -0
  407. package/dist/spectral/index.d.ts +6 -0
  408. package/dist/spectral/index.js +6 -0
  409. package/dist/spectral/types.d.ts +84 -0
  410. package/dist/spectral/types.js +2 -0
  411. package/dist/state.svelte.d.ts +25 -0
  412. package/dist/state.svelte.js +45 -0
  413. package/dist/structure/Arrow.svelte +72 -0
  414. package/dist/structure/Arrow.svelte.d.ts +15 -0
  415. package/dist/structure/AtomLegend.svelte +815 -0
  416. package/dist/structure/AtomLegend.svelte.d.ts +35 -0
  417. package/dist/structure/Bond.svelte +140 -0
  418. package/dist/structure/Bond.svelte.d.ts +9 -0
  419. package/dist/structure/CanvasTooltip.svelte +33 -0
  420. package/dist/structure/CanvasTooltip.svelte.d.ts +12 -0
  421. package/dist/structure/CellSelect.svelte +349 -0
  422. package/dist/structure/CellSelect.svelte.d.ts +13 -0
  423. package/dist/structure/Cylinder.svelte +45 -0
  424. package/dist/structure/Cylinder.svelte.d.ts +10 -0
  425. package/dist/structure/Lattice.svelte +196 -0
  426. package/dist/structure/Lattice.svelte.d.ts +17 -0
  427. package/dist/structure/Structure.svelte +2248 -0
  428. package/dist/structure/Structure.svelte.d.ts +89 -0
  429. package/dist/structure/StructureControls.svelte +1273 -0
  430. package/dist/structure/StructureControls.svelte.d.ts +31 -0
  431. package/dist/structure/StructureExportPane.svelte +252 -0
  432. package/dist/structure/StructureExportPane.svelte.d.ts +17 -0
  433. package/dist/structure/StructureInfoPane.svelte +737 -0
  434. package/dist/structure/StructureInfoPane.svelte.d.ts +19 -0
  435. package/dist/structure/StructureScene.svelte +2255 -0
  436. package/dist/structure/StructureScene.svelte.d.ts +111 -0
  437. package/dist/structure/atom-properties.d.ts +37 -0
  438. package/dist/structure/atom-properties.js +200 -0
  439. package/dist/structure/bond-order-perception.d.ts +13 -0
  440. package/dist/structure/bond-order-perception.js +384 -0
  441. package/dist/structure/bonding.d.ts +68 -0
  442. package/dist/structure/bonding.js +696 -0
  443. package/dist/structure/export.d.ts +20 -0
  444. package/dist/structure/export.js +727 -0
  445. package/dist/structure/index.d.ts +126 -0
  446. package/dist/structure/index.js +169 -0
  447. package/dist/structure/label-placement.d.ts +14 -0
  448. package/dist/structure/label-placement.js +72 -0
  449. package/dist/structure/measure.d.ts +6 -0
  450. package/dist/structure/measure.js +29 -0
  451. package/dist/structure/parse.d.ts +66 -0
  452. package/dist/structure/parse.js +1392 -0
  453. package/dist/structure/partial-occupancy.d.ts +25 -0
  454. package/dist/structure/partial-occupancy.js +99 -0
  455. package/dist/structure/pbc.d.ts +9 -0
  456. package/dist/structure/pbc.js +123 -0
  457. package/dist/structure/supercell.d.ts +8 -0
  458. package/dist/structure/supercell.js +170 -0
  459. package/dist/structure/validation.d.ts +2 -0
  460. package/dist/structure/validation.js +10 -0
  461. package/dist/symmetry/SymmetryStats.svelte +226 -0
  462. package/dist/symmetry/SymmetryStats.svelte.d.ts +21 -0
  463. package/dist/symmetry/WyckoffTable.svelte +120 -0
  464. package/dist/symmetry/WyckoffTable.svelte.d.ts +11 -0
  465. package/dist/symmetry/cell-transform.d.ts +12 -0
  466. package/dist/symmetry/cell-transform.js +91 -0
  467. package/dist/symmetry/index.d.ts +43 -0
  468. package/dist/symmetry/index.js +228 -0
  469. package/dist/symmetry/spacegroups.d.ts +9 -0
  470. package/dist/symmetry/spacegroups.js +394 -0
  471. package/dist/table/HeatmapTable.svelte +1833 -0
  472. package/dist/table/HeatmapTable.svelte.d.ts +49 -0
  473. package/dist/table/ToggleMenu.svelte +385 -0
  474. package/dist/table/ToggleMenu.svelte.d.ts +11 -0
  475. package/dist/table/index.d.ts +74 -0
  476. package/dist/table/index.js +38 -0
  477. package/dist/theme/ThemeControl.svelte +53 -0
  478. package/dist/theme/ThemeControl.svelte.d.ts +9 -0
  479. package/dist/theme/index.d.ts +29 -0
  480. package/dist/theme/index.js +79 -0
  481. package/dist/time.d.ts +4 -0
  482. package/dist/time.js +70 -0
  483. package/dist/tooltip/TooltipContent.svelte +58 -0
  484. package/dist/tooltip/TooltipContent.svelte.d.ts +31 -0
  485. package/dist/tooltip/index.d.ts +2 -0
  486. package/dist/tooltip/index.js +1 -0
  487. package/dist/tooltip/types.d.ts +8 -0
  488. package/dist/tooltip/types.js +1 -0
  489. package/dist/trajectory/Trajectory.svelte +1545 -0
  490. package/dist/trajectory/Trajectory.svelte.d.ts +77 -0
  491. package/dist/trajectory/TrajectoryError.svelte +128 -0
  492. package/dist/trajectory/TrajectoryError.svelte.d.ts +13 -0
  493. package/dist/trajectory/TrajectoryExportPane.svelte +357 -0
  494. package/dist/trajectory/TrajectoryExportPane.svelte.d.ts +17 -0
  495. package/dist/trajectory/TrajectoryInfoPane.svelte +313 -0
  496. package/dist/trajectory/TrajectoryInfoPane.svelte.d.ts +17 -0
  497. package/dist/trajectory/constants.d.ts +6 -0
  498. package/dist/trajectory/constants.js +7 -0
  499. package/dist/trajectory/extract.d.ts +5 -0
  500. package/dist/trajectory/extract.js +162 -0
  501. package/dist/trajectory/format-detect.d.ts +9 -0
  502. package/dist/trajectory/format-detect.js +76 -0
  503. package/dist/trajectory/frame-reader.d.ts +17 -0
  504. package/dist/trajectory/frame-reader.js +332 -0
  505. package/dist/trajectory/helpers.d.ts +15 -0
  506. package/dist/trajectory/helpers.js +164 -0
  507. package/dist/trajectory/index.d.ts +63 -0
  508. package/dist/trajectory/index.js +126 -0
  509. package/dist/trajectory/parse/ase.d.ts +2 -0
  510. package/dist/trajectory/parse/ase.js +73 -0
  511. package/dist/trajectory/parse/hdf5.d.ts +2 -0
  512. package/dist/trajectory/parse/hdf5.js +127 -0
  513. package/dist/trajectory/parse/index.d.ts +12 -0
  514. package/dist/trajectory/parse/index.js +298 -0
  515. package/dist/trajectory/parse/lammps.d.ts +5 -0
  516. package/dist/trajectory/parse/lammps.js +179 -0
  517. package/dist/trajectory/parse/vasp.d.ts +2 -0
  518. package/dist/trajectory/parse/vasp.js +68 -0
  519. package/dist/trajectory/parse/xyz.d.ts +2 -0
  520. package/dist/trajectory/parse/xyz.js +110 -0
  521. package/dist/trajectory/plotting.d.ts +28 -0
  522. package/dist/trajectory/plotting.js +423 -0
  523. package/dist/trajectory/types.d.ts +11 -0
  524. package/dist/trajectory/types.js +1 -0
  525. package/dist/utils.d.ts +6 -0
  526. package/dist/utils.js +45 -0
  527. package/dist/xrd/XrdPlot.svelte +615 -0
  528. package/dist/xrd/XrdPlot.svelte.d.ts +28 -0
  529. package/dist/xrd/broadening.d.ts +20 -0
  530. package/dist/xrd/broadening.js +97 -0
  531. package/dist/xrd/calc-xrd.d.ts +37 -0
  532. package/dist/xrd/calc-xrd.js +336 -0
  533. package/dist/xrd/index.d.ts +37 -0
  534. package/dist/xrd/index.js +4 -0
  535. package/dist/xrd/parse.d.ts +13 -0
  536. package/dist/xrd/parse.js +749 -0
  537. package/license +1 -1
  538. package/package.json +232 -1457
  539. package/readme.md +98 -171
  540. package/.vscode/launch.json +0 -13
  541. package/.vscodeignore +0 -7
  542. package/dist/assets/STLExporter-BpTH3YHE.js +0 -8
  543. package/dist/assets/browser-DdDecX_W.js +0 -1
  544. package/dist/assets/export-qgn-H9y6.js +0 -2
  545. package/dist/assets/main-DiKYzti2.css +0 -1
  546. package/dist/assets/moyo_wasm_bg-0ocwg7xY.wasm +0 -0
  547. package/dist/extension.js +0 -31293
  548. package/dist/src/lib/FilePicker.svelte +0 -360
  549. package/dist/src/lib/MillerIndexInput.svelte +0 -66
  550. package/dist/src/lib/api/mp.ts +0 -26
  551. package/dist/src/lib/api/optimade.ts +0 -204
  552. package/dist/src/lib/brillouin/BrillouinZone.svelte +0 -549
  553. package/dist/src/lib/brillouin/BrillouinZoneControls.svelte +0 -144
  554. package/dist/src/lib/brillouin/BrillouinZoneExportPane.svelte +0 -146
  555. package/dist/src/lib/brillouin/BrillouinZoneInfoPane.svelte +0 -146
  556. package/dist/src/lib/brillouin/BrillouinZoneScene.svelte +0 -476
  557. package/dist/src/lib/brillouin/BrillouinZoneTooltip.svelte +0 -92
  558. package/dist/src/lib/brillouin/compute.ts +0 -529
  559. package/dist/src/lib/brillouin/index.ts +0 -8
  560. package/dist/src/lib/brillouin/types.ts +0 -51
  561. package/dist/src/lib/chempot-diagram/ChemPotDiagram.svelte +0 -327
  562. package/dist/src/lib/chempot-diagram/ChemPotDiagram2D.svelte +0 -846
  563. package/dist/src/lib/chempot-diagram/ChemPotDiagram3D.svelte +0 -3193
  564. package/dist/src/lib/chempot-diagram/async-compute.svelte.ts +0 -94
  565. package/dist/src/lib/chempot-diagram/chempot-worker.ts +0 -11
  566. package/dist/src/lib/chempot-diagram/color.ts +0 -42
  567. package/dist/src/lib/chempot-diagram/compute.ts +0 -1014
  568. package/dist/src/lib/chempot-diagram/index.ts +0 -6
  569. package/dist/src/lib/chempot-diagram/pointer.ts +0 -56
  570. package/dist/src/lib/chempot-diagram/temperature.ts +0 -77
  571. package/dist/src/lib/chempot-diagram/types.ts +0 -130
  572. package/dist/src/lib/colors/index.ts +0 -249
  573. package/dist/src/lib/composition/BarChart.svelte +0 -297
  574. package/dist/src/lib/composition/BubbleChart.svelte +0 -218
  575. package/dist/src/lib/composition/Composition.svelte +0 -165
  576. package/dist/src/lib/composition/Formula.svelte +0 -268
  577. package/dist/src/lib/composition/FormulaFilter.svelte +0 -1257
  578. package/dist/src/lib/composition/PieChart.svelte +0 -323
  579. package/dist/src/lib/composition/format.ts +0 -155
  580. package/dist/src/lib/composition/index.ts +0 -37
  581. package/dist/src/lib/composition/parse.ts +0 -605
  582. package/dist/src/lib/constants.ts +0 -134
  583. package/dist/src/lib/controls.ts +0 -42
  584. package/dist/src/lib/convex-hull/ConvexHull.svelte +0 -157
  585. package/dist/src/lib/convex-hull/ConvexHull2D.svelte +0 -825
  586. package/dist/src/lib/convex-hull/ConvexHull3D.svelte +0 -1801
  587. package/dist/src/lib/convex-hull/ConvexHull4D.svelte +0 -1398
  588. package/dist/src/lib/convex-hull/ConvexHullControls.svelte +0 -535
  589. package/dist/src/lib/convex-hull/ConvexHullInfoPane.svelte +0 -125
  590. package/dist/src/lib/convex-hull/ConvexHullStats.svelte +0 -929
  591. package/dist/src/lib/convex-hull/ConvexHullTooltip.svelte +0 -131
  592. package/dist/src/lib/convex-hull/GasPressureControls.svelte +0 -247
  593. package/dist/src/lib/convex-hull/StructurePopup.svelte +0 -151
  594. package/dist/src/lib/convex-hull/barycentric-coords.ts +0 -246
  595. package/dist/src/lib/convex-hull/demo-temperature.ts +0 -63
  596. package/dist/src/lib/convex-hull/gas-thermodynamics.ts +0 -405
  597. package/dist/src/lib/convex-hull/helpers.ts +0 -932
  598. package/dist/src/lib/convex-hull/index.ts +0 -202
  599. package/dist/src/lib/convex-hull/thermodynamics.ts +0 -2192
  600. package/dist/src/lib/convex-hull/types.ts +0 -267
  601. package/dist/src/lib/coordination/CoordinationBarPlot.svelte +0 -311
  602. package/dist/src/lib/coordination/calc-coordination.ts +0 -93
  603. package/dist/src/lib/coordination/index.ts +0 -9
  604. package/dist/src/lib/effects.svelte.ts +0 -48
  605. package/dist/src/lib/element/ElementHeading.svelte +0 -26
  606. package/dist/src/lib/element/ElementPhoto.svelte +0 -57
  607. package/dist/src/lib/element/ElementStats.svelte +0 -80
  608. package/dist/src/lib/element/ElementTile.svelte +0 -484
  609. package/dist/src/lib/element/data.ts +0 -14
  610. package/dist/src/lib/element/index.ts +0 -8
  611. package/dist/src/lib/element/types.ts +0 -62
  612. package/dist/src/lib/feedback/ClickFeedback.svelte +0 -58
  613. package/dist/src/lib/feedback/DragOverlay.svelte +0 -42
  614. package/dist/src/lib/feedback/index.ts +0 -4
  615. package/dist/src/lib/fermi-surface/FermiSlice.svelte +0 -189
  616. package/dist/src/lib/fermi-surface/FermiSurface.svelte +0 -600
  617. package/dist/src/lib/fermi-surface/FermiSurfaceControls.svelte +0 -448
  618. package/dist/src/lib/fermi-surface/FermiSurfaceScene.svelte +0 -794
  619. package/dist/src/lib/fermi-surface/FermiSurfaceTooltip.svelte +0 -111
  620. package/dist/src/lib/fermi-surface/compute.ts +0 -728
  621. package/dist/src/lib/fermi-surface/constants.ts +0 -32
  622. package/dist/src/lib/fermi-surface/export.ts +0 -64
  623. package/dist/src/lib/fermi-surface/index.ts +0 -14
  624. package/dist/src/lib/fermi-surface/marching-cubes.ts +0 -3
  625. package/dist/src/lib/fermi-surface/parse.ts +0 -574
  626. package/dist/src/lib/fermi-surface/symmetry.ts +0 -56
  627. package/dist/src/lib/fermi-surface/types.ts +0 -159
  628. package/dist/src/lib/heatmap-matrix/HeatmapMatrix.svelte +0 -1545
  629. package/dist/src/lib/heatmap-matrix/HeatmapMatrixControls.svelte +0 -225
  630. package/dist/src/lib/heatmap-matrix/index.ts +0 -167
  631. package/dist/src/lib/heatmap-matrix/shared.ts +0 -7
  632. package/dist/src/lib/icons.ts +0 -650
  633. package/dist/src/lib/index.ts +0 -61
  634. package/dist/src/lib/io/decompress.ts +0 -92
  635. package/dist/src/lib/io/export.ts +0 -385
  636. package/dist/src/lib/io/fetch.ts +0 -46
  637. package/dist/src/lib/io/file-drop.ts +0 -51
  638. package/dist/src/lib/io/index.ts +0 -7
  639. package/dist/src/lib/io/is-binary.ts +0 -24
  640. package/dist/src/lib/io/types.ts +0 -8
  641. package/dist/src/lib/io/url-drop.ts +0 -141
  642. package/dist/src/lib/isosurface/Isosurface.svelte +0 -285
  643. package/dist/src/lib/isosurface/IsosurfaceControls.svelte +0 -277
  644. package/dist/src/lib/isosurface/index.ts +0 -7
  645. package/dist/src/lib/isosurface/parse.ts +0 -656
  646. package/dist/src/lib/isosurface/slice.ts +0 -175
  647. package/dist/src/lib/isosurface/types.ts +0 -309
  648. package/dist/src/lib/labels.ts +0 -320
  649. package/dist/src/lib/layout/FullscreenToggle.svelte +0 -50
  650. package/dist/src/lib/layout/InfoCard.svelte +0 -120
  651. package/dist/src/lib/layout/InfoTag.svelte +0 -185
  652. package/dist/src/lib/layout/PropertyFilter.svelte +0 -246
  653. package/dist/src/lib/layout/SettingsSection.svelte +0 -148
  654. package/dist/src/lib/layout/SubpageGrid.svelte +0 -82
  655. package/dist/src/lib/layout/fullscreen.ts +0 -65
  656. package/dist/src/lib/layout/index.ts +0 -11
  657. package/dist/src/lib/layout/json-tree/JsonNode.svelte +0 -548
  658. package/dist/src/lib/layout/json-tree/JsonTree.svelte +0 -1230
  659. package/dist/src/lib/layout/json-tree/index.ts +0 -3
  660. package/dist/src/lib/layout/json-tree/types.ts +0 -126
  661. package/dist/src/lib/layout/json-tree/utils.ts +0 -682
  662. package/dist/src/lib/marching-cubes.ts +0 -614
  663. package/dist/src/lib/math.ts +0 -1081
  664. package/dist/src/lib/overlays/ContextMenu.svelte +0 -162
  665. package/dist/src/lib/overlays/CopyButton.svelte +0 -45
  666. package/dist/src/lib/overlays/DragControlTab.svelte +0 -98
  667. package/dist/src/lib/overlays/DraggablePane.svelte +0 -487
  668. package/dist/src/lib/overlays/InfoPaneCards.svelte +0 -149
  669. package/dist/src/lib/overlays/index.ts +0 -3
  670. package/dist/src/lib/periodic-table/PeriodicTable.svelte +0 -469
  671. package/dist/src/lib/periodic-table/PeriodicTableControls.svelte +0 -557
  672. package/dist/src/lib/periodic-table/PropertySelect.svelte +0 -37
  673. package/dist/src/lib/periodic-table/index.ts +0 -12
  674. package/dist/src/lib/phase-diagram/IsobaricBinaryPhaseDiagram.svelte +0 -1086
  675. package/dist/src/lib/phase-diagram/PhaseDiagramControls.svelte +0 -444
  676. package/dist/src/lib/phase-diagram/PhaseDiagramEditorPane.svelte +0 -126
  677. package/dist/src/lib/phase-diagram/PhaseDiagramExportPane.svelte +0 -184
  678. package/dist/src/lib/phase-diagram/PhaseDiagramTooltip.svelte +0 -391
  679. package/dist/src/lib/phase-diagram/TdbInfoPanel.svelte +0 -203
  680. package/dist/src/lib/phase-diagram/build-diagram.ts +0 -186
  681. package/dist/src/lib/phase-diagram/colors.ts +0 -58
  682. package/dist/src/lib/phase-diagram/diagram-input.ts +0 -40
  683. package/dist/src/lib/phase-diagram/index.ts +0 -13
  684. package/dist/src/lib/phase-diagram/parse.ts +0 -348
  685. package/dist/src/lib/phase-diagram/svg-to-diagram.ts +0 -1023
  686. package/dist/src/lib/phase-diagram/types.ts +0 -144
  687. package/dist/src/lib/phase-diagram/utils.ts +0 -775
  688. package/dist/src/lib/plot/AxisLabel.svelte +0 -51
  689. package/dist/src/lib/plot/BarPlot.svelte +0 -2113
  690. package/dist/src/lib/plot/BarPlotControls.svelte +0 -66
  691. package/dist/src/lib/plot/BinnedScatterPlot.svelte +0 -1114
  692. package/dist/src/lib/plot/ColorBar.svelte +0 -721
  693. package/dist/src/lib/plot/ColorScaleSelect.svelte +0 -54
  694. package/dist/src/lib/plot/ElementScatter.svelte +0 -63
  695. package/dist/src/lib/plot/Histogram.svelte +0 -1558
  696. package/dist/src/lib/plot/HistogramControls.svelte +0 -212
  697. package/dist/src/lib/plot/InteractiveAxisLabel.svelte +0 -96
  698. package/dist/src/lib/plot/Line.svelte +0 -84
  699. package/dist/src/lib/plot/PlotAxis.svelte +0 -169
  700. package/dist/src/lib/plot/PlotControls.svelte +0 -537
  701. package/dist/src/lib/plot/PlotLegend.svelte +0 -569
  702. package/dist/src/lib/plot/PlotTooltip.svelte +0 -67
  703. package/dist/src/lib/plot/PortalSelect.svelte +0 -253
  704. package/dist/src/lib/plot/ReferenceLine3D.svelte +0 -156
  705. package/dist/src/lib/plot/ReferencePlane.svelte +0 -175
  706. package/dist/src/lib/plot/ScatterPlot.svelte +0 -2778
  707. package/dist/src/lib/plot/ScatterPlot3D.svelte +0 -529
  708. package/dist/src/lib/plot/ScatterPlot3DControls.svelte +0 -437
  709. package/dist/src/lib/plot/ScatterPlot3DScene.svelte +0 -912
  710. package/dist/src/lib/plot/ScatterPlotControls.svelte +0 -306
  711. package/dist/src/lib/plot/ScatterPoint.svelte +0 -182
  712. package/dist/src/lib/plot/SpacegroupBarPlot.svelte +0 -293
  713. package/dist/src/lib/plot/Surface3D.svelte +0 -197
  714. package/dist/src/lib/plot/ZeroLines.svelte +0 -97
  715. package/dist/src/lib/plot/ZoomRect.svelte +0 -23
  716. package/dist/src/lib/plot/adaptive-density.ts +0 -316
  717. package/dist/src/lib/plot/auto-place.ts +0 -184
  718. package/dist/src/lib/plot/axis-utils.ts +0 -122
  719. package/dist/src/lib/plot/binned-scatter-types.ts +0 -83
  720. package/dist/src/lib/plot/data-cleaning.ts +0 -1069
  721. package/dist/src/lib/plot/data-transform.ts +0 -69
  722. package/dist/src/lib/plot/defaults.ts +0 -9
  723. package/dist/src/lib/plot/fill-utils.ts +0 -494
  724. package/dist/src/lib/plot/hover-lock.svelte.ts +0 -60
  725. package/dist/src/lib/plot/index.ts +0 -53
  726. package/dist/src/lib/plot/interactions.ts +0 -119
  727. package/dist/src/lib/plot/layout.ts +0 -425
  728. package/dist/src/lib/plot/reference-line.ts +0 -426
  729. package/dist/src/lib/plot/scales.ts +0 -654
  730. package/dist/src/lib/plot/svg.ts +0 -23
  731. package/dist/src/lib/plot/types.ts +0 -1144
  732. package/dist/src/lib/plot/utils/label-placement.ts +0 -541
  733. package/dist/src/lib/plot/utils/series-visibility.ts +0 -140
  734. package/dist/src/lib/plot/utils.ts +0 -11
  735. package/dist/src/lib/rdf/RdfPlot.svelte +0 -247
  736. package/dist/src/lib/rdf/calc-rdf.ts +0 -167
  737. package/dist/src/lib/rdf/index.ts +0 -27
  738. package/dist/src/lib/sanitize.ts +0 -126
  739. package/dist/src/lib/settings.ts +0 -1479
  740. package/dist/src/lib/spectral/Bands.svelte +0 -1040
  741. package/dist/src/lib/spectral/BandsAndDos.svelte +0 -134
  742. package/dist/src/lib/spectral/BrillouinBandsDos.svelte +0 -252
  743. package/dist/src/lib/spectral/Dos.svelte +0 -697
  744. package/dist/src/lib/spectral/helpers.ts +0 -1381
  745. package/dist/src/lib/spectral/index.ts +0 -8
  746. package/dist/src/lib/spectral/types.ts +0 -112
  747. package/dist/src/lib/state.svelte.ts +0 -64
  748. package/dist/src/lib/structure/Arrow.svelte +0 -72
  749. package/dist/src/lib/structure/AtomLegend.svelte +0 -815
  750. package/dist/src/lib/structure/Bond.svelte +0 -140
  751. package/dist/src/lib/structure/CanvasTooltip.svelte +0 -33
  752. package/dist/src/lib/structure/CellSelect.svelte +0 -349
  753. package/dist/src/lib/structure/Cylinder.svelte +0 -45
  754. package/dist/src/lib/structure/Lattice.svelte +0 -196
  755. package/dist/src/lib/structure/Structure.svelte +0 -2248
  756. package/dist/src/lib/structure/StructureControls.svelte +0 -1273
  757. package/dist/src/lib/structure/StructureExportPane.svelte +0 -252
  758. package/dist/src/lib/structure/StructureInfoPane.svelte +0 -737
  759. package/dist/src/lib/structure/StructureScene.svelte +0 -2255
  760. package/dist/src/lib/structure/atom-properties.ts +0 -316
  761. package/dist/src/lib/structure/bond-order-perception.ts +0 -447
  762. package/dist/src/lib/structure/bonding.ts +0 -944
  763. package/dist/src/lib/structure/export.ts +0 -861
  764. package/dist/src/lib/structure/index.ts +0 -291
  765. package/dist/src/lib/structure/label-placement.ts +0 -130
  766. package/dist/src/lib/structure/measure.ts +0 -45
  767. package/dist/src/lib/structure/parse.ts +0 -1705
  768. package/dist/src/lib/structure/partial-occupancy.ts +0 -183
  769. package/dist/src/lib/structure/pbc.ts +0 -164
  770. package/dist/src/lib/structure/supercell.ts +0 -226
  771. package/dist/src/lib/structure/validation.ts +0 -11
  772. package/dist/src/lib/symmetry/SymmetryStats.svelte +0 -226
  773. package/dist/src/lib/symmetry/WyckoffTable.svelte +0 -120
  774. package/dist/src/lib/symmetry/cell-transform.ts +0 -118
  775. package/dist/src/lib/symmetry/index.ts +0 -348
  776. package/dist/src/lib/symmetry/spacegroups.ts +0 -404
  777. package/dist/src/lib/table/HeatmapTable.svelte +0 -1833
  778. package/dist/src/lib/table/ToggleMenu.svelte +0 -385
  779. package/dist/src/lib/table/index.ts +0 -139
  780. package/dist/src/lib/theme/ThemeControl.svelte +0 -53
  781. package/dist/src/lib/theme/index.ts +0 -107
  782. package/dist/src/lib/time.ts +0 -71
  783. package/dist/src/lib/tooltip/TooltipContent.svelte +0 -58
  784. package/dist/src/lib/tooltip/index.ts +0 -2
  785. package/dist/src/lib/tooltip/types.ts +0 -13
  786. package/dist/src/lib/trajectory/Trajectory.svelte +0 -1545
  787. package/dist/src/lib/trajectory/TrajectoryError.svelte +0 -128
  788. package/dist/src/lib/trajectory/TrajectoryExportPane.svelte +0 -357
  789. package/dist/src/lib/trajectory/TrajectoryInfoPane.svelte +0 -313
  790. package/dist/src/lib/trajectory/constants.ts +0 -7
  791. package/dist/src/lib/trajectory/extract.ts +0 -196
  792. package/dist/src/lib/trajectory/format-detect.ts +0 -96
  793. package/dist/src/lib/trajectory/frame-reader.ts +0 -456
  794. package/dist/src/lib/trajectory/helpers.ts +0 -217
  795. package/dist/src/lib/trajectory/index.ts +0 -218
  796. package/dist/src/lib/trajectory/parse/ase.ts +0 -109
  797. package/dist/src/lib/trajectory/parse/hdf5.ts +0 -173
  798. package/dist/src/lib/trajectory/parse/index.ts +0 -411
  799. package/dist/src/lib/trajectory/parse/lammps.ts +0 -215
  800. package/dist/src/lib/trajectory/parse/vasp.ts +0 -102
  801. package/dist/src/lib/trajectory/parse/xyz.ts +0 -143
  802. package/dist/src/lib/trajectory/plotting.ts +0 -599
  803. package/dist/src/lib/trajectory/types.ts +0 -13
  804. package/dist/src/lib/utils.ts +0 -56
  805. package/dist/src/lib/xrd/XrdPlot.svelte +0 -615
  806. package/dist/src/lib/xrd/broadening.ts +0 -130
  807. package/dist/src/lib/xrd/calc-xrd.ts +0 -397
  808. package/dist/src/lib/xrd/index.ts +0 -38
  809. package/dist/src/lib/xrd/parse.ts +0 -858
  810. package/dist/webview.js +0 -29421
  811. package/icon.png +0 -0
  812. package/matterviz-0.3.2.vsix +0 -0
  813. package/matterviz-0.3.4.vsix +0 -0
  814. package/matterviz-0.3.5.vsix +0 -0
  815. package/scripts/sync-config.ts +0 -101
  816. package/src/declarations.d.ts +0 -2
  817. package/src/extension.ts +0 -972
  818. package/src/node-io.ts +0 -65
  819. package/src/types.ts +0 -17
  820. package/src/webview/JsonBrowser.svelte +0 -1079
  821. package/src/webview/PlotPanel.svelte +0 -346
  822. package/src/webview/detect.ts +0 -444
  823. package/src/webview/main.ts +0 -764
  824. package/src/webview/plot-utils.ts +0 -250
  825. package/test-fixtures/all-viz-types.json.gz +0 -0
  826. package/test-fixtures/plot-demo-data.json.gz +0 -0
  827. package/tests/detect.test.ts +0 -604
  828. package/tests/extension.test.ts +0 -2041
  829. package/tests/node-io.test.ts +0 -39
  830. package/tests/plot-utils.test.ts +0 -302
  831. package/tests/vite-plugin-json-gz.test.ts +0 -114
  832. package/tests/vscode-mock.ts +0 -18
  833. package/tests/webview.test.ts +0 -231
  834. package/tsconfig.json +0 -20
  835. package/vite-plugin-json-gz.ts +0 -29
  836. package/vite.config.ts +0 -34
  837. package/vite.extension.config.ts +0 -34
  838. /package/dist/{src/lib/EmptyState.svelte → EmptyState.svelte} +0 -0
  839. /package/dist/{src/lib/Icon.svelte → Icon.svelte} +0 -0
  840. /package/dist/{src/lib/app.css → app.css} +0 -0
  841. /package/dist/{src/lib/chempot-diagram → chempot-diagram}/ChemPotScene3D.svelte +0 -0
  842. /package/dist/{src/lib/colors → colors}/alloy-colors.json +0 -0
  843. /package/dist/{src/lib/colors → colors}/dark-mode-colors.json +0 -0
  844. /package/dist/{src/lib/colors → colors}/jmol-colors.json +0 -0
  845. /package/dist/{src/lib/colors → colors}/muted-colors.json +0 -0
  846. /package/dist/{src/lib/colors → colors}/pastel-colors.json +0 -0
  847. /package/dist/{src/lib/colors → colors}/vesta-colors.json +0 -0
  848. /package/dist/{src/lib/convex-hull → convex-hull}/TemperatureSlider.svelte +0 -0
  849. /package/dist/{src/lib/element → element}/BohrAtom.svelte +0 -0
  850. /package/dist/{src/lib/element → element}/Nucleus.svelte +0 -0
  851. /package/dist/{src/lib/element → element}/data.json +0 -0
  852. /package/dist/{src/lib/element → element}/data.json.gz +0 -0
  853. /package/dist/{src/lib/element → element}/data.json.gz.d.ts +0 -0
  854. /package/dist/{src/lib/element → element}/data.schema.json +0 -0
  855. /package/dist/{src/lib/element-image-urls.json → element-image-urls.json} +0 -0
  856. /package/dist/{src/lib/feedback → feedback}/Spinner.svelte +0 -0
  857. /package/dist/{src/lib/feedback → feedback}/StatusMessage.svelte +0 -0
  858. /package/dist/{src/lib/layout → layout}/json-tree/JsonValue.svelte +0 -0
  859. /package/dist/{src/lib/periodic-table → periodic-table}/TableInset.svelte +0 -0
  860. /package/dist/{src/lib/plot → plot}/FillArea.svelte +0 -0
  861. /package/dist/{src/lib/plot → plot}/ReferenceLine.svelte +0 -0
  862. /package/dist/{src/lib/theme → theme}/themes.mjs +0 -0
  863. /package/dist/{src/lib/xrd → xrd}/atomic_scattering_params.json +0 -0
@@ -0,0 +1,2113 @@
1
+ <script
2
+ lang="ts"
3
+ generics="Metadata extends Record<string, unknown> = Record<string, unknown>"
4
+ >
5
+ import type { D3ColorSchemeName, D3InterpolateName } from '../colors'
6
+ import { format_value } from '../labels'
7
+ import { sanitize_html } from '../sanitize'
8
+ import { FullscreenToggle, set_fullscreen_bg } from '../layout'
9
+ import type { Point2D, Vec2 } from '../math'
10
+ import type {
11
+ AxisLoadError,
12
+ BarHandlerProps,
13
+ BarMode,
14
+ BarSeries,
15
+ BarStyle,
16
+ BasePlotProps,
17
+ DataLoaderFn,
18
+ InitialRanges,
19
+ InternalPoint,
20
+ LegendConfig,
21
+ LegendItem,
22
+ LineStyle,
23
+ Orientation,
24
+ PanConfig,
25
+ PlotConfig,
26
+ RefLine,
27
+ RefLineEvent,
28
+ ScaleType,
29
+ UserContentProps,
30
+ } from './'
31
+ import {
32
+ BarPlotControls,
33
+ compute_element_placement,
34
+ PlotAxis,
35
+ PlotLegend,
36
+ ReferenceLine,
37
+ ScatterPoint,
38
+ } from './'
39
+ import type { AxisChangeState } from './axis-utils'
40
+ import { create_axis_change_handler } from './axis-utils'
41
+ import { process_prop } from './data-transform'
42
+ import {
43
+ create_dimension_tracker,
44
+ create_hover_lock,
45
+ } from './hover-lock.svelte'
46
+ import {
47
+ get_relative_coords,
48
+ pan_range,
49
+ PINCH_ZOOM_THRESHOLD,
50
+ pixels_to_data_delta,
51
+ } from './interactions'
52
+ import type { IndexedRefLine } from './reference-line'
53
+ import { group_ref_lines_by_z, index_ref_lines } from './reference-line'
54
+ import {
55
+ create_color_scale,
56
+ create_scale,
57
+ create_size_scale,
58
+ generate_ticks,
59
+ get_nice_data_range,
60
+ get_tick_label,
61
+ } from './scales'
62
+ import { DEFAULT_MARKERS, get_scale_type_name } from './types'
63
+ import { DEFAULTS } from '../settings'
64
+ import { extent } from 'd3-array'
65
+ import type { Snippet } from 'svelte'
66
+ import { untrack } from 'svelte'
67
+ import type { HTMLAttributes } from 'svelte/elements'
68
+ import { Tween, type TweenOptions } from 'svelte/motion'
69
+ import { SvelteMap } from 'svelte/reactivity'
70
+ import {
71
+ build_obstacles_norm,
72
+ clip_bar,
73
+ has_explicit_position,
74
+ measured_footprint,
75
+ place_decorations,
76
+ } from './auto-place'
77
+ import {
78
+ calc_auto_padding,
79
+ constrain_tooltip_position,
80
+ filter_padding,
81
+ LABEL_GAP_DEFAULT,
82
+ measure_max_tick_width,
83
+ } from './layout'
84
+ import PlotTooltip from './PlotTooltip.svelte'
85
+ import { bar_path } from './svg'
86
+ import ZeroLines from './ZeroLines.svelte'
87
+ import ZoomRect from './ZoomRect.svelte'
88
+
89
+ // Handler props for line marker events (extends BarHandlerProps with point-specific data)
90
+ interface LineMarkerHandlerProps extends BarHandlerProps<Metadata> {
91
+ point: InternalPoint<Metadata>
92
+ }
93
+
94
+ // Extended point type with computed screen coordinates (used internally for rendering)
95
+ type LineSeriesPoint = InternalPoint<Metadata> & {
96
+ x: number // Screen x coordinate
97
+ y: number // Screen y coordinate
98
+ data_x: number // Original data x value
99
+ data_y: number // Original data y value
100
+ idx: number // Index in series
101
+ }
102
+
103
+ let {
104
+ series = $bindable([]),
105
+ orientation = $bindable(`vertical`),
106
+ mode = $bindable(`overlay`),
107
+ x_axis = $bindable({}),
108
+ x2_axis = $bindable({}),
109
+ y_axis = $bindable({}),
110
+ y2_axis = $bindable({}),
111
+ display = $bindable(DEFAULTS.bar.display),
112
+ x_range = [null, null],
113
+ x2_range = [null, null],
114
+ y_range = [null, null],
115
+ y2_range = [null, null],
116
+ range_padding = 0.05,
117
+ padding = { t: 20, b: 60, l: 60, r: 20 },
118
+ legend = {},
119
+ show_legend,
120
+ bar = {},
121
+ line = {},
122
+ tooltip,
123
+ user_content,
124
+ hovered = $bindable(false),
125
+ change = () => {},
126
+ on_bar_click,
127
+ on_bar_hover,
128
+ // Line marker props (matching ScatterPlot)
129
+ color_scale = {
130
+ type: `linear`,
131
+ scheme: `interpolateViridis`,
132
+ value_range: undefined,
133
+ },
134
+ size_scale = { type: `linear`, radius_range: [2, 10], value_range: undefined },
135
+ point_tween,
136
+ on_point_click,
137
+ on_point_hover,
138
+ ref_lines = $bindable([]),
139
+ on_ref_line_click,
140
+ on_ref_line_hover,
141
+ show_controls = $bindable(true),
142
+ controls_open = $bindable(false),
143
+ controls_toggle_props,
144
+ controls_pane_props,
145
+ fullscreen = $bindable(false),
146
+ fullscreen_toggle = true,
147
+ children,
148
+ header_controls,
149
+ controls_extra,
150
+ data_loader,
151
+ on_axis_change,
152
+ on_error,
153
+ pan = {},
154
+ ...rest
155
+ }: HTMLAttributes<HTMLDivElement> & BasePlotProps & PlotConfig & {
156
+ series?: BarSeries<Metadata>[]
157
+ // Component-specific props
158
+ orientation?: Orientation
159
+ mode?: BarMode
160
+ legend?: LegendConfig | null
161
+ show_legend?: boolean
162
+ bar?: BarStyle
163
+ line?: LineStyle
164
+ tooltip?: Snippet<[BarHandlerProps<Metadata>]>
165
+ user_content?: Snippet<[UserContentProps]>
166
+ header_controls?: Snippet<
167
+ [{ height: number; width: number; fullscreen: boolean }]
168
+ >
169
+ controls_extra?: Snippet<
170
+ [{ orientation: Orientation; mode: BarMode } & Required<PlotConfig>]
171
+ >
172
+ change?: (data: BarHandlerProps<Metadata> | null) => void
173
+ on_bar_click?: (
174
+ data: BarHandlerProps<Metadata> & { event: MouseEvent | KeyboardEvent },
175
+ ) => void
176
+ on_bar_hover?: (
177
+ data:
178
+ | (BarHandlerProps<Metadata> & {
179
+ event: MouseEvent | FocusEvent | KeyboardEvent
180
+ })
181
+ | null,
182
+ ) => void
183
+ // Line marker props (matching ScatterPlot)
184
+ // Note: For line series with markers, BOTH on_bar_* AND on_point_* events fire.
185
+ // Use on_point_* for marker-specific data (includes `point` with InternalPoint details)
186
+ // or on_bar_* for backward compatibility with bar-style event handling.
187
+ color_scale?: {
188
+ type?: ScaleType
189
+ scheme?: D3ColorSchemeName | D3InterpolateName
190
+ value_range?: [number, number]
191
+ } | D3InterpolateName
192
+ size_scale?: {
193
+ type?: ScaleType
194
+ radius_range?: [number, number]
195
+ value_range?: [number, number]
196
+ }
197
+ point_tween?: TweenOptions<Point2D>
198
+ on_point_click?: (
199
+ data: LineMarkerHandlerProps & { event: MouseEvent | KeyboardEvent },
200
+ ) => void
201
+ on_point_hover?: (
202
+ data:
203
+ | (LineMarkerHandlerProps & {
204
+ event: MouseEvent | FocusEvent | KeyboardEvent
205
+ })
206
+ | null,
207
+ ) => void
208
+ ref_lines?: RefLine[]
209
+ on_ref_line_click?: (event: RefLineEvent) => void
210
+ on_ref_line_hover?: (event: RefLineEvent | null) => void
211
+ // Interactive axis props
212
+ data_loader?: DataLoaderFn<Metadata, BarSeries<Metadata>>
213
+ on_axis_change?: (
214
+ axis: `x` | `x2` | `y` | `y2`,
215
+ key: string,
216
+ new_series: BarSeries<Metadata>[],
217
+ ) => void
218
+ on_error?: (error: AxisLoadError) => void
219
+ pan?: PanConfig
220
+ } = $props()
221
+
222
+ // Initialize bar, line, y2_axis with defaults - using $derived for reactivity
223
+ let bar_state = $derived({ ...DEFAULTS.bar.bar, ...bar })
224
+ let line_state = $derived({ ...DEFAULTS.bar.line, ...line })
225
+ y2_axis = {
226
+ format: ``,
227
+ scale_type: `linear`,
228
+ ticks: 5,
229
+ label_shift: { y: 60 },
230
+ tick: { label: { shift: { x: 0, y: 0 } } }, // base offset handled in rendering
231
+ range: [null, null],
232
+ ...y2_axis,
233
+ }
234
+ x2_axis = {
235
+ format: ``,
236
+ scale_type: `linear`,
237
+ ticks: 5,
238
+ label_shift: { x: 0, y: 40 },
239
+ tick: { label: { shift: { x: 0, y: 0 } } },
240
+ range: [null, null],
241
+ ...x2_axis,
242
+ }
243
+
244
+ let [width, height] = $state([0, 0])
245
+ let wrapper: HTMLDivElement | undefined = $state()
246
+ let svg_element: SVGElement | null = $state(null)
247
+ let clip_path_id = `chart-clip-${crypto?.randomUUID?.()}`
248
+
249
+ // Reference line hover state
250
+ let hovered_ref_line_idx = $state<number | null>(null)
251
+
252
+ // Interactive axis loading state
253
+ let axis_loading = $state<`x` | `x2` | `y` | `y2` | null>(null)
254
+
255
+ // Compute ref_lines with index and group by z-index (using shared utilities)
256
+ let indexed_ref_lines = $derived(index_ref_lines(ref_lines))
257
+ let ref_lines_by_z = $derived(group_ref_lines_by_z(indexed_ref_lines))
258
+
259
+ // === Categorical Normalization ===
260
+ // Internal type with guaranteed numeric x (for downstream scale/rendering code)
261
+ type NumericBarSeries = Omit<BarSeries<Metadata>, `x`> & { x: readonly number[] }
262
+
263
+ let is_categorical = $derived(
264
+ series.some((srs) => srs.x.some((val) => typeof val === `string`)),
265
+ )
266
+
267
+ let category_list = $derived.by(() => {
268
+ if (!is_categorical) return [] as string[]
269
+ if (x_axis.categories?.length) return [...x_axis.categories]
270
+ return [...new Set(series.flatMap((srs) => srs.x.map(String)))]
271
+ })
272
+
273
+ let category_indices = $derived(
274
+ category_list.length ? category_list.map((_, idx) => idx) : null,
275
+ )
276
+
277
+ let internal_series = $derived.by<NumericBarSeries[]>(() => {
278
+ // safe: when !category_indices, all x values are numeric (is_categorical is false)
279
+ if (!category_indices) return series as unknown as NumericBarSeries[]
280
+ return series.map((srs) => {
281
+ const orig_map = new Map(srs.x.map((val, idx) => [String(val), idx]))
282
+ if (orig_map.size < srs.x.length) {
283
+ console.warn(
284
+ `BarPlot: series "${
285
+ srs.label ?? `?`
286
+ }" has duplicate x values — last occurrence wins`,
287
+ )
288
+ }
289
+ // Resolve original index for each category (undefined if series lacks it)
290
+ const orig_indices = category_list.map((cat) => orig_map.get(cat))
291
+ const remap = <T>(arr: readonly T[] | null | undefined, fallback: T): T[] =>
292
+ orig_indices.map((oi) => oi != null ? (arr?.[oi] ?? fallback) : fallback)
293
+ const bw_arr = Array.isArray(srs.bar_width) ? srs.bar_width : null
294
+ const meta_arr = Array.isArray(srs.metadata) ? srs.metadata : null
295
+ return {
296
+ ...srs,
297
+ x: category_indices,
298
+ y: remap(srs.y, srs.render_mode === `line` ? NaN : 0),
299
+ labels: remap(srs.labels, null),
300
+ metadata: orig_indices.map((oi) =>
301
+ oi != null ? (meta_arr ? meta_arr[oi] : srs.metadata) : undefined
302
+ ) as Metadata[],
303
+ ...(bw_arr ? { bar_width: remap(bw_arr, 0.5) } : {}),
304
+ ...(srs.color_values ? { color_values: remap(srs.color_values, null) } : {}),
305
+ ...(srs.size_values ? { size_values: remap(srs.size_values, null) } : {}),
306
+ } as NumericBarSeries
307
+ })
308
+ })
309
+
310
+ // Compute auto ranges from visible series
311
+ let visible_series = $derived(
312
+ internal_series.filter((srs) => srs?.visible ?? true),
313
+ )
314
+
315
+ // Separate series by y-axis
316
+ let y1_series = $derived(
317
+ visible_series.filter((srs) => (srs.y_axis ?? `y1`) === `y1`),
318
+ )
319
+ let y2_series = $derived(
320
+ visible_series.filter((srs) => srs.y_axis === `y2`),
321
+ )
322
+ let x2_series = $derived(
323
+ visible_series.filter((srs) => srs.x_axis === `x2`),
324
+ )
325
+
326
+ let auto_ranges = $derived.by(() => {
327
+ // Calculate separate ranges for y1 and y2 axes
328
+ const calc_y_range = (
329
+ series_list: typeof visible_series,
330
+ y_limit: typeof y_range,
331
+ scale_type: ScaleType,
332
+ ) => {
333
+ let points = series_list.flatMap((srs) =>
334
+ srs.x.map((x_val, idx) => ({ x: x_val, y: srs.y[idx] }))
335
+ )
336
+
337
+ // In stacked mode, calculate stacked totals for accurate range (only for bars on the same axis)
338
+ if (mode === `stacked`) {
339
+ const stacked_totals = new SvelteMap<number, { pos: number; neg: number }>()
340
+
341
+ // Only include visible bar series (not lines) in stacking
342
+ series_list
343
+ .filter((srs) => srs.render_mode !== `line`)
344
+ .forEach((srs) =>
345
+ srs.x.forEach((x_val, idx) => {
346
+ const y_val = srs.y[idx] ?? 0
347
+ const totals = stacked_totals.get(x_val) ?? { pos: 0, neg: 0 }
348
+ if (y_val >= 0) totals.pos += y_val
349
+ else totals.neg += y_val
350
+ stacked_totals.set(x_val, totals)
351
+ })
352
+ )
353
+
354
+ // Replace points with stacked totals + line series (which don't stack)
355
+ points = [
356
+ ...Array.from(stacked_totals).flatMap(([x_val, { pos, neg }]) => [
357
+ ...(pos > 0 ? [{ x: x_val, y: pos }] : []),
358
+ ...(neg < 0 ? [{ x: x_val, y: neg }] : []),
359
+ ]),
360
+ ...series_list
361
+ .filter((srs) => srs.render_mode === `line`)
362
+ .flatMap((srs) =>
363
+ srs.x.map((x_val, idx) => ({ x: x_val, y: srs.y[idx] }))
364
+ ),
365
+ ]
366
+ }
367
+
368
+ if (!points.length) return [0, 1]
369
+
370
+ let computed_y_range = get_nice_data_range(
371
+ points,
372
+ (pt) => pt.y,
373
+ y_limit,
374
+ scale_type,
375
+ range_padding,
376
+ false,
377
+ )
378
+
379
+ // For bar plots, ensure the value axis starts at 0 unless there are negative values
380
+ // Only apply zero-clamping for linear and arcsinh scales (not log)
381
+ const type_name = get_scale_type_name(scale_type)
382
+ if (type_name === `linear` || type_name === `arcsinh`) {
383
+ const has_negative = points.some((pt) => pt.y < 0)
384
+ const has_positive = points.some((pt) => pt.y > 0)
385
+
386
+ // Only adjust if no explicit y_range is set
387
+ if (y_limit?.[0] == null && y_limit?.[1] == null) {
388
+ if (has_positive && !has_negative) computed_y_range = [0, computed_y_range[1]]
389
+ else if (has_negative && !has_positive) computed_y_range = [computed_y_range[0], 0]
390
+ }
391
+ }
392
+
393
+ return computed_y_range
394
+ }
395
+
396
+ // Get x values split by axis for range calculation
397
+ // For categorical data, use fixed range centered on integer indices
398
+ let x_auto_range: number[]
399
+ if (category_list.length) {
400
+ x_auto_range = [-0.5, category_list.length - 0.5]
401
+ } else {
402
+ const x1_x_points = visible_series
403
+ .filter((srs) => (srs.x_axis ?? `x1`) === `x1`)
404
+ .flatMap((srs) => srs.x.map((x_val) => ({ x: x_val, y: 0 })))
405
+ x_auto_range = x1_x_points.length
406
+ ? get_nice_data_range(
407
+ x1_x_points,
408
+ (pt) => pt.x,
409
+ x_range,
410
+ x_axis.scale_type ?? `linear`,
411
+ range_padding,
412
+ x_axis.format?.startsWith(`%`) || false,
413
+ )
414
+ : [0, 1]
415
+ }
416
+
417
+ const x2_x_points = x2_series.flatMap((srs) =>
418
+ srs.x.map((x_val) => ({ x: x_val, y: 0 }))
419
+ )
420
+ const x2_scale_type = x2_axis.scale_type ?? `linear`
421
+ const x2_auto_range = x2_x_points.length
422
+ ? get_nice_data_range(
423
+ x2_x_points,
424
+ (pt) => pt.x,
425
+ x2_range,
426
+ x2_scale_type,
427
+ range_padding,
428
+ x2_axis.format?.startsWith(`%`) || false,
429
+ )
430
+ : [0, 1]
431
+
432
+ const y1_range = calc_y_range(y1_series, y_range, y_axis.scale_type ?? `linear`)
433
+ const y2_auto_range = calc_y_range(
434
+ y2_series,
435
+ y2_range,
436
+ y2_axis.scale_type ?? `linear`,
437
+ )
438
+
439
+ // Map data ranges to axis ranges depending on orientation
440
+ return orientation === `horizontal`
441
+ ? ({ x: y1_range, x2: x2_auto_range, y: x_auto_range, y2: y2_auto_range })
442
+ : ({ x: x_auto_range, x2: x2_auto_range, y: y1_range, y2: y2_auto_range })
443
+ })
444
+
445
+ // Initialize and current ranges
446
+ let ranges = $state<{
447
+ initial: { x: Vec2; x2: Vec2; y: Vec2; y2: Vec2 }
448
+ current: { x: Vec2; x2: Vec2; y: Vec2; y2: Vec2 }
449
+ }>({
450
+ initial: { x: [0, 1], x2: [0, 1], y: [0, 1], y2: [0, 1] },
451
+ current: { x: [0, 1], x2: [0, 1], y: [0, 1], y2: [0, 1] },
452
+ })
453
+
454
+ $effect(() => { // handle x_axis.range / x2_axis.range / y_axis.range / y2_axis.range changes
455
+ const new_x = [
456
+ x_axis.range?.[0] ?? auto_ranges.x[0],
457
+ x_axis.range?.[1] ?? auto_ranges.x[1],
458
+ ] as Vec2
459
+ const new_x2 = [
460
+ x2_axis.range?.[0] ?? auto_ranges.x2[0],
461
+ x2_axis.range?.[1] ?? auto_ranges.x2[1],
462
+ ] as Vec2
463
+ const new_y = [
464
+ y_axis.range?.[0] ?? auto_ranges.y[0],
465
+ y_axis.range?.[1] ?? auto_ranges.y[1],
466
+ ] as Vec2
467
+ const new_y2 = [
468
+ y2_axis.range?.[0] ?? auto_ranges.y2[0],
469
+ y2_axis.range?.[1] ?? auto_ranges.y2[1],
470
+ ] as Vec2
471
+ // Only update if the initial (data-driven) ranges changed, not when user pans
472
+ // Comparing against initial preserves user's pan/zoom state
473
+ if (
474
+ ranges.initial.x[0] !== new_x[0] ||
475
+ ranges.initial.x[1] !== new_x[1] ||
476
+ ranges.initial.x2[0] !== new_x2[0] ||
477
+ ranges.initial.x2[1] !== new_x2[1] ||
478
+ ranges.initial.y[0] !== new_y[0] ||
479
+ ranges.initial.y[1] !== new_y[1] ||
480
+ ranges.initial.y2[0] !== new_y2[0] ||
481
+ ranges.initial.y2[1] !== new_y2[1]
482
+ ) {
483
+ ranges = {
484
+ initial: { x: new_x, x2: new_x2, y: new_y, y2: new_y2 },
485
+ current: { x: new_x, x2: new_x2, y: new_y, y2: new_y2 },
486
+ }
487
+ }
488
+ })
489
+
490
+ // Layout: dynamic padding based on tick label widths
491
+ const default_padding = { t: 20, b: 60, l: 60, r: 20 }
492
+ // base_pad reserves space for tick labels/axis titles; pad (below) adds decoration reservations
493
+ let base_pad = $derived(filter_padding(padding, default_padding))
494
+
495
+ // Update padding when format or ticks change
496
+ $effect(() => {
497
+ const new_pad = width && height && ticks.y.length
498
+ ? calc_auto_padding({
499
+ padding,
500
+ default_padding,
501
+ x2_axis: { ...x2_axis, tick_values: ticks.x2 },
502
+ y_axis: { ...y_axis, tick_values: ticks.y },
503
+ y2_axis: { ...y2_axis, tick_values: ticks.y2 },
504
+ })
505
+ : filter_padding(padding, default_padding)
506
+ // Expand right padding if y2 ticks are shown (only for vertical orientation)
507
+ if (
508
+ width && height && y2_series.length && ticks.y2.length &&
509
+ orientation === `vertical`
510
+ ) {
511
+ // Need space for: tick shift + tick width + gap (30px) + label space (20px if present)
512
+ // When ticks are inside, they don't contribute to padding
513
+ const inside = y2_axis.tick?.label?.inside ?? false
514
+ const tick_shift = inside ? 0 : (y2_axis.tick?.label?.shift?.x ?? 0) + 8
515
+ const tick_width_contribution = inside ? 0 : tick_label_widths.y2_max
516
+ const label_space = y2_axis.label ? 20 : 0
517
+ new_pad.r = Math.max(
518
+ new_pad.r,
519
+ tick_shift + tick_width_contribution + 30 + label_space,
520
+ )
521
+ }
522
+ // Expand top padding if x2 ticks are shown (only for vertical orientation)
523
+ if (
524
+ width && height && x2_series.length && ticks.x2.length &&
525
+ orientation === `vertical`
526
+ ) {
527
+ const inside = x2_axis.tick?.label?.inside ?? false
528
+ const tick_shift = inside ? 0 : Math.abs(x2_axis.tick?.label?.shift?.y ?? 0) + 5
529
+ const tick_height = inside ? 0 : 16
530
+ const label_space = x2_axis.label ? 20 : 0
531
+ new_pad.t = Math.max(new_pad.t, tick_shift + tick_height + 30 + label_space)
532
+ }
533
+
534
+ // Only update if padding actually changed (prevents infinite loop)
535
+ if (
536
+ base_pad.t !== new_pad.t || base_pad.b !== new_pad.b ||
537
+ base_pad.l !== new_pad.l || base_pad.r !== new_pad.r
538
+ ) base_pad = new_pad
539
+ })
540
+
541
+ let legend_element = $state<HTMLDivElement | undefined>()
542
+ const legend_footprint = $derived(measured_footprint(legend_element, { width: 120, height: 60 }))
543
+ const legend_has_explicit_pos = $derived(has_explicit_position(legend?.style))
544
+
545
+ // Obstacle field in normalized [0,1] plot coords (y=0 at top). Each bar is modeled as a segment
546
+ // from baseline to its tip so the legend can't hide inside a tall bar. Built from internal_series
547
+ // (pad-independent) + ranges so the crowding decision can't see its own reservation.
548
+ const obstacles_norm = $derived.by(() => {
549
+ if (!width || !height || !visible_series.length) return []
550
+ const base_w = width - base_pad.l - base_pad.r
551
+ const base_h = height - base_pad.t - base_pad.b
552
+ if (base_w <= 0 || base_h <= 0) return []
553
+ const bars: { points: { x: number; y: number }[]; draws_line: boolean }[] = []
554
+ const vertical = orientation === `vertical`
555
+ internal_series.forEach((srs, series_idx) => {
556
+ if (!(srs?.visible ?? true)) return
557
+ const is_line = srs.render_mode === `line`
558
+ const series_offsets = stacked_offsets[series_idx] ?? []
559
+ const [ax0, ax1] = srs.x_axis === `x2` ? ranges.current.x2 : ranges.current.x
560
+ const [vy0, vy1] = srs.y_axis === `y2` ? ranges.current.y2 : ranges.current.y
561
+ const [cy0, cy1] = ranges.current.y
562
+ const x_span = ax1 - ax0
563
+ const y_span = vy1 - vy0
564
+ const cy_span = cy1 - cy0
565
+ if (!(x_span > 0) || !((vertical ? y_span : cy_span) > 0)) return
566
+ srs.x.forEach((x_val, bar_idx) => {
567
+ const base = !is_line && mode === `stacked` ? (series_offsets[bar_idx] ?? 0) : 0
568
+ const value = base + srs.y[bar_idx]
569
+ // vertical: category on x, value rises on y (inverted). horizontal: category on y, value on x
570
+ const seg = vertical
571
+ ? clip_bar(true, (x_val - ax0) / x_span, 1 - (value - vy0) / y_span, 1 - (base - vy0) / y_span)
572
+ : clip_bar(false, 1 - (x_val - cy0) / cy_span, (value - ax0) / x_span, (base - ax0) / x_span)
573
+ if (seg) bars.push(seg)
574
+ })
575
+ })
576
+ return build_obstacles_norm(bars, base_w, base_h)
577
+ })
578
+
579
+ // Move the legend to the bottom margin when no interior spot avoids the bars
580
+ const decor = $derived.by(() =>
581
+ place_decorations({
582
+ base_pad,
583
+ width,
584
+ height,
585
+ obstacles_norm,
586
+ // gate on legend_element (the render signal) not legend_data, whose entries can read pad
587
+ legend: legend != null &&
588
+ (show_legend !== undefined ? show_legend : series.length > 1) &&
589
+ legend_element != null && !legend_has_explicit_pos
590
+ ? { footprint: legend_footprint, clearance: legend?.axis_clearance }
591
+ : null,
592
+ })
593
+ )
594
+ const pad = $derived(decor.pad)
595
+ const legend_auto_outside = $derived(decor.legend_outside)
596
+ const legend_outside_x = $derived(decor.legend_pos.x)
597
+ const legend_outside_y = $derived(decor.legend_pos.y)
598
+ const chart_width = $derived(Math.max(1, width - pad.l - pad.r))
599
+ const chart_height = $derived(Math.max(1, height - pad.t - pad.b))
600
+
601
+ // Scales
602
+ let scales = $derived({
603
+ x: create_scale(x_axis.scale_type ?? `linear`, ranges.current.x, [
604
+ pad.l,
605
+ width - pad.r,
606
+ ]),
607
+ x2: create_scale(x2_axis.scale_type ?? `linear`, ranges.current.x2, [
608
+ pad.l,
609
+ width - pad.r,
610
+ ]),
611
+ y: create_scale(y_axis.scale_type ?? `linear`, ranges.current.y, [
612
+ height - pad.b,
613
+ pad.t,
614
+ ]),
615
+ y2: create_scale(y2_axis.scale_type ?? `linear`, ranges.current.y2, [
616
+ height - pad.b,
617
+ pad.t,
618
+ ]),
619
+ })
620
+
621
+ // Compute plot center for point tweening origin
622
+ let plot_center_x = $derived(pad.l + (width - pad.r - pad.l) / 2)
623
+ let plot_center_y = $derived(pad.t + (height - pad.b - pad.t) / 2)
624
+
625
+ // Compute color values from line series for color scaling (filter to numbers only)
626
+ let all_color_values = $derived(
627
+ visible_series
628
+ .filter((srs: BarSeries<Metadata>) => srs.render_mode === `line`)
629
+ .flatMap((srs: BarSeries<Metadata>) =>
630
+ (srs.color_values ?? []).filter(
631
+ (val): val is number => typeof val === `number`,
632
+ )
633
+ ),
634
+ )
635
+
636
+ // Create auto color range (safely handle empty arrays or undefined extent results)
637
+ let auto_color_range: [number, number] = $derived.by(() => {
638
+ if (all_color_values.length === 0) return [0, 1]
639
+ const [min_val, max_val] = extent(all_color_values)
640
+ return [min_val ?? 0, max_val ?? 1]
641
+ })
642
+
643
+ // All size values from line series (for size scale, filter to numbers only)
644
+ let all_size_values = $derived(
645
+ visible_series
646
+ .filter((srs: BarSeries<Metadata>) => srs.render_mode === `line`)
647
+ .flatMap((srs: BarSeries<Metadata>) =>
648
+ [...(srs.size_values ?? [])].filter(
649
+ (val): val is number => typeof val === `number`,
650
+ )
651
+ ),
652
+ )
653
+
654
+ // Color scale function (using shared utility)
655
+ let color_scale_fn = $derived(create_color_scale(color_scale, auto_color_range))
656
+
657
+ // Size scale function (using shared utility)
658
+ let size_scale_fn = $derived(create_size_scale(size_scale, all_size_values))
659
+
660
+ // Auto-generate tick labels for categorical data (unless user provides explicit ticks)
661
+ // In vertical mode categories are on x-axis; in horizontal mode on y-axis
662
+ let cat_axis = $derived(orientation === `horizontal` ? `y` : `x`)
663
+ let effective_cat_ticks = $derived.by(() => {
664
+ if (!category_list.length) return undefined
665
+ // Only respect user ticks when they're a Record (custom label mapping),
666
+ // not a number (tick count) or array (tick positions)
667
+ const user_ticks = cat_axis === `x` ? x_axis.ticks : y_axis.ticks
668
+ if (
669
+ user_ticks != null && typeof user_ticks === `object` &&
670
+ !Array.isArray(user_ticks)
671
+ ) return user_ticks
672
+ return Object.fromEntries(
673
+ category_list.map((cat, idx) => [idx, cat]),
674
+ ) as Record<number, string>
675
+ })
676
+
677
+ // Ticks
678
+ let ticks = $derived({
679
+ x: width && height
680
+ ? (category_indices && cat_axis === `x` ? category_indices : generate_ticks(
681
+ ranges.current.x,
682
+ x_axis.scale_type ?? `linear`,
683
+ x_axis.ticks,
684
+ scales.x,
685
+ { default_count: 8 },
686
+ ))
687
+ : [],
688
+ y: width && height
689
+ ? (category_indices && cat_axis === `y` ? category_indices : generate_ticks(
690
+ ranges.current.y,
691
+ y_axis.scale_type ?? `linear`,
692
+ y_axis.ticks,
693
+ scales.y,
694
+ { default_count: 6 },
695
+ ))
696
+ : [],
697
+ y2: width && height && y2_series.length > 0 && orientation === `vertical`
698
+ ? generate_ticks(
699
+ ranges.current.y2,
700
+ y2_axis.scale_type ?? `linear`,
701
+ y2_axis.ticks,
702
+ scales.y2,
703
+ {
704
+ default_count: 6,
705
+ },
706
+ )
707
+ : [],
708
+ x2: width && height && x2_series.length > 0 && orientation === `vertical`
709
+ ? generate_ticks(
710
+ ranges.current.x2,
711
+ x2_axis.scale_type ?? `linear`,
712
+ x2_axis.ticks,
713
+ scales.x2,
714
+ {
715
+ default_count: 8,
716
+ },
717
+ )
718
+ : [],
719
+ })
720
+
721
+ // Cache measured tick-label widths so expensive canvas text measurement
722
+ // only runs when ticks/format change, not on every template rerender.
723
+ let tick_label_widths = $derived({
724
+ y_max: measure_max_tick_width(ticks.y, y_axis.format ?? ``),
725
+ y2_max: measure_max_tick_width(ticks.y2, y2_axis.format ?? ``),
726
+ x2_max: measure_max_tick_width(ticks.x2, x2_axis.format ?? ``),
727
+ })
728
+
729
+ // Zoom drag state
730
+ let drag_state = $state<{
731
+ start: { x: number; y: number } | null
732
+ current: { x: number; y: number } | null
733
+ bounds: DOMRect | null
734
+ }>({ start: null, current: null, bounds: null })
735
+
736
+ // Pan state
737
+ let is_focused = $state(false)
738
+ let shift_held = $state(false)
739
+ let pan_drag_state = $state<
740
+ InitialRanges & { start: { x: number; y: number } } | null
741
+ >(null)
742
+ let touch_state = $state<
743
+ InitialRanges & { start_touches: { x: number; y: number }[] } | null
744
+ >(null)
745
+ const on_window_mouse_move = (evt: MouseEvent) => {
746
+ if (!drag_state.start || !drag_state.bounds) return
747
+ drag_state.current = {
748
+ x: evt.clientX - drag_state.bounds.left,
749
+ y: evt.clientY - drag_state.bounds.top,
750
+ }
751
+ }
752
+ const on_window_mouse_up = () => {
753
+ if (drag_state.start && drag_state.current) {
754
+ const x1_raw = scales.x.invert(drag_state.start.x) as number | Date
755
+ const x2_raw = scales.x.invert(drag_state.current.x) as number | Date
756
+ const y1 = scales.y.invert(drag_state.start.y)
757
+ const y2 = scales.y.invert(drag_state.current.y)
758
+ const y2_1 = scales.y2.invert(drag_state.start.y)
759
+ const y2_2 = scales.y2.invert(drag_state.current.y)
760
+ const x2a_1_raw = scales.x2.invert(drag_state.start.x) as number | Date
761
+ const x2a_2_raw = scales.x2.invert(drag_state.current.x) as number | Date
762
+ const dx = Math.abs(drag_state.start.x - drag_state.current.x)
763
+ const dy = Math.abs(drag_state.start.y - drag_state.current.y)
764
+
765
+ let xr1: number, xr2: number
766
+ if (x1_raw instanceof Date && x2_raw instanceof Date) {
767
+ ;[xr1, xr2] = [x1_raw.getTime(), x2_raw.getTime()]
768
+ } else if (typeof x1_raw === `number` && typeof x2_raw === `number`) {
769
+ ;[xr1, xr2] = [x1_raw, x2_raw]
770
+ } else [xr1, xr2] = [NaN, NaN] // bail: mixed types
771
+
772
+ let x2r1: number, x2r2: number
773
+ if (x2a_1_raw instanceof Date && x2a_2_raw instanceof Date) {
774
+ ;[x2r1, x2r2] = [x2a_1_raw.getTime(), x2a_2_raw.getTime()]
775
+ } else if (typeof x2a_1_raw === `number` && typeof x2a_2_raw === `number`) {
776
+ ;[x2r1, x2r2] = [x2a_1_raw, x2a_2_raw]
777
+ } else [x2r1, x2r2] = [NaN, NaN]
778
+
779
+ if (dx > 5 && dy > 5 && Number.isFinite(xr1) && Number.isFinite(xr2)) {
780
+ // Update axis ranges to trigger reactivity and prevent effect from overriding
781
+ x_axis = { ...x_axis, range: [Math.min(xr1, xr2), Math.max(xr1, xr2)] }
782
+ if (x2_series.length > 0 && Number.isFinite(x2r1) && Number.isFinite(x2r2)) {
783
+ x2_axis = {
784
+ ...x2_axis,
785
+ range: [Math.min(x2r1, x2r2), Math.max(x2r1, x2r2)],
786
+ }
787
+ }
788
+ y_axis = { ...y_axis, range: [Math.min(y1, y2), Math.max(y1, y2)] }
789
+ y2_axis = { ...y2_axis, range: [Math.min(y2_1, y2_2), Math.max(y2_1, y2_2)] }
790
+ }
791
+ }
792
+ drag_state = { start: null, current: null, bounds: null }
793
+ window.removeEventListener(`mousemove`, on_window_mouse_move)
794
+ window.removeEventListener(`mouseup`, on_window_mouse_up)
795
+ document.body.style.cursor = `default`
796
+ }
797
+
798
+ // Pan drag handlers
799
+ const on_pan_move = (evt: MouseEvent) => {
800
+ if (!pan_drag_state) return
801
+ const dx = evt.clientX - pan_drag_state.start.x
802
+ const dy = evt.clientY - pan_drag_state.start.y
803
+
804
+ // Convert pixel delta to data delta (note: drag direction is inverted for natural pan feel)
805
+ const sensitivity = pan?.drag_sensitivity ?? 1
806
+
807
+ const x_delta = pixels_to_data_delta(
808
+ -dx * sensitivity,
809
+ pan_drag_state.initial_x_range,
810
+ chart_width,
811
+ )
812
+ const x2_delta = pixels_to_data_delta(
813
+ -dx * sensitivity,
814
+ pan_drag_state.initial_x2_range,
815
+ chart_width,
816
+ )
817
+ const y_delta = pixels_to_data_delta(
818
+ dy * sensitivity,
819
+ pan_drag_state.initial_y_range,
820
+ chart_height,
821
+ )
822
+ const y2_delta = pixels_to_data_delta(
823
+ dy * sensitivity,
824
+ pan_drag_state.initial_y2_range,
825
+ chart_height,
826
+ )
827
+
828
+ ranges.current.x = pan_range(pan_drag_state.initial_x_range, x_delta)
829
+ ranges.current.x2 = pan_range(pan_drag_state.initial_x2_range, x2_delta)
830
+ ranges.current.y = pan_range(pan_drag_state.initial_y_range, y_delta)
831
+ ranges.current.y2 = pan_range(pan_drag_state.initial_y2_range, y2_delta)
832
+ }
833
+
834
+ const on_pan_end = () => {
835
+ pan_drag_state = null
836
+ document.body.style.cursor = ``
837
+ window.removeEventListener(`mousemove`, on_pan_move)
838
+ window.removeEventListener(`mouseup`, on_pan_end)
839
+ }
840
+
841
+ function handle_mouse_down(evt: MouseEvent) {
842
+ const coords = get_relative_coords(evt)
843
+ if (!coords || !svg_element) return
844
+
845
+ // Check if pan is enabled and shift is held for pan mode
846
+ const pan_enabled = pan?.enabled !== false
847
+ if (pan_enabled && evt.shiftKey) {
848
+ evt.preventDefault()
849
+ pan_drag_state = {
850
+ start: { x: evt.clientX, y: evt.clientY },
851
+ initial_x_range: [...ranges.current.x] as [number, number],
852
+ initial_x2_range: [...ranges.current.x2] as [number, number],
853
+ initial_y_range: [...ranges.current.y] as [number, number],
854
+ initial_y2_range: [...ranges.current.y2] as [number, number],
855
+ }
856
+ document.body.style.cursor = `grabbing`
857
+ window.addEventListener(`mousemove`, on_pan_move)
858
+ window.addEventListener(`mouseup`, on_pan_end)
859
+ return
860
+ }
861
+
862
+ drag_state = {
863
+ start: coords,
864
+ current: coords,
865
+ bounds: svg_element.getBoundingClientRect(),
866
+ }
867
+ window.addEventListener(`mousemove`, on_window_mouse_move)
868
+ window.addEventListener(`mouseup`, on_window_mouse_up)
869
+ evt.preventDefault()
870
+ }
871
+
872
+ // Wheel handler for pan (requires focus and shift)
873
+ function handle_wheel(evt: WheelEvent) {
874
+ const pan_enabled = pan?.enabled !== false
875
+ // Only capture wheel when focused AND Shift is held
876
+ // Use shift_held state (tracked via keydown/keyup) for compatibility with synthetic events
877
+ if (!pan_enabled || !is_focused || !shift_held) return
878
+
879
+ evt.preventDefault()
880
+
881
+ const sensitivity = pan?.wheel_sensitivity ?? 1
882
+
883
+ // Determine pan direction based on wheel delta
884
+ const x_delta = pixels_to_data_delta(
885
+ evt.deltaX * sensitivity,
886
+ ranges.current.x,
887
+ chart_width,
888
+ )
889
+ const x2_delta = pixels_to_data_delta(
890
+ evt.deltaX * sensitivity,
891
+ ranges.current.x2,
892
+ chart_width,
893
+ )
894
+ const y_delta = pixels_to_data_delta(
895
+ evt.deltaY * sensitivity,
896
+ ranges.current.y,
897
+ chart_height,
898
+ )
899
+ const y2_delta = pixels_to_data_delta(
900
+ evt.deltaY * sensitivity,
901
+ ranges.current.y2,
902
+ chart_height,
903
+ )
904
+
905
+ if (Math.abs(evt.deltaX) > Math.abs(evt.deltaY)) {
906
+ ranges.current.x = pan_range(ranges.current.x, x_delta)
907
+ ranges.current.x2 = pan_range(ranges.current.x2, x2_delta)
908
+ } else {
909
+ ranges.current.y = pan_range(ranges.current.y, y_delta)
910
+ ranges.current.y2 = pan_range(ranges.current.y2, y2_delta)
911
+ }
912
+ }
913
+
914
+ // Touch handlers for pinch-zoom and two-finger pan
915
+ function handle_touch_start(evt: TouchEvent) {
916
+ const touch_enabled = pan?.enabled !== false && pan?.touch_enabled !== false
917
+ if (!touch_enabled || evt.touches.length !== 2) return
918
+
919
+ evt.preventDefault()
920
+ const touches = Array.from(evt.touches)
921
+ touch_state = {
922
+ start_touches: touches.map((touch) => ({ x: touch.clientX, y: touch.clientY })),
923
+ initial_x_range: [...ranges.current.x] as [number, number],
924
+ initial_x2_range: [...ranges.current.x2] as [number, number],
925
+ initial_y_range: [...ranges.current.y] as [number, number],
926
+ initial_y2_range: [...ranges.current.y2] as [number, number],
927
+ }
928
+ }
929
+
930
+ function handle_touch_move(evt: TouchEvent) {
931
+ if (!touch_state || evt.touches.length !== 2) return
932
+ evt.preventDefault()
933
+
934
+ const [t1, t2] = Array.from(evt.touches)
935
+ const [s1, s2] = touch_state.start_touches
936
+
937
+ // Calculate center movement for pan
938
+ const start_center = { x: (s1.x + s2.x) / 2, y: (s1.y + s2.y) / 2 }
939
+ const curr_center = {
940
+ x: (t1.clientX + t2.clientX) / 2,
941
+ y: (t1.clientY + t2.clientY) / 2,
942
+ }
943
+ const dx = curr_center.x - start_center.x
944
+ const dy = curr_center.y - start_center.y
945
+
946
+ // Calculate pinch scale (curr/start so spread = zoom out, pinch = zoom in)
947
+ const start_dist = Math.hypot(s2.x - s1.x, s2.y - s1.y)
948
+ // Guard against zero-distance pinch to avoid Infinity scale
949
+ if (start_dist < Number.EPSILON) return
950
+ const curr_dist = Math.hypot(t2.clientX - t1.clientX, t2.clientY - t1.clientY)
951
+ const scale = curr_dist / start_dist
952
+
953
+ // If scale changed significantly, treat as pinch-zoom
954
+ // Also guard against scale being too small to avoid division by zero
955
+ if (Math.abs(scale - 1) > PINCH_ZOOM_THRESHOLD && scale > Number.EPSILON) {
956
+ // Pinch zoom centered on gesture center
957
+ // Divide by scale so spread (scale > 1) = smaller span (zoom in)
958
+ const x_span = touch_state.initial_x_range[1] - touch_state.initial_x_range[0]
959
+ const x2_span = touch_state.initial_x2_range[1] -
960
+ touch_state.initial_x2_range[0]
961
+ const y_span = touch_state.initial_y_range[1] - touch_state.initial_y_range[0]
962
+ const y2_span = touch_state.initial_y2_range[1] -
963
+ touch_state.initial_y2_range[0]
964
+ const x_center =
965
+ (touch_state.initial_x_range[0] + touch_state.initial_x_range[1]) / 2
966
+ const x2_center =
967
+ (touch_state.initial_x2_range[0] + touch_state.initial_x2_range[1]) / 2
968
+ const y_center =
969
+ (touch_state.initial_y_range[0] + touch_state.initial_y_range[1]) / 2
970
+ const y2_center =
971
+ (touch_state.initial_y2_range[0] + touch_state.initial_y2_range[1]) / 2
972
+
973
+ ranges.current.x = [
974
+ x_center - x_span / scale / 2,
975
+ x_center + x_span / scale / 2,
976
+ ]
977
+ ranges.current.x2 = [
978
+ x2_center - x2_span / scale / 2,
979
+ x2_center + x2_span / scale / 2,
980
+ ]
981
+ ranges.current.y = [
982
+ y_center - y_span / scale / 2,
983
+ y_center + y_span / scale / 2,
984
+ ]
985
+ ranges.current.y2 = [
986
+ y2_center - y2_span / scale / 2,
987
+ y2_center + y2_span / scale / 2,
988
+ ]
989
+ } else {
990
+ // Pan
991
+ const x_delta = pixels_to_data_delta(
992
+ -dx,
993
+ touch_state.initial_x_range,
994
+ chart_width,
995
+ )
996
+ const x2_delta = pixels_to_data_delta(
997
+ -dx,
998
+ touch_state.initial_x2_range,
999
+ chart_width,
1000
+ )
1001
+ const y_delta = pixels_to_data_delta(
1002
+ dy,
1003
+ touch_state.initial_y_range,
1004
+ chart_height,
1005
+ )
1006
+ const y2_delta = pixels_to_data_delta(
1007
+ dy,
1008
+ touch_state.initial_y2_range,
1009
+ chart_height,
1010
+ )
1011
+ ranges.current.x = pan_range(touch_state.initial_x_range, x_delta)
1012
+ ranges.current.x2 = pan_range(touch_state.initial_x2_range, x2_delta)
1013
+ ranges.current.y = pan_range(touch_state.initial_y_range, y_delta)
1014
+ ranges.current.y2 = pan_range(touch_state.initial_y2_range, y2_delta)
1015
+ }
1016
+ }
1017
+
1018
+ function handle_touch_end() {
1019
+ touch_state = null
1020
+ }
1021
+
1022
+ // Legend data and handlers
1023
+ let legend_data = $derived.by<LegendItem[]>(() =>
1024
+ series.map((srs: BarSeries<Metadata>, idx: number) => {
1025
+ const is_line = srs.render_mode === `line`
1026
+ const series_markers = srs.markers ?? DEFAULT_MARKERS
1027
+ const has_line = series_markers === `line` || series_markers === `line+points`
1028
+ const has_points = series_markers === `points` ||
1029
+ series_markers === `line+points`
1030
+ const series_color = srs.color ?? (is_line ? line_state.color : bar_state.color)
1031
+
1032
+ // Get point style for symbol color (handle array or single object)
1033
+ const first_point_style = Array.isArray(srs.point_style)
1034
+ ? srs.point_style[0]
1035
+ : srs.point_style
1036
+ const first_color_value = srs.color_values?.[0]
1037
+ const point_color = first_color_value != null
1038
+ ? color_scale_fn(first_color_value)
1039
+ : first_point_style?.fill ?? series_color
1040
+
1041
+ if (is_line) {
1042
+ // Line series: show line and/or symbol based on markers
1043
+ return {
1044
+ series_idx: idx,
1045
+ label: srs.label ?? `Series ${idx + 1}`,
1046
+ visible: srs.visible ?? true,
1047
+ legend_group: srs.legend_group,
1048
+ display_style: {
1049
+ ...(has_line
1050
+ ? {
1051
+ line_color: series_color,
1052
+ line_dash: srs.line_style?.line_dash,
1053
+ }
1054
+ : {}),
1055
+ ...(has_points
1056
+ ? {
1057
+ symbol_type: first_point_style?.symbol_type ??
1058
+ DEFAULTS.scatter.symbol_type,
1059
+ symbol_color: point_color,
1060
+ }
1061
+ : {}),
1062
+ },
1063
+ }
1064
+ }
1065
+ // Bar series: show square symbol
1066
+ return {
1067
+ series_idx: idx,
1068
+ label: srs.label ?? `Series ${idx + 1}`,
1069
+ visible: srs.visible ?? true,
1070
+ legend_group: srs.legend_group,
1071
+ display_style: {
1072
+ symbol_type: `Square` as const,
1073
+ symbol_color: series_color,
1074
+ },
1075
+ }
1076
+ })
1077
+ )
1078
+
1079
+ function toggle_series_visibility(series_idx: number) {
1080
+ if (series_idx >= 0 && series_idx < series.length) {
1081
+ series = series.map((srs, idx) =>
1082
+ idx === series_idx ? { ...srs, visible: !(srs.visible ?? true) } : srs
1083
+ )
1084
+ }
1085
+ }
1086
+
1087
+ function toggle_group_visibility(_group_name: string, series_indices: number[]) {
1088
+ // Filter to valid indices upfront (consistent with shared toggle_group_visibility)
1089
+ const valid_indices = series_indices.filter((idx) =>
1090
+ idx >= 0 && idx < series.length
1091
+ )
1092
+ if (valid_indices.length === 0) return
1093
+
1094
+ const idx_set = new Set(valid_indices)
1095
+ // Check if all series in the group are currently visible
1096
+ const all_visible = valid_indices.every((idx) => series[idx].visible ?? true)
1097
+ // Toggle: if all visible, hide all; otherwise show all
1098
+ const new_visibility = !all_visible
1099
+ series = series.map((srs, idx) =>
1100
+ idx_set.has(idx) ? { ...srs, visible: new_visibility } : srs
1101
+ )
1102
+ }
1103
+
1104
+ // Collect bar and line positions for legend placement
1105
+ let bar_points_for_placement = $derived.by(() => {
1106
+ if (!width || !height || !visible_series.length) return []
1107
+
1108
+ return internal_series.flatMap((srs, series_idx) => {
1109
+ if (!(srs?.visible ?? true)) return []
1110
+ const is_line = srs.render_mode === `line`
1111
+ const series_offsets = stacked_offsets[series_idx] ?? []
1112
+ const use_y2 = srs.y_axis === `y2`
1113
+ const y_scale = use_y2 ? scales.y2 : scales.y
1114
+ const use_x2_pl = srs.x_axis === `x2`
1115
+ const x_scale_pl = use_x2_pl ? scales.x2 : scales.x
1116
+ return srs.x
1117
+ .map((x_val, bar_idx) => {
1118
+ const y_val = srs.y[bar_idx]
1119
+ const base = !is_line && mode === `stacked`
1120
+ ? (series_offsets[bar_idx] ?? 0)
1121
+ : 0
1122
+ const [bar_x, bar_y] = orientation === `vertical`
1123
+ ? [x_scale_pl(x_val), y_scale(base + y_val)]
1124
+ : [x_scale_pl(base + y_val), scales.y(x_val)]
1125
+ return { x: bar_x, y: bar_y }
1126
+ })
1127
+ .filter(({ x, y }) => isFinite(x) && isFinite(y))
1128
+ })
1129
+ })
1130
+
1131
+ // Legend placement stability state (legend_element declared above for the auto-place block)
1132
+ let hovered_legend_series_idx = $state<number | null>(null)
1133
+ const legend_hover = create_hover_lock()
1134
+ const dim_tracker = create_dimension_tracker()
1135
+ let has_initial_legend_placement = $state(false)
1136
+
1137
+ // Clear pending hover lock timeout on unmount
1138
+ $effect(() => () => legend_hover.cleanup())
1139
+
1140
+ // Calculate best legend placement using continuous grid sampling
1141
+ let legend_placement = $derived.by(() => {
1142
+ const should_show = show_legend !== undefined ? show_legend : series.length > 1
1143
+ if (!should_show || !width || !height) return null
1144
+
1145
+ const result = compute_element_placement({
1146
+ plot_bounds: { x: pad.l, y: pad.t, width: chart_width, height: chart_height },
1147
+ element: legend_element,
1148
+ element_size: { width: 120, height: 60 }, // fallback before first render
1149
+ axis_clearance: legend?.axis_clearance,
1150
+ exclude_rects: [],
1151
+ points: bar_points_for_placement,
1152
+ })
1153
+
1154
+ return result
1155
+ })
1156
+
1157
+ // Tweened legend coordinates for smooth animation - create once, update target via effect
1158
+ // untrack() explicitly captures initial tween config (intentional - config set once at mount)
1159
+ const tweened_legend_coords = new Tween(
1160
+ { x: 0, y: 0 },
1161
+ untrack(() => ({ duration: 400, ...legend?.tween })),
1162
+ )
1163
+
1164
+ // Update legend position with stability checks
1165
+ $effect(() => {
1166
+ if (!width || !height || !legend_placement) return
1167
+
1168
+ // Track dimensions for resize detection
1169
+ const dims_changed = dim_tracker.has_changed(width, height)
1170
+ if (dims_changed) dim_tracker.update(width, height)
1171
+
1172
+ const is_responsive = legend?.responsive ?? false
1173
+ // Only update if: resize occurred, OR (not hover-locked AND (responsive OR not yet initially placed))
1174
+ const should_update = dims_changed || (!legend_hover.is_locked.current &&
1175
+ (is_responsive || !has_initial_legend_placement))
1176
+
1177
+ if (should_update) {
1178
+ tweened_legend_coords.set(
1179
+ { x: legend_placement.x, y: legend_placement.y },
1180
+ // Skip animation on initial placement to avoid jump from (0, 0)
1181
+ has_initial_legend_placement ? undefined : { duration: 0 },
1182
+ )
1183
+ // Only lock position after we have actual measured size
1184
+ if (legend_element) {
1185
+ has_initial_legend_placement = true
1186
+ }
1187
+ }
1188
+ })
1189
+
1190
+ // Tooltip state
1191
+ let hover_info = $state<BarHandlerProps<Metadata> | null>(null)
1192
+ let tooltip_el = $state<HTMLDivElement | undefined>()
1193
+
1194
+ function get_bar_data(
1195
+ series_idx: number,
1196
+ bar_idx: number,
1197
+ color: string,
1198
+ ): BarHandlerProps<Metadata> {
1199
+ const srs = internal_series[series_idx]
1200
+ const [x, y] = [srs.x[bar_idx], srs.y[bar_idx]]
1201
+ const [orient_x, orient_y] = orientation === `horizontal` ? [y, x] : [x, y]
1202
+ const metadata = Array.isArray(srs.metadata)
1203
+ ? srs.metadata[bar_idx]
1204
+ : srs.metadata
1205
+ const label = srs.labels?.[bar_idx] ?? null
1206
+ const active_y_axis = srs.y_axis ?? `y1`
1207
+ const active_x_axis = srs.x_axis ?? `x1`
1208
+ const category_label = category_list[x]
1209
+ const coords = {
1210
+ x,
1211
+ y,
1212
+ orient_x,
1213
+ orient_y,
1214
+ x_axis: active_x_axis === `x2` ? x2_axis : x_axis,
1215
+ x2_axis,
1216
+ y_axis: active_y_axis === `y2` ? y2_axis : y_axis,
1217
+ y2_axis,
1218
+ }
1219
+ return {
1220
+ ...coords,
1221
+ metadata,
1222
+ color,
1223
+ label,
1224
+ series_idx,
1225
+ bar_idx,
1226
+ active_y_axis,
1227
+ active_x_axis,
1228
+ category_label,
1229
+ }
1230
+ }
1231
+
1232
+ // Find the point closest to the cursor on a polyline overlay (O(n) scan).
1233
+ function find_closest_point(
1234
+ evt: MouseEvent,
1235
+ points: LineSeriesPoint[],
1236
+ ): LineSeriesPoint | null {
1237
+ const target = evt.target
1238
+ if (!(target instanceof Element)) return null
1239
+ const svg_el = target.closest(`svg`)
1240
+ if (!svg_el) return null
1241
+ const rect = svg_el.getBoundingClientRect()
1242
+ const mx = evt.clientX - rect.left
1243
+ const my = evt.clientY - rect.top
1244
+ let best: LineSeriesPoint | null = null
1245
+ let best_dist = Infinity
1246
+ for (const pt of points) {
1247
+ const dist = (pt.x - mx) ** 2 + (pt.y - my) ** 2
1248
+ if (dist < best_dist) {
1249
+ best_dist = dist
1250
+ best = pt
1251
+ }
1252
+ }
1253
+ return best
1254
+ }
1255
+
1256
+ const line_point_fill = (pt: LineSeriesPoint, series_color: string): string =>
1257
+ pt.color_value != null
1258
+ ? color_scale_fn(pt.color_value)
1259
+ : pt.point_style?.fill ?? series_color
1260
+
1261
+ const handle_bar_hover =
1262
+ (series_idx: number, bar_idx: number, color: string) => (event: MouseEvent) => {
1263
+ hovered = true
1264
+ hover_info = get_bar_data(series_idx, bar_idx, color)
1265
+ change(hover_info)
1266
+ on_bar_hover?.({ ...hover_info, event })
1267
+ }
1268
+
1269
+ // Stack offsets (only for bar series in stacked mode, grouped by y-axis)
1270
+ let stacked_offsets = $derived.by(() => {
1271
+ if (mode !== `stacked`) return [] as number[][]
1272
+ const max_len = Math.max(
1273
+ 0,
1274
+ ...internal_series.map((srs) => srs.y.length),
1275
+ )
1276
+ const offsets = internal_series.map(() =>
1277
+ Array.from({ length: max_len }, () => 0)
1278
+ )
1279
+
1280
+ // Separate accumulators for y1 and y2 axes
1281
+ const y1_pos_acc = Array.from({ length: max_len }, () => 0)
1282
+ const y1_neg_acc = Array.from({ length: max_len }, () => 0)
1283
+ const y2_pos_acc = Array.from({ length: max_len }, () => 0)
1284
+ const y2_neg_acc = Array.from({ length: max_len }, () => 0)
1285
+
1286
+ internal_series.forEach((srs, series_idx) => {
1287
+ if (!(srs?.visible ?? true) || srs.render_mode === `line`) return
1288
+
1289
+ const use_y2 = srs.y_axis === `y2`
1290
+ const pos_acc = use_y2 ? y2_pos_acc : y1_pos_acc
1291
+ const neg_acc = use_y2 ? y2_neg_acc : y1_neg_acc
1292
+
1293
+ for (let bar_idx = 0; bar_idx < max_len; bar_idx++) {
1294
+ const y_val = srs.y[bar_idx] ?? 0
1295
+ const acc = y_val >= 0 ? pos_acc : neg_acc
1296
+ offsets[series_idx][bar_idx] = acc[bar_idx]
1297
+ acc[bar_idx] += y_val
1298
+ }
1299
+ })
1300
+ return offsets
1301
+ })
1302
+
1303
+ // Calculate group positions for grouped mode (side-by-side bars)
1304
+ let group_info = $derived.by(() => {
1305
+ if (mode !== `grouped`) return { bar_series_count: 0, bar_series_indices: [] }
1306
+ const bar_series_indices = internal_series
1307
+ .map((srs, idx) =>
1308
+ (srs?.visible ?? true) && srs.render_mode !== `line` ? idx : -1
1309
+ )
1310
+ .filter((idx) => idx >= 0)
1311
+ return { bar_series_count: bar_series_indices.length, bar_series_indices }
1312
+ })
1313
+
1314
+ // Set theme-aware background when entering fullscreen
1315
+ $effect(() => {
1316
+ set_fullscreen_bg(wrapper, fullscreen, `--barplot-fullscreen-bg`)
1317
+ })
1318
+
1319
+ // State accessors for shared axis change handler
1320
+ const axis_state: AxisChangeState<BarSeries<Metadata>> = {
1321
+ get_axis: (axis) => {
1322
+ if (axis === `x`) return x_axis
1323
+ if (axis === `x2`) return x2_axis
1324
+ if (axis === `y`) return y_axis
1325
+ return y2_axis
1326
+ },
1327
+ set_axis: (axis, config) => {
1328
+ // Spread into existing state to preserve merged type structure
1329
+ if (axis === `x`) x_axis = { ...x_axis, ...config }
1330
+ else if (axis === `x2`) x2_axis = { ...x2_axis, ...config }
1331
+ else if (axis === `y`) y_axis = { ...y_axis, ...config }
1332
+ else y2_axis = { ...y2_axis, ...config }
1333
+ },
1334
+ get_series: () => series,
1335
+ set_series: (new_series) => (series = new_series),
1336
+ get_loading: () => axis_loading,
1337
+ set_loading: (axis) => (axis_loading = axis),
1338
+ }
1339
+
1340
+ // Create shared handler bound to this component's state
1341
+ // Using $derived so handler updates when callback props change
1342
+ const handle_axis_change = $derived(create_axis_change_handler(
1343
+ axis_state,
1344
+ data_loader,
1345
+ on_axis_change,
1346
+ on_error,
1347
+ ))
1348
+
1349
+ let auto_load_attempted = false // prevent infinite retries on failure
1350
+
1351
+ // Auto-load data if series is empty but options exist (runs once)
1352
+ $effect(() => {
1353
+ if (series.length === 0 && data_loader && !auto_load_attempted) {
1354
+ // Check x-axis first, then y-axis
1355
+ if (x_axis.options?.length) {
1356
+ auto_load_attempted = true
1357
+ const first_key = x_axis.selected_key ?? x_axis.options[0].key
1358
+ handle_axis_change(`x`, first_key).catch(() => {})
1359
+ } else if (y_axis.options?.length) {
1360
+ auto_load_attempted = true
1361
+ const first_key = y_axis.selected_key ?? y_axis.options[0].key
1362
+ handle_axis_change(`y`, first_key).catch(() => {})
1363
+ }
1364
+ }
1365
+ })
1366
+ </script>
1367
+
1368
+ {#snippet ref_lines_layer(lines: IndexedRefLine[])}
1369
+ {#each lines as line (line.id ?? line.idx)}
1370
+ <ReferenceLine
1371
+ ref_line={line}
1372
+ line_idx={line.idx}
1373
+ x_min={line.x_axis === `x2` ? ranges.current.x2[0] : ranges.current.x[0]}
1374
+ x_max={line.x_axis === `x2` ? ranges.current.x2[1] : ranges.current.x[1]}
1375
+ y_min={line.y_axis === `y2` ? ranges.current.y2[0] : ranges.current.y[0]}
1376
+ y_max={line.y_axis === `y2` ? ranges.current.y2[1] : ranges.current.y[1]}
1377
+ x_scale={scales.x}
1378
+ x2_scale={scales.x2}
1379
+ y_scale={scales.y}
1380
+ y2_scale={scales.y2}
1381
+ {clip_path_id}
1382
+ hovered_line_idx={hovered_ref_line_idx}
1383
+ on_click={(event: RefLineEvent) => {
1384
+ line.on_click?.(event)
1385
+ on_ref_line_click?.(event)
1386
+ }}
1387
+ on_hover={(event: RefLineEvent | null) => {
1388
+ hovered_ref_line_idx = event?.line_idx ?? null
1389
+ line.on_hover?.(event)
1390
+ on_ref_line_hover?.(event)
1391
+ }}
1392
+ />
1393
+ {/each}
1394
+ {/snippet}
1395
+
1396
+ <svelte:window
1397
+ onkeydown={(evt) => {
1398
+ if (evt.key === `Escape` && fullscreen) {
1399
+ evt.preventDefault()
1400
+ fullscreen = false
1401
+ }
1402
+ if (evt.key === `Shift`) shift_held = true
1403
+ }}
1404
+ onkeyup={(evt) => {
1405
+ if (evt.key === `Shift`) shift_held = false
1406
+ }}
1407
+ />
1408
+
1409
+ <div
1410
+ bind:this={wrapper}
1411
+ bind:clientWidth={width}
1412
+ bind:clientHeight={height}
1413
+ {...rest}
1414
+ class="bar-plot {rest.class ?? ``}"
1415
+ class:fullscreen
1416
+ >
1417
+ {#if width && height}
1418
+ <div class="header-controls">
1419
+ {@render header_controls?.({ height, width, fullscreen })}
1420
+ {#if fullscreen_toggle}
1421
+ <FullscreenToggle bind:fullscreen />
1422
+ {/if}
1423
+ </div>
1424
+ <!-- svelte-ignore a11y_no_noninteractive_tabindex -->
1425
+ <!-- svelte-ignore a11y_no_noninteractive_element_interactions -->
1426
+ <svg
1427
+ bind:this={svg_element}
1428
+ role="application"
1429
+ aria-label={rest[`aria-label`] ??
1430
+ ([x_axis.label, y_axis.label].filter(Boolean).join(` vs `) || `Bar chart`)}
1431
+ tabindex="0"
1432
+ onfocusin={() => (is_focused = true)}
1433
+ onfocusout={() => (is_focused = false)}
1434
+ onmousedown={handle_mouse_down}
1435
+ ondblclick={() => {
1436
+ // Reset zoom to initial ranges (undo any pan/zoom)
1437
+ ranges.current.x = [...ranges.initial.x] as [number, number]
1438
+ ranges.current.x2 = [...ranges.initial.x2] as [number, number]
1439
+ ranges.current.y = [...ranges.initial.y] as [number, number]
1440
+ ranges.current.y2 = [...ranges.initial.y2] as [number, number]
1441
+ // Also reset axis props so future data changes recalculate auto ranges
1442
+ x_axis = { ...x_axis, range: [null, null] }
1443
+ x2_axis = { ...x2_axis, range: [null, null] }
1444
+ y_axis = { ...y_axis, range: [null, null] }
1445
+ y2_axis = { ...y2_axis, range: [null, null] }
1446
+ }}
1447
+ onmouseleave={() => {
1448
+ hovered = false
1449
+ hover_info = null
1450
+ change(null)
1451
+ on_bar_hover?.(null)
1452
+ }}
1453
+ onwheel={handle_wheel}
1454
+ ontouchstart={handle_touch_start}
1455
+ ontouchmove={handle_touch_move}
1456
+ ontouchend={handle_touch_end}
1457
+ style:cursor={pan_drag_state
1458
+ ? `grabbing`
1459
+ : shift_held && pan?.enabled !== false
1460
+ ? `grab`
1461
+ : `crosshair`}
1462
+ >
1463
+ <ZoomRect start={drag_state.start} current={drag_state.current} />
1464
+
1465
+ <!-- User content (custom overlays, reference lines, etc.) -->
1466
+ {@render user_content?.({
1467
+ height,
1468
+ width,
1469
+ x_scale_fn: scales.x,
1470
+ x2_scale_fn: scales.x2,
1471
+ y_scale_fn: scales.y,
1472
+ y2_scale_fn: scales.y2,
1473
+ pad,
1474
+ x_range: ranges.current.x,
1475
+ x2_range: ranges.current.x2,
1476
+ y_range: ranges.current.y,
1477
+ y2_range: ranges.current.y2,
1478
+ fullscreen,
1479
+ })}
1480
+
1481
+ <!-- Reference lines: below grid (rendered before axes which contain grid lines) -->
1482
+ {@render ref_lines_layer(ref_lines_by_z.below_grid)}
1483
+
1484
+ <!-- X-axis -->
1485
+ <PlotAxis
1486
+ side="x"
1487
+ ticks={ticks.x as number[]}
1488
+ place={scales.x}
1489
+ axis={x_axis}
1490
+ {pad}
1491
+ {width}
1492
+ {height}
1493
+ show_grid={display.x_grid}
1494
+ tick_label={(tick) =>
1495
+ get_tick_label(tick, cat_axis === `x` ? effective_cat_ticks : x_axis.ticks)}
1496
+ label_x={pad.l + chart_width / 2 + (x_axis.label_shift?.x ?? 0)}
1497
+ label_y={height - pad.b / 3 + (x_axis.label_shift?.y ?? 0)}
1498
+ axis_loading={axis_loading === `x`}
1499
+ on_axis_change={(key) => handle_axis_change(`x`, key)}
1500
+ />
1501
+
1502
+ <!-- X2-axis (Top) -->
1503
+ <!-- Note: x2 axis is only supported for vertical orientation -->
1504
+ {#if x2_series.length > 0 && orientation === `vertical`}
1505
+ <PlotAxis
1506
+ side="x2"
1507
+ ticks={ticks.x2 as number[]}
1508
+ place={scales.x2}
1509
+ axis={x2_axis}
1510
+ {pad}
1511
+ {width}
1512
+ {height}
1513
+ show_grid={display.x2_grid}
1514
+ tick_label={(tick) => get_tick_label(tick, x2_axis.ticks)}
1515
+ label_x={pad.l + chart_width / 2 + (x2_axis.label_shift?.x ?? 0)}
1516
+ label_y={Math.max(12, pad.t - (x2_axis.label_shift?.y ?? 40))}
1517
+ axis_loading={axis_loading === `x2`}
1518
+ on_axis_change={(key) => handle_axis_change(`x2`, key)}
1519
+ />
1520
+ {/if}
1521
+
1522
+ <!-- Y-axis -->
1523
+ <PlotAxis
1524
+ side="y"
1525
+ ticks={ticks.y as number[]}
1526
+ place={scales.y}
1527
+ axis={y_axis}
1528
+ {pad}
1529
+ {width}
1530
+ {height}
1531
+ show_grid={display.y_grid}
1532
+ tick_label={(tick) =>
1533
+ get_tick_label(tick, cat_axis === `y` ? effective_cat_ticks : y_axis.ticks)}
1534
+ label_x={Math.max(
1535
+ 12,
1536
+ pad.l - (y_axis.tick?.label?.inside ? 0 : tick_label_widths.y_max) -
1537
+ LABEL_GAP_DEFAULT,
1538
+ ) + (y_axis.label_shift?.x ?? 0)}
1539
+ label_y={pad.t + chart_height / 2 + (y_axis.label_shift?.y ?? 0)}
1540
+ axis_loading={axis_loading === `y`}
1541
+ on_axis_change={(key) => handle_axis_change(`y`, key)}
1542
+ />
1543
+
1544
+ <!-- Y2-axis (Right) -->
1545
+ <!-- Note: y2 axis is only supported for vertical orientation. Implementing x2 for horizontal mode requires additional complexity. -->
1546
+ {#if y2_series.length > 0 && orientation === `vertical`}
1547
+ {@const y2_inside = y2_axis.tick?.label?.inside ?? false}
1548
+ {@const y2_tick_shift = y2_inside ? 0 : (y2_axis.tick?.label?.shift?.x ?? 0) + 8}
1549
+ {@const y2_tick_width = y2_inside ? 0 : tick_label_widths.y2_max}
1550
+ <PlotAxis
1551
+ side="y2"
1552
+ ticks={ticks.y2 as number[]}
1553
+ place={scales.y2}
1554
+ axis={y2_axis}
1555
+ {pad}
1556
+ {width}
1557
+ {height}
1558
+ show_grid={display.y2_grid}
1559
+ tick_label={(tick) => get_tick_label(tick, y2_axis.ticks)}
1560
+ label_x={width - pad.r + y2_tick_shift + y2_tick_width + LABEL_GAP_DEFAULT +
1561
+ (y2_axis.label_shift?.x ?? 0)}
1562
+ label_y={pad.t + chart_height / 2 + (y2_axis.label_shift?.y ?? 0)}
1563
+ axis_loading={axis_loading === `y2`}
1564
+ on_axis_change={(key) => handle_axis_change(`y2`, key)}
1565
+ />
1566
+ {/if}
1567
+
1568
+ <!-- Define clip path for chart area -->
1569
+ <defs>
1570
+ <clipPath id={clip_path_id}>
1571
+ <rect x={pad.l} y={pad.t} width={chart_width} height={chart_height} />
1572
+ </clipPath>
1573
+ </defs>
1574
+
1575
+ <!-- Clipped content: zero lines, bars, and lines -->
1576
+ <g clip-path="url(#{clip_path_id})">
1577
+ <ZeroLines
1578
+ {display}
1579
+ x_scale_fn={scales.x}
1580
+ x2_scale_fn={scales.x2}
1581
+ y_scale_fn={scales.y}
1582
+ y2_scale_fn={scales.y2}
1583
+ x_range={ranges.current.x}
1584
+ x2_range={ranges.current.x2}
1585
+ y_range={ranges.current.y}
1586
+ y2_range={ranges.current.y2}
1587
+ x_scale_type={x_axis.scale_type}
1588
+ x2_scale_type={x2_axis.scale_type}
1589
+ y_scale_type={y_axis.scale_type}
1590
+ y2_scale_type={y2_axis.scale_type}
1591
+ x_is_time={x_axis.format?.startsWith(`%`) ?? false}
1592
+ x2_is_time={x2_axis.format?.startsWith(`%`) ?? false}
1593
+ has_x2={x2_series.length > 0}
1594
+ has_y2={y2_series.length > 0}
1595
+ {width}
1596
+ {height}
1597
+ {pad}
1598
+ />
1599
+
1600
+ <!-- Reference lines: below lines -->
1601
+ {@render ref_lines_layer(ref_lines_by_z.below_lines)}
1602
+
1603
+ <!-- Bars and Lines -->
1604
+ {#each internal_series as srs, series_idx (srs?.id ?? series_idx)}
1605
+ {#if srs?.visible ?? true}
1606
+ {@const is_line = srs.render_mode === `line`}
1607
+ <g
1608
+ class={is_line ? `line-series` : `bar-series`}
1609
+ data-series-idx={series_idx}
1610
+ opacity={hovered_legend_series_idx !== null &&
1611
+ hovered_legend_series_idx !== series_idx
1612
+ ? 0.25
1613
+ : 1}
1614
+ >
1615
+ {#if is_line}
1616
+ <!-- Render as line -->
1617
+ {@const color = srs.color ?? line_state.color ?? `steelblue`}
1618
+ {@const stroke_width = srs.line_style?.stroke_width ?? line_state.width ?? 2}
1619
+ {@const line_dash = srs.line_style?.line_dash ?? `none`}
1620
+ {@const use_y2 = srs.y_axis === `y2`}
1621
+ {@const y_scale = use_y2 ? scales.y2 : scales.y}
1622
+ {@const use_x2 = srs.x_axis === `x2`}
1623
+ {@const x_scale = use_x2 ? scales.x2 : scales.x}
1624
+ {@const series_markers = srs.markers ?? DEFAULT_MARKERS}
1625
+ {@const show_line = series_markers === `line` ||
1626
+ series_markers === `line+points`}
1627
+ {@const show_points = series_markers === `points` ||
1628
+ series_markers === `line+points`}
1629
+ {@const points = srs.x.map((x_val, idx) => {
1630
+ const y_val = srs.y[idx]
1631
+ // Lines don't stack - they show absolute values (useful for totals/trends)
1632
+ const plot_x = orientation === `vertical`
1633
+ ? x_scale(x_val)
1634
+ : x_scale(y_val)
1635
+ const plot_y = orientation === `vertical`
1636
+ ? y_scale(y_val)
1637
+ : scales.y(x_val)
1638
+ // Create internal point with all needed data
1639
+ const color_value = srs.color_values?.[idx] ?? null
1640
+ const size_value = srs.size_values?.[idx] ?? null
1641
+ const point_style = process_prop(srs.point_style, idx)
1642
+ const point_hover = process_prop(srs.point_hover, idx)
1643
+ const point_label = process_prop(srs.point_label, idx)
1644
+ const point_offset = process_prop(srs.point_offset, idx)
1645
+ const metadata = Array.isArray(srs.metadata)
1646
+ ? srs.metadata[idx]
1647
+ : srs.metadata
1648
+ return {
1649
+ x: plot_x,
1650
+ y: plot_y,
1651
+ data_x: x_val,
1652
+ data_y: y_val,
1653
+ idx,
1654
+ color_value,
1655
+ size_value,
1656
+ point_style,
1657
+ point_hover,
1658
+ point_label,
1659
+ point_offset,
1660
+ metadata,
1661
+ series_idx,
1662
+ point_idx: idx,
1663
+ } as LineSeriesPoint
1664
+ }).filter((pt) => isFinite(pt.x) && isFinite(pt.y))}
1665
+ {@const polyline_str = show_line && points.length > 1
1666
+ ? points.map((pt) => `${pt.x},${pt.y}`).join(` `)
1667
+ : ``}
1668
+ {#if polyline_str}
1669
+ <polyline
1670
+ points={polyline_str}
1671
+ fill="none"
1672
+ stroke={color}
1673
+ stroke-width={stroke_width}
1674
+ stroke-dasharray={line_dash}
1675
+ stroke-linejoin="round"
1676
+ stroke-linecap="round"
1677
+ />
1678
+ {/if}
1679
+ {#if polyline_str && !show_points && (on_bar_hover || on_bar_click)}
1680
+ <!-- svelte-ignore a11y_no_static_element_interactions -->
1681
+ <!-- svelte-ignore a11y_click_events_have_key_events -->
1682
+ <polyline
1683
+ points={polyline_str}
1684
+ fill="none"
1685
+ stroke="transparent"
1686
+ stroke-width={Math.max(10, stroke_width * 3)}
1687
+ stroke-linejoin="round"
1688
+ stroke-linecap="round"
1689
+ style:cursor={on_bar_click ? `pointer` : undefined}
1690
+ onmousemove={(evt) => {
1691
+ const pt = find_closest_point(evt, points)
1692
+ if (!pt) return
1693
+ hovered = true
1694
+ const fill = line_point_fill(pt, color)
1695
+ hover_info = get_bar_data(series_idx, pt.idx, fill)
1696
+ change(hover_info)
1697
+ on_bar_hover?.({ ...hover_info!, event: evt })
1698
+ }}
1699
+ onmouseleave={() => {
1700
+ change(null)
1701
+ hover_info = null
1702
+ on_bar_hover?.(null)
1703
+ }}
1704
+ onclick={(evt) => {
1705
+ const pt = find_closest_point(evt, points)
1706
+ if (!pt) return
1707
+ const fill = line_point_fill(pt, color)
1708
+ const bar_data = get_bar_data(series_idx, pt.idx, fill)
1709
+ on_bar_click?.({ ...bar_data, event: evt })
1710
+ }}
1711
+ />
1712
+ {/if}
1713
+ {#if show_points}
1714
+ {@const clickable = on_bar_click || on_point_click}
1715
+ {@const get_pt = (evt: Event) => {
1716
+ const attr = evt.target instanceof Element
1717
+ ? evt.target.closest(`[data-bar-idx]`)?.getAttribute(
1718
+ `data-bar-idx`,
1719
+ )
1720
+ : null
1721
+ return points.find((pt) => pt.idx === parseInt(attr ?? ``, 10))
1722
+ }}
1723
+ {@const set_hover = (
1724
+ pt: LineSeriesPoint | null,
1725
+ evt: MouseEvent | FocusEvent,
1726
+ ) => {
1727
+ if (pt) {
1728
+ hovered = true
1729
+ const fill = line_point_fill(pt, color)
1730
+ hover_info = get_bar_data(series_idx, pt.idx, fill)
1731
+ change(hover_info)
1732
+ } else {
1733
+ change(null)
1734
+ hover_info = null
1735
+ }
1736
+ on_bar_hover?.(pt ? { ...hover_info!, event: evt } : null)
1737
+ on_point_hover?.(
1738
+ pt ? { ...hover_info!, event: evt, point: pt } : null,
1739
+ )
1740
+ }}
1741
+ {@const do_click = (
1742
+ pt: LineSeriesPoint,
1743
+ evt: MouseEvent | KeyboardEvent,
1744
+ ) => {
1745
+ const fill = line_point_fill(pt, color)
1746
+ const bar_data = get_bar_data(series_idx, pt.idx, fill)
1747
+ on_bar_click?.({ ...bar_data, event: evt })
1748
+ on_point_click?.({ ...bar_data, event: evt, point: pt })
1749
+ }}
1750
+ {@const leaving = (evt: MouseEvent | FocusEvent) =>
1751
+ (evt.relatedTarget instanceof Element
1752
+ ? evt.relatedTarget.closest(`.line-points`)
1753
+ : null) !== evt.currentTarget}
1754
+ <!-- svelte-ignore a11y_no_noninteractive_element_interactions, a11y_mouse_events_have_key_events -->
1755
+ <g
1756
+ class="line-points"
1757
+ role="group"
1758
+ onmouseover={(evt) => {
1759
+ const pt = get_pt(evt)
1760
+ if (pt) set_hover(pt, evt)
1761
+ }}
1762
+ onfocusin={(evt) => {
1763
+ const pt = get_pt(evt)
1764
+ if (pt) set_hover(pt, evt)
1765
+ }}
1766
+ onmouseout={(evt) => {
1767
+ if (leaving(evt)) set_hover(null, evt)
1768
+ }}
1769
+ onfocusout={(evt) => {
1770
+ if (leaving(evt)) set_hover(null, evt)
1771
+ }}
1772
+ onclick={(evt) => {
1773
+ const pt = get_pt(evt)
1774
+ if (pt && clickable) do_click(pt, evt)
1775
+ }}
1776
+ onkeydown={(evt) => {
1777
+ const pt = get_pt(evt)
1778
+ if (pt && clickable && (evt.key === `Enter` || evt.key === ` `)) {
1779
+ evt.preventDefault()
1780
+ do_click(pt, evt)
1781
+ }
1782
+ }}
1783
+ >
1784
+ {#each points as pt (pt.idx)}
1785
+ {@const sty = pt.point_style}
1786
+ {@const fl = line_point_fill(pt, color)}
1787
+ {@const rad = pt.size_value != null
1788
+ ? size_scale_fn(pt.size_value)
1789
+ : sty?.radius ?? 4}
1790
+ {@const hov = hover_info?.series_idx === series_idx &&
1791
+ hover_info?.bar_idx === pt.idx}
1792
+ <ScatterPoint
1793
+ x={pt.x}
1794
+ y={pt.y}
1795
+ is_hovered={hov}
1796
+ {point_tween}
1797
+ style={{
1798
+ ...sty,
1799
+ radius: rad,
1800
+ fill: fl,
1801
+ stroke: sty?.stroke ?? `transparent`,
1802
+ stroke_width: sty?.stroke_width ?? 1,
1803
+ fill_opacity: sty?.fill_opacity ?? 1,
1804
+ stroke_opacity: sty?.stroke_opacity ?? 1,
1805
+ cursor: clickable ? `pointer` : undefined,
1806
+ }}
1807
+ hover={pt.point_hover ?? {}}
1808
+ label={pt.point_label ?? {}}
1809
+ offset={pt.point_offset ?? { x: 0, y: 0 }}
1810
+ origin={{ x: plot_center_x, y: plot_center_y }}
1811
+ --point-fill-color={fl}
1812
+ data-bar-idx={pt.idx}
1813
+ tabindex={clickable ? (hov ? 0 : -1) : undefined}
1814
+ />
1815
+ {/each}
1816
+ </g>
1817
+ {/if}
1818
+ {:else}
1819
+ <!-- Render as bars -->
1820
+ {#each srs.x as x_val, bar_idx (bar_idx)}
1821
+ {@const y_val = srs.y[bar_idx]}
1822
+ {@const base = mode === `stacked`
1823
+ ? (stacked_offsets[series_idx]?.[bar_idx] ?? 0)
1824
+ : 0}
1825
+ {@const color = srs.color ?? bar_state.color ?? `steelblue`}
1826
+ {@const bar_width_val = Array.isArray(srs.bar_width)
1827
+ ? (srs.bar_width[bar_idx] ?? 0.5)
1828
+ : (srs.bar_width ?? 0.5)}
1829
+ {@const half = mode === `grouped` && group_info.bar_series_count > 1
1830
+ ? bar_width_val / (2 * group_info.bar_series_count)
1831
+ : bar_width_val / 2}
1832
+ {@const calculate_group_offset = (idx: number) => {
1833
+ const position = group_info.bar_series_indices.indexOf(idx)
1834
+ const offset = position - (group_info.bar_series_count - 1) / 2
1835
+ return offset * (bar_width_val / group_info.bar_series_count)
1836
+ }}
1837
+ {@const group_offset = mode === `grouped` && group_info.bar_series_count > 1
1838
+ ? calculate_group_offset(series_idx)
1839
+ : 0}
1840
+ {@const is_vertical = orientation === `vertical`}
1841
+ {@const cat_val = x_val}
1842
+ {@const val = y_val}
1843
+ {@const use_y2 = srs.y_axis === `y2`}
1844
+ {@const y_scale = use_y2 ? scales.y2 : scales.y}
1845
+ {@const use_x2_bar = srs.x_axis === `x2`}
1846
+ {@const x_scale_bar = use_x2_bar ? scales.x2 : scales.x}
1847
+ {@const [cat_scale, val_scale] = is_vertical
1848
+ ? [x_scale_bar, y_scale]
1849
+ : [scales.y, x_scale_bar]}
1850
+ {@const c0 = cat_scale(cat_val + group_offset - half)}
1851
+ {@const c1 = cat_scale(cat_val + group_offset + half)}
1852
+ {@const v0 = val_scale(base)}
1853
+ {@const v1 = val_scale(base + val)}
1854
+ {@const [rect_x, rect_y] = is_vertical
1855
+ ? [Math.min(c0, c1), Math.min(v0, v1)]
1856
+ : [Math.min(v0, v1), Math.min(c0, c1)]}
1857
+ {@const [rect_w, rect_h] = is_vertical
1858
+ ? [Math.max(1, Math.abs(c1 - c0)), Math.max(0, Math.abs(v1 - v0))]
1859
+ : [Math.max(1, Math.abs(v1 - v0)), Math.max(0, Math.abs(c1 - c0))]}
1860
+ {#if (is_vertical ? rect_h : rect_w) > 0}
1861
+ <path
1862
+ d={bar_path(
1863
+ rect_x,
1864
+ rect_y,
1865
+ rect_w,
1866
+ rect_h,
1867
+ Math.min(bar_state.border_radius ?? 0, rect_w / 2, rect_h / 2),
1868
+ is_vertical,
1869
+ )}
1870
+ fill={color}
1871
+ opacity={mode === `overlay` ? bar_state.opacity : 1}
1872
+ stroke={bar_state.stroke_color}
1873
+ stroke-opacity={bar_state.stroke_opacity}
1874
+ stroke-width={bar_state.stroke_width}
1875
+ role="button"
1876
+ tabindex="0"
1877
+ aria-label={`bar ${bar_idx + 1} of ${srs.label ?? `series`}`}
1878
+ style:cursor={on_bar_click ? `pointer` : undefined}
1879
+ onmousemove={handle_bar_hover(series_idx, bar_idx, color)}
1880
+ onmouseleave={() => {
1881
+ hover_info = null
1882
+ change(null)
1883
+ on_bar_hover?.(null)
1884
+ }}
1885
+ onclick={(evt) =>
1886
+ on_bar_click?.({
1887
+ ...get_bar_data(series_idx, bar_idx, color),
1888
+ event: evt,
1889
+ })}
1890
+ onkeydown={(evt) => {
1891
+ if (evt.key === `Enter` || evt.key === ` `) {
1892
+ evt.preventDefault()
1893
+ on_bar_click?.({
1894
+ ...get_bar_data(series_idx, bar_idx, color),
1895
+ event: evt,
1896
+ })
1897
+ }
1898
+ }}
1899
+ />
1900
+ {#if srs.labels?.[bar_idx]}
1901
+ <text
1902
+ x={is_vertical ? (c0 + c1) / 2 : Math.max(v0, v1) + 4}
1903
+ y={is_vertical ? Math.max(0, Math.min(v0, v1) - 6) : (c0 + c1) / 2}
1904
+ text-anchor={is_vertical ? `middle` : undefined}
1905
+ dominant-baseline={is_vertical ? undefined : `central`}
1906
+ class="bar-label"
1907
+ >
1908
+ {srs.labels[bar_idx]}
1909
+ </text>
1910
+ {/if}
1911
+ {/if}
1912
+ {/each}
1913
+ {/if}
1914
+ </g>
1915
+ {/if}
1916
+ {/each}
1917
+
1918
+ <!-- Reference lines: below points -->
1919
+ {@render ref_lines_layer(ref_lines_by_z.below_points)}
1920
+
1921
+ <!-- Reference lines: above all -->
1922
+ {@render ref_lines_layer(ref_lines_by_z.above_all)}
1923
+ </g>
1924
+ </svg>
1925
+
1926
+ <!-- Legend -->
1927
+ {#if legend && (show_legend !== undefined ? show_legend : series.length > 1)}
1928
+ {@const legend_left = legend_auto_outside
1929
+ ? legend_outside_x
1930
+ : legend_placement
1931
+ ? tweened_legend_coords.current.x
1932
+ : pad.l + 10}
1933
+ {@const legend_top = legend_auto_outside
1934
+ ? legend_outside_y
1935
+ : legend_placement
1936
+ ? tweened_legend_coords.current.y
1937
+ : pad.t + 10}
1938
+ <PlotLegend
1939
+ bind:root_element={legend_element}
1940
+ {...legend}
1941
+ series_data={legend_data}
1942
+ on_toggle={legend?.on_toggle || toggle_series_visibility}
1943
+ on_group_toggle={legend?.on_group_toggle || toggle_group_visibility}
1944
+ on_hover_change={legend_hover.set_locked}
1945
+ on_item_hover={(series_idx) =>
1946
+ (hovered_legend_series_idx = series_idx != null && series_idx >= 0
1947
+ ? series_idx
1948
+ : null)}
1949
+ active_series_idx={hover_info?.series_idx ?? hovered_legend_series_idx}
1950
+ style={`
1951
+ position: absolute;
1952
+ left: ${legend_left}px;
1953
+ top: ${legend_top}px;
1954
+ pointer-events: auto;
1955
+ ${legend?.style || ``}
1956
+ `}
1957
+ />
1958
+ {/if}
1959
+
1960
+ {#if hover_info && hovered}
1961
+ {@const cx = (hover_info.active_x_axis === `x2` ? scales.x2 : scales.x)(
1962
+ hover_info.orient_x,
1963
+ )}
1964
+ {@const cy = (hover_info.active_y_axis === `y2` ? scales.y2 : scales.y)(
1965
+ hover_info.orient_y,
1966
+ )}
1967
+ {@const tooltip_pos = constrain_tooltip_position(
1968
+ cx,
1969
+ cy,
1970
+ tooltip_el?.offsetWidth ?? 140,
1971
+ tooltip_el?.offsetHeight ?? 50,
1972
+ width,
1973
+ height,
1974
+ { offset_x: 10, offset_y: 5 },
1975
+ )}
1976
+ <PlotTooltip
1977
+ x={tooltip_pos.x}
1978
+ y={tooltip_pos.y}
1979
+ offset={{ x: 0, y: 0 }}
1980
+ bg_color={hover_info.color}
1981
+ bind:wrapper={tooltip_el}
1982
+ >
1983
+ {#if tooltip}
1984
+ {@render tooltip({ ...hover_info, fullscreen })}
1985
+ {:else}
1986
+ {@const series_label = series[hover_info.series_idx]?.label}
1987
+ {#if series.length > 1 && series_label}
1988
+ <div><strong>{series_label}</strong></div>
1989
+ {/if}
1990
+ <div>
1991
+ {@html sanitize_html(hover_info.x_axis.label || `x`)}: {
1992
+ (cat_axis === `x` ? hover_info.category_label : undefined) ??
1993
+ format_value(hover_info.orient_x, hover_info.x_axis.format || `.3~s`)
1994
+ }
1995
+ </div>
1996
+ <div>
1997
+ {@html sanitize_html(hover_info.y_axis.label || `y`)}: {
1998
+ (cat_axis === `y` ? hover_info.category_label : undefined) ??
1999
+ format_value(hover_info.orient_y, hover_info.y_axis.format || `.3~s`)
2000
+ }
2001
+ </div>
2002
+ {/if}
2003
+ </PlotTooltip>
2004
+ {/if}
2005
+
2006
+ {#if show_controls}
2007
+ <BarPlotControls
2008
+ toggle_props={{
2009
+ ...controls_toggle_props,
2010
+ style: `--ctrl-btn-right: var(--fullscreen-btn-offset, 30px); ${
2011
+ controls_toggle_props?.style ?? ``
2012
+ }`,
2013
+ }}
2014
+ pane_props={controls_pane_props}
2015
+ bind:show_controls
2016
+ bind:controls_open
2017
+ bind:orientation
2018
+ bind:mode
2019
+ bind:x_axis
2020
+ bind:x2_axis
2021
+ bind:y_axis
2022
+ bind:y2_axis
2023
+ bind:display
2024
+ auto_x_range={auto_ranges.x as Vec2}
2025
+ auto_x2_range={auto_ranges.x2 as Vec2}
2026
+ auto_y_range={auto_ranges.y as Vec2}
2027
+ auto_y2_range={auto_ranges.y2 as Vec2}
2028
+ has_x2_points={x2_series.length > 0}
2029
+ has_y2_points={y2_series.length > 0}
2030
+ children={controls_extra}
2031
+ />
2032
+ {/if}
2033
+ {/if}
2034
+
2035
+ <!-- User-provided children (e.g. for custom absolutely-positioned overlays) -->
2036
+ {@render children?.({ height, width, fullscreen })}
2037
+ </div>
2038
+
2039
+ <style>
2040
+ .bar-plot {
2041
+ position: relative;
2042
+ width: 100%;
2043
+ height: var(--barplot-height, auto);
2044
+ min-height: var(--barplot-min-height, 300px);
2045
+ container-type: size;
2046
+ z-index: var(--barplot-z-index, auto);
2047
+ border-radius: var(--barplot-border-radius, var(--border-radius, 3pt));
2048
+ flex: var(--barplot-flex, 1);
2049
+ display: var(--barplot-display, flex);
2050
+ flex-direction: column;
2051
+ background: var(--barplot-bg, var(--plot-bg));
2052
+ }
2053
+ .bar-plot.fullscreen {
2054
+ position: fixed;
2055
+ top: 0;
2056
+ left: 0;
2057
+ width: 100vw !important;
2058
+ height: 100vh !important;
2059
+ /* Must be higher than Structure.svelte's --struct-buttons-z-index. */
2060
+ z-index: var(--barplot-fullscreen-z-index, var(--z-index-overlay-nav, 100000001));
2061
+ margin: 0;
2062
+ border-radius: 0;
2063
+ background: var(--barplot-fullscreen-bg, var(--barplot-bg, var(--plot-bg)));
2064
+ max-height: none !important;
2065
+ overflow: hidden;
2066
+ /* Add padding to prevent titles from being cropped at top */
2067
+ padding-top: var(--plot-fullscreen-padding-top, 2em);
2068
+ box-sizing: border-box;
2069
+ }
2070
+ .header-controls {
2071
+ position: absolute;
2072
+ top: var(--ctrl-btn-top, 5pt);
2073
+ right: var(--fullscreen-btn-right, 4px);
2074
+ z-index: var(--fullscreen-btn-z-index, 10);
2075
+ display: flex;
2076
+ align-items: center;
2077
+ gap: 8px;
2078
+ }
2079
+ .header-controls :global(.fullscreen-toggle) {
2080
+ position: static; /* Override absolute positioning since container handles it */
2081
+ opacity: 1; /* Always visible when inside header-controls, container controls visibility */
2082
+ }
2083
+ /* Hide controls and fullscreen toggles by default, show on hover */
2084
+ .bar-plot :global(.pane-toggle),
2085
+ .bar-plot .header-controls {
2086
+ opacity: 0;
2087
+ transition: opacity 0.2s, background-color 0.2s;
2088
+ }
2089
+ .bar-plot:hover :global(.pane-toggle),
2090
+ .bar-plot:hover .header-controls,
2091
+ .bar-plot :global(.pane-toggle:focus-visible),
2092
+ .bar-plot :global(.pane-toggle[aria-expanded='true']),
2093
+ .bar-plot .header-controls:focus-within {
2094
+ opacity: 1;
2095
+ }
2096
+ svg {
2097
+ width: var(--barplot-svg-width, 100%);
2098
+ height: var(--barplot-svg-height, 100%);
2099
+ flex: var(--barplot-svg-flex, 1);
2100
+ overflow: var(--barplot-svg-overflow, visible);
2101
+ fill: var(--text-color);
2102
+ font-weight: var(--scatter-font-weight);
2103
+ font-size: var(--scatter-font-size);
2104
+ }
2105
+ .bar-plot.dragover {
2106
+ border: var(--barplot-dragover-border, var(--dragover-border));
2107
+ background-color: var(--barplot-dragover-bg, var(--dragover-bg));
2108
+ }
2109
+ .bar-label {
2110
+ fill: var(--text-color);
2111
+ font-size: 11px;
2112
+ }
2113
+ </style>