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,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