matterviz 0.4.0 → 0.4.1

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 (326) hide show
  1. package/dist/brillouin/BrillouinZone.svelte +68 -145
  2. package/dist/brillouin/BrillouinZone.svelte.d.ts +5 -14
  3. package/dist/brillouin/BrillouinZoneExportPane.svelte +43 -96
  4. package/dist/brillouin/BrillouinZoneExportPane.svelte.d.ts +1 -1
  5. package/dist/brillouin/BrillouinZoneInfoPane.svelte +9 -32
  6. package/dist/brillouin/BrillouinZoneInfoPane.svelte.d.ts +2 -3
  7. package/dist/brillouin/BrillouinZoneScene.svelte +49 -203
  8. package/dist/brillouin/BrillouinZoneScene.svelte.d.ts +3 -23
  9. package/dist/brillouin/ReciprocalVectors.svelte +39 -0
  10. package/dist/brillouin/ReciprocalVectors.svelte.d.ts +9 -0
  11. package/dist/brillouin/compute.d.ts +2 -0
  12. package/dist/brillouin/compute.js +80 -77
  13. package/dist/brillouin/geometry.d.ts +8 -0
  14. package/dist/brillouin/geometry.js +57 -0
  15. package/dist/brillouin/index.d.ts +2 -0
  16. package/dist/brillouin/index.js +2 -0
  17. package/dist/brillouin/types.d.ts +2 -2
  18. package/dist/chempot-diagram/ChemPotDiagram.svelte.d.ts +1 -1
  19. package/dist/chempot-diagram/ChemPotDiagram2D.svelte +100 -191
  20. package/dist/chempot-diagram/ChemPotDiagram2D.svelte.d.ts +4 -1
  21. package/dist/chempot-diagram/ChemPotDiagram3D.svelte +176 -464
  22. package/dist/chempot-diagram/ChemPotDiagram3D.svelte.d.ts +7 -1
  23. package/dist/chempot-diagram/color.d.ts +3 -6
  24. package/dist/chempot-diagram/color.js +5 -5
  25. package/dist/chempot-diagram/compute.d.ts +3 -3
  26. package/dist/chempot-diagram/compute.js +3 -1
  27. package/dist/chempot-diagram/controls-state.svelte.d.ts +10 -0
  28. package/dist/chempot-diagram/controls-state.svelte.js +42 -0
  29. package/dist/chempot-diagram/export.d.ts +47 -0
  30. package/dist/chempot-diagram/export.js +133 -0
  31. package/dist/chempot-diagram/index.d.ts +1 -0
  32. package/dist/chempot-diagram/index.js +1 -0
  33. package/dist/chempot-diagram/pointer.d.ts +0 -10
  34. package/dist/chempot-diagram/pointer.js +4 -4
  35. package/dist/chempot-diagram/types.d.ts +3 -3
  36. package/dist/colors/index.js +2 -2
  37. package/dist/composition/FormulaFilter.svelte +6 -5
  38. package/dist/composition/PieChart.svelte +5 -5
  39. package/dist/composition/chem-sys.js +3 -2
  40. package/dist/composition/format.js +3 -2
  41. package/dist/composition/parse.d.ts +0 -1
  42. package/dist/composition/parse.js +17 -19
  43. package/dist/controls.d.ts +1 -0
  44. package/dist/controls.js +0 -1
  45. package/dist/convex-hull/ConvexHull.svelte +8 -10
  46. package/dist/convex-hull/ConvexHull.svelte.d.ts +1 -4
  47. package/dist/convex-hull/ConvexHull2D.svelte +94 -175
  48. package/dist/convex-hull/ConvexHull2D.svelte.d.ts +1 -1
  49. package/dist/convex-hull/ConvexHull3D.svelte +176 -680
  50. package/dist/convex-hull/ConvexHull3D.svelte.d.ts +1 -1
  51. package/dist/convex-hull/ConvexHull4D.svelte +180 -680
  52. package/dist/convex-hull/ConvexHull4D.svelte.d.ts +1 -1
  53. package/dist/convex-hull/ConvexHullChrome.svelte +268 -0
  54. package/dist/convex-hull/ConvexHullChrome.svelte.d.ts +30 -0
  55. package/dist/convex-hull/ConvexHullControls.svelte +88 -7
  56. package/dist/convex-hull/ConvexHullControls.svelte.d.ts +7 -6
  57. package/dist/convex-hull/ConvexHullInfoPane.svelte +18 -5
  58. package/dist/convex-hull/ConvexHullInfoPane.svelte.d.ts +6 -5
  59. package/dist/convex-hull/ConvexHullStats.svelte +29 -168
  60. package/dist/convex-hull/ConvexHullStats.svelte.d.ts +3 -1
  61. package/dist/convex-hull/ConvexHullTooltip.svelte +11 -2
  62. package/dist/convex-hull/ConvexHullTooltip.svelte.d.ts +2 -1
  63. package/dist/convex-hull/barycentric-coords.d.ts +2 -4
  64. package/dist/convex-hull/barycentric-coords.js +6 -33
  65. package/dist/convex-hull/canvas-interactions.svelte.d.ts +79 -0
  66. package/dist/convex-hull/canvas-interactions.svelte.js +278 -0
  67. package/dist/convex-hull/helpers.d.ts +39 -7
  68. package/dist/convex-hull/helpers.js +154 -69
  69. package/dist/convex-hull/hull-state.svelte.d.ts +44 -0
  70. package/dist/convex-hull/hull-state.svelte.js +124 -0
  71. package/dist/convex-hull/index.d.ts +9 -7
  72. package/dist/convex-hull/index.js +7 -2
  73. package/dist/convex-hull/thermodynamics.js +91 -920
  74. package/dist/convex-hull/types.d.ts +12 -4
  75. package/dist/convex-hull/types.js +12 -0
  76. package/dist/coordination/CoordinationBarPlot.svelte +4 -11
  77. package/dist/element/BohrAtom.svelte +2 -1
  78. package/dist/element/ElementTile.svelte.d.ts +1 -1
  79. package/dist/element/index.d.ts +4 -0
  80. package/dist/element/index.js +18 -0
  81. package/dist/feedback/DragOverlay.svelte +3 -1
  82. package/dist/feedback/DragOverlay.svelte.d.ts +1 -0
  83. package/dist/feedback/StatusMessage.svelte +13 -3
  84. package/dist/fermi-surface/FermiSurface.svelte +67 -146
  85. package/dist/fermi-surface/FermiSurface.svelte.d.ts +5 -14
  86. package/dist/fermi-surface/FermiSurfaceControls.svelte.d.ts +1 -1
  87. package/dist/fermi-surface/FermiSurfaceScene.svelte +72 -224
  88. package/dist/fermi-surface/FermiSurfaceScene.svelte.d.ts +3 -23
  89. package/dist/fermi-surface/compute.js +11 -10
  90. package/dist/fermi-surface/export.js +4 -15
  91. package/dist/fermi-surface/index.d.ts +0 -1
  92. package/dist/fermi-surface/index.js +0 -1
  93. package/dist/fermi-surface/parse.d.ts +1 -1
  94. package/dist/fermi-surface/parse.js +64 -75
  95. package/dist/fermi-surface/types.d.ts +2 -2
  96. package/dist/heatmap-matrix/HeatmapMatrix.svelte +55 -40
  97. package/dist/heatmap-matrix/HeatmapMatrix.svelte.d.ts +4 -3
  98. package/dist/heatmap-matrix/HeatmapMatrixControls.svelte +3 -2
  99. package/dist/heatmap-matrix/HeatmapMatrixControls.svelte.d.ts +5 -5
  100. package/dist/heatmap-matrix/index.d.ts +3 -2
  101. package/dist/index.d.ts +1 -0
  102. package/dist/index.js +1 -0
  103. package/dist/io/ExportPane.svelte +166 -0
  104. package/dist/io/ExportPane.svelte.d.ts +17 -0
  105. package/dist/io/decompress.js +1 -2
  106. package/dist/io/export.d.ts +5 -1
  107. package/dist/io/export.js +32 -28
  108. package/dist/io/fetch.d.ts +2 -1
  109. package/dist/io/file-drop.d.ts +7 -0
  110. package/dist/io/file-drop.js +13 -0
  111. package/dist/io/index.d.ts +2 -0
  112. package/dist/io/index.js +10 -0
  113. package/dist/io/types.d.ts +13 -0
  114. package/dist/isosurface/parse.js +46 -44
  115. package/dist/labels.js +1 -1
  116. package/dist/layout/FullscreenButton.svelte +33 -0
  117. package/dist/layout/FullscreenButton.svelte.d.ts +10 -0
  118. package/dist/layout/FullscreenToggle.svelte +8 -14
  119. package/dist/layout/ViewerChrome.svelte +116 -0
  120. package/dist/layout/ViewerChrome.svelte.d.ts +17 -0
  121. package/dist/layout/fullscreen.d.ts +4 -0
  122. package/dist/layout/fullscreen.svelte.d.ts +8 -0
  123. package/dist/layout/fullscreen.svelte.js +37 -0
  124. package/dist/layout/index.d.ts +3 -0
  125. package/dist/layout/index.js +3 -0
  126. package/dist/math.d.ts +7 -3
  127. package/dist/math.js +18 -21
  128. package/dist/overlays/index.d.ts +4 -0
  129. package/dist/periodic-table/PeriodicTable.svelte +9 -8
  130. package/dist/phase-diagram/IsobaricBinaryPhaseDiagram.svelte.d.ts +1 -1
  131. package/dist/phase-diagram/PhaseDiagramControls.svelte +3 -2
  132. package/dist/phase-diagram/PhaseDiagramControls.svelte.d.ts +4 -3
  133. package/dist/phase-diagram/PhaseDiagramEditorPane.svelte +2 -1
  134. package/dist/phase-diagram/PhaseDiagramEditorPane.svelte.d.ts +2 -3
  135. package/dist/phase-diagram/PhaseDiagramExportPane.svelte +47 -132
  136. package/dist/phase-diagram/PhaseDiagramExportPane.svelte.d.ts +3 -4
  137. package/dist/phase-diagram/colors.js +1 -1
  138. package/dist/phase-diagram/parse.d.ts +2 -1
  139. package/dist/plot/bar/BarPlot.svelte +79 -316
  140. package/dist/plot/bar/BarPlot.svelte.d.ts +7 -15
  141. package/dist/plot/bar/BarPlotControls.svelte.d.ts +1 -1
  142. package/dist/plot/bar/SpacegroupBarPlot.svelte +2 -1
  143. package/dist/plot/box/BoxPlot.svelte +76 -246
  144. package/dist/plot/box/BoxPlot.svelte.d.ts +4 -3
  145. package/dist/plot/box/BoxPlotControls.svelte.d.ts +1 -1
  146. package/dist/plot/box/Violin.svelte.d.ts +1 -1
  147. package/dist/plot/box/box-plot.d.ts +3 -2
  148. package/dist/plot/box/box-plot.js +5 -2
  149. package/dist/plot/box/kde.d.ts +2 -1
  150. package/dist/plot/box/kde.js +4 -4
  151. package/dist/plot/core/auto-place.d.ts +1 -1
  152. package/dist/plot/core/auto-place.js +4 -1
  153. package/dist/plot/core/components/ColorBar.svelte +5 -5
  154. package/dist/plot/core/components/ColorBar.svelte.d.ts +5 -4
  155. package/dist/plot/core/components/Line.svelte +3 -2
  156. package/dist/plot/core/components/Line.svelte.d.ts +3 -2
  157. package/dist/plot/core/components/PlotAxis.svelte +2 -1
  158. package/dist/plot/core/components/PlotAxis.svelte.d.ts +2 -1
  159. package/dist/plot/core/components/PlotControls.svelte.d.ts +1 -1
  160. package/dist/plot/core/components/ReferenceLine3D.svelte +2 -2
  161. package/dist/plot/core/components/ReferenceLine3D.svelte.d.ts +4 -4
  162. package/dist/plot/core/components/ReferencePlane.svelte +2 -2
  163. package/dist/plot/core/components/ReferencePlane.svelte.d.ts +4 -4
  164. package/dist/plot/core/data-cleaning.js +18 -18
  165. package/dist/plot/core/fill-utils.d.ts +4 -3
  166. package/dist/plot/core/fill-utils.js +6 -3
  167. package/dist/plot/core/interactions.d.ts +5 -1
  168. package/dist/plot/core/interactions.js +14 -0
  169. package/dist/plot/core/pan-zoom.svelte.d.ts +35 -0
  170. package/dist/plot/core/pan-zoom.svelte.js +221 -0
  171. package/dist/plot/core/placed-tween.svelte.d.ts +21 -0
  172. package/dist/plot/core/placed-tween.svelte.js +68 -0
  173. package/dist/plot/core/reference-line.d.ts +10 -10
  174. package/dist/plot/core/reference-line.js +6 -6
  175. package/dist/plot/core/scales.d.ts +17 -25
  176. package/dist/plot/core/scales.js +10 -8
  177. package/dist/plot/core/svg.d.ts +2 -1
  178. package/dist/plot/core/types.d.ts +18 -7
  179. package/dist/plot/core/utils/label-placement.d.ts +1 -1
  180. package/dist/plot/core/utils/label-placement.js +3 -3
  181. package/dist/plot/core/utils.d.ts +2 -1
  182. package/dist/plot/histogram/Histogram.svelte +77 -314
  183. package/dist/plot/histogram/HistogramControls.svelte.d.ts +1 -1
  184. package/dist/plot/sankey/Sankey.svelte +2 -5
  185. package/dist/plot/sankey/Sankey.svelte.d.ts +1 -1
  186. package/dist/plot/sankey/sankey.js +3 -1
  187. package/dist/plot/scatter/BinnedScatterPlot.svelte +3 -5
  188. package/dist/plot/scatter/BinnedScatterPlot.svelte.d.ts +4 -4
  189. package/dist/plot/scatter/ScatterPlot.svelte +160 -450
  190. package/dist/plot/scatter/ScatterPlot.svelte.d.ts +7 -15
  191. package/dist/plot/scatter/ScatterPlotControls.svelte.d.ts +1 -1
  192. package/dist/plot/scatter/binned-scatter-types.d.ts +4 -11
  193. package/dist/plot/scatter/index.d.ts +1 -1
  194. package/dist/plot/scatter-3d/ScatterPlot3D.svelte +15 -26
  195. package/dist/plot/scatter-3d/ScatterPlot3D.svelte.d.ts +6 -14
  196. package/dist/plot/scatter-3d/ScatterPlot3DControls.svelte +9 -10
  197. package/dist/plot/scatter-3d/ScatterPlot3DControls.svelte.d.ts +5 -5
  198. package/dist/plot/scatter-3d/ScatterPlot3DScene.svelte +122 -121
  199. package/dist/plot/scatter-3d/ScatterPlot3DScene.svelte.d.ts +5 -14
  200. package/dist/plot/scatter-3d/Surface3D.svelte +6 -5
  201. package/dist/plot/scatter-3d/Surface3D.svelte.d.ts +4 -3
  202. package/dist/plot/sunburst/Sunburst.svelte +16 -20
  203. package/dist/plot/sunburst/Sunburst.svelte.d.ts +4 -3
  204. package/dist/plot/sunburst/SunburstControls.svelte.d.ts +1 -1
  205. package/dist/plot/sunburst/sunburst.js +4 -1
  206. package/dist/rdf/RdfPlot.svelte.d.ts +1 -1
  207. package/dist/sanitize.js +13 -2
  208. package/dist/scene/SceneCamera.svelte +62 -0
  209. package/dist/scene/SceneCamera.svelte.d.ts +19 -0
  210. package/dist/scene/bind-renderer.svelte.d.ts +2 -0
  211. package/dist/scene/bind-renderer.svelte.js +14 -0
  212. package/dist/scene/index.d.ts +4 -0
  213. package/dist/scene/index.js +5 -0
  214. package/dist/scene/props.js +52 -0
  215. package/dist/scene/types.d.ts +26 -0
  216. package/dist/scene/types.js +1 -0
  217. package/dist/settings.d.ts +14 -2
  218. package/dist/settings.js +59 -1
  219. package/dist/spectral/Bands.svelte +8 -7
  220. package/dist/spectral/Bands.svelte.d.ts +3 -2
  221. package/dist/spectral/BandsAndDos.svelte +22 -24
  222. package/dist/spectral/BrillouinBandsDos.svelte +3 -3
  223. package/dist/spectral/Dos.svelte +5 -4
  224. package/dist/spectral/Dos.svelte.d.ts +2 -1
  225. package/dist/spectral/helpers.d.ts +6 -6
  226. package/dist/spectral/helpers.js +43 -37
  227. package/dist/state.svelte.d.ts +0 -7
  228. package/dist/state.svelte.js +0 -6
  229. package/dist/structure/Arrow.svelte +2 -4
  230. package/dist/structure/AtomLegend.svelte.d.ts +1 -1
  231. package/dist/structure/CanvasTooltip.svelte +1 -0
  232. package/dist/structure/CellSelect.svelte +11 -3
  233. package/dist/structure/CellSelect.svelte.d.ts +2 -1
  234. package/dist/structure/Lattice.svelte +2 -2
  235. package/dist/structure/Structure.svelte +291 -355
  236. package/dist/structure/Structure.svelte.d.ts +5 -15
  237. package/dist/structure/StructureControls.svelte +217 -2
  238. package/dist/structure/StructureControls.svelte.d.ts +5 -3
  239. package/dist/structure/StructureExportPane.svelte +54 -156
  240. package/dist/structure/StructureExportPane.svelte.d.ts +4 -5
  241. package/dist/structure/StructureInfoPane.svelte +5 -3
  242. package/dist/structure/StructureInfoPane.svelte.d.ts +5 -5
  243. package/dist/structure/StructureScene.svelte +365 -198
  244. package/dist/structure/StructureScene.svelte.d.ts +22 -20
  245. package/dist/structure/{label-placement.d.ts → atom-label-placement.d.ts} +3 -3
  246. package/dist/structure/{label-placement.js → atom-label-placement.js} +12 -2
  247. package/dist/structure/atom-properties.d.ts +1 -1
  248. package/dist/structure/atom-properties.js +11 -16
  249. package/dist/structure/bond-order-perception.js +2 -4
  250. package/dist/structure/bonding.d.ts +3 -0
  251. package/dist/structure/bonding.js +91 -48
  252. package/dist/structure/export.d.ts +24 -4
  253. package/dist/structure/export.js +64 -122
  254. package/dist/structure/index.d.ts +2 -0
  255. package/dist/structure/index.js +2 -0
  256. package/dist/structure/parse.d.ts +3 -2
  257. package/dist/structure/parse.js +333 -370
  258. package/dist/structure/partial-occupancy.d.ts +0 -1
  259. package/dist/structure/partial-occupancy.js +1 -1
  260. package/dist/structure/pbc.d.ts +1 -1
  261. package/dist/structure/pbc.js +186 -13
  262. package/dist/structure/polyhedra.d.ts +41 -0
  263. package/dist/structure/polyhedra.js +602 -0
  264. package/dist/structure/site.d.ts +4 -0
  265. package/dist/structure/site.js +1 -0
  266. package/dist/structure/supercell.js +3 -2
  267. package/dist/structure/validation.js +5 -6
  268. package/dist/symmetry/SymmetryElementControls.svelte +69 -0
  269. package/dist/symmetry/SymmetryElementControls.svelte.d.ts +9 -0
  270. package/dist/symmetry/SymmetryElements.svelte +354 -0
  271. package/dist/symmetry/SymmetryElements.svelte.d.ts +24 -0
  272. package/dist/symmetry/SymmetryStats.svelte +111 -6
  273. package/dist/symmetry/WyckoffTable.svelte +68 -7
  274. package/dist/symmetry/WyckoffTable.svelte.d.ts +3 -0
  275. package/dist/symmetry/cell-transform.js +7 -14
  276. package/dist/symmetry/index.d.ts +14 -4
  277. package/dist/symmetry/index.js +301 -80
  278. package/dist/symmetry/spacegroups.d.ts +5 -1
  279. package/dist/symmetry/spacegroups.js +15 -1
  280. package/dist/symmetry/symmetry-elements.d.ts +33 -0
  281. package/dist/symmetry/symmetry-elements.js +521 -0
  282. package/dist/symmetry/wyckoff-db.d.ts +9 -0
  283. package/dist/symmetry/wyckoff-db.js +87 -0
  284. package/dist/table/HeatmapTable.svelte +4 -15
  285. package/dist/table/HeatmapTable.svelte.d.ts +1 -1
  286. package/dist/trajectory/Trajectory.svelte +58 -61
  287. package/dist/trajectory/Trajectory.svelte.d.ts +10 -22
  288. package/dist/trajectory/TrajectoryExportPane.svelte +15 -24
  289. package/dist/trajectory/TrajectoryExportPane.svelte.d.ts +4 -5
  290. package/dist/trajectory/TrajectoryInfoPane.svelte +3 -2
  291. package/dist/trajectory/TrajectoryInfoPane.svelte.d.ts +3 -2
  292. package/dist/trajectory/constants.js +6 -2
  293. package/dist/trajectory/extract.js +17 -37
  294. package/dist/trajectory/format-detect.d.ts +0 -1
  295. package/dist/trajectory/format-detect.js +3 -9
  296. package/dist/trajectory/frame-reader.d.ts +0 -1
  297. package/dist/trajectory/frame-reader.js +62 -128
  298. package/dist/trajectory/helpers.d.ts +10 -2
  299. package/dist/trajectory/helpers.js +56 -36
  300. package/dist/trajectory/parse/ase.d.ts +9 -1
  301. package/dist/trajectory/parse/ase.js +47 -32
  302. package/dist/trajectory/parse/diagnostics.d.ts +3 -0
  303. package/dist/trajectory/parse/diagnostics.js +14 -0
  304. package/dist/trajectory/parse/index.d.ts +1 -1
  305. package/dist/trajectory/parse/index.js +54 -102
  306. package/dist/trajectory/parse/lammps.d.ts +0 -2
  307. package/dist/trajectory/parse/lammps.js +8 -6
  308. package/dist/trajectory/parse/pymatgen.d.ts +2 -0
  309. package/dist/trajectory/parse/pymatgen.js +74 -0
  310. package/dist/trajectory/parse/vasp.js +4 -3
  311. package/dist/trajectory/parse/xyz.d.ts +9 -21
  312. package/dist/trajectory/parse/xyz.js +28 -33
  313. package/dist/trajectory/plotting.d.ts +0 -1
  314. package/dist/trajectory/plotting.js +3 -100
  315. package/dist/utils.d.ts +1 -0
  316. package/dist/utils.js +1 -1
  317. package/dist/xrd/XrdPlot.svelte +14 -29
  318. package/dist/xrd/broadening.d.ts +2 -1
  319. package/dist/xrd/calc-xrd.js +6 -11
  320. package/dist/xrd/index.d.ts +2 -2
  321. package/package.json +29 -16
  322. package/dist/element/data.json +0 -11864
  323. package/dist/fermi-surface/marching-cubes.d.ts +0 -2
  324. package/dist/fermi-surface/marching-cubes.js +0 -2
  325. package/dist/plot/core/hover-lock.svelte.d.ts +0 -14
  326. package/dist/plot/core/hover-lock.svelte.js +0 -45
