matterviz 0.3.2 → 0.3.3

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 (280) 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/feedback/ClickFeedback.svelte +16 -5
  76. package/dist/feedback/DragOverlay.svelte +10 -2
  77. package/dist/feedback/Spinner.svelte +4 -2
  78. package/dist/feedback/StatusMessage.svelte +8 -2
  79. package/dist/fermi-surface/FermiSlice.svelte +118 -88
  80. package/dist/fermi-surface/FermiSurface.svelte +328 -187
  81. package/dist/fermi-surface/FermiSurface.svelte.d.ts +1 -1
  82. package/dist/fermi-surface/FermiSurfaceControls.svelte +113 -46
  83. package/dist/fermi-surface/FermiSurfaceControls.svelte.d.ts +1 -1
  84. package/dist/fermi-surface/FermiSurfaceScene.svelte +535 -342
  85. package/dist/fermi-surface/FermiSurfaceScene.svelte.d.ts +1 -1
  86. package/dist/fermi-surface/FermiSurfaceTooltip.svelte +14 -5
  87. package/dist/fermi-surface/compute.js +16 -20
  88. package/dist/fermi-surface/parse.js +24 -14
  89. package/dist/fermi-surface/symmetry.js +2 -7
  90. package/dist/fermi-surface/types.d.ts +3 -5
  91. package/dist/heatmap-matrix/HeatmapMatrix.svelte +1019 -765
  92. package/dist/heatmap-matrix/HeatmapMatrix.svelte.d.ts +1 -1
  93. package/dist/heatmap-matrix/HeatmapMatrixControls.svelte +76 -22
  94. package/dist/heatmap-matrix/HeatmapMatrixControls.svelte.d.ts +2 -3
  95. package/dist/icons.js +47 -0
  96. package/dist/index.d.ts +2 -1
  97. package/dist/index.js +2 -1
  98. package/dist/io/decompress.js +1 -1
  99. package/dist/io/export.d.ts +3 -0
  100. package/dist/io/export.js +129 -143
  101. package/dist/io/is-binary.js +2 -3
  102. package/dist/io/url-drop.js +1 -2
  103. package/dist/isosurface/Isosurface.svelte +202 -148
  104. package/dist/isosurface/IsosurfaceControls.svelte +46 -28
  105. package/dist/isosurface/parse.js +34 -29
  106. package/dist/isosurface/slice.js +5 -10
  107. package/dist/isosurface/types.d.ts +2 -1
  108. package/dist/isosurface/types.js +61 -12
  109. package/dist/labels.js +11 -8
  110. package/dist/layout/FullscreenToggle.svelte +11 -2
  111. package/dist/layout/InfoCard.svelte +38 -6
  112. package/dist/layout/InfoTag.svelte +63 -32
  113. package/dist/layout/PropertyFilter.svelte +82 -37
  114. package/dist/layout/SettingsSection.svelte +85 -55
  115. package/dist/layout/SubpageGrid.svelte +10 -2
  116. package/dist/layout/json-tree/JsonNode.svelte +183 -138
  117. package/dist/layout/json-tree/JsonTree.svelte +499 -413
  118. package/dist/layout/json-tree/JsonValue.svelte +127 -99
  119. package/dist/layout/json-tree/utils.js +4 -2
  120. package/dist/marching-cubes.js +25 -2
  121. package/dist/math.d.ts +13 -17
  122. package/dist/math.js +133 -67
  123. package/dist/overlays/ContextMenu.svelte +65 -40
  124. package/dist/overlays/DraggablePane.svelte +211 -139
  125. package/dist/periodic-table/PeriodicTable.svelte +278 -145
  126. package/dist/periodic-table/PeriodicTableControls.svelte +178 -128
  127. package/dist/periodic-table/PropertySelect.svelte +25 -7
  128. package/dist/periodic-table/TableInset.svelte +8 -3
  129. package/dist/phase-diagram/IsobaricBinaryPhaseDiagram.svelte +446 -309
  130. package/dist/phase-diagram/IsobaricBinaryPhaseDiagram.svelte.d.ts +1 -1
  131. package/dist/phase-diagram/PhaseDiagramControls.svelte +102 -43
  132. package/dist/phase-diagram/PhaseDiagramControls.svelte.d.ts +1 -1
  133. package/dist/phase-diagram/PhaseDiagramEditorPane.svelte +63 -40
  134. package/dist/phase-diagram/PhaseDiagramExportPane.svelte +71 -28
  135. package/dist/phase-diagram/PhaseDiagramExportPane.svelte.d.ts +1 -1
  136. package/dist/phase-diagram/PhaseDiagramTooltip.svelte +158 -101
  137. package/dist/phase-diagram/TdbInfoPanel.svelte +28 -4
  138. package/dist/phase-diagram/build-diagram.js +9 -9
  139. package/dist/phase-diagram/colors.js +1 -3
  140. package/dist/phase-diagram/parse.js +10 -9
  141. package/dist/phase-diagram/svg-to-diagram.js +53 -49
  142. package/dist/phase-diagram/utils.d.ts +1 -0
  143. package/dist/phase-diagram/utils.js +80 -25
  144. package/dist/plot/AxisLabel.svelte +28 -3
  145. package/dist/plot/BarPlot.svelte +1182 -734
  146. package/dist/plot/BarPlot.svelte.d.ts +2 -2
  147. package/dist/plot/BarPlotControls.svelte +31 -5
  148. package/dist/plot/BarPlotControls.svelte.d.ts +1 -1
  149. package/dist/plot/ColorBar.svelte +479 -329
  150. package/dist/plot/ColorScaleSelect.svelte +27 -6
  151. package/dist/plot/ElementScatter.svelte +36 -15
  152. package/dist/plot/FillArea.svelte +152 -95
  153. package/dist/plot/Histogram.svelte +934 -571
  154. package/dist/plot/Histogram.svelte.d.ts +1 -1
  155. package/dist/plot/HistogramControls.svelte +53 -9
  156. package/dist/plot/HistogramControls.svelte.d.ts +1 -1
  157. package/dist/plot/InteractiveAxisLabel.svelte +34 -11
  158. package/dist/plot/InteractiveAxisLabel.svelte.d.ts +1 -1
  159. package/dist/plot/Line.svelte +63 -28
  160. package/dist/plot/PlotControls.svelte +157 -114
  161. package/dist/plot/PlotControls.svelte.d.ts +1 -1
  162. package/dist/plot/PlotLegend.svelte +174 -91
  163. package/dist/plot/PlotTooltip.svelte +45 -6
  164. package/dist/plot/PortalSelect.svelte +175 -147
  165. package/dist/plot/ReferenceLine.svelte +76 -22
  166. package/dist/plot/ReferenceLine3D.svelte +132 -107
  167. package/dist/plot/ReferencePlane.svelte +146 -121
  168. package/dist/plot/ScatterPlot.svelte +1681 -1091
  169. package/dist/plot/ScatterPlot.svelte.d.ts +2 -2
  170. package/dist/plot/ScatterPlot3D.svelte +256 -131
  171. package/dist/plot/ScatterPlot3D.svelte.d.ts +2 -2
  172. package/dist/plot/ScatterPlot3DControls.svelte +113 -63
  173. package/dist/plot/ScatterPlot3DControls.svelte.d.ts +2 -1
  174. package/dist/plot/ScatterPlot3DScene.svelte +608 -403
  175. package/dist/plot/ScatterPlot3DScene.svelte.d.ts +2 -2
  176. package/dist/plot/ScatterPlotControls.svelte +65 -25
  177. package/dist/plot/ScatterPlotControls.svelte.d.ts +1 -1
  178. package/dist/plot/ScatterPoint.svelte +98 -26
  179. package/dist/plot/ScatterPoint.svelte.d.ts +1 -0
  180. package/dist/plot/SpacegroupBarPlot.svelte +142 -85
  181. package/dist/plot/Surface3D.svelte +159 -108
  182. package/dist/plot/ZeroLines.svelte +55 -3
  183. package/dist/plot/ZoomRect.svelte +4 -2
  184. package/dist/plot/axis-utils.js +1 -3
  185. package/dist/plot/data-cleaning.js +12 -28
  186. package/dist/plot/data-transform.js +2 -1
  187. package/dist/plot/fill-utils.js +2 -0
  188. package/dist/plot/layout.d.ts +4 -1
  189. package/dist/plot/layout.js +33 -14
  190. package/dist/plot/reference-line.d.ts +2 -2
  191. package/dist/plot/reference-line.js +7 -5
  192. package/dist/plot/scales.js +24 -36
  193. package/dist/plot/types.d.ts +11 -23
  194. package/dist/plot/types.js +6 -11
  195. package/dist/plot/utils/label-placement.d.ts +32 -15
  196. package/dist/plot/utils/label-placement.js +227 -66
  197. package/dist/plot/utils/series-visibility.js +2 -3
  198. package/dist/rdf/RdfPlot.svelte +143 -91
  199. package/dist/rdf/calc-rdf.js +4 -5
  200. package/dist/sanitize.d.ts +4 -0
  201. package/dist/sanitize.js +107 -0
  202. package/dist/settings.d.ts +18 -6
  203. package/dist/settings.js +46 -16
  204. package/dist/spectral/Bands.svelte +632 -453
  205. package/dist/spectral/BandsAndDos.svelte +90 -49
  206. package/dist/spectral/BrillouinBandsDos.svelte +151 -93
  207. package/dist/spectral/Dos.svelte +389 -258
  208. package/dist/spectral/helpers.js +55 -43
  209. package/dist/state.svelte.d.ts +1 -1
  210. package/dist/state.svelte.js +3 -2
  211. package/dist/structure/Arrow.svelte +59 -20
  212. package/dist/structure/AtomLegend.svelte +215 -134
  213. package/dist/structure/Bond.svelte +73 -47
  214. package/dist/structure/CanvasTooltip.svelte +10 -2
  215. package/dist/structure/CellSelect.svelte +72 -45
  216. package/dist/structure/Cylinder.svelte +33 -17
  217. package/dist/structure/Lattice.svelte +88 -33
  218. package/dist/structure/Structure.svelte +1063 -797
  219. package/dist/structure/Structure.svelte.d.ts +1 -1
  220. package/dist/structure/StructureControls.svelte +349 -118
  221. package/dist/structure/StructureExportPane.svelte +124 -89
  222. package/dist/structure/StructureExportPane.svelte.d.ts +1 -1
  223. package/dist/structure/StructureInfoPane.svelte +304 -237
  224. package/dist/structure/StructureScene.svelte +879 -443
  225. package/dist/structure/StructureScene.svelte.d.ts +15 -7
  226. package/dist/structure/atom-properties.js +8 -8
  227. package/dist/structure/bonding.js +6 -7
  228. package/dist/structure/export.js +14 -29
  229. package/dist/structure/ferrox-wasm.js +1 -1
  230. package/dist/structure/index.d.ts +13 -3
  231. package/dist/structure/index.js +83 -23
  232. package/dist/structure/measure.d.ts +2 -2
  233. package/dist/structure/measure.js +4 -44
  234. package/dist/structure/parse.js +113 -141
  235. package/dist/structure/partial-occupancy.js +7 -10
  236. package/dist/structure/pbc.d.ts +1 -0
  237. package/dist/structure/pbc.js +16 -6
  238. package/dist/structure/supercell.d.ts +2 -2
  239. package/dist/structure/supercell.js +12 -22
  240. package/dist/structure/validation.js +1 -2
  241. package/dist/symmetry/SymmetryStats.svelte +84 -41
  242. package/dist/symmetry/WyckoffTable.svelte +26 -6
  243. package/dist/symmetry/cell-transform.js +5 -3
  244. package/dist/symmetry/index.js +8 -7
  245. package/dist/symmetry/spacegroups.js +148 -148
  246. package/dist/table/HeatmapTable.svelte +790 -554
  247. package/dist/table/HeatmapTable.svelte.d.ts +1 -1
  248. package/dist/table/ToggleMenu.svelte +125 -92
  249. package/dist/table/index.js +2 -4
  250. package/dist/theme/ThemeControl.svelte +21 -12
  251. package/dist/time.js +4 -1
  252. package/dist/tooltip/TooltipContent.svelte +33 -8
  253. package/dist/trajectory/Trajectory.svelte +758 -558
  254. package/dist/trajectory/TrajectoryError.svelte +14 -3
  255. package/dist/trajectory/TrajectoryExportPane.svelte +137 -83
  256. package/dist/trajectory/TrajectoryInfoPane.svelte +272 -143
  257. package/dist/trajectory/extract.js +10 -26
  258. package/dist/trajectory/format-detect.js +5 -5
  259. package/dist/trajectory/frame-reader.d.ts +1 -1
  260. package/dist/trajectory/frame-reader.js +5 -12
  261. package/dist/trajectory/helpers.d.ts +0 -1
  262. package/dist/trajectory/helpers.js +2 -17
  263. package/dist/trajectory/index.js +14 -12
  264. package/dist/trajectory/parse/ase.js +5 -4
  265. package/dist/trajectory/parse/hdf5.js +26 -18
  266. package/dist/trajectory/parse/index.js +13 -18
  267. package/dist/trajectory/parse/lammps.js +17 -7
  268. package/dist/trajectory/parse/vasp.js +5 -2
  269. package/dist/trajectory/parse/xyz.js +8 -7
  270. package/dist/trajectory/plotting.js +13 -8
  271. package/dist/utils.d.ts +1 -0
  272. package/dist/utils.js +13 -0
  273. package/dist/xrd/XrdPlot.svelte +337 -247
  274. package/dist/xrd/broadening.js +14 -9
  275. package/dist/xrd/calc-xrd.js +12 -18
  276. package/dist/xrd/parse.d.ts +1 -1
  277. package/dist/xrd/parse.js +17 -17
  278. package/package.json +99 -103
  279. package/readme.md +1 -1
  280. /package/dist/theme/{themes.js → themes.mjs} +0 -0
