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
@@ -2,7 +2,6 @@
2
2
  lang="ts"
3
3
  generics="Metadata extends Record<string, unknown> = Record<string, unknown>"
4
4
  >
5
- import type { D3ColorSchemeName, D3InterpolateName } from '../../colors'
6
5
  import { format_num } from '../../labels'
7
6
  import type { Vec2, Vec3 } from '../../math'
8
7
  import type {
@@ -13,12 +12,13 @@
13
12
  InternalPoint3D,
14
13
  RefLine3D,
15
14
  RefPlane,
16
- ScaleType,
17
15
  Scatter3DHandlerEvent,
16
+ SizeScaleConfig,
18
17
  StyleOverrides3D,
19
18
  Surface3DConfig,
20
19
  } from '../core/types'
21
- import { T, useTask, useThrelte } from '@threlte/core'
20
+ import { bind_renderer } from '../../scene'
21
+ import { T, useTask } from '@threlte/core'
22
22
  import * as extras from '@threlte/extras'
23
23
  import { scaleLinear } from 'd3-scale'
24
24
  import { type ComponentProps, onDestroy, type Snippet, untrack } from 'svelte'
@@ -31,7 +31,7 @@
31
31
  import { normalize_to_scene } from '../core/reference-line'
32
32
  import ReferenceLine3D from '../core/components/ReferenceLine3D.svelte'
33
33
  import ReferencePlane from '../core/components/ReferencePlane.svelte'
34
- import { create_color_scale, create_size_scale } from '../core/scales'
34
+ import { create_size_scale } from '../core/scales'
35
35
  import Surface3D from './Surface3D.svelte'
36
36
 
37
37
  let {
@@ -45,7 +45,7 @@
45
45
  surfaces = [],
46
46
  ref_lines = [],
47
47
  ref_planes = [],
48
- color_scale = { type: `linear`, scheme: `interpolateViridis` },
48
+ color_scale_fn = () => get_series_color(0),
49
49
  size_scale = { type: `linear`, radius_range: [0.05, 0.2] },
50
50
  camera_position = [10, 10, 10] as Vec3,
51
51
  camera_projection = `perspective` as CameraProjection3D,
@@ -81,16 +81,9 @@
81
81
  surfaces?: Surface3DConfig[]
82
82
  ref_lines?: RefLine3D[]
83
83
  ref_planes?: RefPlane[]
84
- color_scale?: {
85
- type?: ScaleType
86
- scheme?: D3ColorSchemeName | D3InterpolateName
87
- value_range?: [number, number]
88
- }
89
- size_scale?: {
90
- type?: ScaleType
91
- radius_range?: [number, number]
92
- value_range?: [number, number]
93
- }
84
+ // Color scale function for color_values (computed once by the ScatterPlot3D wrapper)
85
+ color_scale_fn?: (value: number) => string
86
+ size_scale?: SizeScaleConfig
94
87
  camera_position?: Vec3
95
88
  camera_projection?: CameraProjection3D
96
89
  auto_rotate?: number
@@ -116,10 +109,10 @@
116
109
  height?: number
117
110
  } = $props()
118
111
 
