matterviz 0.3.2 → 0.3.4

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 (281) hide show
  1. package/dist/EmptyState.svelte +10 -2
  2. package/dist/FilePicker.svelte +123 -82
  3. package/dist/Icon.svelte +18 -12
  4. package/dist/MillerIndexInput.svelte +27 -21
  5. package/dist/api/optimade.js +6 -6
  6. package/dist/app.css +216 -207
  7. package/dist/brillouin/BrillouinZone.svelte +292 -149
  8. package/dist/brillouin/BrillouinZone.svelte.d.ts +1 -1
  9. package/dist/brillouin/BrillouinZoneControls.svelte +32 -5
  10. package/dist/brillouin/BrillouinZoneExportPane.svelte +69 -42
  11. package/dist/brillouin/BrillouinZoneExportPane.svelte.d.ts +1 -1
  12. package/dist/brillouin/BrillouinZoneInfoPane.svelte +99 -68
  13. package/dist/brillouin/BrillouinZoneScene.svelte +275 -163
  14. package/dist/brillouin/BrillouinZoneScene.svelte.d.ts +1 -1
  15. package/dist/brillouin/BrillouinZoneTooltip.svelte +17 -7
  16. package/dist/brillouin/compute.js +11 -6
  17. package/dist/chempot-diagram/ChemPotDiagram.svelte +162 -27
  18. package/dist/chempot-diagram/ChemPotDiagram2D.svelte +451 -281
  19. package/dist/chempot-diagram/ChemPotDiagram3D.svelte +2148 -1642
  20. package/dist/chempot-diagram/ChemPotScene3D.svelte +8 -5
  21. package/dist/chempot-diagram/async-compute.svelte.d.ts +3 -0
  22. package/dist/chempot-diagram/async-compute.svelte.js +77 -0
  23. package/dist/chempot-diagram/chempot-worker.d.ts +1 -0
  24. package/dist/chempot-diagram/chempot-worker.js +11 -0
  25. package/dist/chempot-diagram/color.js +1 -2
  26. package/dist/chempot-diagram/compute.d.ts +10 -0
  27. package/dist/chempot-diagram/compute.js +250 -88
  28. package/dist/chempot-diagram/index.d.ts +2 -1
  29. package/dist/chempot-diagram/index.js +2 -1
  30. package/dist/chempot-diagram/temperature.js +8 -9
  31. package/dist/chempot-diagram/types.d.ts +3 -0
  32. package/dist/chempot-diagram/types.js +1 -0
  33. package/dist/colors/index.d.ts +1 -1
  34. package/dist/colors/index.js +5 -3
  35. package/dist/composition/BarChart.svelte +128 -55
  36. package/dist/composition/BubbleChart.svelte +102 -49
  37. package/dist/composition/Composition.svelte +100 -79
  38. package/dist/composition/Formula.svelte +108 -62
  39. package/dist/composition/FormulaFilter.svelte +665 -537
  40. package/dist/composition/PieChart.svelte +183 -108
  41. package/dist/composition/format.d.ts +5 -0
  42. package/dist/composition/format.js +20 -3
  43. package/dist/composition/parse.js +14 -9
  44. package/dist/convex-hull/ConvexHull.svelte +93 -40
  45. package/dist/convex-hull/ConvexHull.svelte.d.ts +1 -1
  46. package/dist/convex-hull/ConvexHull2D.svelte +549 -360
  47. package/dist/convex-hull/ConvexHull2D.svelte.d.ts +1 -1
  48. package/dist/convex-hull/ConvexHull3D.svelte +1296 -827
  49. package/dist/convex-hull/ConvexHull3D.svelte.d.ts +1 -1
  50. package/dist/convex-hull/ConvexHull4D.svelte +1004 -688
  51. package/dist/convex-hull/ConvexHull4D.svelte.d.ts +1 -1
  52. package/dist/convex-hull/ConvexHullControls.svelte +115 -28
  53. package/dist/convex-hull/ConvexHullControls.svelte.d.ts +1 -1
  54. package/dist/convex-hull/ConvexHullInfoPane.svelte +29 -3
  55. package/dist/convex-hull/ConvexHullStats.svelte +425 -328
  56. package/dist/convex-hull/ConvexHullTooltip.svelte +40 -16
  57. package/dist/convex-hull/GasPressureControls.svelte +104 -61
  58. package/dist/convex-hull/StructurePopup.svelte +25 -4
  59. package/dist/convex-hull/TemperatureSlider.svelte +45 -25
  60. package/dist/convex-hull/barycentric-coords.js +13 -7
  61. package/dist/convex-hull/demo-temperature.js +8 -4
  62. package/dist/convex-hull/gas-thermodynamics.js +17 -12
  63. package/dist/convex-hull/helpers.d.ts +9 -0
  64. package/dist/convex-hull/helpers.js +77 -34
  65. package/dist/convex-hull/thermodynamics.js +61 -56
  66. package/dist/convex-hull/types.d.ts +9 -14
  67. package/dist/convex-hull/types.js +0 -17
  68. package/dist/coordination/CoordinationBarPlot.svelte +227 -154
  69. package/dist/element/BohrAtom.svelte +55 -12
  70. package/dist/element/ElementHeading.svelte +7 -2
  71. package/dist/element/ElementPhoto.svelte +15 -9
  72. package/dist/element/ElementStats.svelte +10 -4
  73. package/dist/element/ElementTile.svelte +137 -73
  74. package/dist/element/Nucleus.svelte +39 -11
  75. package/dist/element/data.js +1 -1
  76. package/dist/feedback/ClickFeedback.svelte +16 -5
  77. package/dist/feedback/DragOverlay.svelte +10 -2
  78. package/dist/feedback/Spinner.svelte +4 -2
  79. package/dist/feedback/StatusMessage.svelte +8 -2
  80. package/dist/fermi-surface/FermiSlice.svelte +118 -88
  81. package/dist/fermi-surface/FermiSurface.svelte +328 -187
  82. package/dist/fermi-surface/FermiSurface.svelte.d.ts +1 -1
  83. package/dist/fermi-surface/FermiSurfaceControls.svelte +113 -46
  84. package/dist/fermi-surface/FermiSurfaceControls.svelte.d.ts +1 -1
  85. package/dist/fermi-surface/FermiSurfaceScene.svelte +535 -342
  86. package/dist/fermi-surface/FermiSurfaceScene.svelte.d.ts +1 -1
  87. package/dist/fermi-surface/FermiSurfaceTooltip.svelte +14 -5
  88. package/dist/fermi-surface/compute.js +16 -20
  89. package/dist/fermi-surface/parse.js +24 -14
  90. package/dist/fermi-surface/symmetry.js +2 -7
  91. package/dist/fermi-surface/types.d.ts +3 -5
  92. package/dist/heatmap-matrix/HeatmapMatrix.svelte +1019 -765
  93. package/dist/heatmap-matrix/HeatmapMatrix.svelte.d.ts +1 -1
  94. package/dist/heatmap-matrix/HeatmapMatrixControls.svelte +76 -22
  95. package/dist/heatmap-matrix/HeatmapMatrixControls.svelte.d.ts +2 -3
  96. package/dist/icons.js +47 -0
  97. package/dist/index.d.ts +2 -1
  98. package/dist/index.js +2 -1
  99. package/dist/io/decompress.js +1 -1
  100. package/dist/io/export.d.ts +3 -0
  101. package/dist/io/export.js +129 -143
  102. package/dist/io/is-binary.js +2 -3
  103. package/dist/io/url-drop.js +1 -2
  104. package/dist/isosurface/Isosurface.svelte +202 -148
  105. package/dist/isosurface/IsosurfaceControls.svelte +46 -28
  106. package/dist/isosurface/parse.js +34 -29
  107. package/dist/isosurface/slice.js +5 -10
  108. package/dist/isosurface/types.d.ts +2 -1
  109. package/dist/isosurface/types.js +61 -12
  110. package/dist/labels.js +11 -8
  111. package/dist/layout/FullscreenToggle.svelte +11 -2
  112. package/dist/layout/InfoCard.svelte +38 -6
  113. package/dist/layout/InfoTag.svelte +63 -32
  114. package/dist/layout/PropertyFilter.svelte +82 -37
  115. package/dist/layout/SettingsSection.svelte +85 -55
  116. package/dist/layout/SubpageGrid.svelte +10 -2
  117. package/dist/layout/json-tree/JsonNode.svelte +183 -138
  118. package/dist/layout/json-tree/JsonTree.svelte +499 -413
  119. package/dist/layout/json-tree/JsonValue.svelte +127 -99
  120. package/dist/layout/json-tree/utils.js +4 -2
  121. package/dist/marching-cubes.js +25 -2
  122. package/dist/math.d.ts +13 -17
  123. package/dist/math.js +133 -67
  124. package/dist/overlays/ContextMenu.svelte +65 -40
  125. package/dist/overlays/DraggablePane.svelte +211 -139
  126. package/dist/periodic-table/PeriodicTable.svelte +278 -145
  127. package/dist/periodic-table/PeriodicTableControls.svelte +178 -128
  128. package/dist/periodic-table/PropertySelect.svelte +25 -7
  129. package/dist/periodic-table/TableInset.svelte +8 -3
  130. package/dist/phase-diagram/IsobaricBinaryPhaseDiagram.svelte +446 -309
  131. package/dist/phase-diagram/IsobaricBinaryPhaseDiagram.svelte.d.ts +1 -1
  132. package/dist/phase-diagram/PhaseDiagramControls.svelte +102 -43
  133. package/dist/phase-diagram/PhaseDiagramControls.svelte.d.ts +1 -1
  134. package/dist/phase-diagram/PhaseDiagramEditorPane.svelte +63 -40
  135. package/dist/phase-diagram/PhaseDiagramExportPane.svelte +71 -28
  136. package/dist/phase-diagram/PhaseDiagramExportPane.svelte.d.ts +1 -1
  137. package/dist/phase-diagram/PhaseDiagramTooltip.svelte +158 -101
  138. package/dist/phase-diagram/TdbInfoPanel.svelte +28 -4
  139. package/dist/phase-diagram/build-diagram.js +9 -9
  140. package/dist/phase-diagram/colors.js +1 -3
  141. package/dist/phase-diagram/parse.js +10 -9
  142. package/dist/phase-diagram/svg-to-diagram.js +53 -49
  143. package/dist/phase-diagram/utils.d.ts +1 -0
  144. package/dist/phase-diagram/utils.js +80 -25
  145. package/dist/plot/AxisLabel.svelte +28 -3
  146. package/dist/plot/BarPlot.svelte +1182 -734
  147. package/dist/plot/BarPlot.svelte.d.ts +2 -2
  148. package/dist/plot/BarPlotControls.svelte +31 -5
  149. package/dist/plot/BarPlotControls.svelte.d.ts +1 -1
  150. package/dist/plot/ColorBar.svelte +479 -329
  151. package/dist/plot/ColorScaleSelect.svelte +27 -6
  152. package/dist/plot/ElementScatter.svelte +36 -15
  153. package/dist/plot/FillArea.svelte +152 -95
  154. package/dist/plot/Histogram.svelte +934 -571
  155. package/dist/plot/Histogram.svelte.d.ts +1 -1
  156. package/dist/plot/HistogramControls.svelte +53 -9
  157. package/dist/plot/HistogramControls.svelte.d.ts +1 -1
  158. package/dist/plot/InteractiveAxisLabel.svelte +34 -11
  159. package/dist/plot/InteractiveAxisLabel.svelte.d.ts +1 -1
  160. package/dist/plot/Line.svelte +63 -28
  161. package/dist/plot/PlotControls.svelte +157 -114
  162. package/dist/plot/PlotControls.svelte.d.ts +1 -1
  163. package/dist/plot/PlotLegend.svelte +174 -91
  164. package/dist/plot/PlotTooltip.svelte +45 -6
  165. package/dist/plot/PortalSelect.svelte +175 -147
  166. package/dist/plot/ReferenceLine.svelte +76 -22
  167. package/dist/plot/ReferenceLine3D.svelte +132 -107
  168. package/dist/plot/ReferencePlane.svelte +146 -121
  169. package/dist/plot/ScatterPlot.svelte +1681 -1091
  170. package/dist/plot/ScatterPlot.svelte.d.ts +2 -2
  171. package/dist/plot/ScatterPlot3D.svelte +256 -131
  172. package/dist/plot/ScatterPlot3D.svelte.d.ts +2 -2
  173. package/dist/plot/ScatterPlot3DControls.svelte +113 -63
  174. package/dist/plot/ScatterPlot3DControls.svelte.d.ts +2 -1
  175. package/dist/plot/ScatterPlot3DScene.svelte +608 -403
  176. package/dist/plot/ScatterPlot3DScene.svelte.d.ts +2 -2
  177. package/dist/plot/ScatterPlotControls.svelte +65 -25
  178. package/dist/plot/ScatterPlotControls.svelte.d.ts +1 -1
  179. package/dist/plot/ScatterPoint.svelte +98 -26
  180. package/dist/plot/ScatterPoint.svelte.d.ts +1 -0
  181. package/dist/plot/SpacegroupBarPlot.svelte +142 -85
  182. package/dist/plot/Surface3D.svelte +159 -108
  183. package/dist/plot/ZeroLines.svelte +55 -3
  184. package/dist/plot/ZoomRect.svelte +4 -2
  185. package/dist/plot/axis-utils.js +1 -3
  186. package/dist/plot/data-cleaning.js +12 -28
  187. package/dist/plot/data-transform.js +2 -1
  188. package/dist/plot/fill-utils.js +2 -0
  189. package/dist/plot/layout.d.ts +4 -1
  190. package/dist/plot/layout.js +33 -14
  191. package/dist/plot/reference-line.d.ts +2 -2
  192. package/dist/plot/reference-line.js +7 -5
  193. package/dist/plot/scales.js +24 -36
  194. package/dist/plot/types.d.ts +11 -23
  195. package/dist/plot/types.js +6 -11
  196. package/dist/plot/utils/label-placement.d.ts +32 -15
  197. package/dist/plot/utils/label-placement.js +227 -66
  198. package/dist/plot/utils/series-visibility.js +2 -3
  199. package/dist/rdf/RdfPlot.svelte +143 -91
  200. package/dist/rdf/calc-rdf.js +4 -5
  201. package/dist/sanitize.d.ts +4 -0
  202. package/dist/sanitize.js +107 -0
  203. package/dist/settings.d.ts +18 -6
  204. package/dist/settings.js +46 -16
  205. package/dist/spectral/Bands.svelte +632 -453
  206. package/dist/spectral/BandsAndDos.svelte +90 -49
  207. package/dist/spectral/BrillouinBandsDos.svelte +151 -93
  208. package/dist/spectral/Dos.svelte +389 -258
  209. package/dist/spectral/helpers.js +55 -43
  210. package/dist/state.svelte.d.ts +1 -1
  211. package/dist/state.svelte.js +3 -2
  212. package/dist/structure/Arrow.svelte +59 -20
  213. package/dist/structure/AtomLegend.svelte +215 -134
  214. package/dist/structure/Bond.svelte +73 -47
  215. package/dist/structure/CanvasTooltip.svelte +10 -2
  216. package/dist/structure/CellSelect.svelte +72 -45
  217. package/dist/structure/Cylinder.svelte +33 -17
  218. package/dist/structure/Lattice.svelte +88 -33
  219. package/dist/structure/Structure.svelte +1063 -797
  220. package/dist/structure/Structure.svelte.d.ts +1 -1
  221. package/dist/structure/StructureControls.svelte +349 -118
  222. package/dist/structure/StructureExportPane.svelte +124 -89
  223. package/dist/structure/StructureExportPane.svelte.d.ts +1 -1
  224. package/dist/structure/StructureInfoPane.svelte +304 -237
  225. package/dist/structure/StructureScene.svelte +879 -443
  226. package/dist/structure/StructureScene.svelte.d.ts +15 -7
  227. package/dist/structure/atom-properties.js +8 -8
  228. package/dist/structure/bonding.js +6 -7
  229. package/dist/structure/export.js +14 -29
  230. package/dist/structure/ferrox-wasm.js +1 -1
  231. package/dist/structure/index.d.ts +13 -3
  232. package/dist/structure/index.js +83 -23
  233. package/dist/structure/measure.d.ts +2 -2
  234. package/dist/structure/measure.js +4 -44
  235. package/dist/structure/parse.js +113 -141
  236. package/dist/structure/partial-occupancy.js +7 -10
  237. package/dist/structure/pbc.d.ts +1 -0
  238. package/dist/structure/pbc.js +16 -6
  239. package/dist/structure/supercell.d.ts +2 -2
  240. package/dist/structure/supercell.js +12 -22
  241. package/dist/structure/validation.js +1 -2
  242. package/dist/symmetry/SymmetryStats.svelte +84 -41
  243. package/dist/symmetry/WyckoffTable.svelte +26 -6
  244. package/dist/symmetry/cell-transform.js +5 -3
  245. package/dist/symmetry/index.js +8 -7
  246. package/dist/symmetry/spacegroups.js +148 -148
  247. package/dist/table/HeatmapTable.svelte +790 -554
  248. package/dist/table/HeatmapTable.svelte.d.ts +1 -1
  249. package/dist/table/ToggleMenu.svelte +125 -92
  250. package/dist/table/index.js +2 -4
  251. package/dist/theme/ThemeControl.svelte +21 -12
  252. package/dist/time.js +4 -1
  253. package/dist/tooltip/TooltipContent.svelte +33 -8
  254. package/dist/trajectory/Trajectory.svelte +758 -558
  255. package/dist/trajectory/TrajectoryError.svelte +14 -3
  256. package/dist/trajectory/TrajectoryExportPane.svelte +137 -83
  257. package/dist/trajectory/TrajectoryInfoPane.svelte +272 -143
  258. package/dist/trajectory/extract.js +10 -26
  259. package/dist/trajectory/format-detect.js +5 -5
  260. package/dist/trajectory/frame-reader.d.ts +1 -1
  261. package/dist/trajectory/frame-reader.js +5 -12
  262. package/dist/trajectory/helpers.d.ts +0 -1
  263. package/dist/trajectory/helpers.js +2 -17
  264. package/dist/trajectory/index.js +14 -12
  265. package/dist/trajectory/parse/ase.js +5 -4
  266. package/dist/trajectory/parse/hdf5.js +26 -18
  267. package/dist/trajectory/parse/index.js +13 -18
  268. package/dist/trajectory/parse/lammps.js +17 -7
  269. package/dist/trajectory/parse/vasp.js +5 -2
  270. package/dist/trajectory/parse/xyz.js +8 -7
  271. package/dist/trajectory/plotting.js +13 -8
  272. package/dist/utils.d.ts +1 -0
  273. package/dist/utils.js +13 -0
  274. package/dist/xrd/XrdPlot.svelte +337 -247
  275. package/dist/xrd/broadening.js +14 -9
  276. package/dist/xrd/calc-xrd.js +12 -18
  277. package/dist/xrd/parse.d.ts +1 -1
  278. package/dist/xrd/parse.js +17 -17
  279. package/package.json +99 -103
  280. package/readme.md +1 -1
  281. /package/dist/theme/{themes.js → themes.mjs} +0 -0