@@ -1,128 +1,203 @@
1
- <script lang="ts">import { ELEMENT_COLOR_SCHEMES, pick_contrast_color } from '../colors';
2
- import { format_num } from '../labels';
3
- import { get_chart_font_scale } from './index';
4
- import { count_atoms_in_composition, fractional_composition } from './parse';
5
- // Constants for pie chart calculations
6
- const VERY_THIN_SLICE_THRESHOLD = 20; // degrees
7
- const MEDIUM_SLICE_THRESHOLD = 90; // degrees - increased to move more slices toward outer edge
8
- const MAX_ANGLE_FOR_FULL_SCALE = 120; // degrees
9
- let { composition, size = 200, stroke_width = 0.5, inner_radius = 0, show_labels = true, show_percentages = false, show_amounts = true, color_scheme = `Vesta`, center_content, segment_content, interactive = true, svg_node = $bindable(null), children, ...rest } = $props();
10
- let element_colors = $derived(ELEMENT_COLOR_SCHEMES[color_scheme] || ELEMENT_COLOR_SCHEMES.Vesta);
11
- let fractions = $derived(fractional_composition(composition));
12
- let total_atoms = $derived(count_atoms_in_composition(composition));
13
- let outer_radius = $derived(size / 2 - stroke_width);
14
- let inner_radius_adjusted = $derived(Math.min(inner_radius, outer_radius - 10));
15
- let center = $derived(size / 2);
16
- // Calculate pie segments
17
- let segments = $derived.by(() => {
18
- let current_angle = -90; // Start from top
1
+ <script lang="ts">
2
+ import type { ColorSchemeName } from '../colors'
3
+ import { ELEMENT_COLOR_SCHEMES, pick_contrast_color } from '../colors'
4
+ import type { CompositionType } from './'
5
+ import type { ElementSymbol } from '../element'
6
+ import { format_num } from '../labels'
7
+ import type { Snippet } from 'svelte'
8
+ import type { SVGAttributes } from 'svelte/elements'
9
+ import { type ChartSegmentData, get_chart_font_scale } from './index'
10
+ import { count_atoms_in_composition, fractional_composition } from './parse'
11
+
12
+ // Constants for pie chart calculations
13
+ const VERY_THIN_SLICE_THRESHOLD = 20 // degrees
14
+ const MEDIUM_SLICE_THRESHOLD = 90 // degrees - increased to move more slices toward outer edge
15
+ const MAX_ANGLE_FOR_FULL_SCALE = 120 // degrees
16
+
17
+ type PieSegmentData = ChartSegmentData & {
18
+ start_angle: number
19
+ end_angle: number
20
+ path: string
21
+ label_x: number
22
+ label_y: number
23
+ is_outside_slice: boolean
24
+ }
25
+ let {
26
+ composition,
27
+ size = 200,
28
+ stroke_width = 0.5,
29
+ inner_radius = 0,
30
+ show_labels = true,
31
+ show_percentages = false,
32
+ show_amounts = true,
33
+ color_scheme = `Vesta`,
34
+ center_content,
35
+ segment_content,
36
+ interactive = true,
37
+ svg_node = $bindable(null),
38
+ children,
39
+ ...rest
40
+ }: SVGAttributes<SVGSVGElement> & {
41
+ composition: CompositionType
42
+ size?: number
43
+ stroke_width?: number
44
+ inner_radius?: number
45
+ show_labels?: boolean
46
+ show_percentages?: boolean
47
+ show_amounts?: boolean
48
+ color_scheme?: ColorSchemeName
49
+ center_content?: Snippet<[{ composition: CompositionType; total_atoms: number }]>
50
+ segment_content?: Snippet<[PieSegmentData]>
51
+ interactive?: boolean
52
+ svg_node?: SVGSVGElement | null
53
+ children?: Snippet<[{ hovered_element: ElementSymbol | null }]>
54
+ } = $props()
55
+
56
+ let element_colors = $derived(
57
+ ELEMENT_COLOR_SCHEMES[color_scheme] || ELEMENT_COLOR_SCHEMES.Vesta,
58
+ )
59
+ let fractions = $derived(fractional_composition(composition))
60
+ let total_atoms = $derived(count_atoms_in_composition(composition))
61
+ let outer_radius = $derived(size / 2 - stroke_width)
62
+ let inner_radius_adjusted = $derived(Math.min(inner_radius, outer_radius - 10))
63
+ let center = $derived(size / 2)
64
+
65
+ // Calculate pie segments
66
+ let segments = $derived.by(() => {
67
+ let current_angle = -90 // Start from top
68
+
19
69
  return Object.entries(composition)
20
- .filter(([_, amount]) => amount && amount > 0)
21
- .map(([element_key, amount]) => {
22
- const element = element_key;
23
- const fraction = fractions[element] || 0;
24
- const color = element_colors[element] || `#cccccc`;
70
+ .filter(([_, amount]) => amount && amount > 0)
71
+ .map(([element_key, amount]) => {
72
+ const element = element_key as ElementSymbol
73
+ const fraction = fractions[element] || 0
74
+ const color = element_colors[element] || `#cccccc`
75
+
25
76
  // Single element: full circle with no radial stroke line, label at center
26
77
  if (fraction === 1) {
27
- const r = outer_radius;
28
- const ir = inner_radius_adjusted;
29
- // Two semicircular arcs to form a full circle (avoids SVG 360° arc bug)
30
- const outer_arc = `M ${center} ${center - r} A ${r} ${r} 0 1 1 ${center} ${center + r} A ${r} ${r} 0 1 1 ${center} ${center - r} Z`;
31
- const path = ir > 0
32
- ? `${outer_arc} M ${center} ${center - ir} A ${ir} ${ir} 0 1 0 ${center} ${center + ir} A ${ir} ${ir} 0 1 0 ${center} ${center - ir} Z`
33
- : outer_arc;
34
- const label_text = element + (show_amounts ? String(amount) : ``) +
35
- (show_percentages ? `${format_num(fraction, `.1~%`)}` : ``);
36
- return {
37
- element,
38
- amount,
39
- fraction,
40
- color,
41
- start_angle: -90,
42
- end_angle: 270,
43
- path,
44
- label_x: center,
45
- label_y: center,
46
- is_outside_slice: false,
47
- font_scale: get_chart_font_scale(2.6, label_text, r * 2),
48
- text_color: pick_contrast_color({ bg_color: color }),
49
- };
78
+ const r = outer_radius
79
+ const ir = inner_radius_adjusted
80
+ // Two semicircular arcs to form a full circle (avoids SVG 360° arc bug)
81
+ const outer_arc = `M ${center} ${center - r} A ${r} ${r} 0 1 1 ${center} ${
82
+ center + r
83
+ } A ${r} ${r} 0 1 1 ${center} ${center - r} Z`
84
+ const path = ir > 0
85
+ ? `${outer_arc} M ${center} ${
86
+ center - ir
87
+ } A ${ir} ${ir} 0 1 0 ${center} ${
88
+ center + ir
89
+ } A ${ir} ${ir} 0 1 0 ${center} ${center - ir} Z`
90
+ : outer_arc
91
+ const label_text = element + (show_amounts ? String(amount) : ``) +
92
+ (show_percentages ? `${format_num(fraction, `.1~%`)}` : ``)
93
+ return {
94
+ element,
95
+ amount,
96
+ fraction,
97
+ color,
98
+ start_angle: -90,
99
+ end_angle: 270,
100
+ path,
101
+ label_x: center,
102
+ label_y: center,
103
+ is_outside_slice: false,
104
+ font_scale: get_chart_font_scale(2.6, label_text, r * 2),
105
+ text_color: pick_contrast_color({ bg_color: color }),
106
+ }
50
107
  }
51
- const angle_span = fraction * 360;
52
- const start_angle = current_angle;
53
- const end_angle = current_angle + angle_span;
54
- current_angle = end_angle;
108
+
109
+ const angle_span = fraction * 360
110
+ const start_angle = current_angle
111
+ const end_angle = current_angle + angle_span
112
+
113
+ current_angle = end_angle
114
+
55
115
  // Convert to radians for calculations
56
- const start_rad = (start_angle * Math.PI) / 180;
57
- const end_rad = (end_angle * Math.PI) / 180;
58
- const mid_rad = (((start_angle + end_angle) / 2) * Math.PI) / 180;
116
+ const start_rad = (start_angle * Math.PI) / 180
117
+ const end_rad = (end_angle * Math.PI) / 180
118
+ const mid_rad = (((start_angle + end_angle) / 2) * Math.PI) / 180
119
+
59
120
  // Arc coordinates for outer radius
60
- const x1_outer = center + outer_radius * Math.cos(start_rad);
61
- const y1_outer = center + outer_radius * Math.sin(start_rad);
62
- const x2_outer = center + outer_radius * Math.cos(end_rad);
63
- const y2_outer = center + outer_radius * Math.sin(end_rad);
121
+ const x1_outer = center + outer_radius * Math.cos(start_rad)
122
+ const y1_outer = center + outer_radius * Math.sin(start_rad)
123
+ const x2_outer = center + outer_radius * Math.cos(end_rad)
124
+ const y2_outer = center + outer_radius * Math.sin(end_rad)
125
+
64
126
  // Arc coordinates for inner radius
65
- const x1_inner = center + inner_radius_adjusted * Math.cos(start_rad);
66
- const y1_inner = center + inner_radius_adjusted * Math.sin(start_rad);
67
- const x2_inner = center + inner_radius_adjusted * Math.cos(end_rad);
68
- const y2_inner = center + inner_radius_adjusted * Math.sin(end_rad);
69
- const large_arc = angle_span > 180 ? 1 : 0;
127
+ const x1_inner = center + inner_radius_adjusted * Math.cos(start_rad)
128
+ const y1_inner = center + inner_radius_adjusted * Math.sin(start_rad)
129
+ const x2_inner = center + inner_radius_adjusted * Math.cos(end_rad)
130
+ const y2_inner = center + inner_radius_adjusted * Math.sin(end_rad)
131
+
132
+ const large_arc = angle_span > 180 ? 1 : 0
133
+
70
134
  // Create donut path if inner radius > 0, otherwise regular pie slice
71
135
  const path = inner_radius_adjusted > 0
72
- ? `M ${x1_outer} ${y1_outer} A ${outer_radius} ${outer_radius} 0 ${large_arc} 1 ${x2_outer} ${y2_outer} L ${x2_inner} ${y2_inner} A ${inner_radius_adjusted} ${inner_radius_adjusted} 0 ${large_arc} 0 ${x1_inner} ${y1_inner} Z`
73
- : `M ${center} ${center} L ${x1_outer} ${y1_outer} A ${outer_radius} ${outer_radius} 0 ${large_arc} 1 ${x2_outer} ${y2_outer} Z`;
136
+ ? `M ${x1_outer} ${y1_outer} A ${outer_radius} ${outer_radius} 0 ${large_arc} 1 ${x2_outer} ${y2_outer} L ${x2_inner} ${y2_inner} A ${inner_radius_adjusted} ${inner_radius_adjusted} 0 ${large_arc} 0 ${x1_inner} ${y1_inner} Z`
137
+ : `M ${center} ${center} L ${x1_outer} ${y1_outer} A ${outer_radius} ${outer_radius} 0 ${large_arc} 1 ${x2_outer} ${y2_outer} Z`
138
+
74
139
  // Position labels with three-tier strategy
75
- const is_very_thin_slice = angle_span < VERY_THIN_SLICE_THRESHOLD; // Place outside
140
+ const is_very_thin_slice = angle_span < VERY_THIN_SLICE_THRESHOLD // Place outside
76
141
  const is_medium_slice = angle_span >= VERY_THIN_SLICE_THRESHOLD &&
77
- angle_span < MEDIUM_SLICE_THRESHOLD; // Near outer edge
78
- let label_radius;
79
- let is_outside_slice = false;
142
+ angle_span < MEDIUM_SLICE_THRESHOLD // Near outer edge
143
+
144
+ let label_radius: number
145
+ let is_outside_slice = false
146
+
80
147
  if (is_very_thin_slice) {
81
- // Very thin slices: place outside with distance proportional to chart size
82
- label_radius = outer_radius + outer_radius * 0.2;
83
- is_outside_slice = true;
84
- }
85
- else if (is_medium_slice) {
86
- // Medium slices: place closer to outer edge, proportional to chart size
87
- label_radius = outer_radius - outer_radius * 0.3;
88
- is_outside_slice = false;
89
- }
90
- else {
91
- // Large slices: place in middle of ring
92
- label_radius = (outer_radius + inner_radius_adjusted) / 2;
93
- is_outside_slice = false;
148
+ // Very thin slices: place outside with distance proportional to chart size
149
+ label_radius = outer_radius + outer_radius * 0.2
150
+ is_outside_slice = true
151
+ } else if (is_medium_slice) {
152
+ // Medium slices: place closer to outer edge, proportional to chart size
153
+ label_radius = outer_radius - outer_radius * 0.3
154
+ is_outside_slice = false
155
+ } else {
156
+ // Large slices: place in middle of ring
157
+ label_radius = (outer_radius + inner_radius_adjusted) / 2
158
+ is_outside_slice = false
94
159
  }
160
+
95
161
  // Calculate font scale based on slice size and smart text fitting
96
- const [min_font_scale, max_font_scale] = [1.4, 2];
97
- const scale_factor = angle_span / MAX_ANGLE_FOR_FULL_SCALE;
162
+ const [min_font_scale, max_font_scale] = [1.4, 2] as const
163
+ const scale_factor = angle_span / MAX_ANGLE_FOR_FULL_SCALE
98
164
  const base_scale = min_font_scale +
99
- scale_factor * (max_font_scale - min_font_scale);
100
- const label_text = element + (show_amounts ? amount.toString() : ``) +
101
- (show_percentages ? `${format_num(fraction, `.1~%`)}` : ``);
165
+ scale_factor * (max_font_scale - min_font_scale)
166
+ const label_text = element + (show_amounts ? amount?.toString() ?? `` : ``) +
167
+ (show_percentages ? `${format_num(fraction, `.1~%`)}` : ``)
102
168
  const available_space = is_very_thin_slice
103
- ? outer_radius * 0.8 // More space outside the slice
104
- : Math.min(outer_radius - inner_radius_adjusted, // Radial space
105
- (angle_span * Math.PI / 180) * label_radius * 0.8);
106
- const font_scale = get_chart_font_scale(base_scale, label_text, available_space);
169
+ ? outer_radius * 0.8 // More space outside the slice
170
+ : Math.min(
171
+ outer_radius - inner_radius_adjusted, // Radial space
172
+ (angle_span * Math.PI / 180) * label_radius * 0.8, // Arc space at label radius
173
+ )
174
+
175
+ const font_scale = get_chart_font_scale(
176
+ base_scale,
177
+ label_text,
178
+ available_space,
179
+ )
180
+
107
181
  return {
108
- element,
109
- amount,
110
- fraction,
111
- color,
112
- start_angle,
113
- end_angle,
114
- path,
115
- label_x: center + label_radius * Math.cos(mid_rad),
116
- label_y: center + label_radius * Math.sin(mid_rad),
117
- is_outside_slice,
118
- font_scale,
119
- text_color: is_outside_slice
120
- ? `var(--text-color, #333)`
121
- : pick_contrast_color({ bg_color: color }),
122
- };
123
- });
124
- });
125
- let hovered_element = $state(null);
182
+ element,
183
+ amount,
184
+ fraction,
185
+ color,
186
+ start_angle,
187
+ end_angle,
188
+ path,
189
+ label_x: center + label_radius * Math.cos(mid_rad),
190
+ label_y: center + label_radius * Math.sin(mid_rad),
191
+ is_outside_slice,
192
+ font_scale,
193
+ text_color: is_outside_slice
194
+ ? `var(--text-color, #333)`
195
+ : pick_contrast_color({ bg_color: color }),
196
+ }
197
+ })
198
+ })
199
+
200
+ let hovered_element: ElementSymbol | null = $state(null)
126
201
  </script>
