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,62 +1,103 @@
1
- <script lang="ts">import { untrack } from 'svelte';
2
- import Bands from './Bands.svelte';
3
- import Dos from './Dos.svelte';
4
- import { compute_frequency_range, detect_zoom_change, extract_efermi, is_valid_range, ranges_equal, } from './helpers';
5
- let { band_structs, doses, bands_props = {}, dos_props = {}, shared_y_axis = true, sync_y_zoom = true, children, ...rest } = $props();
6
- let shared_frequency_range = $derived(shared_y_axis ? compute_frequency_range(band_structs, doses) : undefined);
7
- let fermi_level = $derived(extract_efermi(band_structs) ?? extract_efermi(doses));
8
- // Synced zoom state (null = use auto-computed range)
9
- let synced_zoom_range = $state(null);
10
- let bands_y_axis = $state({});
11
- let dos_y_axis = $state({ label: `` });
12
- // Detect zoom changes and sync between components (runs first to capture child updates)
13
- $effect(() => {
14
- if (!sync_y_zoom || !shared_frequency_range)
15
- return;
16
- const result = detect_zoom_change(bands_y_axis.range, dos_y_axis.range, shared_frequency_range, untrack(() => synced_zoom_range));
17
- if (result !== undefined)
18
- synced_zoom_range = result;
19
- });
20
- // Propagate synced range to bands y-axis (untrack current to avoid overwriting child zoom)
21
- $effect(() => {
22
- const base_range = synced_zoom_range ?? shared_frequency_range;
23
- const current_range = untrack(() => bands_y_axis.range);
1
+ <script lang="ts">
2
+ import type { Vec2 } from '../math'
3
+ import type { AxisConfig } from '../plot/types'
4
+ import type { ComponentProps, Snippet } from 'svelte'
5
+ import { untrack } from 'svelte'
6
+ import type { HTMLAttributes } from 'svelte/elements'
7
+ import Bands from './Bands.svelte'
8
+ import Dos from './Dos.svelte'
9
+ import {
10
+ compute_frequency_range,
11
+ detect_zoom_change,
12
+ extract_efermi,
13
+ is_valid_range,
14
+ ranges_equal,
15
+ } from './helpers'
16
+ import type { BaseBandStructure, DosInput, HoveredData } from './types'
17
+
18
+ let {
19
+ band_structs,
20
+ doses,
21
+ bands_props = {},
22
+ dos_props = {},
23
+ shared_y_axis = true,
24
+ sync_y_zoom = true,
25
+ children,
26
+ ...rest
27
+ }: HTMLAttributes<HTMLDivElement> & {
28
+ band_structs: BaseBandStructure | Record<string, BaseBandStructure>
29
+ doses: DosInput | Record<string, DosInput>
30
+ bands_props?: Partial<ComponentProps<typeof Bands>>
31
+ dos_props?: Partial<ComponentProps<typeof Dos>>
32
+ shared_y_axis?: boolean
33
+ sync_y_zoom?: boolean
34
+ class?: string
35
+ children?: Snippet<[HoveredData]>
36
+ } = $props()
37
+
38
+ let shared_frequency_range = $derived(
39
+ shared_y_axis ? compute_frequency_range(band_structs, doses) : undefined,
40
+ )
41
+ let fermi_level = $derived(extract_efermi(band_structs) ?? extract_efermi(doses))
42
+
43
+ // Synced zoom state (null = use auto-computed range)
44
+ let synced_zoom_range = $state<Vec2 | null>(null)
45
+ let bands_y_axis = $state<AxisConfig>({})
46
+ let dos_y_axis = $state<AxisConfig>({ label: `` })
47
+
48
+ // Detect zoom changes and sync between components (runs first to capture child updates)
49
+ $effect(() => {
50
+ if (!sync_y_zoom || !shared_frequency_range) return
51
+ const result = detect_zoom_change(
52
+ bands_y_axis.range,
53
+ dos_y_axis.range,
54
+ shared_frequency_range,
55
+ untrack(() => synced_zoom_range),
56
+ )
57
+ if (result !== undefined) synced_zoom_range = result
58
+ })
59
+
60
+ // Propagate synced range to bands y-axis (untrack current to avoid overwriting child zoom)
61
+ $effect(() => {
62
+ const base_range = synced_zoom_range ?? shared_frequency_range
63
+ const current_range = untrack(() => bands_y_axis.range) as Vec2 | undefined
24
64
  // Skip if current range already matches base, or is valid but differs (child zoom in progress)
25
- if (ranges_equal(current_range, base_range))
26
- return;
65
+ if (ranges_equal(current_range, base_range)) return
27
66
  if (is_valid_range(current_range) && !ranges_equal(current_range, base_range)) {
28
- return;
67
+ return
29
68
  }
30
69
  // Only include range if it's valid (don't override child's auto-range with undefined)
31
70
  bands_y_axis = shared_y_axis
32
- ? {
33
- ...(bands_props.y_axis ?? {}),
34
- ...(is_valid_range(base_range) && { range: base_range }),
35
- }
36
- : { ...(bands_props.y_axis ?? {}) };
37
- });
38
- // Propagate synced range to DOS y-axis (untrack current to avoid overwriting child zoom)
39
- $effect(() => {
40
- const base_range = synced_zoom_range ?? shared_frequency_range;
41
- const current_range = untrack(() => dos_y_axis.range);
71
+ ? {
72
+ ...(bands_props.y_axis ?? {}),
73
+ ...(is_valid_range(base_range) && { range: base_range }),
74
+ }
75
+ : { ...(bands_props.y_axis ?? {}) }
76
+ })
77
+
78
+ // Propagate synced range to DOS y-axis (untrack current to avoid overwriting child zoom)
79
+ $effect(() => {
80
+ const base_range = synced_zoom_range ?? shared_frequency_range
81
+ const current_range = untrack(() => dos_y_axis.range) as Vec2 | undefined
42
82
  // Skip if current range already matches base, or is valid but differs (child zoom in progress)
43
- if (ranges_equal(current_range, base_range))
44
- return;
83
+ if (ranges_equal(current_range, base_range)) return
45
84
  if (is_valid_range(current_range) && !ranges_equal(current_range, base_range)) {
46
- return;
85
+ return
47
86
  }
48
87
  // Only include range if it's valid (don't override child's auto-range with undefined)
49
88
  dos_y_axis = shared_y_axis
50
- ? {
51
- label: ``,
52
- ...(dos_props.y_axis ?? {}),
53
- ...(is_valid_range(base_range) && { range: base_range }),
54
- }
55
- : { label: ``, ...(dos_props.y_axis ?? {}) };
56
- });
57
- let hovered_frequency = $state(null);
58
- // Ensure both plots use identical top/bottom padding for aligned y_scale_fn
59
- const shared_tb_padding = { t: 20, b: 50 };
89
+ ? {
90
+ label: ``,
91
+ ...(dos_props.y_axis ?? {}),
92
+ ...(is_valid_range(base_range) && { range: base_range }),
93
+ }
94
+ : { label: ``, ...(dos_props.y_axis ?? {}) }
95
+ })
96
+
97
+ let hovered_frequency = $state<number | null>(null)
98
+
99
+ // Ensure both plots use identical top/bottom padding for aligned y_scale_fn
100
+ const shared_tb_padding = { t: 20, b: 50 }
60
101
  </script>