@@ -36,21 +36,17 @@
36
36
  has_explicit_position,
37
37
  measured_footprint,
38
38
  place_decorations,
39
+ placed_coords,
39
40
  } from '../core/auto-place'
40
41
  import { compute_box_stats } from './box-plot'
41
42
  import { gaussian_kde, type KdeResult } from './kde'
42
- import { create_dimension_tracker, create_hover_lock } from '../core/hover-lock.svelte'
43
+ import { create_placed_tween } from '../core/placed-tween.svelte'
44
+ import { create_pan_zoom } from '../core/pan-zoom.svelte'
43
45
  import { create_legend_visibility } from '../core/utils/series-visibility'
44
46
  import {
45
47
  axis_ranges_equal,
46
- get_relative_coords,
47
- MIN_TOUCH_DISTANCE_PIXELS,
48
- pan_range_by_pixels,
49
- PINCH_ZOOM_THRESHOLD,
50
- remove_drag_listeners,
48
+ invert_rect_range,
51
49
  resolve_axis_ranges,
52
- sorted_range,
53
- zoom_range_by_factor,
54
50
  } from '../core/interactions'
55
51
  import {
56
52
  calc_auto_padding,
@@ -68,14 +64,12 @@
68
64
  get_nice_data_range,
69
65
  get_tick_label,
70
66
  } from '../core/scales'