127
202
 
128
203
  <svg
@@ -6,5 +6,10 @@ export declare const get_alphabetical_formula: (input: string | CompositionType
6
6
  export declare const sort_by_electronegativity: (symbols: ElementSymbol[]) => ElementSymbol[];
7
7
  export declare const sort_by_hill_notation: (symbols: ElementSymbol[]) => ElementSymbol[];
8
8
  export declare const get_electro_neg_formula: (input: string | CompositionType | AnyStructure, plain_text?: boolean, delim?: string, amount_format?: string) => string;
9
+ export interface FormulaLabelSegment {
10
+ text: string;
11
+ subscript: boolean;
12
+ }
13
+ export declare function get_formula_label_segments(formula: string): FormulaLabelSegment[];
9
14
  export declare const get_hill_formula: (input: string | CompositionType | AnyStructure, plain_text?: boolean, delim?: string, amount_format?: string) => string;
10
15
  export declare function format_oxi_state(oxidation?: number): string;
@@ -27,9 +27,7 @@ export const format_composition_formula = (composition, sort_fn, plain_text = fa
27
27
  if (amount === 1)
28
28
  return el;
29
29
  const formatted_amount = format_num(Number(amount), amount_format);
30
- return plain_text
31
- ? `${el}${formatted_amount}`
32
- : `${el}<sub>${formatted_amount}</sub>`;
30
+ return plain_text ? `${el}${formatted_amount}` : `${el}<sub>${formatted_amount}</sub>`;
33
31
  })