@@ -1,7 +1,28 @@
1
- <script lang="ts">import { ColorBar } from './';
2
- import * as d3_sc from 'd3-scale-chromatic';
3
- import Select from 'svelte-multiselect';
4
- let { options = Object.keys(d3_sc).filter((key) => key.startsWith(`interpolate`)), value = $bindable(options[0]), selected = $bindable([]), minSelect = 1, placeholder = `Select a color scale`, colorbar = {}, ...rest } = $props();
1
+ <script lang="ts">
2
+ import { ColorBar } from './'
3
+ import * as d3_sc from 'd3-scale-chromatic'
4
+ import type { ComponentProps } from 'svelte'
5
+ import Select from 'svelte-multiselect'
6
+ import type { D3InterpolateName } from '../colors'
7
+
8
+ let {
9
+ options = Object.keys(d3_sc).filter((key) =>
10
+ key.startsWith(`interpolate`)
11
+ ) as D3InterpolateName[],
12
+ value = $bindable(options[0]),
13
+ selected = $bindable([]),
14
+ minSelect = 1,
15
+ placeholder = `Select a color scale`,
16
+ colorbar = {},
17
+ ...rest
18
+ }: Omit<ComponentProps<typeof Select>, `options`> & {
19
+ options?: D3InterpolateName[]
20
+ value?: D3InterpolateName
21
+ selected?: D3InterpolateName[]
22
+ minSelect?: number
23
+ placeholder?: string
24
+ colorbar?: ComponentProps<typeof ColorBar>
25
+ } = $props()
5
26
  </script>