71
- import type { InitialRanges } from '../core/types'
72
67
  import { DEFAULT_SERIES_COLORS } from '../core/types'
73
68
  import { unique_id } from '../core/utils'
74
69
  import { DEFAULTS } from '../../settings'
75
70
  import type { Snippet } from 'svelte'
76
71
  import { onDestroy, untrack } from 'svelte'
77
72
  import type { HTMLAttributes } from 'svelte/elements'
78
- import { Tween, type TweenOptions } from 'svelte/motion'
79
73
  import { SvelteMap } from 'svelte/reactivity'
80
74
  import PlotTooltip from '../core/components/PlotTooltip.svelte'
81
75
  import { violin_path } from '../core/svg'
@@ -176,7 +170,7 @@
176
170
  outlier_style?: OutlierStyle
177
171
  whisker_mode?: WhiskerMode
178
172
  whisker_range?: number
179
- whisker_percentiles?: [number, number]
173
+ whisker_percentiles?: Vec2
180
174
  show_outliers?: boolean
181
175
  show_mean?: boolean
182
176
  show_value_labels?: boolean
@@ -586,178 +580,46 @@
586
580
  x2_max: measure_max_tick_width(ticks.x2, x2_axis.format ?? ``),
587
581
  })
588
582
 
589
- // === Interaction state (pan / zoom / touch) ===
590
- let drag_state = $state<{
591
- start: { x: number; y: number } | null
592
- current: { x: number; y: number } | null
593
- bounds: DOMRect | null
594
- }>({ start: null, current: null, bounds: null })
595
- let is_focused = $state(false)
596
- let shift_held = $state(false)
597
- let pan_drag_state = $state<InitialRanges & { start: { x: number; y: number } } | null>(null)
598
- let touch_state = $state<InitialRanges & { start_touches: { x: number; y: number }[] } | null>(
599
- null,
600
- )
601
-
602
- const on_window_mouse_move = (evt: MouseEvent) => {
603
- if (!drag_state.start || !drag_state.bounds) return
604
- drag_state.current = {
605
- x: evt.clientX - drag_state.bounds.left,
606
- y: evt.clientY - drag_state.bounds.top,
607
- }
608
- }
609
- const on_window_mouse_up = () => {
610
- if (drag_state.start && drag_state.current) {
611
- const x1 = scales.x.invert(drag_state.start.x) as number
612
- const x2 = scales.x.invert(drag_state.current.x) as number
613
- const y1 = scales.y.invert(drag_state.start.y)
614
- const y2 = scales.y.invert(drag_state.current.y)
615
- const y2_1 = scales.y2.invert(drag_state.start.y)
616
- const y2_2 = scales.y2.invert(drag_state.current.y)
617
- const x2_1 = scales.x2.invert(drag_state.start.x) as number
618
- const x2_2 = scales.x2.invert(drag_state.current.x) as number
619
- const dx = Math.abs(drag_state.start.x - drag_state.current.x)
620
- const dy = Math.abs(drag_state.start.y - drag_state.current.y)
621
- if (dx > 5 && dy > 5 && Number.isFinite(x1) && Number.isFinite(x2)) {
622
- x_axis = { ...x_axis, range: sorted_range(x1, x2) }
623
- // the secondary value axis is x2 only in horizontal mode, y2 only in vertical
624
- // (is_secondary keys off orientation); writing the off-orientation axis would
625
- // store a phantom range from its [0, 1] sentinel scale into the bound prop
626
- if (
627
- has_secondary && orientation === `horizontal` &&
628
- Number.isFinite(x2_1) && Number.isFinite(x2_2)
629
- ) {
630
- x2_axis_prop = { ...x2_axis_prop, range: sorted_range(x2_1, x2_2) }
631
- }
632
- y_axis = { ...y_axis, range: sorted_range(y1, y2) }
633
- if (
634
- has_secondary && orientation === `vertical` &&
635
- Number.isFinite(y2_1) && Number.isFinite(y2_2)
636
- ) {
637
- y2_axis_prop = { ...y2_axis_prop, range: sorted_range(y2_1, y2_2) }
638
- }
583
+ // Shared pan/zoom/touch/drag-rect interaction controller
584
+ const pan_zoom = create_pan_zoom({
585
+ ranges: () => ranges.current,
586
+ scale_type: (axis) => ({ x: x_axis, x2: x2_axis, y: y_axis, y2: y2_axis })[axis].scale_type,
587
+ plot_dims: () => ({ width: chart_width, height: chart_height }),
588
+ pan: () => pan,
589
+ set_range: (axis, range) => (ranges.current[axis] = range),
590
+ svg: () => svg_element,
591
+ on_rect_zoom: (start, current) => {
592
+ const next_x = invert_rect_range(scales.x, start.x, current.x)
593
+ if (!next_x) return
594
+ x_axis = { ...x_axis, range: next_x }
595
+ // the secondary value axis is x2 only in horizontal mode, y2 only in vertical
596
+ // (is_secondary keys off orientation); writing the off-orientation axis would
597
+ // store a phantom range from its [0, 1] sentinel scale into the bound prop
598
+ const next_x2 = has_secondary && orientation === `horizontal`
599
+ ? invert_rect_range(scales.x2, start.x, current.x)
600
+ : null
601
+ if (next_x2) x2_axis_prop = { ...x2_axis_prop, range: next_x2 }
602
+ const next_y = invert_rect_range(scales.y, start.y, current.y)
603
+ if (next_y) y_axis = { ...y_axis, range: next_y }
604
+ const next_y2 = has_secondary && orientation === `vertical`
605
+ ? invert_rect_range(scales.y2, start.y, current.y)
606
+ : null
607
+ if (next_y2) y2_axis_prop = { ...y2_axis_prop, range: next_y2 }
608
+ },
609
+ on_reset: () => {
610
+ ranges.current = {
611
+ x: [...ranges.initial.x] as Vec2,
612
+ x2: [...ranges.initial.x2] as Vec2,
613
+ y: [...ranges.initial.y] as Vec2,
614
+ y2: [...ranges.initial.y2] as Vec2,
639
615
  }
640
- }
641
- drag_state = { start: null, current: null, bounds: null }
642
- window.removeEventListener(`mousemove`, on_window_mouse_move)
643
- window.removeEventListener(`mouseup`, on_window_mouse_up)
644
- document.body.style.cursor = `default`
645
- }
646
-
647
- // Pan/zoom all four axes from an interaction-start snapshot, each in its own
648
- // scale's transform space (log axes pan by a constant factor, linear by a shift)
649
- const pan_all_axes = (init: InitialRanges, dx_px: number, dy_px: number) => {
650
- ranges.current.x = pan_range_by_pixels(init.initial_x_range, dx_px, chart_width, x_axis.scale_type)
651
- ranges.current.x2 = pan_range_by_pixels(init.initial_x2_range, dx_px, chart_width, x2_axis.scale_type)
652
- ranges.current.y = pan_range_by_pixels(init.initial_y_range, dy_px, chart_height, y_axis.scale_type)
653
- ranges.current.y2 = pan_range_by_pixels(init.initial_y2_range, dy_px, chart_height, y2_axis.scale_type)
654
- }
655
- const zoom_all_axes = (init: InitialRanges, factor: number) => {
656
- ranges.current.x = zoom_range_by_factor(init.initial_x_range, factor, x_axis.scale_type)
657
- ranges.current.x2 = zoom_range_by_factor(init.initial_x2_range, factor, x2_axis.scale_type)
658
- ranges.current.y = zoom_range_by_factor(init.initial_y_range, factor, y_axis.scale_type)
659
- ranges.current.y2 = zoom_range_by_factor(init.initial_y2_range, factor, y2_axis.scale_type)
660
- }
661
-
662
- // Pan drag handler (drag direction inverted on x for natural pan feel)
663
- const on_pan_move = (evt: MouseEvent) => {
664
- if (!pan_drag_state) return
665
- const sensitivity = pan?.drag_sensitivity ?? 1
666
- pan_all_axes(
667
- pan_drag_state,
668
- -(evt.clientX - pan_drag_state.start.x) * sensitivity,
669
- (evt.clientY - pan_drag_state.start.y) * sensitivity,
670
- )
671
- }
672
- const on_pan_end = () => {
673
- pan_drag_state = null
674
- document.body.style.cursor = ``
675
- window.removeEventListener(`mousemove`, on_pan_move)
676
- window.removeEventListener(`mouseup`, on_pan_end)
677
- }
678
-
679
- // Tear down any window listeners + cursor override if the component unmounts mid-drag
680
- // (mouseup/panend would otherwise never fire, leaking listeners and a stuck cursor).
681
- // onDestroy also runs during SSR teardown, where window/document don't exist.
682
- onDestroy(() => {
683
- remove_drag_listeners([on_window_mouse_move, on_pan_move], [on_window_mouse_up, on_pan_end])
684
- drag_state = { start: null, current: null, bounds: null }
685
- pan_drag_state = null
616
+ x_axis = { ...x_axis, range: [null, null] }
617
+ x2_axis_prop = { ...x2_axis_prop, range: [null, null] }
618
+ y_axis = { ...y_axis, range: [null, null] }
619
+ y2_axis_prop = { ...y2_axis_prop, range: [null, null] }
620
+ },
686
621
  })
687
-
688
- function handle_mouse_down(evt: MouseEvent) {
689
- const coords = get_relative_coords(evt)
690
- if (!coords || !svg_element) return
691
- const pan_enabled = pan?.enabled !== false
692
- if (pan_enabled && evt.shiftKey) {
693
- evt.preventDefault()
694
- pan_drag_state = {
695
- start: { x: evt.clientX, y: evt.clientY },
696
- initial_x_range: [...ranges.current.x] as Vec2,
697
- initial_x2_range: [...ranges.current.x2] as Vec2,
698
- initial_y_range: [...ranges.current.y] as Vec2,
699
- initial_y2_range: [...ranges.current.y2] as Vec2,
700
- }
701
- document.body.style.cursor = `grabbing`
702
- window.addEventListener(`mousemove`, on_pan_move)
703
- window.addEventListener(`mouseup`, on_pan_end)
704
- return
705
- }
706
- drag_state = { start: coords, current: coords, bounds: svg_element.getBoundingClientRect() }
707
- window.addEventListener(`mousemove`, on_window_mouse_move)
708
- window.addEventListener(`mouseup`, on_window_mouse_up)
709
- evt.preventDefault()
710
- }
711
-
712
- function handle_wheel(evt: WheelEvent) {
713
- const pan_enabled = pan?.enabled !== false
714
- if (!pan_enabled || !is_focused || !shift_held) return
715
- evt.preventDefault()
716
- const sensitivity = pan?.wheel_sensitivity ?? 1
717
- if (Math.abs(evt.deltaX) > Math.abs(evt.deltaY)) {
718
- const dx = evt.deltaX * sensitivity
719
- ranges.current.x = pan_range_by_pixels(ranges.current.x, dx, chart_width, x_axis.scale_type)
720
- ranges.current.x2 = pan_range_by_pixels(ranges.current.x2, dx, chart_width, x2_axis.scale_type)
721
- } else {
722
- const dy = evt.deltaY * sensitivity
723
- ranges.current.y = pan_range_by_pixels(ranges.current.y, dy, chart_height, y_axis.scale_type)
724
- ranges.current.y2 = pan_range_by_pixels(ranges.current.y2, dy, chart_height, y2_axis.scale_type)
725
- }
726
- }
727
-
728
- function handle_touch_start(evt: TouchEvent) {
729
- const touch_enabled = pan?.enabled !== false && pan?.touch_enabled !== false
730
- if (!touch_enabled || evt.touches.length !== 2) return
731
- evt.preventDefault()
732
- const touches = Array.from(evt.touches)
733
- touch_state = {
734
- start_touches: touches.map((touch) => ({ x: touch.clientX, y: touch.clientY })),
735
- initial_x_range: [...ranges.current.x] as Vec2,
736
- initial_x2_range: [...ranges.current.x2] as Vec2,
737
- initial_y_range: [...ranges.current.y] as Vec2,
738
- initial_y2_range: [...ranges.current.y2] as Vec2,
739
- }
740
- }
741
- function handle_touch_move(evt: TouchEvent) {
742
- if (!touch_state || evt.touches.length !== 2) return
743
- evt.preventDefault()
744
- const [t1, t2] = Array.from(evt.touches)
745
- const [s1, s2] = touch_state.start_touches
746
- const start_center = { x: (s1.x + s2.x) / 2, y: (s1.y + s2.y) / 2 }
747
- const curr_center = { x: (t1.clientX + t2.clientX) / 2, y: (t1.clientY + t2.clientY) / 2 }
748
- const dx = curr_center.x - start_center.x
749
- const dy = curr_center.y - start_center.y
750
- const start_dist = Math.hypot(s2.x - s1.x, s2.y - s1.y)
751
- // ignore near-coincident touches so curr_dist / start_dist can't blow up the scale
752
- if (start_dist < MIN_TOUCH_DISTANCE_PIXELS) return
753
- const curr_dist = Math.hypot(t2.clientX - t1.clientX, t2.clientY - t1.clientY)
754
- const scale = curr_dist / start_dist
755
- // Pinch zoom about the view center (spread = zoom in, pinch = zoom out)
756
- if (Math.abs(scale - 1) > PINCH_ZOOM_THRESHOLD && scale > Number.EPSILON) {
757
- zoom_all_axes(touch_state, scale)
758
- } else pan_all_axes(touch_state, -dx, dy)
759
- }
760
- const handle_touch_end = () => (touch_state = null)
622
+ onDestroy(() => pan_zoom.destroy())
761
623
 
762
624
  // === Legend ===
763
625
  let legend_data = $derived<LegendItem[]>(
@@ -787,10 +649,6 @@
787
649
  })
788
650
 
789
651
  let hovered_legend_series_idx = $state<number | null>(null)
790
- const legend_hover = create_hover_lock()
791
- const dim_tracker = create_dimension_tracker()
792
- let has_initial_legend_placement = $state(false)
793
- $effect(() => () => legend_hover.cleanup())
794
652
 
795
653
  let legend_placement = $derived.by(() => {
796
654
  if (!should_show_legend || !width || !height) return null
@@ -804,24 +662,13 @@
804
662
  })
805
663
  })