34
32
  .join(delim);
35
33
  };
@@ -82,6 +80,25 @@ export const sort_by_hill_notation = (symbols) => {
82
80
  };
83
81
  // Create electronegativity-sorted formula
84
82
  export const get_electro_neg_formula = (input, plain_text = false, delim = ` `, amount_format = `.3~f`) => format_formula_generic(input, sort_by_electronegativity, plain_text, delim, amount_format);
83
+ export function get_formula_label_segments(formula) {
84
+ const segments = [];
85
+ let cursor = 0;
86
+ for (const match of formula.matchAll(/([A-Za-z])(\d+(?:\.\d+)?)/g)) {
87
+ const match_idx = match.index ?? 0;
88
+ const prefix = match[1];
89
+ const amount = match[2];
90
+ const amount_idx = match_idx + prefix.length;
91
+ if (amount_idx > cursor) {
92
+ segments.push({ text: formula.slice(cursor, amount_idx), subscript: false });
93
+ }
94
+ segments.push({ text: amount, subscript: true });
95
+ cursor = amount_idx + amount.length;
96
+ }
97
+ if (cursor < formula.length) {
98
+ segments.push({ text: formula.slice(cursor), subscript: false });
99
+ }
100
+ return segments.length > 0 ? segments : [{ text: formula, subscript: false }];
101
+ }
85
102
  // Create Hill notation formula (C first, H second, then alphabetical)
