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,76 +1,107 @@
1
- <script lang="ts">import DraggablePane from '../overlays/DraggablePane.svelte';
2
- import { format_num } from '../labels';
3
- import { analyze_structure_symmetry } from '../symmetry';
4
- let { pane_open = $bindable(false), structure, bz_data, pane_props = {}, } = $props();
5
- let sym_data = $state(null);
6
- $effect(() => {
7
- sym_data = null;
8
- if (!pane_open || !structure || !(`lattice` in structure))
9
- return;
1
+ <script lang="ts">
2
+ import type { InfoItem } from '../layout'
3
+ import DraggablePane from '../overlays/DraggablePane.svelte'
4
+ import { format_num } from '../labels'
5
+ import { sanitize_html } from '../sanitize'
6
+ import type { Crystal } from '../structure'
7
+ import { analyze_structure_symmetry } from '../symmetry'
8
+ import type { MoyoDataset } from '@spglib/moyo-wasm'
9
+ import type { ComponentProps } from 'svelte'
10
+ import type { BrillouinZoneData } from './types'
11
+
12
+ let {
13
+ pane_open = $bindable(false),
14
+ structure,
15
+ bz_data,
16
+ pane_props = {},
17
+ }: {
18
+ pane_open?: boolean
19
+ structure?: Crystal
20
+ bz_data?: BrillouinZoneData
21
+ pane_props?: ComponentProps<typeof DraggablePane>[`pane_props`]
22
+ } = $props()
23
+
24
+ let sym_data = $state<MoyoDataset | null>(null)
25
+
26
+ $effect(() => {
27
+ sym_data = null
28
+ if (!pane_open || !structure || !(`lattice` in structure)) return
29
+
10
30
  analyze_structure_symmetry(structure, {})
11
- .then((data) => (sym_data = data))
12
- .catch(console.error);
13
- });
14
- let pane_data = $derived.by(() => {
15
- if (!structure || !bz_data)
16
- return [];
17
- const sections = [];
31
+ .then((data) => (sym_data = data))
32
+ .catch(console.error)
33
+ })
34
+
35
+ let pane_data = $derived.by(() => {
36
+ if (!structure || !bz_data) return []
37
+ const sections: { title: string; items: InfoItem[] }[] = []
38
+
18
39
  // Brillouin Zone section
19
- const bz_order_suffix = [`st`, `nd`, `rd`][bz_data.order - 1] ?? `th`;
40
+ const bz_order_suffix = [`st`, `nd`, `rd`][bz_data.order - 1] ?? `th`
20
41
  sections.push({
21
- title: `Brillouin Zone`,
22
- items: [
23
- {
24
- label: `Order`,
25
- value: `${bz_data.order}${bz_order_suffix}`,
26
- key: `bz-order`,
27
- },
28
- {
29
- label: `Volume`,
30
- value: `${format_num(bz_data.volume, `.3f`)} Å⁻³`,
31
- key: `bz-volume`,
32
- },
33
- {
34
- label: `Vertices / Faces`,
35
- value: `${bz_data.vertices.length} / ${bz_data.faces.length}`,
36
- key: `bz-vertices`,
37
- },
38
- {
39
- label: `Space Group`,
40
- value: `${sym_data?.number ?? ``} ${sym_data?.hm_symbol ? `(${sym_data.hm_symbol})` : ``}`.trim(),
41
- key: `space-group`,
42
- },
43
- ],
44
- });
42
+ title: `Brillouin Zone`,
43
+ items: [
44
+ {
45
+ label: `Order`,
46
+ value: `${bz_data.order}${bz_order_suffix}`,
47
+ key: `bz-order`,
48
+ },
49
+ {
50
+ label: `Volume`,
51
+ value: `${format_num(bz_data.volume, `.3f`)} Å⁻³`,
52
+ key: `bz-volume`,
53
+ },
54
+ {
55
+ label: `Vertices / Faces`,
56
+ value: `${bz_data.vertices.length} / ${bz_data.faces.length}`,
57
+ key: `bz-vertices`,
58
+ },
59
+ {
60
+ label: `Space Group`,
61
+ value: `${sym_data?.number ?? ``} ${
62
+ sym_data?.hm_symbol ? `(${sym_data.hm_symbol})` : ``
63
+ }`.trim(),
64
+ key: `space-group`,
65
+ },
66
+ ],
67
+ })
68
+
45
69
  // Real Lattice section
46
70
  sections.push({
47
- title: `Real Lattice`,
48
- items: [
49
- {
50
- label: `a, b, c`,
51
- value: `${[structure.lattice.a, structure.lattice.b, structure.lattice.c]
52
- .map((val) => format_num(val, `.3~f`))
53
- .join(`, `)} Å`,
54
- key: `real-lattice-abc`,
55
- },
56
- {
57
- label: `α, β, γ`,
58
- value: `${[structure.lattice.alpha, structure.lattice.beta, structure.lattice.gamma]
59
- .map((val) => format_num(val, `.2~f`))
60
- .join(`, `)}°`,
61
- key: `real-lattice-angles`,
62
- },
63
- ],
64
- });
71
+ title: `Real Lattice`,
72
+ items: [
73
+ {
74
+ label: `a, b, c`,
75
+ value: `${
76
+ [structure.lattice.a, structure.lattice.b, structure.lattice.c]
77
+ .map((val) => format_num(val, `.3~f`))
78
+ .join(`, `)
79
+ } Å`,
80
+ key: `real-lattice-abc`,
81
+ },
82
+ {
83
+ label: `α, β, γ`,
84
+ value: `${
85
+ [structure.lattice.alpha, structure.lattice.beta, structure.lattice.gamma]
86
+ .map((val) => format_num(val, `.2~f`))
87
+ .join(`, `)
88
+ }°`,
89
+ key: `real-lattice-angles`,
90
+ },
91
+ ],
92
+ })
93
+
65
94
  // Reciprocal Lattice section