806
664
 
807
- const tweened_legend_coords = new Tween(
808
- { x: 0, y: 0 },
809
- untrack(() => ({ duration: 400, ...legend?.tween })),
810
- )
811
- $effect(() => {
812
- if (!width || !height || !legend_placement) return
813
- const dims_changed = dim_tracker.has_changed(width, height)
814
- if (dims_changed) dim_tracker.update(width, height)
815
- const is_responsive = legend?.responsive ?? false
816
- const should_update = dims_changed ||
817
- (!legend_hover.is_locked.current && (is_responsive || !has_initial_legend_placement))
818
- if (should_update) {
819
- tweened_legend_coords.set(
820
- { x: legend_placement.x, y: legend_placement.y },
821
- has_initial_legend_placement ? undefined : { duration: 0 },
822
- )
823
- if (legend_element) has_initial_legend_placement = true
824
- }
665
+ // Tweened legend coordinates with shared placement stability gating
666
+ const legend_tween = create_placed_tween({
667
+ placement: () => legend_placement,
668
+ dims: () => ({ width, height }),
669
+ responsive: () => legend?.responsive ?? false,
670
+ element: () => legend_element,
671
+ tween: () => legend?.tween,
825
672
  })
826
673
 
827
674
  // === Tooltip / hover ===
@@ -882,8 +729,8 @@
882
729
  </script>
883
730
 
884
731
  {#snippet seg(
885
- p1: [number, number],
886
- p2: [number, number],
732
+ p1: Vec2,
733
+ p2: Vec2,
887
734
  stroke: string,
888
735
  sw: number,
889
736
  dash?: string,
@@ -933,11 +780,9 @@
933
780
  evt.preventDefault()
934
781
  fullscreen = false
935
782
  }
936
- if (evt.key === `Shift`) shift_held = true
937
- }}
938
- onkeyup={(evt) => {
939
- if (evt.key === `Shift`) shift_held = false
783
+ pan_zoom.on_window_key_down(evt)
940
784
  }}