86
103
  export const get_hill_formula = (input, plain_text = false, delim = ` `, amount_format = `.3~s`) => format_formula_generic(input, sort_by_hill_notation, plain_text, delim, amount_format);
87
104
  export function format_oxi_state(oxidation) {
@@ -21,8 +21,8 @@ export const is_valid_element = (sym) => ELEM_SYMBOLS.includes(sym);
21
21
  // Check if object has atomic numbers as keys (1-118)
22
22
  const is_atomic_number_composition = (obj) => {
23
23
  const keys = Object.keys(obj);
24
- return keys.length > 0 &&
25
- keys.map(Number).every((num) => Number.isInteger(num) && num >= 1 && num <= 118);
24
+ return (keys.length > 0 &&
25
+ keys.map(Number).every((num) => Number.isInteger(num) && num >= 1 && num <= 118));
26
26
  };
27
27
  // Convert atomic numbers to element symbols
28
28
  export const atomic_num_to_symbols = (atomic_composition) => {
@@ -148,7 +148,7 @@ export const parse_composition = (input) => {
148
148
  return normalize_composition(input);
149
149
  };
150
150
  // Calculate GCD of two numbers
151
- const gcd = (num_a, num_b) => (num_b === 0 ? num_a : gcd(num_b, num_a % num_b));
151
+ const gcd = (num_a, num_b) => num_b === 0 ? num_a : gcd(num_b, num_a % num_b);
152
152
  // Get reduced formula by dividing all amounts by their GCD
153
153
  // Example: Fe2O4 -> FeO2, H4O2 -> H2O
154
154
  export const get_reduced_formula = (composition) => {
@@ -176,7 +176,7 @@ const parse_oxidation_state = (oxidation_str) => {
176
176
  return oxidation_str === `+` ? 1 : -1;
177
177
  }
178
178
  // Handle formats like "2+", "+2", "2-", "-2"
179
- const ox_match = oxidation_str.match(/([+-]?)(\d+)([+-]?)/);
179
+ const ox_match = /([+-]?)(\d+)([+-]?)/.exec(oxidation_str);
180
180
  if (!ox_match)
181
181
  return 0;
182
182
  const [, sign_before, number, sign_after] = ox_match;
@@ -211,9 +211,7 @@ export const parse_formula_with_oxidation = (formula, strict = false) => {
211
211
  const count = count_str ? parseInt(count_str, 10) : 1;
212
212
  if (!is_valid_element(element))
213
213
  throw new Error(`Invalid element symbol: ${element}`);
214
- const oxidation_state = oxidation_str
215
- ? parse_oxidation_state(oxidation_str)
216
- : undefined;
214
+ const oxidation_state = oxidation_str ? parse_oxidation_state(oxidation_str) : undefined;
217
215
  // Find or add element entry
218
216
  const existing = elements.find((el) => el.element === element);
219
217
  if (existing) {
@@ -304,7 +302,10 @@ export function generate_chem_sys_subspaces(input) {
304
302
  // Example: "Zr, Nb, InvalidElement, H" -> ["H", "Nb", "Zr"]
305
303
  // Note: Matching is case-sensitive. Use all_symbols to filter against a subset.
306
304
  export const normalize_element_symbols = (csv, all_symbols) => {
307
- const input_set = new Set(csv.split(`,`).map((sym) => sym.trim()).filter(Boolean));
305
+ const input_set = new Set(csv
306
+ .split(`,`)
307
+ .map((sym) => sym.trim())
308
+ .filter(Boolean));
308
309
  // Cast needed: ELEM_SYMBOLS is readonly const tuple, T is generic string subtype
309
310
  return (all_symbols ?? ELEM_SYMBOLS).filter((sym) => input_set.has(sym));
310
311
  };
@@ -315,7 +316,11 @@ export const has_wildcards = (input) => input.includes(`*`);
315
316
  // Accepts both hyphen and comma separators.
316
317
  // Throws if any non-wildcard token is not a valid element symbol.
317
318
  export function parse_chemsys_with_wildcards(input) {
318
- const tokens = input.replace(/-/g, `,`).split(`,`).map((tok) => tok.trim()).filter(Boolean);
319
+ const tokens = input
320
+ .replace(/-/g, `,`)
321
+ .split(`,`)
322
+ .map((tok) => tok.trim())
323
+ .filter(Boolean);
319
324
  const elements = [];
320
325
  let wildcard_count = 0;
321
326
  for (const token of tokens) {
@@ -1,46 +1,99 @@
1
- <script lang="ts">import { extract_formula_elements } from '../composition/parse';
2
- import { DEFAULTS } from '../settings';
3
- import { SvelteSet } from 'svelte/reactivity';
4
- import ConvexHull2D from './ConvexHull2D.svelte';
5
- import ConvexHull3D from './ConvexHull3D.svelte';
6
- import ConvexHull4D from './ConvexHull4D.svelte';
7
- let { entries = [],
8
- // bindable props not part of rest because Svelte 5 doesn't support spreading bindable props.
9
- fullscreen = $bindable(false), wrapper = $bindable(), show_stable = $bindable(true), show_unstable = $bindable(true), show_hull_faces = $bindable(true), hull_face_opacity: hull_face_opacity_prop = $bindable(undefined), color_mode = $bindable(`energy`), color_scale = $bindable(`interpolateViridis`), info_pane_open = $bindable(false), legend_pane_open = $bindable(false), max_hull_dist_show_phases = $bindable(0.1), max_hull_dist_show_labels = $bindable(0.1), show_stable_labels = $bindable(true), show_unstable_labels = $bindable(false), energy_source_mode = $bindable(`precomputed`), phase_stats = $bindable(null), display = $bindable({ x_grid: false, y_grid: false }), stable_entries = $bindable([]), unstable_entries = $bindable([]), highlighted_entries = $bindable([]), selected_entry = $bindable(null), temperature = $bindable(), gas_pressures = $bindable({}), ...rest } = $props();
10
- // Lightweight element extraction - count unique elements, stripping oxidation states
11
- // (e.g. "V4+" -> "V") to avoid counting the same element multiple times
12
- function extract_unique_elements(entries) {
13
- const elements = new SvelteSet();
1
+ <script lang="ts">
2
+ import { extract_formula_elements } from '../composition/parse'
3
+ import type { AxisConfig } from '../plot'
4
+ import { DEFAULTS } from '../settings'
5
+ import type { Component } from 'svelte'
6
+ import { SvelteSet } from 'svelte/reactivity'
7
+ import ConvexHull2D from './ConvexHull2D.svelte'
8
+ import ConvexHull3D from './ConvexHull3D.svelte'
9
+ import ConvexHull4D from './ConvexHull4D.svelte'
10
+ import type { BaseConvexHullProps, Hull3DProps } from './index'
11
+ import type { GasSpecies, GasThermodynamicsConfig } from './types'
12
+
13
+ // Union type combining all possible props from 2D, 3D, and 4D components
14
+ // each specific component will only use its relevant props from this super set
15
+ type ConvexHullProps = BaseConvexHullProps & Hull3DProps & {
16
+ x_axis?: AxisConfig
17
+ y_axis?: AxisConfig
18
+ // Gas thermodynamics config - enables atmosphere-controlled phase diagrams
19
+ gas_config?: GasThermodynamicsConfig
20
+ // Gas pressure binding - enables two-way binding for atmosphere control
21
+ gas_pressures?: Partial<Record<GasSpecies, number>>
22
+ }
23
+
24
+ let {
25
+ entries = [],
26
+ // bindable props not part of rest because Svelte 5 doesn't support spreading bindable props.
27
+ fullscreen = $bindable(false),
28
+ wrapper = $bindable(),
29
+ show_stable = $bindable(true),
30
+ show_unstable = $bindable(true),
31
+ show_hull_faces = $bindable(true),
32
+ hull_face_opacity: hull_face_opacity_prop = $bindable(
33
+ undefined as number | undefined,
34
+ ),
35
+ color_mode = $bindable(`energy`),
36
+ color_scale = $bindable(`interpolateViridis`),
37
+ info_pane_open = $bindable(false),
38
+ legend_pane_open = $bindable(false),
39
+ max_hull_dist_show_phases = $bindable(0.1),
40
+ max_hull_dist_show_labels = $bindable(0.1),
41
+ show_stable_labels = $bindable(true),
42
+ show_unstable_labels = $bindable(false),
43
+ energy_source_mode = $bindable(`precomputed`),
44
+ phase_stats = $bindable(null),
45
+ display = $bindable({ x_grid: false, y_grid: false }),
46
+ stable_entries = $bindable([]),
47
+ unstable_entries = $bindable([]),
48
+ highlighted_entries = $bindable([]),
49
+ selected_entry = $bindable(null),
50
+ temperature = $bindable(),
51
+ gas_pressures = $bindable({}),
52
+ ...rest
53
+ }: ConvexHullProps = $props()
54
+
55
+ // Lightweight element extraction - count unique elements, stripping oxidation states
56
+ // (e.g. "V4+" -> "V") to avoid counting the same element multiple times
57
+ function extract_unique_elements(
58
+ entries: { composition: Record<string, number> }[],
59
+ ): string[] {
60
+ const elements = new SvelteSet<string>()
14
61
  for (const entry of entries) {
15
- for (const key of Object.keys(entry.composition)) {
16
- // Extract valid element symbols, stripping oxidation states
17
- for (const elem of extract_formula_elements(key, { unique: false })) {
18
- elements.add(elem);
19
- }
62
+ for (const key of Object.keys(entry.composition)) {
63
+ // Extract valid element symbols, stripping oxidation states
64
+ for (const elem of extract_formula_elements(key, { unique: false })) {
65
+ elements.add(elem)
20
66
  }
67
+ }
21
68
  }
22
- return Array.from(elements).sort();
23
- }
24
- // Detect dimensionality by counting unique elements (lightweight operation)
25
- const elements = $derived(extract_unique_elements(entries));
26
- const element_count = $derived(elements.length);
27
- // Resolve hull face opacity: use caller's value if provided,
28
- // otherwise pick the right default for the dimensionality (ternary=30%, quaternary=3%).
29
- // Use writable derived so child bind updates can sync back to parent.
30
- const default_opacity = $derived(element_count === 4
31
- ? DEFAULTS.convex_hull.quaternary.hull_face_opacity
32
- : DEFAULTS.convex_hull.ternary.hull_face_opacity);
33
- let hull_face_opacity = $derived(hull_face_opacity_prop ?? default_opacity);
34
- $effect(() => {
35
- if (hull_face_opacity_prop === hull_face_opacity)
36
- return;
37
- hull_face_opacity_prop = hull_face_opacity;
38
- });
39
- // Map element count to corresponding component
40
- // Note: Type assertion needed because TypeScript can't infer that all components
41
- // accept a compatible superset of props (BaseConvexHullProps + dimension-specific)
42
- const ConvexHullComponent = $derived({ 2: ConvexHull2D, 3: ConvexHull3D, 4: ConvexHull4D }[element_count] ??
43
- null);
69
+ return Array.from(elements).toSorted()
70
+ }
71
+
72
+ // Detect dimensionality by counting unique elements (lightweight operation)
73
+ const elements = $derived(extract_unique_elements(entries))
74
+ const element_count = $derived(elements.length)
75
+
76
+ // Resolve hull face opacity: use caller's value if provided,
77
+ // otherwise pick the right default for the dimensionality (ternary=30%, quaternary=3%).
78
+ // Use writable derived so child bind updates can sync back to parent.
79
+ const default_opacity = $derived(
80
+ element_count === 4
81
+ ? DEFAULTS.convex_hull.quaternary.hull_face_opacity
82
+ : DEFAULTS.convex_hull.ternary.hull_face_opacity,
83
+ )
84
+ let hull_face_opacity = $derived(hull_face_opacity_prop ?? default_opacity)
85
+ $effect(() => {
86
+ if (hull_face_opacity_prop === hull_face_opacity) return
87
+ hull_face_opacity_prop = hull_face_opacity
88
+ })
89
+
90
+ // Map element count to corresponding component
91
+ // Note: Type assertion needed because TypeScript can't infer that all components
92
+ // accept a compatible superset of props (BaseConvexHullProps + dimension-specific)
93
+ const ConvexHullComponent = $derived(
94
+ { 2: ConvexHull2D, 3: ConvexHull3D, 4: ConvexHull4D }[element_count] ??
95
+ null,
96
+ ) as Component<ConvexHullProps> | null
44
97
  </script>
45
98
 
46
99
  {#if ConvexHullComponent}
@@ -8,6 +8,6 @@ type ConvexHullProps = BaseConvexHullProps & Hull3DProps & {
8
8
  gas_config?: GasThermodynamicsConfig;
9
9
  gas_pressures?: Partial<Record<GasSpecies, number>>;
10
10
  };
11
- declare const ConvexHull: Component<ConvexHullProps, {}, "temperature" | "display" | "color_scale" | "fullscreen" | "show_hull_faces" | "hull_face_opacity" | "color_mode" | "show_stable" | "show_unstable" | "show_stable_labels" | "show_unstable_labels" | "max_hull_dist_show_phases" | "max_hull_dist_show_labels" | "info_pane_open" | "legend_pane_open" | "wrapper" | "energy_source_mode" | "stable_entries" | "unstable_entries" | "phase_stats" | "highlighted_entries" | "selected_entry" | "gas_pressures">;
11
+ declare const ConvexHull: Component<ConvexHullProps, {}, "temperature" | "display" | "fullscreen" | "show_hull_faces" | "hull_face_opacity" | "color_mode" | "color_scale" | "show_stable" | "show_unstable" | "show_stable_labels" | "show_unstable_labels" | "max_hull_dist_show_phases" | "max_hull_dist_show_labels" | "info_pane_open" | "legend_pane_open" | "wrapper" | "energy_source_mode" | "stable_entries" | "unstable_entries" | "phase_stats" | "highlighted_entries" | "selected_entry" | "gas_pressures">;
12
12
  type ConvexHull = ReturnType<typeof ConvexHull>;
13
13
  export default ConvexHull;