61
102
 
62
103
  <div
@@ -1,104 +1,162 @@
1
- <script lang="ts">import { BrillouinZone, reciprocal_lattice } from '../brillouin';
2
- import { untrack } from 'svelte';
3
- import Bands from './Bands.svelte';
4
- import Dos from './Dos.svelte';
5
- import * as helpers from './helpers';
6
- let { structure, band_structs, doses, bands_props = {}, dos_props = {}, bz_props = {}, sync_y_zoom = true, children, ...rest } = $props();
7
- // Get the first normalized band structure for path calculations
8
- // Support both qpoints (phonon) and kpoints (electronic) to detect single vs dict
9
- let first_band_struct = $derived(helpers.normalize_band_structure(`qpoints` in band_structs || `kpoints` in band_structs
10
- ? band_structs
11
- : Object.values(band_structs)[0]));
12
- // Compute shared frequency/energy range from both bands and DOS data
13
- let shared_frequency_range = $derived(helpers.compute_frequency_range(band_structs, doses));
14
- // Extract Fermi level from electronic band structure or DOS data
15
- let fermi_level = $derived.by(() => {
16
- // Check band structures for efermi
17
- const bs_source = `efermi` in band_structs
1
+ <script lang="ts">
2
+ import { BrillouinZone, reciprocal_lattice } from '../brillouin'
3
+ import type { Vec2, Vec3 } from '../math'
4
+ import type { InternalPoint } from '../plot'
5
+ import type { AxisConfig } from '../plot/types'
6
+ import type { Crystal } from '../structure'
7
+ import type { ComponentProps, Snippet } from 'svelte'
8
+ import { untrack } from 'svelte'
9
+ import type { HTMLAttributes } from 'svelte/elements'
10
+ import Bands from './Bands.svelte'
11
+ import Dos from './Dos.svelte'
12
+ import * as helpers from './helpers'
13
+ import type { BaseBandStructure, DosData, HoveredData } from './types'
14
+
15
+ let {
16
+ structure,
17
+ band_structs,
18
+ doses,
19
+ bands_props = {},
20
+ dos_props = {},
21
+ bz_props = {},
22
+ sync_y_zoom = true,
23
+ children,
24
+ ...rest
25
+ }: HTMLAttributes<HTMLDivElement> & {
26
+ structure: Crystal
27
+ band_structs: BaseBandStructure | Record<string, BaseBandStructure>
28
+ doses: DosData | Record<string, DosData>
29
+ bands_props?: Partial<ComponentProps<typeof Bands>>
30
+ dos_props?: Partial<ComponentProps<typeof Dos>>
31
+ bz_props?: Partial<ComponentProps<typeof BrillouinZone>>
32
+ sync_y_zoom?: boolean // Sync frequency/energy axis zoom between plots (default: true)
33
+ children?: Snippet<[HoveredData]>
34
+ } = $props()
35
+
36
+ // Get the first normalized band structure for path calculations
37
+ // Support both qpoints (phonon) and kpoints (electronic) to detect single vs dict
38
+ let first_band_struct = $derived(
39
+ helpers.normalize_band_structure(
40
+ `qpoints` in (band_structs as object) || `kpoints` in (band_structs as object)
18
41
  ? band_structs
19
- : Object.values(band_structs)[0];
20
- const bs_efermi = bs_source?.efermi;
21
- if (typeof bs_efermi === `number`)
22
- return bs_efermi;
42
+ : Object.values(band_structs)[0],
43
+ ),
44
+ ) as BaseBandStructure | null
45
+
46
+ // Compute shared frequency/energy range from both bands and DOS data
47
+ let shared_frequency_range = $derived(
48
+ helpers.compute_frequency_range(band_structs, doses),
49
+ )
50
+
51
+ // Extract Fermi level from electronic band structure or DOS data
52
+ let fermi_level = $derived.by((): number | undefined => {
53
+ // Check band structures for efermi
54
+ const bs_source = `efermi` in (band_structs as object)
55
+ ? band_structs
56
+ : Object.values(band_structs)[0]
57
+ const bs_efermi = (bs_source as Record<string, unknown>)?.efermi
58
+ if (typeof bs_efermi === `number`) return bs_efermi
59
+
23
60
  // Check DOS for efermi
24
- const dos_source = `efermi` in doses ? doses : Object.values(doses)[0];
25
- const dos_efermi = dos_source?.efermi;
26
- return typeof dos_efermi === `number` ? dos_efermi : undefined;
27
- });
28
- // Convert fractional k-point coordinates to Cartesian reciprocal space
29
- // using the structure's reciprocal lattice (consistent with BZ computation)
30
- let k_path_points = $derived.by(() => {
31
- if (!first_band_struct?.qpoints || !structure?.lattice?.matrix)
32
- return [];
33
- const k_lattice = reciprocal_lattice(structure.lattice.matrix);
34
- return helpers.extract_k_path_points(first_band_struct, k_lattice);
35
- });
36
- let hovered_band_point = $state(null);
37
- let bands_x_positions = $state({});
38
- let hovered_qpoint_index = $derived(hovered_band_point && first_band_struct &&
39
- Object.keys(bands_x_positions).length > 0
40
- ? helpers.find_qpoint_at_rescaled_x(first_band_struct, hovered_band_point.x, bands_x_positions)
41
- : null);
42
- let hovered_k_point = $derived(hovered_qpoint_index !== null
43
- ? k_path_points[hovered_qpoint_index]
44
- : null);
45
- const [desktop_width, tablet_width] = [1200, 600];
46
- let clientWidth = $state(desktop_width);
47
- let is_desktop = $derived(clientWidth >= desktop_width);
48
- let is_mobile = $derived(clientWidth < tablet_width);
49
- let screen_class = $derived(clientWidth >= desktop_width
50
- ? `desktop`
51
- : clientWidth >= tablet_width
52
- ? `tablet`
53
- : `phone`);
54
- // Synced zoom state (null = use auto-computed range)
55
- let synced_zoom_range = $state(null);
56
- let bands_y_axis = $state({});
57
- let dos_y_axis = $state({});
58
- // Detect zoom changes and sync between components (runs first to capture child updates)
59
- $effect(() => {
60
- if (!sync_y_zoom || !shared_frequency_range)
61
- return;
62
- const result = helpers.detect_zoom_change(bands_y_axis.range, dos_y_axis.range, shared_frequency_range, untrack(() => synced_zoom_range), is_desktop);
63
- if (result !== undefined)
64
- synced_zoom_range = result;
65
- });
66
- // Propagate synced range to bands y-axis (untrack current to avoid overwriting child zoom)
67
- $effect(() => {
68
- const base_range = synced_zoom_range ?? shared_frequency_range;
69
- const current_range = untrack(() => bands_y_axis.range);
61
+ const dos_source = `efermi` in (doses as object) ? doses : Object.values(doses)[0]
62
+ const dos_efermi = (dos_source as Record<string, unknown>)?.efermi
63
+ return typeof dos_efermi === `number` ? dos_efermi : undefined
64
+ })
65
+
66
+ // Convert fractional k-point coordinates to Cartesian reciprocal space
67
+ // using the structure's reciprocal lattice (consistent with BZ computation)
68
+ let k_path_points = $derived.by(() => {
69
+ if (!first_band_struct?.qpoints || !structure?.lattice?.matrix) return []
70
+
71
+ const k_lattice = reciprocal_lattice(structure.lattice.matrix)
72
+ return helpers.extract_k_path_points(first_band_struct, k_lattice)
73
+ })
74
+
75
+ let hovered_band_point = $state<InternalPoint | null>(null)
76
+ let bands_x_positions = $state<Record<string, [number, number]>>({})
77
+ let hovered_qpoint_index = $derived(
78
+ hovered_band_point && first_band_struct &&
79
+ Object.keys(bands_x_positions).length > 0
80
+ ? helpers.find_qpoint_at_rescaled_x(
81
+ first_band_struct,
82
+ hovered_band_point.x,
83
+ bands_x_positions,
84
+ )
85
+ : null,
86
+ )
87
+ let hovered_k_point = $derived(
88
+ hovered_qpoint_index !== null
89
+ ? (k_path_points[hovered_qpoint_index] as Vec3)
90
+ : null,
91
+ )
92
+ const [desktop_width, tablet_width] = [1200, 600]
93
+ let clientWidth = $state(desktop_width)
94
+ let is_desktop = $derived(clientWidth >= desktop_width)
95
+ let is_mobile = $derived(clientWidth < tablet_width)
96
+ let screen_class = $derived(
97
+ clientWidth >= desktop_width
98
+ ? `desktop`
99
+ : clientWidth >= tablet_width
100
+ ? `tablet`
101
+ : `phone`,
102
+ )
103
+
104
+ // Synced zoom state (null = use auto-computed range)
105
+ let synced_zoom_range = $state<Vec2 | null>(null)
106
+ let bands_y_axis = $state<AxisConfig>({})
107
+ let dos_y_axis = $state<AxisConfig>({})
108
+
109
+ // Detect zoom changes and sync between components (runs first to capture child updates)
110
+ $effect(() => {
111
+ if (!sync_y_zoom || !shared_frequency_range) return
112
+ const result = helpers.detect_zoom_change(
113
+ bands_y_axis.range,
114
+ dos_y_axis.range,
115
+ shared_frequency_range,
116
+ untrack(() => synced_zoom_range),
117
+ is_desktop, // DOS sync only enabled on desktop
118
+ )
119
+ if (result !== undefined) synced_zoom_range = result
120
+ })
121
+
122
+ // Propagate synced range to bands y-axis (untrack current to avoid overwriting child zoom)
123
+ $effect(() => {
124
+ const base_range = synced_zoom_range ?? shared_frequency_range
125
+ const current_range = untrack(() => bands_y_axis.range) as Vec2 | undefined
70
126
  // Skip if current range already matches base, or is valid but differs (child zoom in progress)
71
- if (helpers.ranges_equal(current_range, base_range))
72
- return;
73
- if (helpers.is_valid_range(current_range) &&
74
- !helpers.ranges_equal(current_range, base_range))
75
- return;
127
+ if (helpers.ranges_equal(current_range, base_range)) return
128
+ if (
129
+ helpers.is_valid_range(current_range) &&
130
+ !helpers.ranges_equal(current_range, base_range)
131
+ ) return
76
132
  // Only include range if it's valid (don't override child's auto-range with undefined)
77
133
  bands_y_axis = {
78
- ...(bands_props.y_axis ?? {}),
79
- ...(helpers.is_valid_range(base_range) && { range: base_range }),
80
- };
81
- });
82
- // Propagate synced range to DOS y-axis (untrack current to avoid overwriting child zoom)
83
- $effect(() => {
84
- const base_range = synced_zoom_range ?? shared_frequency_range;
85
- const current_range = untrack(() => dos_y_axis.range);
134
+ ...(bands_props.y_axis ?? {}),
135
+ ...(helpers.is_valid_range(base_range) && { range: base_range }),
136
+ }
137
+ })
138
+
139
+ // Propagate synced range to DOS y-axis (untrack current to avoid overwriting child zoom)
140
+ $effect(() => {
141
+ const base_range = synced_zoom_range ?? shared_frequency_range
142
+ const current_range = untrack(() => dos_y_axis.range) as Vec2 | undefined
86
143
  // Skip if current range already matches base, or is valid but differs (child zoom in progress)
87
- if (helpers.ranges_equal(current_range, base_range))
88
- return;
89
- if (helpers.is_valid_range(current_range) &&
90
- !helpers.ranges_equal(current_range, base_range))
91
- return;
144
+ if (helpers.ranges_equal(current_range, base_range)) return
145
+ if (
146
+ helpers.is_valid_range(current_range) &&
147
+ !helpers.ranges_equal(current_range, base_range)
148
+ ) return
92
149
  // Only include range if it's valid (don't override child's auto-range with undefined)
93
150
  dos_y_axis = is_desktop
94
- ? {
95
- label: ``,
96
- ...(dos_props.y_axis ?? {}),
97
- ...(helpers.is_valid_range(base_range) && { range: base_range }),
98
- }
99
- : { ...(dos_props.y_axis ?? {}) };
100
- });
101
- let hovered_frequency = $state(null);
151
+ ? {
152
+ label: ``,
153
+ ...(dos_props.y_axis ?? {}),
154
+ ...(helpers.is_valid_range(base_range) && { range: base_range }),
155
+ }
156
+ : { ...(dos_props.y_axis ?? {}) }
157
+ })
158
+
159
+ let hovered_frequency = $state<number | null>(null)
102
160
  </script>
103
161
 
104
162
  <div