785
+ onkeyup={pan_zoom.on_window_key_up}
941
786
  />
942
787
 
943
788
  <div
@@ -963,37 +808,25 @@
963
808
  aria-label={rest[`aria-label`] ??
964
809
  ([x_axis.label, y_axis.label].filter(Boolean).join(` vs `) || `Box plot`)}
965
810
  tabindex="0"
966
- onfocusin={() => (is_focused = true)}
967
- onfocusout={() => (is_focused = false)}
968
- onmousedown={handle_mouse_down}
969
- ondblclick={() => {
970
- ranges.current.x = [...ranges.initial.x] as Vec2
971
- ranges.current.x2 = [...ranges.initial.x2] as Vec2
972
- ranges.current.y = [...ranges.initial.y] as Vec2
973
- ranges.current.y2 = [...ranges.initial.y2] as Vec2
974
- x_axis = { ...x_axis, range: [null, null] }
975
- x2_axis_prop = { ...x2_axis_prop, range: [null, null] }
976
- y_axis = { ...y_axis, range: [null, null] }
977
- y2_axis_prop = { ...y2_axis_prop, range: [null, null] }
978
- }}
811
+ onfocusin={() => pan_zoom.set_focused(true)}
812
+ onfocusout={() => pan_zoom.set_focused(false)}
813
+ onmousedown={pan_zoom.on_mouse_down}
814
+ ondblclick={pan_zoom.reset_view}
815
+ onkeydown={pan_zoom.on_key_down}
979
816
  onmouseleave={() => {
980
817
  hovered = false
981
818
  hover_info = null
982
819
  change(null)
983
820
  on_box_hover?.(null)
984
821
  }}