6
27
 
7
28
  <Select
@@ -14,7 +35,7 @@ let { options = Object.keys(d3_sc).filter((key) => key.startsWith(`interpolate`)
14
35
  liOptionStyle="padding: 3pt 6pt;"
15
36
  liSelectedStyle="width: 100%; background-color: transparent;"
16
37
  ulSelectedStyle="display: contents;"
17
- inputStyle="min-width: 0;"
38
+ inputStyle="min-width: 0; width: 0; padding: 0; border: none; caret-color: transparent;"
18
39
  {...rest}
19
40
  style={`min-width: 0; ${rest.style ?? ``}`}
20
41
  >
@@ -26,7 +47,7 @@ let { options = Object.keys(d3_sc).filter((key) => key.startsWith(`interpolate`)
26
47
  tick_labels={0}
27
48
  title_side="left"
28
49
  wrapper_style="width: 100%;"
29
- title_style="width: 6em; font-size: 1.5em; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; text-align: left;"
50
+ title_style="width: 6em; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; text-align: left;"
30
51
  {...colorbar}
31
52
  />
32
53
  {/snippet}
@@ -1,19 +1,40 @@
1
- <script lang="ts">import { element_data } from '../element';
2
- import { format_num } from '../labels';
3
- import { ScatterPlot } from './';
4
- import { selected } from '../state.svelte';
5
- let { y, x_axis = {}, y_axis = {}, y_unit = ``, tooltip_point = $bindable(null), hovered = $bindable(false), ...rest } = $props();
6
- // update tooltip on hover element tile
7
- $effect.pre(() => {
1
+ <script lang="ts">
2
+ import { element_data } from '../element'
3
+ import { format_num } from '../labels'
4
+ import { sanitize_html } from '../sanitize'
5
+ import type { AxisConfig, InternalPoint } from './'
6
+ import { ScatterPlot } from './'
7
+ import { selected } from '../state.svelte'
8
+ import type { ComponentProps } from 'svelte'
9
+
10
+ let {
11
+ y,
12
+ x_axis = {},
13
+ y_axis = {},
14
+ y_unit = ``,
15
+ tooltip_point = $bindable(null),
16
+ hovered = $bindable(false),
17
+ ...rest
18
+ }: ComponentProps<typeof ScatterPlot> & {
19
+ y: number[] // array of length 118 (one value for each element)
20
+ x_axis?: AxisConfig
21
+ y_axis?: AxisConfig
22
+ y_unit?: string | null
23
+ tooltip_point?: InternalPoint | null
24
+ hovered?: boolean
25
+ } = $props()
26
+
27
+ // update tooltip on hover element tile
28
+ $effect.pre(() => {
8
29
  if (selected.element?.number && !hovered) {
9
- tooltip_point = {
10
- x: selected.element.number,
11
- y: y[selected.element.number - 1],
12
- series_idx: 0,
13
- point_idx: selected.element.number - 1,
14
- };
30
+ tooltip_point = {
31
+ x: selected.element.number,
32
+ y: y[selected.element.number - 1],
33
+ series_idx: 0,
34
+ point_idx: selected.element.number - 1,
35
+ }
15
36
  }
16
- });
37
+ })
17
38
  </script>
18
39
 
19
40
  <ScatterPlot
@@ -37,6 +58,6 @@ $effect.pre(() => {
37
58
  {#snippet tooltip({ x, y })}
38
59
  {@const elem = element_data[x - 1]}
39
60
  <strong>{elem ? `${x} ${elem.symbol} - ${elem.name}` : `Element ${x}`}</strong><br />
40
- {@html y_axis.label || `Value`}: {format_num(y, y_axis.format ?? `~s`)}{y_unit ?? ``}
61
+ {@html sanitize_html(y_axis.label || `Value`)}: {format_num(y, y_axis.format ?? `~s`)}{y_unit ?? ``}
41
62
  {/snippet}
42
63
  </ScatterPlot>
@@ -1,95 +1,123 @@
1
- <script lang="ts">// FillArea component for rendering fill-between regions in ScatterPlot
2
- // Supports gradients, hover/click interactions, and animated path transitions
3
- import { interpolatePath } from 'd3-interpolate-path';
4
- import { untrack } from 'svelte';
5
- import { Tween } from 'svelte/motion';
6
- let { region, region_idx, path, clip_path_id, x_scale_fn, y_scale_fn, hovered_region = null, on_click, on_hover, tween_options, } = $props();
7
- // Stable instance ID for gradient uniqueness (generated once per component instance)
8
- const instance_id = crypto.randomUUID().slice(0, 8);
9
- let gradient_id = $derived(`fill-gradient-${region.id ?? region_idx}-${instance_id}`);
10
- // Effective styling based on hover state
11
- let is_hovered = $derived(hovered_region === region_idx);
12
- let effective_opacity = $derived(is_hovered && region.hover_style?.fill_opacity != null
13
- ? region.hover_style.fill_opacity
14
- : region.fill_opacity ?? 0.3);
15
- let effective_fill = $derived(is_hovered && region.hover_style?.fill
16
- ? region.hover_style.fill
17
- : region.fill ?? `steelblue`);
18
- let path_fill = $derived(typeof effective_fill === `object` ? `url(#${gradient_id})` : effective_fill);
19
- let is_clickable = $derived(Boolean(on_click || region.on_click));
20
- let cursor_style = $derived(region.hover_style?.cursor ?? (is_clickable ? `pointer` : `default`));
21
- // Path animation using Tween - create once, update target via effect
22
- // untrack() explicitly captures initial values (intentional - config set once at mount)
23
- const tweened_path = new Tween(untrack(() => path), untrack(() => ({
24
- duration: 300,
25
- interpolate: interpolatePath,
26
- ...tween_options,
27
- })));
28
- $effect.pre(() => {
29
- tweened_path.target = path;
30
- });
31
- // Emit helpers - call both region-level and prop-level handlers when distinct
32
- const emit_hover = (evt) => {
33
- region.on_hover?.(evt);
34
- if (on_hover !== region.on_hover)
35
- on_hover?.(evt);
36
- };
37
- const emit_click = (evt) => {
38
- region.on_click?.(evt);
39
- if (on_click !== region.on_click)
40
- on_click?.(evt);
41
- };
42
- // Event handlers
43
- const handle_mouse_enter = (event) => emit_hover(construct_event(event));
44
- const handle_mouse_leave = () => emit_hover(null);
45
- const handle_mouse_move = (event) => is_hovered && emit_hover(construct_event(event));
46
- const handle_click = (event) => emit_click(construct_event(event));
47
- // Keyboard handler - creates event with default coordinates since no mouse position
48
- function handle_keydown(event) {
1
+ <script lang="ts">
2
+ // FillArea component for rendering fill-between regions in ScatterPlot
3
+ // Supports gradients, hover/click interactions, and animated path transitions
4
+ import { interpolatePath } from 'd3-interpolate-path'
5
+ import { untrack } from 'svelte'
6
+ import { Tween } from 'svelte/motion'
7
+ import type {
8
+ FillGradient,
9
+ FillHandlerEvent,
10
+ FillRegion,
11
+ TweenedOptions,
12
+ } from './types'
13
+
14
+ let {
15
+ region,
16
+ region_idx,
17
+ path,
18
+ clip_path_id,
19
+ x_scale_fn,
20
+ y_scale_fn,
21
+ hovered_region = null,
22
+ on_click,
23
+ on_hover,
24
+ tween_options,
25
+ }: {
26
+ region: FillRegion
27
+ region_idx: number
28
+ path: string
29
+ clip_path_id: string
30
+ x_scale_fn: ((x: number) => number) & { invert?: (y: number) => number | Date }
31
+ y_scale_fn: ((y: number) => number) & { invert?: (y: number) => number }
32
+ hovered_region?: number | null
33
+ on_click?: (event: FillHandlerEvent) => void
34
+ on_hover?: (event: FillHandlerEvent | null) => void
35
+ tween_options?: TweenedOptions<string>
36
+ } = $props()
37
+
38
+ // Stable instance ID for gradient uniqueness (generated once per component instance)
39
+ const instance_id = crypto.randomUUID().slice(0, 8)
40
+ let gradient_id = $derived(
41
+ `fill-gradient-${region.id ?? region_idx}-${instance_id}`,
42
+ )
43
+
44
+ // Effective styling based on hover state
45
+ let is_hovered = $derived(hovered_region === region_idx)
46
+ let effective_opacity = $derived(
47
+ is_hovered && region.hover_style?.fill_opacity != null
48
+ ? region.hover_style.fill_opacity
49
+ : region.fill_opacity ?? 0.3,
50
+ )
51
+ let effective_fill = $derived(
52
+ is_hovered && region.hover_style?.fill
53
+ ? region.hover_style.fill
54
+ : region.fill ?? `steelblue`,
55
+ )
56
+ let path_fill = $derived(
57
+ typeof effective_fill === `object` ? `url(#${gradient_id})` : effective_fill,
58
+ )
59
+ let is_clickable = $derived(Boolean(on_click || region.on_click))
60
+ let cursor_style = $derived(
61
+ region.hover_style?.cursor ?? (is_clickable ? `pointer` : `default`),
62
+ )
63
+
64
+ // Path animation using Tween - create once, update target via effect
65
+ // untrack() explicitly captures initial values (intentional - config set once at mount)
66
+ const tweened_path = new Tween(
67
+ untrack(() => path),
68
+ untrack(() => ({
69
+ duration: 300,
70
+ interpolate: interpolatePath,
71
+ ...tween_options,
72
+ })),
73
+ )
74
+
75
+ $effect.pre(() => {
76
+ tweened_path.target = path
77
+ })
78
+
79
+ // Emit helpers - call both region-level and prop-level handlers when distinct
80
+ const emit_hover = (evt: FillHandlerEvent | null) => {
81
+ region.on_hover?.(evt)
82
+ if (on_hover !== region.on_hover) on_hover?.(evt)
83
+ }
84
+ const emit_click = (evt: FillHandlerEvent) => {
85
+ region.on_click?.(evt)
86
+ if (on_click !== region.on_click) on_click?.(evt)
87
+ }
88
+
89
+ // Event handlers
90
+ const handle_mouse_enter = (event: MouseEvent) => emit_hover(construct_event(event))
91
+ const handle_mouse_leave = () => emit_hover(null)
92
+ const handle_mouse_move = (event: MouseEvent) =>
93
+ is_hovered && emit_hover(construct_event(event))
94
+ const handle_click = (event: MouseEvent) => emit_click(construct_event(event))
95
+
96
+ // Keyboard handler - creates event with default coordinates since no mouse position
97
+ function handle_keydown(event: KeyboardEvent) {
49
98
  if (event.key === `Enter` || event.key === ` `) {
50
- event.preventDefault();
51
- if (!is_clickable)
52
- return;
53
- // For keyboard activation, use center of element or default coordinates
54
- const target = event.currentTarget;
55
- if (!(target instanceof SVGElement))
56
- return;
57
- const rect = target.ownerSVGElement?.getBoundingClientRect();
58
- const element_rect = target.getBoundingClientRect();
59
- // Use center of the fill region element
60
- const px = element_rect
61
- ? (element_rect.left + element_rect.right) / 2 - (rect?.left ?? 0)
62
- : 0;
63
- const py = element_rect
64
- ? (element_rect.top + element_rect.bottom) / 2 - (rect?.top ?? 0)
65
- : 0;
66
- const raw_x = x_scale_fn.invert?.(px) ?? 0;
67
- const data_x = raw_x instanceof Date ? raw_x.getTime() : raw_x;
68
- const data_y = y_scale_fn.invert?.(py) ?? 0;
69
- emit_click({
70
- event,
71
- region_idx,
72
- region_id: region.id,
73
- x: data_x,
74
- y: data_y,
75
- px,
76
- py,
77
- label: region.label,
78
- metadata: region.metadata,
79
- });
80
- }
81
- }
82
- // Construct FillHandlerEvent from MouseEvent
83
- function construct_event(event) {
84
- const current = event.currentTarget;
85
- const rect = (current instanceof SVGElement ? current.ownerSVGElement : null)
86
- ?.getBoundingClientRect();
87
- const px = event.clientX - (rect?.left ?? 0);
88
- const py = event.clientY - (rect?.top ?? 0);
89
- const raw_x = x_scale_fn.invert?.(px) ?? 0;
90
- const data_x = raw_x instanceof Date ? raw_x.getTime() : raw_x;
91
- const data_y = y_scale_fn.invert?.(py) ?? 0;
92
- return {
99
+ event.preventDefault()
100
+ if (!is_clickable) return
101
+
102
+ // For keyboard activation, use center of element or default coordinates
103
+ const target = event.currentTarget
104
+ if (!(target instanceof SVGElement)) return
105
+ const rect = target.ownerSVGElement?.getBoundingClientRect()
106
+ const element_rect = target.getBoundingClientRect()
107
+
108
+ // Use center of the fill region element
109
+ const px = element_rect
110
+ ? (element_rect.left + element_rect.right) / 2 - (rect?.left ?? 0)
111
+ : 0
112
+ const py = element_rect
113
+ ? (element_rect.top + element_rect.bottom) / 2 - (rect?.top ?? 0)
114
+ : 0
115
+
116
+ const raw_x = x_scale_fn.invert?.(px) ?? 0
117
+ const data_x = raw_x instanceof Date ? raw_x.getTime() : raw_x
118
+ const data_y = y_scale_fn.invert?.(py) ?? 0
119
+
120
+ emit_click({
93
121
  event,
94
122
  region_idx,
95
123
  region_id: region.id,
@@ -99,10 +127,39 @@ function construct_event(event) {
99
127
  py,
100
128
  label: region.label,
101
129
  metadata: region.metadata,
102
- };
103
- }
104
- // Type guard for gradient fill
105
- const is_gradient = (fill) => typeof fill === `object` && fill !== null && `type` in fill;
130
+ })
131
+ }
132
+ }
133
+
134
+ // Construct FillHandlerEvent from MouseEvent
135
+ function construct_event(event: MouseEvent): FillHandlerEvent {
136
+ const current = event.currentTarget
137
+ const rect = (current instanceof SVGElement ? current.ownerSVGElement : null)
138
+ ?.getBoundingClientRect()
139
+ const px = event.clientX - (rect?.left ?? 0)
140
+ const py = event.clientY - (rect?.top ?? 0)
141
+ const raw_x = x_scale_fn.invert?.(px) ?? 0
142
+ const data_x = raw_x instanceof Date ? raw_x.getTime() : raw_x
143
+ const data_y = y_scale_fn.invert?.(py) ?? 0
144
+
145
+ return {
146
+ event,
147
+ region_idx,
148
+ region_id: region.id,
149
+ x: data_x,
150
+ y: data_y,
151
+ px,
152
+ py,
153
+ label: region.label,
154
+ metadata: region.metadata,
155
+ }
156
+ }
157
+
158
+ // Type guard for gradient fill
159
+ const is_gradient = (
160
+ fill: string | FillGradient | undefined,
161
+ ): fill is FillGradient =>
162
+ typeof fill === `object` && fill !== null && `type` in fill
106
163
  </script>
107
164
 
108
165
  <!-- svelte-ignore a11y_no_noninteractive_element_interactions -->