119
- const threlte = useThrelte()
120
- $effect(() => {
121
- scene = threlte.scene
122
- camera = threlte.camera.current
112
+ // Mirrors scene/camera into bindable props and tags the canvas so export_canvas_as_png can re-render at export DPI
113
+ bind_renderer((threlte_scene, threlte_camera) => {
114
+ scene = threlte_scene
115
+ camera = threlte_camera
123
116
  })
124
117
 
125
118
  extras.interactivity()
@@ -182,24 +175,28 @@
182
175
  function sample_surface(
183
176
  surface: Surface3DConfig,
184
177
  ): { x: number; y: number; z: number }[] {
185
- const n = 10
178
+ const grid_steps = 10
186
179
  const pts: { x: number; y: number; z: number }[] = []
187
180
  if (surface.type === `grid` && surface.z_fn) {
188
181
  const [x0, x1] = surface.x_range ?? [-1, 1]
189
182
  const [y0, y1] = surface.y_range ?? [-1, 1]
190
- for (let i = 0; i <= n; i++) {
191
- for (let j = 0; j <= n; j++) {
192
- const x = x0 + (i / n) * (x1 - x0), y = y0 + (j / n) * (y1 - y0)
183
+ for (let idx_x = 0; idx_x <= grid_steps; idx_x++) {
184
+ for (let idx_y = 0; idx_y <= grid_steps; idx_y++) {
185
+ const x = x0 + (idx_x / grid_steps) * (x1 - x0),
186
+ y = y0 + (idx_y / grid_steps) * (y1 - y0)
193
187
  pts.push({ x, y, z: surface.z_fn(x, y) })
194
188
  }
195
189
  }
196
190
  } else if (surface.type === `parametric` && surface.parametric_fn) {
197
191
  const [u0, u1] = surface.u_range ?? [0, 1]
198
192
  const [v0, v1] = surface.v_range ?? [0, 1]
199
- for (let i = 0; i <= n; i++) {
200
- for (let j = 0; j <= n; j++) {
193
+ for (let idx_u = 0; idx_u <= grid_steps; idx_u++) {
194
+ for (let idx_v = 0; idx_v <= grid_steps; idx_v++) {
201
195
  pts.push(
202
- surface.parametric_fn(u0 + (i / n) * (u1 - u0), v0 + (j / n) * (v1 - v0)),
196
+ surface.parametric_fn(
197
+ u0 + (idx_u / grid_steps) * (u1 - u0),
198
+ v0 + (idx_v / grid_steps) * (v1 - v0),
199
+ ),
203
200
  )
204
201
  }
205
202
  }
@@ -209,15 +206,14 @@
209
206
  return pts.filter((pt) => isFinite(pt.x) && isFinite(pt.y) && isFinite(pt.z))
210
207
  }
211
208
 
212
- // Compute axis range with D3's nice() for clean boundaries
209
+ // Compute axis range with D3's nice(); data_min/data_max are the finite extent (Infinity/-Infinity when empty)
213
210
  function compute_range(
214
- values: number[],
211
+ [data_min, data_max]: Vec2,
215
212
  range?: [number | null, number | null],
216
213
  ): Vec2 {
217
214
  if (range?.[0] != null && range?.[1] != null) return range as Vec2
218
- const valid = values.filter(isFinite)
219
- if (valid.length === 0) return [0, 1]
220
- let [min, max] = [Math.min(...valid), Math.max(...valid)]
215
+ if (data_min > data_max) return [0, 1] // no finite values
216
+ let [min, max] = [data_min, data_max]
221
217
  const pad = min === max
222
218
  ? (min === 0 ? 1 : Math.abs(min * 0.1))
223
219
  : (max - min) * 0.05
@@ -227,49 +223,39 @@
227
223
  .domain() as Vec2
228
224
  }
229
225
 
230
- // Collect xyz values from points and surfaces
226
+ // Collect xyz extents from points and surfaces in one pass (no intermediate arrays)
231
227
  let surface_samples = $derived(surfaces.flatMap(sample_surface))
232
- let x_range = $derived(
233
- compute_range([
234
- ...all_points.map((point) => point.x),
235
- ...surface_samples.map((point) => point.x),
236
- ], x_axis.range),
237
- )
238
- let y_range = $derived(
239
- compute_range([
240
- ...all_points.map((point) => point.y),
241
- ...surface_samples.map((point) => point.y),
242
- ], y_axis.range),
243
- )
244
- let z_range = $derived(
245
- compute_range([
246
- ...all_points.map((point) => point.z),
247
- ...surface_samples.map((point) => point.z),
248
- ], z_axis.range),
249
- )
228
+ let data_extents = $derived.by(() => {
229
+ const extents = {
230
+ x: [Infinity, -Infinity] as Vec2,
231
+ y: [Infinity, -Infinity] as Vec2,
232
+ z: [Infinity, -Infinity] as Vec2,
233
+ }
234
+ for (const points of [all_points, surface_samples]) {
235
+ for (const pt of points) {
236
+ for (const axis of [`x`, `y`, `z`] as const) {
237
+ const val = pt[axis]
238
+ if (!isFinite(val)) continue
239
+ const extent = extents[axis]
240
+ if (val < extent[0]) extent[0] = val
241
+ if (val > extent[1]) extent[1] = val
242
+ }
243
+ }
244
+ }
245
+ return extents
246
+ })
247
+ let x_range = $derived(compute_range(data_extents.x, x_axis.range))
248
+ let y_range = $derived(compute_range(data_extents.y, y_axis.range))
249
+ let z_range = $derived(compute_range(data_extents.z, z_axis.range))
250
250
 
251
251
  const normalize_x = (value: number) => normalize_to_scene(value, x_range, scene_x)
252
252
  const normalize_y = (value: number) => normalize_to_scene(value, y_range, scene_y)
253
253
  const normalize_z = (value: number) => normalize_to_scene(value, z_range, scene_z)
254
254
 
255
- // Color/size scales
256
- let all_color_values = $derived(
257
- all_points.map((pt) => pt.color_value).filter((val): val is number => val != null),
258
- )
259
- let auto_color_range: [number, number] = $derived.by(() => {
260
- if (all_color_values.length === 0) return [0, 1]
261
- let min = all_color_values[0]
262
- let max = all_color_values[0]
263
- for (const val of all_color_values) {
264
- if (val < min) min = val
265
- else if (val > max) max = val
266
- }
267
- return [min, max]
268
- })
255
+ // Size scale (the color scale is computed by the wrapper and passed as a prop)
269
256
  let all_size_values = $derived(
270
257
  all_points.map((pt) => pt.size_value).filter((val): val is number => val != null),
271
258
  )
272
- let color_scale_fn = $derived(create_color_scale(color_scale, auto_color_range))
273
259
  let size_scale_fn = $derived(create_size_scale(size_scale, all_size_values))
274
260
 
275
261
  // Process points with normalized positions
@@ -331,83 +317,98 @@
331
317
  )
332
318
 
333
319
  // Series line data for connecting points
334
- type SeriesLineData = {
320
+ type SeriesLineInput = {
335
321
  series_idx: number
322
+ positions: number[]
336
323
  color: string
337
324
  width: number
338
325
  dashed: boolean
326
+ }
327
+ type SeriesLineData = SeriesLineInput & {
339
328
  line2: Line2
340
329
  geometry: LineGeometry
341
330
  material: LineMaterial
342
331
  }
343
332
 
344
- // Track previous lines for cleanup
345
- let series_lines: SeriesLineData[] = $state([])
346
-
347
- $effect(() => {
348
- // Dispose old lines before creating new ones
349
- for (const line_data of untrack(() => series_lines)) {
350
- line_data.geometry.dispose()
351
- line_data.material.dispose()
352
- }
353
-
354
- const lines: SeriesLineData[] = []
333
+ // Per-series fat-line inputs (ordered positions + resolved stroke style) as a derived so
334
+ // the effect below can diff against previous lines and only rebuild what changed
335
+ let line_inputs = $derived.by((): SeriesLineInput[] => {
336
+ const eligible: SeriesLineInput[] = []
337
+ const positions_by_series = new Map<number, number[]>()
355
338
  for (let series_idx = 0; series_idx < series.length; series_idx++) {
356
339
  const srs = series[series_idx]
357
- if (!srs?.line_style) continue
340
+ const line_style = srs?.line_style
341
+ if (!line_style) continue
358
342
  if (!(series_visibility[series_idx] ?? srs.visible ?? true)) continue
359
-
360
- // Get points for this series in order
361
- const series_points = processed_points
362
- .filter((pt) => pt.series_idx === series_idx)
363
- .sort((a, b) => a.point_idx - b.point_idx)
364
-
365
- if (series_points.length < 2) continue
366
-
367
- // Create fat line geometry (LineGeometry for Line2)
368
343
  const positions: number[] = []
369
- for (const pt of series_points) {
370
- positions.push(pt.x, pt.y, pt.z)
371
- }
372
- const geometry = new LineGeometry()
373
- geometry.setPositions(positions)
374
-
375
- // Determine line style
376
- const line_style = srs.line_style
344
+ positions_by_series.set(series_idx, positions)
377
345
  const color = line_style.stroke ??
378
346
  (Array.isArray(srs.point_style)
379
347
  ? srs.point_style[0]?.fill
380
348
  : srs.point_style?.fill) ??
381
349
  get_series_color(series_idx)
382
- const line_width = line_style.stroke_width ?? 2
383
- const dashed = Boolean(line_style.line_dash)
384
-
385
- // Create LineMaterial for fat lines (linewidth is in pixels when resolution is set)
386
- // Use placeholder resolution; the separate resolution effect updates it
387
- const material = new LineMaterial({
388
- color: new THREE.Color(color).getHex(),
389
- linewidth: line_width, // Width in pixels
390
- dashed,
391
- dashScale: dashed ? 2 : 1,
392
- dashSize: 0.1,
393
- gapSize: 0.05,
394
- resolution: new THREE.Vector2(1, 1),
395
- })
396
-
397
- const line2 = new Line2(geometry, material)
398
- line2.computeLineDistances()
399
-
400
- lines.push({
350
+ eligible.push({
401
351
  series_idx,
352
+ positions,
402
353
  color,
403
- width: line_width,
404
- dashed,
405
- line2,
406
- geometry,
407
- material,
354
+ width: line_style.stroke_width ?? 2,
355
+ dashed: Boolean(line_style.line_dash),
408
356
  })
409
357
  }
410
- series_lines = lines
358
+ // processed_points are emitted in (series_idx, point_idx) order, so one ordered pass replaces the old per-series filter + sort
359
+ for (const pt of processed_points) {
360
+ positions_by_series.get(pt.series_idx)?.push(pt.x, pt.y, pt.z)
361
+ }
362
+ return eligible.filter((input) => input.positions.length >= 6) // >= 2 points
363
+ })
364
+
365
+ const same_line_input = (prev: SeriesLineData, next: SeriesLineInput): boolean =>
366
+ prev.color === next.color && prev.width === next.width &&
367
+ prev.dashed === next.dashed &&
368
+ prev.positions.length === next.positions.length &&
369
+ prev.positions.every((coord, idx) => coord === next.positions[idx])
370
+
371
+ // Track previous lines for reuse/cleanup
372
+ let series_lines: SeriesLineData[] = $state([])
373
+
374
+ $effect(() => {
375
+ const inputs = line_inputs
376
+ untrack(() => {
377
+ const prev_by_idx = new Map(series_lines.map((line) => [line.series_idx, line]))
378
+ const next_lines = inputs.map((input): SeriesLineData => {
379
+ const prev = prev_by_idx.get(input.series_idx)
380
+ if (prev && same_line_input(prev, input)) {
381
+ prev_by_idx.delete(input.series_idx) // reused - don't dispose below
382
+ return prev
383
+ }
384
+ // Create fat line geometry (LineGeometry for Line2)
385
+ const geometry = new LineGeometry()
386
+ geometry.setPositions(input.positions)
387
+ // Create LineMaterial for fat lines (linewidth is in pixels when resolution
388
+ // is set). Use placeholder resolution; the separate resolution effect updates it
389
+ const material = new LineMaterial({
390
+ color: new THREE.Color(input.color).getHex(),
391
+ linewidth: input.width, // Width in pixels
392
+ dashed: input.dashed,
393
+ dashScale: input.dashed ? 2 : 1,
394
+ dashSize: 0.1,
395
+ gapSize: 0.05,
396
+ resolution: new THREE.Vector2(1, 1),
397
+ })
398
+ const line2 = new Line2(geometry, material)
399
+ line2.computeLineDistances()
400
+ return { ...input, line2, geometry, material }
401
+ })
402
+ // Dispose lines that were replaced or removed
403
+ for (const stale of prev_by_idx.values()) {
404
+ stale.geometry.dispose()
405
+ stale.material.dispose()
406
+ }
407
+ // Skip reassignment when every line was reused to avoid invalidating consumers
408
+ const unchanged = next_lines.length === series_lines.length &&
409
+ next_lines.every((line, idx) => line === series_lines[idx])
410
+ if (!unchanged) series_lines = next_lines
411
+ })
411
412
  })
412
413
 
413
414
  // Update LineMaterial resolution when canvas size changes
@@ -434,7 +435,7 @@
434
435
 
435
436
  // Generate axis ticks using D3's smart tick generation
436
437
  function gen_ticks(
437
- range: [number, number],
438
+ range: Vec2,
438
439
  ticks?: AxisConfig3D[`ticks`],
439
440
  ): number[] {
440
441
  if (Array.isArray(ticks)) return ticks
@@ -1,6 +1,5 @@
1
- import type { D3ColorSchemeName, D3InterpolateName } from '../../colors';
2
1
  import type { Vec3 } from '../../math';
3
- import type { AxisConfig3D, CameraProjection3D, DataSeries3D, DisplayConfig3D, InternalPoint3D, RefLine3D, RefPlane, ScaleType, Scatter3DHandlerEvent, StyleOverrides3D, Surface3DConfig } from '../core/types';
2
+ import type { AxisConfig3D, CameraProjection3D, DataSeries3D, DisplayConfig3D, InternalPoint3D, RefLine3D, RefPlane, Scatter3DHandlerEvent, SizeScaleConfig, StyleOverrides3D, Surface3DConfig } from '../core/types';
4
3
  import * as extras from '@threlte/extras';
5
4
  import { type ComponentProps, type Snippet } from 'svelte';
6
5
  import type { Camera, Scene } from 'three';
@@ -16,16 +15,8 @@ declare function $$render<Metadata extends Record<string, unknown> = Record<stri
16
15
  surfaces?: Surface3DConfig[];
17
16
  ref_lines?: RefLine3D[];
18
17
  ref_planes?: RefPlane[];
19
- color_scale?: {
20
- type?: ScaleType;
21
- scheme?: D3ColorSchemeName | D3InterpolateName;
22
- value_range?: [number, number];
23
- };
24
- size_scale?: {
25
- type?: ScaleType;
26
- radius_range?: [number, number];
27
- value_range?: [number, number];
28
- };
18
+ color_scale_fn?: (value: number) => string;
19
+ size_scale?: SizeScaleConfig;
29
20
  camera_position?: Vec3;
30
21
  camera_projection?: CameraProjection3D;
31
22
  auto_rotate?: number;
@@ -51,7 +42,7 @@ declare function $$render<Metadata extends Record<string, unknown> = Record<stri
51
42
  height?: number;
52
43
  };
53
44
  exports: {};
54
- bindings: "camera" | "hovered_point" | "scene" | "orbit_controls";
45
+ bindings: "scene" | "camera" | "orbit_controls" | "hovered_point";
55
46
  slots: {};
56
47
  events: {};
57
48
  };
@@ -59,7 +50,7 @@ declare class __sveltets_Render<Metadata extends Record<string, unknown> = Recor
59
50
  props(): ReturnType<typeof $$render<Metadata>>['props'];
60
51
  events(): ReturnType<typeof $$render<Metadata>>['events'];
61
52
  slots(): ReturnType<typeof $$render<Metadata>>['slots'];
62
- bindings(): "camera" | "hovered_point" | "scene" | "orbit_controls";
53
+ bindings(): "scene" | "camera" | "orbit_controls" | "hovered_point";
63
54
  exports(): {};
64
55
  }
65
56
  interface $$IsomorphicComponent {
@@ -1,4 +1,5 @@
1
1
  <script lang="ts">
2
+ import type { Vec2 } from '../../math'
2
3
  import type { Surface3DConfig } from '../core/types'
3
4
  import { T } from '@threlte/core'
4
5
  import * as THREE from 'three'
@@ -13,9 +14,9 @@
13
14
  scene_z = 5,
14
15
  }: {
15
16
  config: Surface3DConfig
16
- x_range?: [number, number]
17
- y_range?: [number, number]
18
- z_range?: [number, number]
17
+ x_range?: Vec2
18
+ y_range?: Vec2
19
+ z_range?: Vec2
19
20
  scene_x?: number
20
21
  scene_y?: number
21
22
  scene_z?: number
@@ -24,7 +25,7 @@
24
25
  // Normalize value to scene coordinates (centered around 0)
25
26
  const normalize = (
26
27
  value: number,
27
- [min_val, max_val]: [number, number],
28
+ [min_val, max_val]: Vec2,
28
29
  scene_size: number,
29
30
  ): number => ((value - min_val) / (max_val - min_val || 1) - 0.5) * scene_size
30
31
 
@@ -96,7 +97,7 @@
96
97
  }
97
98
 
98
99
  // Parse resolution config into [res_a, res_b]
99
- const get_resolution = (): [number, number] =>
100
+ const get_resolution = (): Vec2 =>
100
101
  Array.isArray(config.resolution)
101
102
  ? config.resolution
102
103
  : [config.resolution ?? 20, config.resolution ?? 20]
@@ -1,9 +1,10 @@
1
+ import type { Vec2 } from '../../math';
1
2
  import type { Surface3DConfig } from '../core/types';
2
3
  type $$ComponentProps = {
3
4
  config: Surface3DConfig;
4
- x_range?: [number, number];
5
- y_range?: [number, number];
6
- z_range?: [number, number];
5
+ x_range?: Vec2;
6
+ y_range?: Vec2;
7
+ z_range?: Vec2;
7
8
  scene_x?: number;
8
9
  scene_y?: number;
9
10
  scene_z?: number;
@@ -7,7 +7,7 @@
7
7
  import { export_svg_as_png, export_svg_as_svg } from '../../io/export'
8
8
  import { format_value } from '../../labels'
9
9
  import { FullscreenToggle, set_fullscreen_bg } from '../../layout'
10
- import { DEG_TO_RAD } from '../../math'
10
+ import { DEG_TO_RAD, type Vec2 } from '../../math'
11
11
  import type {
12
12
  BasePlotProps,
13
13
  LegendConfig,
@@ -29,12 +29,8 @@
29
29
  } from '../core/layout'
30
30
  import type { Sides } from '../core/layout'
31
31
  import { create_color_scale } from '../core/scales'
32
- import {
33
- arc_label_transform,
34
- arrow_nav_target,
35
- project_arcs,
36
- type ScreenArc as ScreenArcOf,
37
- } from './render'
32
+ import { arc_label_transform, arrow_nav_target, project_arcs } from './render'
33
+ import type { ScreenArc as ScreenArcOf } from './render'
38
34
  import { compute_sunburst_layout, type PositionedArc } from './sunburst'
39
35
  import { DEFAULTS } from '../../settings'
40
36
  import { arc as d3_arc } from 'd3-shape'
@@ -118,7 +114,7 @@
118
114
  // inheritance; return null to keep an arc's categorical color
119
115
  color_values?: (arc: PositionedArc<Metadata>) => number | null
120
116
  color_scale?: D3InterpolateName
121
- color_range?: [number, number] // defaults to the metric's [min, max]
117
+ color_range?: Vec2 // defaults to the metric's [min, max]
122
118
  colorbar?: ComponentProps<typeof ColorBar> | null // null hides it
123
119
  export_buttons?: boolean // SVG/PNG download buttons in the controls pane
124
120
  export_filename?: string
@@ -266,10 +262,10 @@
266
262
 
267
263
  let arc_gen = $derived(
268
264
  d3_arc<ScreenArc>()
269
- .startAngle((d) => d.a0)
270
- .endAngle((d) => d.a1)
271
- .innerRadius((d) => d.r0)
272
- .outerRadius((d) => d.r1)
265
+ .startAngle((screen) => screen.a0)
266
+ .endAngle((screen) => screen.a1)
267
+ .innerRadius((screen) => screen.r0)
268
+ .outerRadius((screen) => screen.r1)
273
269
  .padAngle(pad_angle * DEG_TO_RAD)
274
270
  .padRadius(radius || 1),
275
271
  )
@@ -287,19 +283,19 @@
287
283
  )
288
284
 
289
285
  // Arc centroid in container (pad-offset) pixel space, for tooltip + legend placement
290
- const arc_center = (d: ScreenArc): { x: number; y: number } => {
286
+ const arc_center = (screen: ScreenArc): { x: number; y: number } => {
291
287
  if (shape === `icicle`) {
292
- return { x: pad.l + (d.a0 + d.a1) / 2, y: pad.t + (d.r0 + d.r1) / 2 }
288
+ return { x: pad.l + (screen.a0 + screen.a1) / 2, y: pad.t + (screen.r0 + screen.r1) / 2 }
293
289
  }
294
- const mid_a = (d.a0 + d.a1) / 2
295
- const mid_r = (d.r0 + d.r1) / 2
290
+ const mid_a = (screen.a0 + screen.a1) / 2
291
+ const mid_r = (screen.r0 + screen.r1) / 2
296
292
  return { x: cx + Math.sin(mid_a) * mid_r, y: cy - Math.cos(mid_a) * mid_r }
297
293
  }
298
294
 
299
295
  // Continuous metric coloring: when color_values is given, arcs are colored by their
300
296
  // metric on a d3 colormap (arcs returning null keep their categorical color).
301
297
  // The user accessor runs exactly once per arc.
302
- let metric = $derived.by<{ range: [number, number]; colors: string[] } | null>(() => {
298
+ let metric = $derived.by<{ range: Vec2; colors: string[] } | null>(() => {
303
299
  if (!color_values) return null
304
300
  const vals = layout.arcs.map((arc) => {
305
301
  const val = arc.depth === 0 ? null : color_values(arc)
@@ -574,10 +570,10 @@
574
570
  )
575
571
 
576
572
  // Label text + placement transform for an arc; null = doesn't fit, hide the label
577
- function label_attrs(d: ScreenArc): { transform: string; text: string } | null {
578
- const { text, width: text_w } = arc_info[d.arc.node_idx]
573
+ function label_attrs(screen: ScreenArc): { transform: string; text: string } | null {
574
+ const { text, width: text_w } = arc_info[screen.arc.node_idx]
579
575
  if (!text) return null
580
- const transform = arc_label_transform(d, text_w, shape, label_rotation)
576
+ const transform = arc_label_transform(screen, text_w, shape, label_rotation)
581
577
  return transform ? { transform, text } : null
582
578
  }
583
579
 
@@ -1,4 +1,5 @@
1
1
  import type { D3InterpolateName } from '../../colors';
2
+ import { type Vec2 } from '../../math';
2
3
  import type { BasePlotProps, LegendConfig, SunburstLabelRotation, SunburstLabelText, SunburstNode, SunburstNodeHandlerProps, SunburstShape, SunburstSort, SunburstValueMode } from '..';
3
4
  import { ColorBar } from '..';
4
5
  import type { Sides } from '../core/layout';
@@ -26,7 +27,7 @@ declare function $$render<Metadata extends Record<string, unknown> = Record<stri
26
27
  show_breadcrumbs?: boolean;
27
28
  color_values?: (arc: PositionedArc<Metadata>) => number | null;
28
29
  color_scale?: D3InterpolateName;
29
- color_range?: [number, number];
30
+ color_range?: Vec2;
30
31
  colorbar?: ComponentProps<typeof ColorBar> | null;
31
32
  export_buttons?: boolean;
32
33
  export_filename?: string;
@@ -73,7 +74,7 @@ declare function $$render<Metadata extends Record<string, unknown> = Record<stri
73
74
  }]>;
74
75
  };
75
76
  exports: {};
76
- bindings: "data" | "show_controls" | "fullscreen" | "hovered" | "controls_open" | "value_mode" | "min_fraction" | "show_labels" | "shape" | "max_depth" | "inner_radius" | "pad_angle" | "label_rotation" | "label_text" | "zoom_on_click" | "show_breadcrumbs" | "zoom_root_id";
77
+ bindings: "data" | "show_controls" | "show_labels" | "fullscreen" | "hovered" | "controls_open" | "shape" | "value_mode" | "max_depth" | "inner_radius" | "pad_angle" | "min_fraction" | "label_rotation" | "label_text" | "zoom_on_click" | "show_breadcrumbs" | "zoom_root_id";
77
78
  slots: {};
78
79
  events: {};
79
80
  };
@@ -81,7 +82,7 @@ declare class __sveltets_Render<Metadata extends Record<string, unknown> = Recor
81
82
  props(): ReturnType<typeof $$render<Metadata>>['props'];
82
83
  events(): ReturnType<typeof $$render<Metadata>>['events'];
83
84
  slots(): ReturnType<typeof $$render<Metadata>>['slots'];
84
- bindings(): "data" | "show_controls" | "fullscreen" | "hovered" | "controls_open" | "value_mode" | "min_fraction" | "show_labels" | "shape" | "max_depth" | "inner_radius" | "pad_angle" | "label_rotation" | "label_text" | "zoom_on_click" | "show_breadcrumbs" | "zoom_root_id";
85
+ bindings(): "data" | "show_controls" | "show_labels" | "fullscreen" | "hovered" | "controls_open" | "shape" | "value_mode" | "max_depth" | "inner_radius" | "pad_angle" | "min_fraction" | "label_rotation" | "label_text" | "zoom_on_click" | "show_breadcrumbs" | "zoom_root_id";
85
86
  exports(): {};
86
87
  }
87
88
  interface $$IsomorphicComponent {
@@ -21,6 +21,6 @@ type $$ComponentProps = {
21
21
  pane_props?: HTMLAttributes<HTMLDivElement>;
22
22
  children?: Snippet;
23
23
  };
24
- declare const SunburstControls: import("svelte").Component<$$ComponentProps, {}, "show_controls" | "controls_open" | "value_mode" | "min_fraction" | "show_labels" | "shape" | "max_depth" | "inner_radius" | "pad_angle" | "label_rotation" | "label_text" | "zoom_on_click" | "show_breadcrumbs">;
24
+ declare const SunburstControls: import("svelte").Component<$$ComponentProps, {}, "show_controls" | "show_labels" | "controls_open" | "shape" | "value_mode" | "max_depth" | "inner_radius" | "pad_angle" | "min_fraction" | "label_rotation" | "label_text" | "zoom_on_click" | "show_breadcrumbs">;
25
25
  type SunburstControls = ReturnType<typeof SunburstControls>;
26
26
  export default SunburstControls;
@@ -7,11 +7,14 @@
7
7
  import { hsl } from 'd3-color';
8
8
  import { hierarchy, partition } from 'd3-hierarchy';
9
9
  import { DEFAULT_SERIES_COLORS } from '../core/types';
10
+ import { DEFAULTS } from '../../settings';
10
11
  // Compute normalized arc extents, resolved colors and breadcrumbs for a node tree.
11
12
  // Never mutates user data: d3-hierarchy wraps inputs in HierarchyNodes and all derived
12
13
  // fields (value overrides, ids, colors) are written onto the returned arcs only.
13
14
  export function compute_sunburst_layout(data, opts = {}) {
14
- const { value_mode = `leaf-sum`, sort = `none`, level_lighten = 0, min_fraction = 0, other_label = `Other`, } = opts;
15
+ const {
16
+ // value_mode/min_fraction fallbacks derive from DEFAULTS.sunburst to prevent drift
17
+ value_mode = DEFAULTS.sunburst.value_mode, sort = `none`, level_lighten = 0, min_fraction = DEFAULTS.sunburst.min_fraction, other_label = `Other`, } = opts;
15
18
  // Fresh object each call (not a shared constant) so callers can't corrupt each other
16
19
  if (Array.isArray(data) ? data.length === 0 : !data) {
17
20
  return { arcs: [], root: null, max_depth: 0 };
@@ -22,6 +22,6 @@ type $$ComponentProps = {
22
22
  drag_dropped?: Crystal[];
23
23
  dragging?: boolean;
24
24
  } & ComponentProps<typeof ScatterPlot>;
25
- declare const RdfPlot: import("svelte").Component<$$ComponentProps, {}, "loading" | "error_msg" | "dragging" | "drag_dropped">;
25
+ declare const RdfPlot: import("svelte").Component<$$ComponentProps, {}, "loading" | "dragging" | "error_msg" | "drag_dropped">;
26
26
  type RdfPlot = ReturnType<typeof RdfPlot>;
27
27
  export default RdfPlot;
package/dist/sanitize.js CHANGED
@@ -75,21 +75,32 @@ const stringify_html_input = (html) => {
75
75
  return ``;
76
76
  }
77
77
  };
78
+ // Memoize by input: two DOMPurify passes per call are costly when a component re-sanitizes
79
+ // many cells on every render (e.g. HeatmapTable). Sanitization is deterministic for the
80
+ // fixed config, so caching is output-identical.
81
+ const sanitize_cache = new Map();
78
82
  // Sanitize HTML string, allowing only safe formatting tags and links.
79
83
  // Two-pass: happy-dom promotes dangerous children when a non-allowed parent is
80
84
  // stripped (e.g. <div><script>…</script></div> → <script>…</script>). The first
81
85
  // pass explicitly removes dangerous tags so they can't survive promotion.
82
86
  export function sanitize_html(html) {
83
87
  const str = stringify_html_input(html);
88
+ const cached = sanitize_cache.get(str);
89
+ if (cached !== undefined)
90
+ return cached;
84
91
  const dp = get_purify();
85
92
  if (!dp)
86
- return str;
93
+ return str; // no DOM (SSR): return as-is, don't cache
87
94
  // oxfmt-ignore
88
95
  const safe = dp.sanitize(str, { ADD_ATTR: [`target`], FORBID_TAGS: [
89
96
  `script`, `style`, `iframe`, `object`, `embed`, `form`, `input`, `textarea`,
90
97
  `select`, `button`, `meta`, `link`, `base`, `template`, `noscript`,
91
98
  ] });
92
- return dp.sanitize(safe, { ALLOWED_TAGS: SAFE_TAGS, ALLOWED_ATTR: SAFE_ATTRS });
99
+ const result = dp.sanitize(safe, { ALLOWED_TAGS: SAFE_TAGS, ALLOWED_ATTR: SAFE_ATTRS });
100
+ if (sanitize_cache.size >= 4096)
101
+ sanitize_cache.clear(); // bound memory (rarely hit)
102
+ sanitize_cache.set(str, result);
103
+ return result;
93
104
  }
94
105
  export const compact_formula = (formula) => formula.replaceAll(/\s+/g, ``);
95
106
  // Sanitize a chemical formula with optional subscript formatting