985
- onwheel={handle_wheel}
986
- ontouchstart={handle_touch_start}
987
- ontouchmove={handle_touch_move}
988
- ontouchend={handle_touch_end}
989
- ontouchcancel={handle_touch_end}
990
- style:cursor={pan_drag_state
991
- ? `grabbing`
992
- : shift_held && pan?.enabled !== false
993
- ? `grab`
994
- : `crosshair`}
822
+ onwheel={pan_zoom.on_wheel}
823
+ ontouchstart={pan_zoom.on_touch_start}
824
+ ontouchmove={pan_zoom.on_touch_move}
825
+ ontouchend={pan_zoom.on_touch_end}
826
+ ontouchcancel={pan_zoom.on_touch_end}
827
+ style:cursor={pan_zoom.cursor}
995
828
  >
996
- <ZoomRect start={drag_state.start} current={drag_state.current} />
829
+ <ZoomRect start={pan_zoom.drag_start} current={pan_zoom.drag_current} />
997
830
 
998
831
  {@render user_content?.({
999
832
  height,
@@ -1144,7 +977,7 @@
1144
977
  {@const v_wl = val_scale(stats.whisker_low)}
1145
978
  {@const v_wh = val_scale(stats.whisker_high)}
1146
979
  {@const v_mean = val_scale(stats.mean)}
1147
- {@const pt = (cross: number, val: number): [number, number] =>
980
+ {@const pt = (cross: number, val: number): Vec2 =>
1148
981
  vertical ? [cross, val] : [val, cross]}
1149
982
  {@const [q1x, q1y] = pt(c_lo, v_q1)}
1150
983
  {@const [q3x, q3y] = pt(c_hi, v_q3)}
@@ -1290,16 +1123,13 @@
1290
1123
  </svg>
1291
1124
 
1292
1125
  {#if legend && should_show_legend}
1293
- {@const legend_left = legend_auto_outside
1294
- ? legend_outside_x
1295
- : legend_placement
1296
- ? tweened_legend_coords.current.x
1297
- : pad.l + 10}
1298
- {@const legend_top = legend_auto_outside
1299
- ? legend_outside_y
1300
- : legend_placement
1301
- ? tweened_legend_coords.current.y
1302
- : pad.t + 10}
1126
+ {@const legend_pos = placed_coords(
1127
+ legend_auto_outside,
1128
+ { x: legend_outside_x, y: legend_outside_y },
1129
+ legend_placement,
1130
+ legend_tween.coords.current,
1131
+ { x: pad.l + 10, y: pad.t + 10 },
1132
+ )}
1303
1133
  <PlotLegend
1304
1134
  bind:root_element={legend_element}
1305
1135
  {...legend}
@@ -1307,13 +1137,13 @@
1307
1137
  on_toggle={legend?.on_toggle ?? legend_vis.on_toggle}
1308
1138
  on_group_toggle={legend?.on_group_toggle ?? legend_vis.on_group_toggle}
1309
1139
  on_double_click={legend?.on_double_click ?? legend_vis.on_double_click}
1310
- on_hover_change={legend_hover.set_locked}
1140
+ on_hover_change={legend_tween.set_locked}
1311
1141
  on_item_hover={(item) =>
1312
1142
  (hovered_legend_series_idx = item != null && item.series_idx >= 0
1313
1143
  ? item.series_idx
1314
1144
  : null)}
1315
1145
  active_series_idx={hover_info?.series_idx ?? hovered_legend_series_idx}
1316
- style={`position: absolute; left: ${legend_left}px; top: ${legend_top}px; pointer-events: auto; ${
1146
+ style={`position: absolute; left: ${legend_pos.x}px; top: ${legend_pos.y}px; pointer-events: auto; ${
1317
1147
  legend?.style || ``
1318
1148
  }`}
1319
1149
  />
@@ -1,3 +1,4 @@
1
+ import type { Vec2 } from '../../math';
1
2
  import type { BandwidthOption, BasePlotProps, BoxHandlerProps, BoxPlotSeries, LegendConfig, Orientation, PanConfig, PlotConfig, RefLine, RefLineEvent, UserContentProps, ViolinKind, ViolinSide, WhiskerMode } from '..';
2
3
  import type { Snippet } from 'svelte';
3
4
  import type { HTMLAttributes } from 'svelte/elements';
@@ -30,7 +31,7 @@ declare function $$render<Metadata extends Record<string, unknown> = Record<stri
30
31
  };
31
32
  whisker_mode?: WhiskerMode;
32
33
  whisker_range?: number;
33
- whisker_percentiles?: [number, number];
34
+ whisker_percentiles?: Vec2;
34
35
  show_outliers?: boolean;
35
36
  show_mean?: boolean;
36
37
  show_value_labels?: boolean;
@@ -71,7 +72,7 @@ declare function $$render<Metadata extends Record<string, unknown> = Record<stri
71
72
  pan?: PanConfig;
72
73
  };
73
74
  exports: {};
74
- bindings: "orientation" | "display" | "show_controls" | "fullscreen" | "series" | "hovered" | "ref_lines" | "controls_open" | "x_axis" | "y_axis" | "whisker_mode" | "x2_axis" | "y2_axis" | "show_outliers" | "show_mean" | "kind" | "side";
75
+ bindings: "display" | "orientation" | "show_controls" | "x2_axis" | "y_axis" | "y2_axis" | "fullscreen" | "series" | "hovered" | "ref_lines" | "controls_open" | "x_axis" | "kind" | "side" | "whisker_mode" | "show_outliers" | "show_mean";
75
76
  slots: {};
76
77
  events: {};
77
78
  };
@@ -79,7 +80,7 @@ declare class __sveltets_Render<Metadata extends Record<string, unknown> = Recor
79
80
  props(): ReturnType<typeof $$render<Metadata>>['props'];
80
81
  events(): ReturnType<typeof $$render<Metadata>>['events'];
81
82
  slots(): ReturnType<typeof $$render<Metadata>>['slots'];
82
- bindings(): "orientation" | "display" | "show_controls" | "fullscreen" | "series" | "hovered" | "ref_lines" | "controls_open" | "x_axis" | "y_axis" | "whisker_mode" | "x2_axis" | "y2_axis" | "show_outliers" | "show_mean" | "kind" | "side";
83
+ bindings(): "display" | "orientation" | "show_controls" | "x2_axis" | "y_axis" | "y2_axis" | "fullscreen" | "series" | "hovered" | "ref_lines" | "controls_open" | "x_axis" | "kind" | "side" | "whisker_mode" | "show_outliers" | "show_mean";
83
84
  exports(): {};
84
85
  }
85
86
  interface $$IsomorphicComponent {
@@ -14,6 +14,6 @@ type $$ComponentProps = Omit<PlotControlsProps, `children` | `post_children`> &
14
14
  orientation: Orientation;
15
15
  } & Required<PlotConfig>]>;
16
16
  };
17
- declare const BoxPlotControls: import("svelte").Component<$$ComponentProps, {}, "orientation" | "display" | "show_controls" | "controls_open" | "x_axis" | "y_axis" | "whisker_mode" | "x2_axis" | "y2_axis" | "show_outliers" | "show_mean" | "kind" | "side">;
17
+ declare const BoxPlotControls: import("svelte").Component<$$ComponentProps, {}, "display" | "orientation" | "show_controls" | "x2_axis" | "y_axis" | "y2_axis" | "controls_open" | "x_axis" | "kind" | "side" | "whisker_mode" | "show_outliers" | "show_mean">;
18
18
  type BoxPlotControls = ReturnType<typeof BoxPlotControls>;
19
19
  export default BoxPlotControls;
@@ -26,7 +26,7 @@ declare const Violin: import("svelte").Component<import("svelte/elements").HTMLA
26
26
  } | undefined;
27
27
  whisker_mode?: import("./box-plot").WhiskerMode;
28
28
  whisker_range?: number;
29
- whisker_percentiles?: [number, number];
29
+ whisker_percentiles?: import("../..").Vec2;
30
30
  show_outliers?: boolean;
31
31
  show_mean?: boolean;
32
32
  show_value_labels?: boolean;
@@ -1,3 +1,4 @@
1
+ import type { Vec2 } from '../../math';
1
2
  import type { HandlerProps } from '../core/types';
2
3
  export type WhiskerMode = `tukey` | `minmax` | `percentile` | `std`;
3
4
  export type ViolinKind = `box` | `violin` | `violin+box`;
@@ -16,7 +17,7 @@ export interface BoxPlotSeries<Metadata = Record<string, unknown>> {
16
17
  y_axis?: `y1` | `y2`;
17
18
  whisker_mode?: WhiskerMode;
18
19
  whisker_range?: number;
19
- whisker_percentiles?: [number, number];
20
+ whisker_percentiles?: Vec2;
20
21
  kind?: ViolinKind;
21
22
  side?: ViolinSide;
22
23
  bandwidth?: BandwidthOption;
@@ -47,7 +48,7 @@ export interface BoxStats {
47
48
  export interface BoxStatsOptions {
48
49
  whisker_mode?: WhiskerMode;
49
50
  whisker_range?: number;
50
- whisker_percentiles?: [number, number];
51
+ whisker_percentiles?: Vec2;
51
52
  collect_outliers?: boolean;
52
53
  }
53
54
  export declare const WHISKER_MODES: readonly ["tukey", "minmax", "percentile", "std"];
@@ -2,6 +2,7 @@
2
2
  // Single source of truth for the quantile math used by BoxPlot.svelte.
3
3
  import { ascending } from 'd3-array';
4
4
  import { quantile_unordered } from './quantile';
5
+ import { DEFAULTS } from '../../settings';
5
6
  export const WHISKER_MODES = [`tukey`, `minmax`, `percentile`, `std`];
6
7
  const WHISKER_MODE_SET = new Set(WHISKER_MODES);
7
8
  export const is_whisker_mode = (val) => WHISKER_MODE_SET.has(val);
@@ -56,7 +57,9 @@ function tukey_scan(values, low_bound, high_bound, collect, data_min, data_max)
56
57
  // Quartiles use type-7 linear interpolation, matching d3/numpy/pandas defaults.
57
58
  // Non-finite values are filtered out; the input array is never mutated.
58
59
  export function compute_box_stats(values, opts = {}) {
59
- const { whisker_mode = `tukey`, whisker_range = 1.5, whisker_percentiles = [5, 95], collect_outliers = true, } = opts;
60
+ const {
61
+ // Fallback derives from DEFAULTS.box so component and helper defaults can't drift
62
+ whisker_mode = DEFAULTS.box.whisker_mode, whisker_range = 1.5, whisker_percentiles = [5, 95], collect_outliers = true, } = opts;
60
63
  const vals = values.filter((val) => Number.isFinite(val));
61
64
  const n_vals = vals.length;
62
65
  if (n_vals === 0)
@@ -72,7 +75,7 @@ export function compute_box_stats(values, opts = {}) {
72
75
  data_max = val;
73
76
  }
74
77
  const mean = sum / n_vals;
75
- const qtl = (p) => quantile_unordered(vals, p);
78
+ const qtl = (prob) => quantile_unordered(vals, prob);
76
79
  const collect_beyond = (lo, hi) => collect_outliers_by_scan(vals, lo, hi, collect_outliers);
77
80
  const q1 = qtl(0.25);
78
81
  const median = qtl(0.5);
@@ -1,3 +1,4 @@
1
+ import type { Vec2 } from '../../math';
1
2
  export interface KdeResult {
2
3
  grid: number[];
3
4
  density: number[];
@@ -8,7 +9,7 @@ export interface KdeOptions {
8
9
  n_points?: number;
9
10
  cut?: number;
10
11
  clip?: [number | null, number | null];
11
- range?: [number, number];
12
+ range?: Vec2;
12
13
  max_samples?: number;
13
14
  }
14
15
  export declare function silverman_bandwidth(sorted: readonly number[]): number;
@@ -55,8 +55,8 @@ function exact_density(eval_samples, grid, band) {
55
55
  const g_val = grid[grid_idx];
56
56
  let sum = 0;
57
57
  for (const sample of eval_samples) {
58
- const u = (g_val - sample) / band;
59
- sum += Math.exp(-0.5 * u * u);
58
+ const z_score = (g_val - sample) / band;
59
+ sum += Math.exp(-0.5 * z_score * z_score);
60
60
  }
61
61
  density[grid_idx] = sum * norm;
62
62
  }
@@ -98,8 +98,8 @@ function binned_density(eval_samples, grid, band) {
98
98
  const count = counts[bin_idx];
99
99
  if (count === 0)
100
100
  continue;
101
- const u = (g_val - centers[bin_idx]) / band;
102
- sum += count * Math.exp(-0.5 * u * u);
101
+ const z_score = (g_val - centers[bin_idx]) / band;
102
+ sum += count * Math.exp(-0.5 * z_score * z_score);
103
103
  }
104
104
  density[grid_idx] = sum * norm;
105
105
  }
@@ -1,5 +1,4 @@
1
1
  import type { Sides } from './layout';
2
- export declare const DECOR_GAP = 8;
3
2
  type Pt = {
4
3
  x: number;
5
4
  y: number;
@@ -8,6 +7,7 @@ type Size = {
8
7
  width: number;
9
8
  height: number;
10
9
  };
10
+ export declare const placed_coords: (auto_outside: boolean, outside: Pt, placement: Pt | null, tweened: Pt, fallback: Pt) => Pt;
11
11
  export declare const has_explicit_position: (style?: string | null) => boolean;
12
12
  export declare const measured_footprint: (el: HTMLElement | null | undefined, fallback: Size) => Size;
13
13
  export declare function build_obstacles_norm(series: {
@@ -1,7 +1,10 @@
1
1
  import { compute_element_placement, sample_series_obstacle_points, } from './layout';
2
2
  // Shared "move a decoration (legend/colorbar) outside the plot when interior overlap is
3
3
  // unavoidable" logic, reused by every 2D plot (ScatterPlot/BarPlot/Histogram/BinnedScatterPlot).
4
- export const DECOR_GAP = 8; // px gap between an outside decoration and the plot edge
4
+ const DECOR_GAP = 8; // px gap between an outside decoration and the plot edge
5
+ // Final on-screen position for an auto-placed decoration: explicit outside placement
6
+ // wins, then the tweened auto placement, else a static padding fallback
7
+ export const placed_coords = (auto_outside, outside, placement, tweened, fallback) => (auto_outside ? outside : placement ? tweened : fallback);
5
8
  // True when the user pinned a decoration via its style (an edge property or position:absolute),
6
9
  // in which case auto-placement must leave it alone.
7
10
  export const has_explicit_position = (style) => /(^|[;{]\s*)(top|bottom|left|right)\s*:|position\s*:\s*absolute/.test(style ?? ``);
@@ -59,7 +59,7 @@
59
59
  wrapper_style?: string
60
60
  tick_labels?: (string | number)[] | number
61
61
  tick_format?: string
62
- range?: [number, number]
62
+ range?: Vec2
63
63
  // tick_side determines tick placement relative to orientation:
64
64
  // 'primary' = bottom (horizontal) / right (vertical), outside bar
65
65
  // 'secondary' = top (horizontal) / left (vertical), outside bar
@@ -72,18 +72,18 @@
72
72
  steps?: number
73
73
  // computed "nice" range resulting from snapping ticks
74
74
  // https://github.com/d3/d3-scale/issues/86
75
- nice_range?: [number, number]
75
+ nice_range?: Vec2
76
76
  // type of scale to use for ticks and potentially color (if color_scale_fn not provided)
77
77
  scale_type?: ScaleType
78
78
  // Optional pre-configured d3 color scale function
79
79
  color_scale_fn?: (value: number) => string
80
80
  // Optional domain for pre-configured color scale function
81
- color_scale_domain?: [number, number]
81
+ color_scale_domain?: Vec2
82
82
  // Property selection options (makes title interactive)
83
83
  property_options?: AxisOption[]
84
84
  selected_property_key?: string
85
85
  data_loader?: ColorBarDataLoaderFn
86
- on_property_change?: (key: string, range: [number, number]) => void
86
+ on_property_change?: (key: string, range: Vec2) => void
87
87
  // Color scale selection options
88
88
  color_scale_options?: ColorScaleOption[]
89
89
  selected_color_scale_key?: string
@@ -301,7 +301,7 @@
301
301
  // Use potentially adjusted min/max for domain (ascending)
302
302
  const lo = Math.min(min_val, max_val)
303
303
  const hi = Math.max(min_val, max_val)
304
- const domain_for_scale: [number, number] = [lo, hi]
304
+ const domain_for_scale: Vec2 = [lo, hi]
305
305
 
306
306
  // For arcsinh, create a custom color scale
307
307
  if (type_name === `arcsinh`) {