66
- const k_lattice_items = bz_data.k_lattice.map((vec, idx) => ({
67
- label: [`b₁`, `b₂`, `b₃`][idx],
68
- value: `(${vec.map((x) => format_num(x, `.3~f`)).join(`, `)})`,
69
- key: `reciprocal-${[`b1`, `b2`, `b3`][idx]}`,
70
- }));
71
- sections.push({ title: `Reciprocal Lattice (Å⁻¹)`, items: k_lattice_items });
72
- return sections;
73
- });
95
+ const k_lattice_items: InfoItem[] = bz_data.k_lattice.map((vec, idx) => ({
96
+ label: [`b₁`, `b₂`, `b₃`][idx],
97
+ value: `(${vec.map((x) => format_num(x, `.3~f`)).join(`, `)})`,
98
+ key: `reciprocal-${[`b1`, `b2`, `b3`][idx]}`,
99
+ }))
100
+
101
+ sections.push({ title: `Reciprocal Lattice (Å⁻¹)`, items: k_lattice_items })
102
+
103
+ return sections
104
+ })
74
105
  </script>
75
106
 
76
107
  {#if structure && bz_data}
@@ -88,7 +119,7 @@ let pane_data = $derived.by(() => {
88
119
  {#each section.items as item (item.key ?? item.label)}
89
120
  <div class="info-item">
90
121
  <span>{item.label}</span>
91
- <span>{@html item.value}</span>
122
+ <span>{@html sanitize_html(item.value)}</span>
92
123
  </div>
93
124
  {/each}
94
125
  </section>
@@ -1,59 +1,150 @@
1
- <script lang="ts">import { AXIS_COLORS, NEG_AXIS_COLORS } from '../colors';
2
- import * as math from '../math';
3
- import { DEFAULTS } from '../settings';
4
- import Arrow from '../structure/Arrow.svelte';
5
- import Cylinder from '../structure/Cylinder.svelte';
6
- import { T, useThrelte } from '@threlte/core';
7
- import * as extras from '@threlte/extras';
8
- import { BufferAttribute, BufferGeometry, Vector3 } from 'three';
9
- let { bz_data = $bindable(), camera_position = $bindable(), camera_projection = $bindable(`perspective`), surface_color = $bindable(`#4488ff`), surface_opacity = $bindable(0.3), edge_color = $bindable(`#000000`), edge_width = $bindable(0.05), show_vectors = $bindable(true), vector_scale = $bindable(1.0),
10
- // Irreducible BZ options
11
- show_ibz = false, ibz_data = null, ibz_color = `#ff8844`, ibz_opacity = 0.5, rotation_damping = DEFAULTS.structure.rotation_damping, max_zoom = DEFAULTS.structure.max_zoom, min_zoom = DEFAULTS.structure.min_zoom, rotate_speed = DEFAULTS.structure.rotate_speed, zoom_speed = DEFAULTS.structure.zoom_speed, pan_speed = DEFAULTS.structure.pan_speed, zoom_to_cursor = DEFAULTS.structure.zoom_to_cursor, fov = DEFAULTS.structure.fov, initial_zoom = DEFAULTS.structure.initial_zoom, ambient_light = DEFAULTS.structure.ambient_light, directional_light = DEFAULTS.structure.directional_light, gizmo = DEFAULTS.structure.show_gizmo, auto_rotate = DEFAULTS.structure.auto_rotate, camera_is_moving = $bindable(false), scene = $bindable(), camera = $bindable(), k_path_points = [], k_path_labels = [], hovered_k_point = null, hovered_qpoint_index = null, hover_data = $bindable(null), } = $props();
12
- const threlte = useThrelte();
13
- $effect(() => {
14
- scene = threlte.scene;
15
- camera = threlte.camera.current;
1
+ <script lang="ts">
2
+ import { AXIS_COLORS, NEG_AXIS_COLORS } from '../colors'
3
+ import type { Vec3 } from '../math'
4
+ import * as math from '../math'
5
+ import { type CameraProjection, DEFAULTS } from '../settings'
6
+ import Arrow from '../structure/Arrow.svelte'
7
+ import Cylinder from '../structure/Cylinder.svelte'
8
+ import { T, useThrelte } from '@threlte/core'
9
+ import * as extras from '@threlte/extras'
10
+ import type { ComponentProps } from 'svelte'
11
+ import type { Camera, Scene } from 'three'
12
+ import { BufferAttribute, BufferGeometry, Vector3 } from 'three'
13
+ import type { BrillouinZoneData, BZHoverData, IrreducibleBZData } from './types'
14
+
15
+ // Threlte pointer event type for mesh interactions
16
+ type ThreltePointerEvent = { point: Vector3; nativeEvent: PointerEvent }
17
+
18
+ let {
19
+ bz_data = $bindable(),
20
+ camera_position = $bindable(),
21
+ camera_projection = $bindable(`perspective`),
22
+ surface_color = $bindable(`#4488ff`),
23
+ surface_opacity = $bindable(0.3),
24
+ edge_color = $bindable(`#000000`),
25
+ edge_width = $bindable(0.05),
26
+ show_vectors = $bindable(true),
27
+ vector_scale = $bindable(1.0),
28
+ // Irreducible BZ options
29
+ show_ibz = false,
30
+ ibz_data = null as IrreducibleBZData | null,
31
+ ibz_color = `#ff8844`,
32
+ ibz_opacity = 0.5,
33
+ rotation_damping = DEFAULTS.structure.rotation_damping,
34
+ max_zoom = DEFAULTS.structure.max_zoom,
35
+ min_zoom = DEFAULTS.structure.min_zoom,
36
+ rotate_speed = DEFAULTS.structure.rotate_speed,
37
+ zoom_speed = DEFAULTS.structure.zoom_speed,
38
+ pan_speed = DEFAULTS.structure.pan_speed,
39
+ zoom_to_cursor = DEFAULTS.structure.zoom_to_cursor,
40
+ fov = DEFAULTS.structure.fov,
41
+ initial_zoom = DEFAULTS.structure.initial_zoom,
42
+ ambient_light = DEFAULTS.structure.ambient_light,
43
+ directional_light = DEFAULTS.structure.directional_light,
44
+ gizmo = DEFAULTS.structure.show_gizmo,
45
+ auto_rotate = DEFAULTS.structure.auto_rotate,
46
+ camera_is_moving = $bindable(false),
47
+ scene = $bindable(),
48
+ camera = $bindable(),
49
+ k_path_points = [],
50
+ k_path_labels = [],
51
+ hovered_k_point = null,
52
+ hovered_qpoint_index = null,
53
+ hover_data = $bindable<BZHoverData | null>(null),
54
+ }: {
55
+ bz_data?: BrillouinZoneData
56
+ camera_position?: Vec3 | undefined
57
+ camera_projection?: CameraProjection
58
+ surface_color?: string
59
+ surface_opacity?: number
60
+ edge_color?: string
61
+ edge_width?: number
62
+ show_vectors?: boolean
63
+ vector_scale?: number
64
+ // Irreducible BZ options
65
+ show_ibz?: boolean
66
+ ibz_data?: IrreducibleBZData | null
67
+ ibz_color?: string
68
+ ibz_opacity?: number
69
+ rotation_damping?: number
70
+ max_zoom?: number
71
+ min_zoom?: number
72
+ rotate_speed?: number
73
+ zoom_speed?: number
74
+ pan_speed?: number
75
+ zoom_to_cursor?: boolean
76
+ fov?: number
77
+ initial_zoom?: number
78
+ ambient_light?: number
79
+ directional_light?: number
80
+ gizmo?: boolean | ComponentProps<typeof extras.Gizmo>
81
+ auto_rotate?: number
82
+ camera_is_moving?: boolean
83
+ scene?: Scene
84
+ camera?: Camera
85
+ k_path_points?: Vec3[]
86
+ k_path_labels?: { position: Vec3; label: string | null }[]
87
+ hovered_k_point?: Vec3 | null
88
+ hovered_qpoint_index?: number | null
89
+ hover_data?: BZHoverData | null
90
+ } = $props()
91
+
92
+ const threlte = useThrelte()
93
+ $effect(() => {
94
+ scene = threlte.scene
95
+ camera = threlte.camera.current
16
96
  if (threlte.renderer) {
17
- Object.assign(threlte.renderer.domElement, { __renderer: threlte.renderer });
97
+ Object.assign(threlte.renderer.domElement, { __renderer: threlte.renderer })
18
98
  }
19
- });
20
- extras.interactivity();
21
- // Compute centroid of BZ vertices for proper rotation center
22
- const rotation_target = $derived.by(() => {
23
- if (!bz_data?.vertices || bz_data.vertices.length === 0)
24
- return [0, 0, 0];
25
- const sum = bz_data.vertices.reduce((acc, v) => math.add(acc, v), [0, 0, 0]);
26
- return math.scale(sum, 1 / bz_data.vertices.length);
27
- });
28
- // BZ size for camera positioning: average magnitude of k-vectors
29
- const bz_size = $derived.by(() => {
30
- if (!bz_data?.k_lattice)
31
- return 10;
32
- const mags = bz_data.k_lattice.map((vec) => Math.hypot(...vec));
33
- return mags.reduce((sum, mag) => sum + mag, 0) / 3;
34
- });
35
- const computed_camera_position = $derived.by(() => camera_position || [10, 3, 8].map((x) => x * Math.max(1, bz_size)));
36
- const gizmo_props = $derived({
99
+ })
100
+
101
+ extras.interactivity()
102
+
103
+ // Compute centroid of BZ vertices for proper rotation center
104
+ const rotation_target = $derived.by((): Vec3 => {
105
+ if (!bz_data?.vertices || bz_data.vertices.length === 0) return [0, 0, 0]
106
+ const sum = bz_data.vertices.reduce(
107
+ (acc, v) => math.add(acc, v),
108
+ [0, 0, 0] as Vec3,
109
+ )
110
+ return math.scale(sum, 1 / bz_data.vertices.length)
111
+ })
112
+
113
+ // BZ size for camera positioning: average magnitude of k-vectors
114
+ const bz_size = $derived.by(() => {
115
+ if (!bz_data?.k_lattice) return 10
116
+ const mags = bz_data.k_lattice.map((vec) => Math.hypot(...vec))
117
+ return mags.reduce((sum, mag) => sum + mag, 0) / 3
118
+ })
119
+
120
+ const computed_camera_position = $derived.by(() =>
121
+ camera_position || ([10, 3, 8].map((x) => x * Math.max(1, bz_size)) as Vec3)
122
+ )
123
+
124
+ const gizmo_props = $derived({
37
125
  background: { enabled: false },
38
126
  className: `responsive-gizmo`,
39
- ...Object.fromEntries([...AXIS_COLORS, ...NEG_AXIS_COLORS].map(([axis, color, hover]) => [
127
+ ...Object.fromEntries(
128
+ [...AXIS_COLORS, ...NEG_AXIS_COLORS].map(([axis, color, hover]) => [
40
129
  axis,
41
130
  {
42
- color,
43
- labelColor: `#111`,
44
- opacity: axis.startsWith(`n`) ? 0.9 : 0.8,
45
- hover: {
46
- color: hover,
47
- labelColor: `#222`,
48
- opacity: axis.startsWith(`n`) ? 1 : 0.9,
49
- },
131
+ color,
132
+ labelColor: `#111`,
133
+ opacity: axis.startsWith(`n`) ? 0.9 : 0.8,
134
+ hover: {
135
+ color: hover,
136
+ labelColor: `#222`,
137
+ opacity: axis.startsWith(`n`) ? 1 : 0.9,
138
+ },
50
139
  },
51
- ])),
140
+ ]),
141
+ ),
52
142
  ...(typeof gizmo === `object` ? gizmo : {}),
53
143
  offset: { left: 5, bottom: 5 },
54
- });
55
- const is_ortho = $derived(camera_projection === `orthographic`);
56
- const orbit_controls_props = $derived({
144
+ })
145
+
146
+ const is_ortho = $derived(camera_projection === `orthographic`)
147
+ const orbit_controls_props = $derived({
57
148
  position: [0, 0, 0],
58
149
  target: rotation_target,
59
150
  enableRotate: rotate_speed > 0,
@@ -71,134 +162,155 @@ const orbit_controls_props = $derived({
71
162
  dampingFactor: rotation_damping,
72
163
  onstart: () => (camera_is_moving = true),
73
164
  onend: () => (camera_is_moving = false),
74
- });
75
- const vector_colors = [`red`, `green`, `blue`];
76
- const vector_labels = [`b₁`, `b₂`, `b₃`];
77
- // Create mesh geometry from faces with fan triangulation
78
- function create_mesh_geometry(vertices, faces) {
79
- if (faces.length === 0)
80
- return null;
81
- const positions = [];
82
- const normals = [];
165
+ })
166
+
167
+ const vector_colors = [`red`, `green`, `blue`]
168
+ const vector_labels = [`b₁`, `b₂`, `b₃`]
169
+
170
+ // Create mesh geometry from faces with fan triangulation
171
+ function create_mesh_geometry(
172
+ vertices: Vec3[],
173
+ faces: number[][],
174
+ ): BufferGeometry | null {
175
+ if (faces.length === 0) return null
176
+
177
+ const positions: number[] = []
178
+ const normals: number[] = []
179
+
83
180
  for (const face of faces) {
84
- if (face.length < 3)
85
- continue;
86
- for (let face_idx = 1; face_idx < face.length - 1; face_idx++) {
87
- const indices = [face[0], face[face_idx], face[face_idx + 1]];
88
- if (indices.some((idx) => idx < 0 || idx >= vertices.length))
89
- continue;
90
- const [v0, v1, v2] = indices.map((idx) => vertices[idx]);
91
- positions.push(...v0, ...v1, ...v2);
92
- const e1 = math.subtract(v1, v0);
93
- const e2 = math.subtract(v2, v0);
94
- const normal_vec = math.cross_3d(e1, e2);
95
- const len = Math.hypot(...normal_vec);
96
- const norm = len > 1e-10 ? normal_vec.map((x) => x / len) : [0, 0, 0];
97
- normals.push(...norm, ...norm, ...norm);
98
- }
181
+ if (face.length < 3) continue
182
+ for (let face_idx = 1; face_idx < face.length - 1; face_idx++) {
183
+ const indices = [face[0], face[face_idx], face[face_idx + 1]]
184
+ if (indices.some((idx) => idx < 0 || idx >= vertices.length)) continue
185
+ const [v0, v1, v2] = indices.map((idx) => vertices[idx])
186
+ positions.push(...v0, ...v1, ...v2)
187
+
188
+ const e1: Vec3 = math.subtract(v1, v0)
189
+ const e2: Vec3 = math.subtract(v2, v0)
190
+ const normal_vec = math.cross_3d(e1, e2)
191
+ const len = Math.hypot(...normal_vec)
192
+ const norm = len > 1e-10 ? normal_vec.map((x) => x / len) : [0, 0, 0]
193
+ normals.push(...norm, ...norm, ...norm)
194
+ }
99
195
  }
100
- const geometry = new BufferGeometry();
101
- geometry.setAttribute(`position`, new BufferAttribute(new Float32Array(positions), 3));
102
- geometry.setAttribute(`normal`, new BufferAttribute(new Float32Array(normals), 3));
103
- geometry.computeBoundingSphere();
104
- return geometry;
105
- }
106
- const bz_geometry = $derived(bz_data ? create_mesh_geometry(bz_data.vertices, bz_data.faces) : null);
107
- const ibz_geometry = $derived(show_ibz && ibz_data
108
- ? create_mesh_geometry(ibz_data.vertices, ibz_data.faces)
109
- : null);
110
- // Separate effects to avoid disposing one geometry when only the other changes
111
- $effect(() => {
112
- const prev = bz_geometry;
113
- return () => prev?.dispose();
114
- });
115
- $effect(() => {
116
- const prev = ibz_geometry;
117
- return () => prev?.dispose();
118
- });
119
- // Compute inverse of k_lattice for Cartesian->fractional conversion
120
- const k_lattice_inv = $derived.by(() => {
121
- if (!bz_data?.k_lattice)
122
- return null;
196
+
197
+ const geometry = new BufferGeometry()
198
+ geometry.setAttribute(
199
+ `position`,
200
+ new BufferAttribute(new Float32Array(positions), 3),
201
+ )
202
+ geometry.setAttribute(`normal`, new BufferAttribute(new Float32Array(normals), 3))
203
+ geometry.computeBoundingSphere()
204
+ return geometry
205
+ }
206
+
207
+ const bz_geometry = $derived(
208
+ bz_data ? create_mesh_geometry(bz_data.vertices, bz_data.faces) : null,
209
+ )
210
+ const ibz_geometry = $derived(
211
+ show_ibz && ibz_data
212
+ ? create_mesh_geometry(ibz_data.vertices, ibz_data.faces)
213
+ : null,
214
+ )
215
+
216
+ // Separate effects to avoid disposing one geometry when only the other changes
217
+ $effect(() => {
218
+ const prev = bz_geometry
219
+ return () => prev?.dispose()
220
+ })
221
+ $effect(() => {
222
+ const prev = ibz_geometry
223
+ return () => prev?.dispose()
224
+ })
225
+
226
+ // Compute inverse of k_lattice for Cartesian->fractional conversion
227
+ const k_lattice_inv = $derived.by(() => {
228
+ if (!bz_data?.k_lattice) return null
123
229
  try {
124
- return math.matrix_inverse_3x3(bz_data.k_lattice);
125
- }
126
- catch {
127
- return null;
230
+ return math.matrix_inverse_3x3(bz_data.k_lattice)
231
+ } catch {
232
+ return null
128
233
  }
129
- });
130
- // Convert Cartesian k-coordinates to fractional (reciprocal lattice units)
131
- function cartesian_to_fractional(cart) {
132
- if (!k_lattice_inv)
133
- return null;
134
- return math.mat3x3_vec3_multiply(k_lattice_inv, cart);
135
- }
136
- // Throttle state for pointer move events
137
- let last_hover_time = 0;
138
- let last_hover_mesh = null;
139
- const HOVER_THROTTLE_MS = 16; // ~60fps
140
- // Reset throttle when bz_data changes to ensure immediate response
141
- $effect(() => {
234
+ })
235
+
236
+ // Convert Cartesian k-coordinates to fractional (reciprocal lattice units)
237
+ function cartesian_to_fractional(cart: Vec3): Vec3 | null {
238
+ if (!k_lattice_inv) return null
239
+ return math.mat3x3_vec3_multiply(k_lattice_inv, cart)
240
+ }
241
+
242
+ // Throttle state for pointer move events
243
+ let last_hover_time = 0
244
+ let last_hover_mesh: `bz` | `ibz` | null = null
245
+ const HOVER_THROTTLE_MS = 16 // ~60fps
246
+
247
+ // Reset throttle when bz_data changes to ensure immediate response
248
+ $effect(() => {
142
249
  if (bz_data) {
143
- last_hover_time = 0;
144
- last_hover_mesh = null;
250
+ last_hover_time = 0
251
+ last_hover_mesh = null
145
252
  }
146
- });
147
- // Track IBZ hover state - IBZ takes priority over BZ
148
- let ibz_hovered = false;
149
- $effect(() => {
253
+ })
254
+
255
+ // Track IBZ hover state - IBZ takes priority over BZ
256
+ let ibz_hovered = false
257
+ $effect(() => {
150
258
  if (!show_ibz) {
151
- ibz_hovered = false;
152
- // Clear hover tooltip if it was showing IBZ data
153
- if (hover_data?.is_ibz)
154
- hover_data = null;
259
+ ibz_hovered = false
260
+ // Clear hover tooltip if it was showing IBZ data
261
+ if (hover_data?.is_ibz) hover_data = null
155
262
  }
156
- });
157
- // Create hover data from pointer event
158
- function create_hover_data(event, is_ibz) {
159
- if (!bz_data)
160
- return null;
161
- const position_cartesian = [event.point.x, event.point.y, event.point.z];
162
- const position_fractional = cartesian_to_fractional(position_cartesian);
163
- const { clientX, clientY } = event.nativeEvent;
164
- const ibz_vol = ibz_data?.volume ?? null;
263
+ })
264
+
265
+ // Create hover data from pointer event
266
+ function create_hover_data(
267
+ event: ThreltePointerEvent,
268
+ is_ibz: boolean,
269
+ ): BZHoverData | null {
270
+ if (!bz_data) return null
271
+
272
+ const position_cartesian: Vec3 = [event.point.x, event.point.y, event.point.z]
273
+ const position_fractional = cartesian_to_fractional(position_cartesian)
274
+
275
+ const { clientX, clientY } = event.nativeEvent
276
+ const ibz_vol = ibz_data?.volume ?? null
165
277
  // Round to nearest integer since symmetry multiplicity is the point group order
166
278
  const symmetry_multiplicity = ibz_vol != null && ibz_vol > 0
167
- ? Math.round(bz_data.volume / ibz_vol)
168
- : null;
279
+ ? Math.round(bz_data.volume / ibz_vol)
280
+ : null
281
+
169
282
  return {
170
- position_cartesian,
171
- position_fractional,
172
- screen_position: { x: clientX, y: clientY },
173
- is_ibz,
174
- bz_order: bz_data.order,
175
- bz_volume: bz_data.volume,
176
- ibz_volume: ibz_vol,
177
- symmetry_multiplicity,
178
- };
179
- }
180
- // Throttled hover handler - IBZ takes priority over BZ
181
- function handle_hover(event, is_ibz) {
182
- if (is_ibz)
183
- ibz_hovered = true;
184
- else if (ibz_hovered)
185
- return; // BZ defers to IBZ
186
- const mesh = is_ibz ? `ibz` : `bz`;
187
- const now = performance.now();
283
+ position_cartesian,
284
+ position_fractional,
285
+ screen_position: { x: clientX, y: clientY },
286
+ is_ibz,
287
+ bz_order: bz_data.order,
288
+ bz_volume: bz_data.volume,
289
+ ibz_volume: ibz_vol,
290
+ symmetry_multiplicity,
291
+ }
292
+ }
293
+
294
+ // Throttled hover handler - IBZ takes priority over BZ
295
+ function handle_hover(event: ThreltePointerEvent, is_ibz: boolean): void {
296
+ if (is_ibz) ibz_hovered = true
297
+ else if (ibz_hovered) return // BZ defers to IBZ
298
+
299
+ const mesh = is_ibz ? `ibz` : `bz`
300
+ const now = performance.now()
188
301
  // Bypass throttle when switching meshes for responsive transitions
189
- if (last_hover_mesh === mesh && now - last_hover_time < HOVER_THROTTLE_MS)
190
- return;
191
- last_hover_time = now;
192
- last_hover_mesh = mesh;
193
- hover_data = create_hover_data(event, is_ibz);
194
- }
195
- // Leave handler - IBZ clears state, BZ only clears if IBZ not hovered
196
- function handle_leave(is_ibz) {
197
- if (is_ibz)
198
- ibz_hovered = false;
199
- if (is_ibz || !ibz_hovered)
200
- hover_data = null;
201
- }
302
+ if (last_hover_mesh === mesh && now - last_hover_time < HOVER_THROTTLE_MS) return
303
+
304
+ last_hover_time = now
305
+ last_hover_mesh = mesh
306
+ hover_data = create_hover_data(event, is_ibz)
307
+ }
308
+
309
+ // Leave handler - IBZ clears state, BZ only clears if IBZ not hovered
310
+ function handle_leave(is_ibz: boolean): void {
311
+ if (is_ibz) ibz_hovered = false
312
+ if (is_ibz || !ibz_hovered) hover_data = null
313
+ }
202
314
  </script>
203
315
 
204
316
  {#if camera_projection === `perspective`}