matterviz 0.4.1 → 0.4.2

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 (395) hide show
  1. package/dist/EmptyState.svelte +10 -4
  2. package/dist/FilePicker.svelte +12 -14
  3. package/dist/Icon.svelte +7 -4
  4. package/dist/MillerIndexInput.svelte +2 -2
  5. package/dist/app.css +53 -0
  6. package/dist/brillouin/BrillouinZone.svelte +75 -85
  7. package/dist/brillouin/BrillouinZone.svelte.d.ts +5 -7
  8. package/dist/brillouin/BrillouinZoneControls.svelte +3 -6
  9. package/dist/brillouin/BrillouinZoneExportPane.svelte +18 -14
  10. package/dist/brillouin/BrillouinZoneInfoPane.svelte +6 -10
  11. package/dist/brillouin/BrillouinZoneScene.svelte +26 -39
  12. package/dist/brillouin/BrillouinZoneScene.svelte.d.ts +1 -1
  13. package/dist/chempot-diagram/ChemPotDiagram.svelte +33 -38
  14. package/dist/chempot-diagram/ChemPotDiagram2D.svelte +62 -74
  15. package/dist/chempot-diagram/ChemPotDiagram2D.svelte.d.ts +1 -1
  16. package/dist/chempot-diagram/ChemPotDiagram3D.svelte +511 -547
  17. package/dist/chempot-diagram/ChemPotDiagram3D.svelte.d.ts +1 -1
  18. package/dist/chempot-diagram/async-compute.svelte.js +1 -1
  19. package/dist/chempot-diagram/controls-state.svelte.js +1 -1
  20. package/dist/colors/index.d.ts +0 -4
  21. package/dist/colors/index.js +19 -20
  22. package/dist/composition/BarChart.svelte +37 -31
  23. package/dist/composition/BubbleChart.svelte +17 -17
  24. package/dist/composition/Composition.svelte +7 -11
  25. package/dist/composition/Formula.svelte +18 -25
  26. package/dist/composition/FormulaFilter.svelte +92 -95
  27. package/dist/composition/PieChart.svelte +55 -41
  28. package/dist/composition/format.js +1 -1
  29. package/dist/composition/index.d.ts +2 -0
  30. package/dist/composition/index.js +14 -0
  31. package/dist/composition/parse.d.ts +2 -2
  32. package/dist/composition/parse.js +11 -10
  33. package/dist/constants.js +11 -9
  34. package/dist/convex-hull/ConvexHull.svelte +12 -15
  35. package/dist/convex-hull/ConvexHull.svelte.d.ts +1 -1
  36. package/dist/convex-hull/ConvexHull2D.svelte +93 -92
  37. package/dist/convex-hull/ConvexHull2D.svelte.d.ts +1 -1
  38. package/dist/convex-hull/ConvexHull3D.svelte +109 -140
  39. package/dist/convex-hull/ConvexHull3D.svelte.d.ts +1 -1
  40. package/dist/convex-hull/ConvexHull4D.svelte +75 -94
  41. package/dist/convex-hull/ConvexHull4D.svelte.d.ts +1 -1
  42. package/dist/convex-hull/ConvexHullChrome.svelte +36 -40
  43. package/dist/convex-hull/ConvexHullControls.svelte +46 -48
  44. package/dist/convex-hull/ConvexHullStats.svelte +193 -195
  45. package/dist/convex-hull/ConvexHullTooltip.svelte +5 -12
  46. package/dist/convex-hull/GasPressureControls.svelte +5 -12
  47. package/dist/convex-hull/StructurePopup.svelte +17 -21
  48. package/dist/convex-hull/StructurePopup.svelte.d.ts +2 -0
  49. package/dist/convex-hull/TemperatureSlider.svelte +4 -10
  50. package/dist/convex-hull/canvas-interactions.svelte.js +2 -1
  51. package/dist/convex-hull/helpers.d.ts +8 -10
  52. package/dist/convex-hull/helpers.js +36 -36
  53. package/dist/convex-hull/hull-state.svelte.d.ts +1 -1
  54. package/dist/convex-hull/thermodynamics.js +18 -17
  55. package/dist/coordination/CoordinationBarPlot.svelte +38 -33
  56. package/dist/coordination/CoordinationBarPlot.svelte.d.ts +1 -1
  57. package/dist/coordination/calc-coordination.d.ts +1 -1
  58. package/dist/coordination/calc-coordination.js +28 -25
  59. package/dist/element/BohrAtom.svelte +5 -8
  60. package/dist/element/ElementHeading.svelte +4 -1
  61. package/dist/element/ElementPhoto.svelte +11 -9
  62. package/dist/element/ElementStats.svelte +12 -10
  63. package/dist/element/ElementTile.svelte +24 -29
  64. package/dist/element/Nucleus.svelte +4 -2
  65. package/dist/element/data.d.ts +1 -2
  66. package/dist/element/helpers.d.ts +4 -0
  67. package/dist/element/helpers.js +18 -0
  68. package/dist/element/index.d.ts +1 -4
  69. package/dist/element/index.js +3 -18
  70. package/dist/feedback/DragOverlay.svelte +5 -5
  71. package/dist/feedback/DragOverlay.svelte.d.ts +2 -2
  72. package/dist/feedback/StatusMessage.svelte +7 -4
  73. package/dist/fermi-surface/FermiSlice.svelte +21 -18
  74. package/dist/fermi-surface/FermiSurface.svelte +14 -22
  75. package/dist/fermi-surface/FermiSurface.svelte.d.ts +5 -7
  76. package/dist/fermi-surface/FermiSurfaceControls.svelte +6 -20
  77. package/dist/fermi-surface/FermiSurfaceControls.svelte.d.ts +1 -1
  78. package/dist/fermi-surface/FermiSurfaceScene.svelte +37 -64
  79. package/dist/fermi-surface/FermiSurfaceScene.svelte.d.ts +1 -1
  80. package/dist/fermi-surface/FermiSurfaceTooltip.svelte +9 -6
  81. package/dist/fermi-surface/compute.js +3 -3
  82. package/dist/fermi-surface/parse.js +22 -24
  83. package/dist/heatmap-matrix/HeatmapMatrix.svelte +109 -148
  84. package/dist/heatmap-matrix/HeatmapMatrix.svelte.d.ts +2 -2
  85. package/dist/heatmap-matrix/HeatmapMatrixControls.svelte +9 -7
  86. package/dist/heatmap-matrix/HeatmapMatrixControls.svelte.d.ts +1 -1
  87. package/dist/heatmap-matrix/index.d.ts +5 -0
  88. package/dist/icons.d.ts +4 -0
  89. package/dist/icons.js +4 -0
  90. package/dist/io/ExportPane.svelte +10 -6
  91. package/dist/io/decompress.d.ts +2 -1
  92. package/dist/io/decompress.js +22 -35
  93. package/dist/io/export.d.ts +4 -0
  94. package/dist/io/export.js +5 -1
  95. package/dist/io/fetch.d.ts +0 -3
  96. package/dist/io/fetch.js +0 -11
  97. package/dist/io/index.d.ts +0 -1
  98. package/dist/io/index.js +2 -9
  99. package/dist/io/is-binary.d.ts +9 -0
  100. package/dist/io/is-binary.js +45 -1
  101. package/dist/io/url-drop.js +13 -25
  102. package/dist/isosurface/Isosurface.svelte +17 -23
  103. package/dist/isosurface/IsosurfaceControls.svelte +37 -42
  104. package/dist/isosurface/parse-vaspwave.d.ts +3 -0
  105. package/dist/isosurface/parse-vaspwave.js +138 -0
  106. package/dist/isosurface/parse.js +6 -6
  107. package/dist/labels.d.ts +6 -2
  108. package/dist/labels.js +43 -13
  109. package/dist/layout/FullscreenButton.svelte +2 -1
  110. package/dist/layout/FullscreenToggle.svelte +10 -4
  111. package/dist/layout/InfoCard.svelte +7 -18
  112. package/dist/layout/InfoTag.svelte +1 -3
  113. package/dist/layout/NumberRangeInput.svelte +46 -0
  114. package/dist/layout/NumberRangeInput.svelte.d.ts +12 -0
  115. package/dist/layout/PropertyFilter.svelte +2 -6
  116. package/dist/layout/SettingsSection.svelte +21 -17
  117. package/dist/layout/SubpageGrid.svelte +3 -1
  118. package/dist/layout/ViewerChrome.svelte +9 -10
  119. package/dist/layout/ViewerChrome.svelte.d.ts +2 -1
  120. package/dist/layout/fullscreen.js +3 -5
  121. package/dist/layout/fullscreen.svelte.js +1 -2
  122. package/dist/layout/index.d.ts +1 -0
  123. package/dist/layout/index.js +1 -0
  124. package/dist/layout/json-tree/JsonNode.svelte +8 -11
  125. package/dist/layout/json-tree/JsonTree.svelte +53 -77
  126. package/dist/layout/json-tree/JsonValue.svelte +7 -15
  127. package/dist/layout/json-tree/utils.js +14 -23
  128. package/dist/math.d.ts +2 -0
  129. package/dist/math.js +19 -0
  130. package/dist/overlays/ContextMenu.svelte +4 -2
  131. package/dist/overlays/CopyButton.svelte +11 -5
  132. package/dist/overlays/DragControlTab.svelte +6 -1
  133. package/dist/overlays/DraggablePane.svelte +81 -26
  134. package/dist/overlays/DraggablePane.svelte.d.ts +1 -0
  135. package/dist/overlays/GlassChip.svelte +30 -0
  136. package/dist/overlays/GlassChip.svelte.d.ts +8 -0
  137. package/dist/overlays/InfoPaneCards.svelte +11 -23
  138. package/dist/overlays/index.d.ts +7 -0
  139. package/dist/overlays/index.js +26 -0
  140. package/dist/overlays/portal.d.ts +2 -0
  141. package/dist/overlays/portal.js +14 -0
  142. package/dist/periodic-table/PeriodicTable.svelte +113 -145
  143. package/dist/periodic-table/PeriodicTable.svelte.d.ts +5 -3
  144. package/dist/periodic-table/PeriodicTableControls.svelte +11 -63
  145. package/dist/periodic-table/TableInset.svelte +9 -4
  146. package/dist/phase-diagram/IsobaricBinaryPhaseDiagram.svelte +50 -71
  147. package/dist/phase-diagram/IsobaricBinaryPhaseDiagram.svelte.d.ts +6 -8
  148. package/dist/phase-diagram/PhaseDiagramControls.svelte +70 -94
  149. package/dist/phase-diagram/PhaseDiagramControls.svelte.d.ts +1 -1
  150. package/dist/phase-diagram/PhaseDiagramEditorPane.svelte +2 -1
  151. package/dist/phase-diagram/PhaseDiagramExportPane.svelte +12 -12
  152. package/dist/phase-diagram/PhaseDiagramTooltip.svelte +54 -58
  153. package/dist/phase-diagram/TdbInfoPanel.svelte +21 -15
  154. package/dist/phase-diagram/build-diagram.js +3 -3
  155. package/dist/phase-diagram/diagram-input.d.ts +1 -2
  156. package/dist/phase-diagram/parse.js +15 -15
  157. package/dist/phase-diagram/svg-to-diagram.js +21 -15
  158. package/dist/phase-diagram/utils.js +2 -3
  159. package/dist/plot/bar/BarPlot.svelte +430 -391
  160. package/dist/plot/bar/BarPlot.svelte.d.ts +2 -0
  161. package/dist/plot/bar/BarPlotControls.svelte +1 -3
  162. package/dist/plot/bar/BarPlotControls.svelte.d.ts +4 -6
  163. package/dist/plot/bar/SpacegroupBarPlot.svelte +29 -36
  164. package/dist/plot/bar/data.d.ts +5 -4
  165. package/dist/plot/bar/data.js +2 -1
  166. package/dist/plot/box/BoxPlot.svelte +301 -209
  167. package/dist/plot/box/BoxPlot.svelte.d.ts +2 -0
  168. package/dist/plot/box/Violin.svelte.d.ts +1 -0
  169. package/dist/plot/box/box-plot.js +1 -1
  170. package/dist/plot/core/auto-place.js +1 -1
  171. package/dist/plot/core/axis-utils.d.ts +12 -7
  172. package/dist/plot/core/axis-utils.js +48 -48
  173. package/dist/plot/core/components/AxisLabel.svelte +82 -20
  174. package/dist/plot/core/components/AxisLabel.svelte.d.ts +1 -0
  175. package/dist/plot/core/components/ColorBar.svelte +101 -106
  176. package/dist/plot/core/components/ColorScaleSelect.svelte +1 -1
  177. package/dist/plot/core/components/FillArea.svelte +10 -17
  178. package/dist/plot/core/components/HierarchyControls.svelte +249 -0
  179. package/dist/plot/{sunburst/SunburstControls.svelte.d.ts → core/components/HierarchyControls.svelte.d.ts} +12 -8
  180. package/dist/plot/core/components/InteractiveAxisLabel.svelte +1 -1
  181. package/dist/plot/core/components/InteractiveAxisLabel.svelte.d.ts +1 -1
  182. package/dist/plot/core/components/Line.svelte +18 -9
  183. package/dist/plot/core/components/Line.svelte.d.ts +2 -0
  184. package/dist/plot/core/components/PlotAxis.svelte +40 -17
  185. package/dist/plot/core/components/PlotControls.svelte +65 -41
  186. package/dist/plot/core/components/PlotLegend.svelte +31 -35
  187. package/dist/plot/core/components/PlotMarginals.svelte +616 -0
  188. package/dist/plot/core/components/PlotMarginals.svelte.d.ts +15 -0
  189. package/dist/plot/core/components/PlotTooltip.svelte +1 -1
  190. package/dist/plot/core/components/PortalSelect.svelte +4 -8
  191. package/dist/plot/core/components/ReferenceLine.svelte +27 -24
  192. package/dist/plot/core/components/ReferenceLine3D.svelte +54 -57
  193. package/dist/plot/core/components/ReferencePlane.svelte +7 -8
  194. package/dist/plot/core/components/ZeroLines.svelte +4 -8
  195. package/dist/plot/core/components/ZoomRect.svelte +1 -2
  196. package/dist/plot/core/components/index.d.ts +1 -0
  197. package/dist/plot/core/components/index.js +1 -0
  198. package/dist/plot/core/data-cleaning-signal.d.ts +46 -0
  199. package/dist/plot/core/data-cleaning-signal.js +467 -0
  200. package/dist/plot/core/data-cleaning.d.ts +2 -42
  201. package/dist/plot/core/data-cleaning.js +27 -474
  202. package/dist/plot/core/data-transform.js +9 -5
  203. package/dist/plot/core/fill-utils.d.ts +3 -1
  204. package/dist/plot/core/fill-utils.js +28 -6
  205. package/dist/plot/core/index.d.ts +1 -0
  206. package/dist/plot/core/index.js +1 -0
  207. package/dist/plot/core/interactions.js +0 -2
  208. package/dist/plot/core/layout.d.ts +3 -1
  209. package/dist/plot/core/layout.js +22 -13
  210. package/dist/plot/core/marginals.d.ts +170 -0
  211. package/dist/plot/core/marginals.js +436 -0
  212. package/dist/plot/core/reference-line.js +1 -1
  213. package/dist/plot/core/scales.d.ts +23 -0
  214. package/dist/plot/core/scales.js +39 -13
  215. package/dist/plot/core/types/fills.d.ts +101 -0
  216. package/dist/plot/core/types/fills.js +15 -0
  217. package/dist/plot/core/types/plot-3d.d.ts +87 -0
  218. package/dist/plot/core/types/plot-3d.js +4 -0
  219. package/dist/plot/core/types/reference-lines.d.ts +140 -0
  220. package/dist/plot/core/types/reference-lines.js +9 -0
  221. package/dist/plot/core/types.d.ts +29 -324
  222. package/dist/plot/core/types.js +23 -20
  223. package/dist/plot/core/utils/hierarchy-chart.d.ts +51 -0
  224. package/dist/plot/core/utils/hierarchy-chart.js +179 -0
  225. package/dist/plot/core/utils/hierarchy-labels.d.ts +20 -0
  226. package/dist/plot/core/utils/hierarchy-labels.js +99 -0
  227. package/dist/plot/core/utils/label-placement.js +2 -2
  228. package/dist/plot/histogram/Histogram.svelte +304 -325
  229. package/dist/plot/histogram/Histogram.svelte.d.ts +7 -7
  230. package/dist/plot/histogram/HistogramControls.svelte +30 -28
  231. package/dist/plot/histogram/histogram.d.ts +31 -0
  232. package/dist/plot/histogram/histogram.js +70 -0
  233. package/dist/plot/histogram/index.d.ts +1 -0
  234. package/dist/plot/histogram/index.js +1 -0
  235. package/dist/plot/index.d.ts +1 -0
  236. package/dist/plot/index.js +1 -0
  237. package/dist/plot/sankey/Sankey.svelte +78 -69
  238. package/dist/plot/sankey/Sankey.svelte.d.ts +2 -2
  239. package/dist/plot/sankey/SankeyControls.svelte +22 -16
  240. package/dist/plot/scatter/BinnedScatterPlot.svelte +263 -109
  241. package/dist/plot/scatter/BinnedScatterPlot.svelte.d.ts +7 -0
  242. package/dist/plot/scatter/ElementScatter.svelte +4 -1
  243. package/dist/plot/scatter/ScatterPlot.svelte +477 -385
  244. package/dist/plot/scatter/ScatterPlot.svelte.d.ts +2 -0
  245. package/dist/plot/scatter/ScatterPlotControls.svelte +18 -19
  246. package/dist/plot/scatter/ScatterPlotControls.svelte.d.ts +1 -1
  247. package/dist/plot/scatter/ScatterPoint.svelte +16 -9
  248. package/dist/plot/scatter/binned-scatter-types.d.ts +3 -2
  249. package/dist/plot/scatter/binned-scatter-types.js +6 -1
  250. package/dist/plot/scatter/scatter-data.d.ts +1 -1
  251. package/dist/plot/scatter/scatter-data.js +8 -7
  252. package/dist/plot/scatter-3d/ScatterPlot3D.svelte +25 -34
  253. package/dist/plot/scatter-3d/ScatterPlot3D.svelte.d.ts +2 -2
  254. package/dist/plot/scatter-3d/ScatterPlot3DControls.svelte +8 -5
  255. package/dist/plot/scatter-3d/ScatterPlot3DScene.svelte +113 -116
  256. package/dist/plot/scatter-3d/ScatterPlot3DScene.svelte.d.ts +2 -2
  257. package/dist/plot/scatter-3d/Surface3D.svelte +4 -13
  258. package/dist/plot/sunburst/Sunburst.svelte +251 -329
  259. package/dist/plot/sunburst/Sunburst.svelte.d.ts +2 -2
  260. package/dist/plot/sunburst/index.d.ts +1 -1
  261. package/dist/plot/sunburst/index.js +2 -1
  262. package/dist/plot/sunburst/render.d.ts +2 -2
  263. package/dist/plot/sunburst/render.js +47 -22
  264. package/dist/plot/sunburst/sunburst.d.ts +5 -1
  265. package/dist/plot/sunburst/sunburst.js +10 -3
  266. package/dist/plot/treemap/Treemap.svelte +907 -0
  267. package/dist/plot/treemap/Treemap.svelte.d.ts +84 -0
  268. package/dist/plot/treemap/index.d.ts +3 -0
  269. package/dist/plot/treemap/index.js +4 -0
  270. package/dist/plot/treemap/treemap.d.ts +26 -0
  271. package/dist/plot/treemap/treemap.js +99 -0
  272. package/dist/rdf/RdfPlot.svelte +22 -26
  273. package/dist/rdf/RdfPlot.svelte.d.ts +1 -1
  274. package/dist/rdf/calc-rdf.js +4 -8
  275. package/dist/sanitize.js +1 -1
  276. package/dist/scene/bind-renderer.svelte.js +14 -6
  277. package/dist/settings.d.ts +19 -9
  278. package/dist/settings.js +77 -50
  279. package/dist/spectral/Bands.svelte +223 -230
  280. package/dist/spectral/BandsAndDos.svelte +11 -9
  281. package/dist/spectral/BrillouinBandsDos.svelte +19 -27
  282. package/dist/spectral/Dos.svelte +70 -73
  283. package/dist/spectral/helpers.d.ts +3 -3
  284. package/dist/spectral/helpers.js +25 -35
  285. package/dist/state.svelte.js +5 -18
  286. package/dist/structure/Arrow.svelte +5 -18
  287. package/dist/structure/ArrowInstances.svelte +160 -0
  288. package/dist/structure/ArrowInstances.svelte.d.ts +16 -0
  289. package/dist/structure/AtomLegend.svelte +115 -75
  290. package/dist/structure/AtomLegend.svelte.d.ts +1 -1
  291. package/dist/structure/Bond.svelte +31 -23
  292. package/dist/structure/CanvasTooltip.svelte +15 -3
  293. package/dist/structure/CellSelect.svelte +11 -26
  294. package/dist/structure/Cylinder.svelte +24 -40
  295. package/dist/structure/InstancedAtoms.svelte +114 -0
  296. package/dist/structure/InstancedAtoms.svelte.d.ts +15 -0
  297. package/dist/structure/Lattice.svelte +85 -149
  298. package/dist/structure/SiteLabels.svelte +122 -0
  299. package/dist/structure/SiteLabels.svelte.d.ts +18 -0
  300. package/dist/structure/Structure.svelte +473 -419
  301. package/dist/structure/Structure.svelte.d.ts +4 -2
  302. package/dist/structure/StructureCarousel.svelte +630 -0
  303. package/dist/structure/StructureCarousel.svelte.d.ts +19 -0
  304. package/dist/structure/StructureControls.svelte +157 -399
  305. package/dist/structure/StructureControls.svelte.d.ts +1 -1
  306. package/dist/structure/StructureExportPane.svelte +17 -21
  307. package/dist/structure/StructureInfoPane.svelte +72 -66
  308. package/dist/structure/StructureInfoPane.svelte.d.ts +1 -1
  309. package/dist/structure/StructureScene.svelte +467 -476
  310. package/dist/structure/StructureScene.svelte.d.ts +3 -1
  311. package/dist/structure/StructureViewport.svelte +386 -0
  312. package/dist/structure/StructureViewport.svelte.d.ts +63 -0
  313. package/dist/structure/atom-label-placement.d.ts +16 -12
  314. package/dist/structure/atom-label-placement.js +70 -37
  315. package/dist/structure/atom-properties.d.ts +2 -0
  316. package/dist/structure/atom-properties.js +104 -38
  317. package/dist/structure/bonding.d.ts +10 -3
  318. package/dist/structure/bonding.js +84 -28
  319. package/dist/structure/edit-history.d.ts +6 -0
  320. package/dist/structure/edit-history.js +27 -0
  321. package/dist/structure/export.d.ts +1 -0
  322. package/dist/structure/export.js +39 -31
  323. package/dist/structure/format-detect.d.ts +1 -0
  324. package/dist/structure/format-detect.js +22 -0
  325. package/dist/structure/geometry.d.ts +9 -0
  326. package/dist/structure/geometry.js +27 -0
  327. package/dist/structure/index.d.ts +16 -1
  328. package/dist/structure/index.js +13 -2
  329. package/dist/structure/measure.d.ts +1 -1
  330. package/dist/structure/measure.js +6 -12
  331. package/dist/structure/parse.d.ts +2 -1
  332. package/dist/structure/parse.js +243 -222
  333. package/dist/structure/partial-occupancy.js +4 -2
  334. package/dist/structure/pbc.js +78 -98
  335. package/dist/structure/polyhedra.d.ts +0 -1
  336. package/dist/structure/polyhedra.js +3 -18
  337. package/dist/structure/supercell.d.ts +1 -2
  338. package/dist/structure/supercell.js +7 -13
  339. package/dist/symmetry/SymmetryElements.svelte +11 -15
  340. package/dist/symmetry/SymmetryStats.svelte +56 -68
  341. package/dist/symmetry/WyckoffTable.svelte +5 -24
  342. package/dist/symmetry/cell-transform.js +1 -0
  343. package/dist/symmetry/index.d.ts +1 -0
  344. package/dist/symmetry/index.js +8 -2
  345. package/dist/symmetry/spacegroups.js +3 -2
  346. package/dist/table/HeatmapTable.svelte +1102 -365
  347. package/dist/table/HeatmapTable.svelte.d.ts +12 -2
  348. package/dist/table/ToggleMenu.svelte +5 -12
  349. package/dist/table/index.d.ts +21 -6
  350. package/dist/table/index.js +34 -21
  351. package/dist/theme/ThemeControl.svelte +16 -8
  352. package/dist/theme/index.d.ts +1 -5
  353. package/dist/theme/index.js +4 -10
  354. package/dist/theme/themes.mjs +14 -7
  355. package/dist/tooltip/KCoords.svelte +4 -1
  356. package/dist/tooltip/TooltipContent.svelte +2 -5
  357. package/dist/trajectory/Trajectory.svelte +515 -308
  358. package/dist/trajectory/Trajectory.svelte.d.ts +1 -1
  359. package/dist/trajectory/TrajectoryError.svelte +11 -8
  360. package/dist/trajectory/TrajectoryExportPane.svelte +14 -31
  361. package/dist/trajectory/TrajectoryInfoPane.svelte +85 -97
  362. package/dist/trajectory/extract.js +56 -34
  363. package/dist/trajectory/format-detect.js +11 -9
  364. package/dist/trajectory/frame-reader.d.ts +2 -0
  365. package/dist/trajectory/frame-reader.js +33 -29
  366. package/dist/trajectory/helpers.d.ts +2 -0
  367. package/dist/trajectory/helpers.js +18 -7
  368. package/dist/trajectory/index.d.ts +1 -0
  369. package/dist/trajectory/index.js +3 -0
  370. package/dist/trajectory/parse/h5-utils.d.ts +13 -0
  371. package/dist/trajectory/parse/h5-utils.js +109 -0
  372. package/dist/trajectory/parse/hdf5.d.ts +1 -1
  373. package/dist/trajectory/parse/hdf5.js +116 -106
  374. package/dist/trajectory/parse/index.d.ts +2 -3
  375. package/dist/trajectory/parse/index.js +17 -20
  376. package/dist/trajectory/parse/lammps.js +8 -12
  377. package/dist/trajectory/parse/vasp.js +10 -7
  378. package/dist/trajectory/parse/vaspout-electronic.d.ts +13 -0
  379. package/dist/trajectory/parse/vaspout-electronic.js +207 -0
  380. package/dist/trajectory/parse/vaspout-h5.d.ts +5 -0
  381. package/dist/trajectory/parse/vaspout-h5.js +284 -0
  382. package/dist/trajectory/parse/xyz.js +11 -7
  383. package/dist/trajectory/plotting.d.ts +8 -9
  384. package/dist/trajectory/plotting.js +99 -27
  385. package/dist/utils.d.ts +3 -0
  386. package/dist/utils.js +7 -0
  387. package/dist/xrd/XrdPlot.svelte +47 -61
  388. package/dist/xrd/broadening.js +2 -1
  389. package/dist/xrd/calc-xrd.js +2 -4
  390. package/dist/xrd/parse.d.ts +0 -1
  391. package/dist/xrd/parse.js +56 -73
  392. package/package.json +61 -33
  393. package/dist/api/mp.d.ts +0 -6
  394. package/dist/api/mp.js +0 -22
  395. package/dist/plot/sunburst/SunburstControls.svelte +0 -200
@@ -9,22 +9,18 @@
9
9
  import type { ExportSection } from '../io'
10
10
  import ExportPane from '../io/ExportPane.svelte'
11
11
  import { format_num } from '../labels'
12
- import { FullscreenButton, type FullscreenToggleProp, SettingsSection, toggle_fullscreen } from '../layout'
12
+ import {
13
+ FullscreenButton,
14
+ type FullscreenToggleProp,
15
+ SettingsSection,
16
+ toggle_fullscreen,
17
+ } from '../layout'
13
18
  import { sync_fullscreen } from '../layout/fullscreen.svelte'
14
19
  import type { Vec2, Vec3 } from '../math'
15
- import {
16
- convex_hull_2d,
17
- cross_3d,
18
- merge_coplanar_triangles,
19
- normalize_vec,
20
- } from '../math'
20
+ import { convex_hull_2d, cross_3d, merge_coplanar_triangles, normalize_vec } from '../math'
21
21
  import DraggablePane from '../overlays/DraggablePane.svelte'
22
22
  import { ColorBar, ScatterPlot3DControls } from '../plot'
23
- import {
24
- constrain_tooltip_position,
25
- pad_rect,
26
- rects_overlap,
27
- } from '../plot/core/layout'
23
+ import { constrain_tooltip_position, pad_rect, rects_overlap } from '../plot/core/layout'
28
24
  import type {
29
25
  AxisConfig3D,
30
26
  CameraProjection3D,
@@ -129,18 +125,22 @@
129
125
  } = $props()
130
126
 
131
127
  // Control overrides (override ?? config ?? default, cleared by Reset)
132
- const overrides = create_chempot_overrides(() => config, [
133
- `formal_chempots`,
134
- `label_stable`,
135
- `element_padding`,
136
- `default_min_limit`,
137
- `formulas_to_draw`,
138
- `draw_formula_meshes`,
139
- `draw_formula_lines`,
140
- `color_mode`,
141
- `color_scale`,
142
- `reverse_color_scale`,
143
- ], { color_mode: `arity`, formulas_to_draw: [] })
128
+ const overrides = create_chempot_overrides(
129
+ () => config,
130
+ [
131
+ `formal_chempots`,
132
+ `label_stable`,
133
+ `element_padding`,
134
+ `default_min_limit`,
135
+ `formulas_to_draw`,
136
+ `draw_formula_meshes`,
137
+ `draw_formula_lines`,
138
+ `color_mode`,
139
+ `color_scale`,
140
+ `reverse_color_scale`,
141
+ ],
142
+ { color_mode: `arity`, formulas_to_draw: [] },
143
+ )
144
144
  const formal_chempots = $derived(overrides.resolve(`formal_chempots`))
145
145
  const label_stable = $derived(overrides.resolve(`label_stable`))
146
146
  const element_padding = $derived(overrides.resolve(`element_padding`))
@@ -156,9 +156,7 @@
156
156
  config.tooltip_detail_level ?? CHEMPOT_DEFAULTS.tooltip_detail_level,
157
157
  )
158
158
  const formula_colors = $derived(
159
- config.formula_colors?.length
160
- ? config.formula_colors
161
- : CHEMPOT_DEFAULTS.formula_colors,
159
+ config.formula_colors?.length ? config.formula_colors : CHEMPOT_DEFAULTS.formula_colors,
162
160
  )
163
161
 
164
162
  const formula_label_segments = (formula: string): FormulaLabelSegment[] =>
@@ -181,21 +179,38 @@
181
179
  // Separate effects so each reacts to its own pane opening independently —
182
180
  // a single $derived ternary would create priority ordering where opening
183
181
  // a "lower" pane while a "higher" one is open fails silently.
184
- $effect(() => { if (export_pane_open) { formula_picker_open = false; controls_open = false } })
185
- $effect(() => { if (formula_picker_open) { export_pane_open = false; controls_open = false } })
186
- $effect(() => { if (controls_open) { export_pane_open = false; formula_picker_open = false } })
182
+ $effect(() => {
183
+ if (export_pane_open) {
184
+ formula_picker_open = false
185
+ controls_open = false
186
+ }
187
+ })
188
+ $effect(() => {
189
+ if (formula_picker_open) {
190
+ export_pane_open = false
191
+ controls_open = false
192
+ }
193
+ })
194
+ $effect(() => {
195
+ if (controls_open) {
196
+ export_pane_open = false
197
+ formula_picker_open = false
198
+ }
199
+ })
187
200
  let container_width = $state(0)
188
201
  let container_height = $state(0)
189
202
  const base_aspect_ratio = $derived(height > 0 && width > 0 ? height / width : 1)
190
203
  const render_width = $derived(container_width > 0 ? container_width : width)
191
204
  const render_height = $derived(
192
205
  fullscreen
193
- ? (container_height > 0 ? container_height : height)
206
+ ? container_height > 0
207
+ ? container_height
208
+ : height
194
209
  : Math.round(render_width * base_aspect_ratio),
195
210
  )
196
211
 
197
212
  let mounted = $state(false)
198
- onMount(() => mounted = true)
213
+ onMount(() => (mounted = true))
199
214
  let orbit_controls_ref = $state<OrbitControls | undefined>(undefined)
200
215
  // Backside tracking: axes/ticks/labels render on the far side from the camera
201
216
  // back[i] = backside data coordinate value for data axis i
@@ -248,9 +263,7 @@
248
263
  if (next_temperature !== temperature) temperature = next_temperature
249
264
  })
250
265
 
251
- const show_temperature_slider = $derived(
252
- has_temp_data && available_temperatures.length > 0,
253
- )
266
+ const show_temperature_slider = $derived(has_temp_data && available_temperatures.length > 0)
254
267
 
255
268
  const projection_source_entries = $derived(
256
269
  get_projection_source_entries(entries, temp_filtered_entries),
@@ -262,10 +275,10 @@
262
275
  projection_source_entries.flatMap((entry) =>
263
276
  Object.entries(entry.composition)
264
277
  .filter(([, amount]) => amount > 0)
265
- .map(([element]) => element)
278
+ .map(([element]) => element),
266
279
  ),
267
280
  ),
268
- ).sort()
281
+ ).sort(),
269
282
  )
270
283
  const has_multinary_system = $derived(all_entry_elements.length > 3)
271
284
  let projection_elements_override = $state<string[] | null>(null)
@@ -287,9 +300,7 @@
287
300
  })
288
301
  const effective_config = $derived({
289
302
  ...config,
290
- elements: projection_elements.length === 3
291
- ? projection_elements
292
- : config.elements,
303
+ elements: projection_elements.length === 3 ? projection_elements : config.elements,
293
304
  formal_chempots,
294
305
  label_stable,
295
306
  element_padding,
@@ -319,7 +330,9 @@
319
330
  diagram_data = null
320
331
  diagram_computing = false
321
332
  })
322
- return () => { cancelled = true }
333
+ return () => {
334
+ cancelled = true
335
+ }
323
336
  })
324
337
 
325
338
  const plot_elements = $derived(diagram_data?.elements ?? projection_elements)
@@ -348,15 +361,11 @@
348
361
  })
349
362
  const current_projection_key = $derived(plot_elements.join(`|`))
350
363
  let formula_filter_query = $state(``)
351
- const available_formulas = $derived.by(() =>
352
- Object.keys(diagram_data?.domains ?? {}).sort()
353
- )
364
+ const available_formulas = $derived.by(() => Object.keys(diagram_data?.domains ?? {}).sort())
354
365
  const filtered_formulas = $derived.by(() => {
355
366
  const query = formula_filter_query.trim().toLowerCase()
356
367
  if (!query) return available_formulas
357
- return available_formulas.filter((formula) =>
358
- formula.toLowerCase().includes(query)
359
- )
368
+ return available_formulas.filter((formula) => formula.toLowerCase().includes(query))
360
369
  })
361
370
 
362
371
  // Process domains for rendering
@@ -380,45 +389,49 @@
380
389
  max_energy_per_atom: number | null
381
390
  }
382
391
  type NumericColorMode = Exclude<ChemPotColorMode, `none` | `arity`>
392
+ const domain_annotation_cache = new Map<string, number[]>()
393
+
394
+ function get_domain_ann_loc(points_3d: number[][]): number[] {
395
+ if (points_3d.length >= 3) {
396
+ const cache_key = points_3d.map((point) => point.join(`,`)).join(`;`)
397
+ const cached = domain_annotation_cache.get(cache_key)
398
+ if (cached) return cached
399
+ const ann_loc = get_3d_domain_simplexes_and_ann_loc(points_3d).ann_loc
400
+ domain_annotation_cache.set(cache_key, ann_loc)
401
+ return ann_loc
402
+ }
403
+ return points_3d[0].map(
404
+ (_, col_idx) =>
405
+ points_3d.reduce((sum, point) => sum + point[col_idx], 0) / points_3d.length,
406
+ )
407
+ }
383
408
 
384
409
  const render_domains = $derived.by((): DomainRenderData[] => {
385
410
  if (!diagram_data || plot_elements.length < 2) return []
386
411
 
387
412
  const dim = diagram_data.elements.length
388
413
  const indices = Array.from({ length: dim }, (_, idx) => idx)
389
- const new_lims = element_padding > 0
390
- ? apply_element_padding(
391
- diagram_data.domains,
392
- indices,
393
- element_padding,
394
- default_min_limit,
395
- )
396
- : null
414
+ const new_lims =
415
+ element_padding > 0
416
+ ? apply_element_padding(
417
+ diagram_data.domains,
418
+ indices,
419
+ element_padding,
420
+ default_min_limit,
421
+ )
422
+ : null
397
423
 
398
424
  const result: DomainRenderData[] = []
399
425
  for (const [formula, pts] of Object.entries(diagram_data.domains)) {
400
426
  const padded = new_lims
401
- ? pad_domain_points(
402
- pts,
403
- indices,
404
- new_lims,
405
- default_min_limit,
406
- element_padding,
407
- )
427
+ ? pad_domain_points(pts, indices, new_lims, default_min_limit, element_padding)
408
428
  : pts
409
429
  if (padded.length < 2) continue
410
- const is_draw = formulas_to_draw.includes(formula)
411
- const centroid = padded[0].map((_, col_idx) =>
412
- padded.reduce((sum, point) => sum + point[col_idx], 0) / padded.length
413
- )
414
- const ann_loc = padded.length >= 3
415
- ? get_3d_domain_simplexes_and_ann_loc(padded).ann_loc
416
- : centroid
417
430
  result.push({
418
431
  formula,
419
432
  points_3d: padded,
420
- ann_loc,
421
- is_draw_formula: is_draw,
433
+ ann_loc: get_domain_ann_loc(padded),
434
+ is_draw_formula: formulas_to_draw.includes(formula),
422
435
  label_font_size: bbox_diagonal(padded),
423
436
  })
424
437
  }
@@ -469,9 +482,7 @@
469
482
  // Original (non-renormalized) elemental references for formation energy computation.
470
483
  // diagram_data.el_refs may be renormalized to zero when formal_chempots is true,
471
484
  // so we compute our own from the raw entries to get true DFT reference energies.
472
- const raw_el_refs = $derived(
473
- get_min_entries_and_el_refs(temp_filtered_entries).el_refs,
474
- )
485
+ const raw_el_refs = $derived(get_min_entries_and_el_refs(temp_filtered_entries).el_refs)
475
486
 
476
487
  const color_mode_labels: Record<NumericColorMode, string> = {
477
488
  energy: `Energy per atom (eV)`,
@@ -486,11 +497,7 @@
486
497
  return entry_energy_stats_by_formula.get(formula)?.min_energy_per_atom ?? null
487
498
  }
488
499
  if (active_color_mode === `formation_energy`) {
489
- return best_form_energy_for_formula(
490
- temp_filtered_entries,
491
- formula,
492
- raw_el_refs,
493
- ) ?? null
500
+ return best_form_energy_for_formula(temp_filtered_entries, formula, raw_el_refs) ?? null
494
501
  }
495
502
  return entry_energy_stats_by_formula.get(formula)?.matching_entry_count ?? 0
496
503
  }
@@ -537,24 +544,22 @@
537
544
  })
538
545
 
539
546
  // Range and label for the color bar (null for none/arity which are categorical)
540
- const color_range = $derived.by(
541
- (): { min: number; max: number; label: string } | null => {
542
- const values = domain_color_values?.values ?? []
543
- if (values.length === 0) return null
544
- let lo = values[0], hi = values[0]
545
- for (let idx = 1; idx < values.length; idx++) {
546
- if (values[idx] < lo) lo = values[idx]
547
- if (values[idx] > hi) hi = values[idx]
548
- }
549
- return {
550
- min: lo,
551
- max: Math.max(hi, lo + 1e-6),
552
- label: color_mode === `none` || color_mode === `arity`
553
- ? ``
554
- : color_mode_labels[color_mode],
555
- }
556
- },
557
- )
547
+ const color_range = $derived.by((): { min: number; max: number; label: string } | null => {
548
+ const values = domain_color_values?.values ?? []
549
+ if (values.length === 0) return null
550
+ let lo = values[0],
551
+ hi = values[0]
552
+ for (let idx = 1; idx < values.length; idx++) {
553
+ if (values[idx] < lo) lo = values[idx]
554
+ if (values[idx] > hi) hi = values[idx]
555
+ }
556
+ return {
557
+ min: lo,
558
+ max: Math.max(hi, lo + 1e-6),
559
+ label:
560
+ color_mode === `none` || color_mode === `arity` ? `` : color_mode_labels[color_mode],
561
+ }
562
+ })
558
563
 
559
564
  const arity_legend_labels = $derived.by((): string[] => {
560
565
  let has_four_plus_regions = false
@@ -574,9 +579,12 @@
574
579
  const render_axis_scale = $derived.by((): Vec3 => {
575
580
  const points = render_domains.flatMap((domain) => domain.points_3d)
576
581
  if (points.length === 0) return [1, 1, 1]
577
- let min0 = Infinity, max0 = -Infinity
578
- let min1 = Infinity, max1 = -Infinity
579
- let min2 = Infinity, max2 = -Infinity
582
+ let min0 = Infinity,
583
+ max0 = -Infinity
584
+ let min1 = Infinity,
585
+ max1 = -Infinity
586
+ let min2 = Infinity,
587
+ max2 = -Infinity
580
588
  for (const point of points) {
581
589
  if (point[0] < min0) min0 = point[0]
582
590
  if (point[0] > max0) max0 = point[0]
@@ -616,11 +624,7 @@
616
624
  sum_z += z_val
617
625
  }
618
626
  const n_points = points.length
619
- const center = new THREE.Vector3(
620
- sum_x / n_points,
621
- sum_y / n_points,
622
- sum_z / n_points,
623
- )
627
+ const center = new THREE.Vector3(sum_x / n_points, sum_y / n_points, sum_z / n_points)
624
628
  // Compute max distance from center
625
629
  let max_dist = 0
626
630
  for (const point of points) {
@@ -635,30 +639,22 @@
635
639
  data_center.y + data_extent,
636
640
  data_center.z + data_extent,
637
641
  ])
638
- const default_camera_target = $derived<Vec3>([
639
- data_center.x,
640
- data_center.y,
641
- data_center.z,
642
- ])
642
+ const default_camera_target = $derived<Vec3>([data_center.x, data_center.y, data_center.z])
643
643
  const default_orthographic_zoom = $derived(
644
644
  Math.min(render_width, render_height) / (data_extent * 1.6),
645
645
  )
646
646
  let camera_position_override = $state<Vec3 | null>(null)
647
647
  let camera_target_override = $state<Vec3 | null>(null)
648
648
  let orthographic_zoom_override = $state<number | null>(null)
649
- const camera_position = $derived(
650
- camera_position_override ?? default_camera_position,
651
- )
652
- const camera_target = $derived(
653
- camera_target_override ?? default_camera_target,
654
- )
655
- const orthographic_zoom = $derived(
656
- orthographic_zoom_override ?? default_orthographic_zoom,
657
- )
649
+ const camera_position = $derived(camera_position_override ?? default_camera_position)
650
+ const camera_target = $derived(camera_target_override ?? default_camera_target)
651
+ const orthographic_zoom = $derived(orthographic_zoom_override ?? default_orthographic_zoom)
658
652
  // Label scale factor: zoom relative to default, so labels grow/shrink with zoom
659
653
  // Labels scale sub-linearly with zoom so they grow but don't dominate when zoomed in
660
654
  const zoom_scale = $derived(
661
- default_orthographic_zoom > 0 ? Math.sqrt(orthographic_zoom / default_orthographic_zoom) : 1,
655
+ default_orthographic_zoom > 0
656
+ ? Math.sqrt(orthographic_zoom / default_orthographic_zoom)
657
+ : 1,
662
658
  )
663
659
  let last_data_center: Vec3 | null = null
664
660
  let last_data_extent: number | null = null
@@ -667,14 +663,16 @@
667
663
  // Each domain in a chem pot diagram is a convex polygon/polyhedron. We project
668
664
  // to 2D (trying all 3 axis-aligned planes) and use the best projection's
669
665
  // convex hull boundary. This reliably handles both flat and 3D domains.
670
- function get_domain_edges(
671
- pts: number[][],
672
- ): [number[], number[]][] {
666
+ function get_domain_edges(pts: number[][]): [number[], number[]][] {
673
667
  const unique = dedup_3d(pts)
674
668
  if (unique.length < 2) return []
675
669
  if (unique.length === 2) return [[unique[0], unique[1]]]
676
670
  if (unique.length === 3) {
677
- return [[unique[0], unique[1]], [unique[1], unique[2]], [unique[0], unique[2]]]
671
+ return [
672
+ [unique[0], unique[1]],
673
+ [unique[1], unique[2]],
674
+ [unique[0], unique[2]],
675
+ ]
678
676
  }
679
677
  return get_2d_hull_edges(unique)
680
678
  }
@@ -694,9 +692,7 @@
694
692
  // (largest non-degenerate hull area). Unioning multiple projections can add
695
693
  // non-physical diagonals for nearly coplanar domains.
696
694
  // Called only from get_domain_edges with 4+ unique points
697
- function get_2d_hull_edges(
698
- pts: number[][],
699
- ): [number[], number[]][] {
695
+ function get_2d_hull_edges(pts: number[][]): [number[], number[]][] {
700
696
  let selected_hull: Vec2[] = []
701
697
  let selected_coord_to_idx: SvelteMap<string, number> | null = null
702
698
  let selected_hull_area = -1
@@ -706,15 +702,20 @@
706
702
 
707
703
  // Skip this projection if points collapse to a line (near-zero range in
708
704
  // either projected axis). This avoids spurious edges from edge-on views.
709
- let min0 = Infinity, max0 = -Infinity, min1 = Infinity, max1 = -Infinity
705
+ let min0 = Infinity,
706
+ max0 = -Infinity,
707
+ min1 = Infinity,
708
+ max1 = -Infinity
710
709
  for (const pt of pts) {
711
- const v0 = pt[axes[0]], v1 = pt[axes[1]]
710
+ const v0 = pt[axes[0]],
711
+ v1 = pt[axes[1]]
712
712
  if (v0 < min0) min0 = v0
713
713
  if (v0 > max0) max0 = v0
714
714
  if (v1 < min1) min1 = v1
715
715
  if (v1 > max1) max1 = v1
716
716
  }
717
- const range0 = max0 - min0, range1 = max1 - min1
717
+ const range0 = max0 - min0,
718
+ range1 = max1 - min1
718
719
  const max_2d_range = Math.max(range0, range1)
719
720
  if (max_2d_range < 1e-6 || Math.min(range0, range1) < max_2d_range * 0.01) {
720
721
  continue
@@ -752,7 +753,9 @@
752
753
  `${point_b[0].toFixed(6)},${point_b[1].toFixed(6)}`,
753
754
  )
754
755
  if (
755
- point_a_idx == null || point_b_idx == null || point_a_idx >= pts.length ||
756
+ point_a_idx == null ||
757
+ point_b_idx == null ||
758
+ point_a_idx >= pts.length ||
756
759
  point_b_idx >= pts.length
757
760
  ) {
758
761
  console.warn(`get_2d_hull_edges: invalid edge`, {
@@ -846,7 +849,9 @@
846
849
  const n_verts = pos.count
847
850
  const n_faces = n_verts / 3
848
851
  // Hull centroid for orienting face normals outward
849
- let hx = 0, hy = 0, hz = 0
852
+ let hx = 0,
853
+ hy = 0,
854
+ hz = 0
850
855
  for (let vert_idx = 0; vert_idx < n_verts; vert_idx++) {
851
856
  hx += pos.getX(vert_idx)
852
857
  hy += pos.getY(vert_idx)
@@ -900,7 +905,9 @@
900
905
  const centroids = render_domains
901
906
  .filter((domain) => !domain.is_draw_formula && domain.points_3d.length > 0)
902
907
  .map((domain) => {
903
- let sx = 0, sy = 0, sz = 0
908
+ let sx = 0,
909
+ sy = 0,
910
+ sz = 0
904
911
  for (const pt of domain.points_3d) {
905
912
  const [x_val, y_val, z_val] = to_render_xyz(pt)
906
913
  sx += x_val
@@ -908,7 +915,12 @@
908
915
  sz += z_val
909
916
  }
910
917
  const n_points = domain.points_3d.length
911
- return { formula: domain.formula, cx: sx / n_points, cy: sy / n_points, cz: sz / n_points }
918
+ return {
919
+ formula: domain.formula,
920
+ cx: sx / n_points,
921
+ cy: sy / n_points,
922
+ cz: sz / n_points,
923
+ }
912
924
  })
913
925
 
914
926
  // Assign each face to the nearest domain centroid
@@ -938,9 +950,9 @@
938
950
  const tol = 1e-3
939
951
  const round = (val: number): number => Math.round(val / tol)
940
952
  const vkey = (vert_idx: number): string =>
941
- `${round(pos.getX(vert_idx))},${round(pos.getY(vert_idx))},${
942
- round(pos.getZ(vert_idx))
943
- }`
953
+ `${round(pos.getX(vert_idx))},${round(pos.getY(vert_idx))},${round(
954
+ pos.getZ(vert_idx),
955
+ )}`
944
956
  // Compute face normals
945
957
  const normals: Vec3[] = []
946
958
  for (let face_idx = 0; face_idx < n_faces; face_idx++) {
@@ -962,13 +974,11 @@
962
974
  for (let face_idx = 0; face_idx < n_faces; face_idx++) {
963
975
  const base = face_idx * 3
964
976
  const keys = [vkey(base), vkey(base + 1), vkey(base + 2)]
965
- for (
966
- const ek of [
967
- edge_key(keys[0], keys[1]),
968
- edge_key(keys[1], keys[2]),
969
- edge_key(keys[0], keys[2]),
970
- ]
971
- ) {
977
+ for (const ek of [
978
+ edge_key(keys[0], keys[1]),
979
+ edge_key(keys[1], keys[2]),
980
+ edge_key(keys[0], keys[2]),
981
+ ]) {
972
982
  const list = edge_faces.get(ek)
973
983
  if (list) list.push(face_idx)
974
984
  else edge_faces.set(ek, [face_idx])
@@ -984,13 +994,15 @@
984
994
  return node
985
995
  }
986
996
  const union = (a_idx: number, b_idx: number): void => {
987
- const ra = find(a_idx), rb = find(b_idx)
997
+ const ra = find(a_idx),
998
+ rb = find(b_idx)
988
999
  if (ra !== rb) parent[ra] = rb
989
1000
  }
990
1001
  for (const pair of edge_faces.values()) {
991
1002
  if (pair.length !== 2) continue
992
1003
  const [fa, fb] = pair
993
- const na = normals[fa], nb = normals[fb]
1004
+ const na = normals[fa],
1005
+ nb = normals[fb]
994
1006
  if (Math.abs(na[0] * nb[0] + na[1] * nb[1] + na[2] * nb[2]) > 1 - tol) {
995
1007
  union(fa, fb)
996
1008
  }
@@ -1140,15 +1152,9 @@
1140
1152
 
1141
1153
  const controls_series = $derived<DataSeries3D[]>([
1142
1154
  {
1143
- x: render_domains.flatMap((domain) =>
1144
- domain.points_3d.map((point) => point[1])
1145
- ),
1146
- y: render_domains.flatMap((domain) =>
1147
- domain.points_3d.map((point) => point[2])
1148
- ),
1149
- z: render_domains.flatMap((domain) =>
1150
- domain.points_3d.map((point) => point[0])
1151
- ),
1155
+ x: render_domains.flatMap((domain) => domain.points_3d.map((point) => point[1])),
1156
+ y: render_domains.flatMap((domain) => domain.points_3d.map((point) => point[2])),
1157
+ z: render_domains.flatMap((domain) => domain.points_3d.map((point) => point[0])),
1152
1158
  label: `domains`,
1153
1159
  },
1154
1160
  ])
@@ -1159,8 +1165,7 @@
1159
1165
  const result: { geometry: THREE.BufferGeometry; color: string }[] = []
1160
1166
  for (const domain of render_domains) {
1161
1167
  if (!domain.is_draw_formula) continue
1162
- const color_idx = formulas_to_draw.indexOf(domain.formula) %
1163
- formula_colors.length
1168
+ const color_idx = formulas_to_draw.indexOf(domain.formula) % formula_colors.length
1164
1169
  const swizzled = domain.points_3d.map((point) => to_render_xyz(point))
1165
1170
  const positions: number[] = []
1166
1171
  for (const [pa, pb] of get_domain_edges(swizzled)) {
@@ -1179,8 +1184,7 @@
1179
1184
  if (!draw_formula_meshes) return result
1180
1185
  for (const domain of render_domains) {
1181
1186
  if (!domain.is_draw_formula || domain.points_3d.length < 4) continue
1182
- const color_idx = formulas_to_draw.indexOf(domain.formula) %
1183
- formula_colors.length
1187
+ const color_idx = formulas_to_draw.indexOf(domain.formula) % formula_colors.length
1184
1188
  const unique = dedup_3d(domain.points_3d)
1185
1189
  if (unique.length < 4) continue
1186
1190
  const vectors = unique.map((pt) => to_vec3(pt))
@@ -1194,10 +1198,7 @@
1194
1198
  return result
1195
1199
  })
1196
1200
 
1197
- function get_touches_limits(
1198
- points_3d: number[][],
1199
- lims: Vec2[],
1200
- ): string[] {
1201
+ function get_touches_limits(points_3d: number[][], lims: Vec2[]): string[] {
1201
1202
  const limit_tol = 1e-3
1202
1203
  const touches_limits: string[] = []
1203
1204
  for (
@@ -1207,11 +1208,11 @@
1207
1208
  ) {
1208
1209
  const [axis_min, axis_max] = lims[axis_idx]
1209
1210
  const axis_name = plot_elements[axis_idx] ?? `axis_${axis_idx}`
1210
- const touches_min = points_3d.some((point) =>
1211
- Math.abs(point[axis_idx] - axis_min) < limit_tol
1211
+ const touches_min = points_3d.some(
1212
+ (point) => Math.abs(point[axis_idx] - axis_min) < limit_tol,
1212
1213
  )
1213
- const touches_max = points_3d.some((point) =>
1214
- Math.abs(point[axis_idx] - axis_max) < limit_tol
1214
+ const touches_max = points_3d.some(
1215
+ (point) => Math.abs(point[axis_idx] - axis_max) < limit_tol,
1215
1216
  )
1216
1217
  if (touches_min) touches_limits.push(`${axis_name} lower bound`)
1217
1218
  if (touches_max) touches_limits.push(`${axis_name} upper bound`)
@@ -1269,9 +1270,7 @@
1269
1270
  const vertex_owners = new SvelteMap<string, string[]>()
1270
1271
  for (const domain of render_domains) {
1271
1272
  for (const pt of domain.points_3d) {
1272
- const key = pt.map((val) => (Math.round(val / tol) * tol).toFixed(4)).join(
1273
- `,`,
1274
- )
1273
+ const key = pt.map((val) => (Math.round(val / tol) * tol).toFixed(4)).join(`,`)
1275
1274
  const owners = vertex_owners.get(key)
1276
1275
  if (owners) {
1277
1276
  if (!owners.includes(domain.formula)) owners.push(domain.formula)
@@ -1349,9 +1348,7 @@
1349
1348
  geometry.dispose()
1350
1349
  }
1351
1350
 
1352
- function dispose_geometries(
1353
- geometries: (THREE.BufferGeometry | null | undefined)[],
1354
- ): void {
1351
+ function dispose_geometries(geometries: (THREE.BufferGeometry | null | undefined)[]): void {
1355
1352
  for (const geometry of geometries) dispose_geometry(geometry)
1356
1353
  }
1357
1354
 
@@ -1455,10 +1452,7 @@
1455
1452
  })
1456
1453
 
1457
1454
  // Helper to create a line geometry from two Vec3 arrays
1458
- function make_line_geom(
1459
- start: Vec3,
1460
- end: Vec3,
1461
- ): THREE.BufferGeometry {
1455
+ function make_line_geom(start: Vec3, end: Vec3): THREE.BufferGeometry {
1462
1456
  const geom = new THREE.BufferGeometry()
1463
1457
  geom.setAttribute(
1464
1458
  `position`,
@@ -1506,11 +1500,12 @@
1506
1500
  return [0, 1, 2].map((axis) => {
1507
1501
  const ticks = data_ticks[axis]
1508
1502
  const color = axis_colors[axis]
1509
- const label = axis === 0
1510
- ? (z_axis.label || chem_axis_label(0))
1511
- : axis === 1
1512
- ? (x_axis.label || chem_axis_label(1))
1513
- : (y_axis.label || chem_axis_label(2))
1503
+ const label =
1504
+ axis === 0
1505
+ ? z_axis.label || chem_axis_label(0)
1506
+ : axis === 1
1507
+ ? x_axis.label || chem_axis_label(1)
1508
+ : y_axis.label || chem_axis_label(2)
1514
1509
 
1515
1510
  const tick_geoms: THREE.BufferGeometry[] = []
1516
1511
  const grid_geoms: THREE.BufferGeometry[] = []
@@ -1530,16 +1525,14 @@
1530
1525
  back[2] + out_y * tick_label_dist,
1531
1526
  )
1532
1527
  for (const val of ticks) {
1533
- tick_geoms.push(make_line_geom(
1534
- swiz(val, back[1], back[2]),
1535
- swiz(val, back[1], back[2] + out_y * tick_size),
1536
- ))
1537
- grid_geoms.push(
1538
- make_line_geom(swiz(val, r1[0], back[2]), swiz(val, r1[1], back[2])),
1539
- )
1540
- grid_geoms.push(
1541
- make_line_geom(swiz(val, back[1], r2[0]), swiz(val, back[1], r2[1])),
1528
+ tick_geoms.push(
1529
+ make_line_geom(
1530
+ swiz(val, back[1], back[2]),
1531
+ swiz(val, back[1], back[2] + out_y * tick_size),
1532
+ ),
1542
1533
  )
1534
+ grid_geoms.push(make_line_geom(swiz(val, r1[0], back[2]), swiz(val, r1[1], back[2])))
1535
+ grid_geoms.push(make_line_geom(swiz(val, back[1], r2[0]), swiz(val, back[1], r2[1])))
1543
1536
  tick_labels.push({
1544
1537
  pos: swiz(
1545
1538
  val,
@@ -1560,16 +1553,14 @@
1560
1553
  back[2] + out_y * tick_label_dist,
1561
1554
  )
1562
1555
  for (const val of ticks) {
1563
- tick_geoms.push(make_line_geom(
1564
- swiz(back[0], val, back[2]),
1565
- swiz(back[0], val, back[2] + out_y * tick_size),
1566
- ))
1567
- grid_geoms.push(
1568
- make_line_geom(swiz(r0[0], val, back[2]), swiz(r0[1], val, back[2])),
1569
- )
1570
- grid_geoms.push(
1571
- make_line_geom(swiz(back[0], val, r2[0]), swiz(back[0], val, r2[1])),
1556
+ tick_geoms.push(
1557
+ make_line_geom(
1558
+ swiz(back[0], val, back[2]),
1559
+ swiz(back[0], val, back[2] + out_y * tick_size),
1560
+ ),
1572
1561
  )
1562
+ grid_geoms.push(make_line_geom(swiz(r0[0], val, back[2]), swiz(r0[1], val, back[2])))
1563
+ grid_geoms.push(make_line_geom(swiz(back[0], val, r2[0]), swiz(back[0], val, r2[1])))
1573
1564
  tick_labels.push({
1574
1565
  pos: swiz(back[0], val, back[2] + out_y * tick_label_dist),
1575
1566
  text: format_num(val, `.3~g`),
@@ -1586,16 +1577,14 @@
1586
1577
  outer_end(r2) + outer_direction(r2) * axis_label_dist,
1587
1578
  )
1588
1579
  for (const val of ticks) {
1589
- tick_geoms.push(make_line_geom(
1590
- swiz(back[0], back[1], val),
1591
- swiz(back[0], back[1] + out_x * tick_size, val),
1592
- ))
1593
- grid_geoms.push(
1594
- make_line_geom(swiz(r0[0], back[1], val), swiz(r0[1], back[1], val)),
1595
- )
1596
- grid_geoms.push(
1597
- make_line_geom(swiz(back[0], r1[0], val), swiz(back[0], r1[1], val)),
1580
+ tick_geoms.push(
1581
+ make_line_geom(
1582
+ swiz(back[0], back[1], val),
1583
+ swiz(back[0], back[1] + out_x * tick_size, val),
1584
+ ),
1598
1585
  )
1586
+ grid_geoms.push(make_line_geom(swiz(r0[0], back[1], val), swiz(r0[1], back[1], val)))
1587
+ grid_geoms.push(make_line_geom(swiz(back[0], r1[0], val), swiz(back[0], r1[1], val)))
1599
1588
  tick_labels.push({
1600
1589
  pos: swiz(back[0], back[1] + out_x * tick_label_dist, val),
1601
1590
  text: format_num(val, `.3~g`),
@@ -1623,16 +1612,12 @@
1623
1612
 
1624
1613
  function update_label_occlusion(): void {
1625
1614
  if (!wrapper) return
1626
- const tick_labels = Array.from(
1627
- wrapper.querySelectorAll<HTMLElement>(`.axis-tick-label`),
1628
- )
1615
+ const tick_labels = Array.from(wrapper.querySelectorAll<HTMLElement>(`.axis-tick-label`))
1629
1616
  tick_labels_occluded = false
1630
1617
  for (const tick_label of tick_labels) {
1631
1618
  tick_label.style.visibility = ``
1632
1619
  }
1633
- const domain_rects = Array.from(
1634
- wrapper.querySelectorAll<HTMLElement>(`.domain-label`),
1635
- )
1620
+ const domain_rects = Array.from(wrapper.querySelectorAll<HTMLElement>(`.domain-label`))
1636
1621
  .filter((domain_label) => {
1637
1622
  const style = getComputedStyle(domain_label)
1638
1623
  return style.display !== `none` && style.visibility !== `hidden`
@@ -1700,11 +1685,7 @@
1700
1685
  }
1701
1686
  const controls_target = controls?.target
1702
1687
  if (controls_target) {
1703
- camera_target_override = [
1704
- controls_target.x,
1705
- controls_target.y,
1706
- controls_target.z,
1707
- ]
1688
+ camera_target_override = [controls_target.x, controls_target.y, controls_target.z]
1708
1689
  }
1709
1690
  }
1710
1691
 
@@ -1788,9 +1769,8 @@
1788
1769
  const projections = display.projections
1789
1770
  if (!projections) return []
1790
1771
  const [r0, r1, r2] = niced_range
1791
- const s0 = (r0[1] - r0[0]) * (display.projection_scale ?? 0.5)
1792
- const s1 = (r1[1] - r1[0]) * (display.projection_scale ?? 0.5)
1793
- const s2 = (r2[1] - r2[0]) * (display.projection_scale ?? 0.5)
1772
+ const projection_scale = display.projection_scale ?? 0.5
1773
+ const [s0, s1, s2] = niced_range.map(([lo, hi]) => (hi - lo) * projection_scale)
1794
1774
  const planes: {
1795
1775
  key: string
1796
1776
  pos: Vec3
@@ -1880,18 +1860,12 @@
1880
1860
  next_projection[current_owner_idx] = next_projection[axis_idx]
1881
1861
  }
1882
1862
  next_projection[axis_idx] = element
1883
- const normalized = normalize_projection_triplet(
1884
- next_projection,
1885
- all_entry_elements,
1886
- )
1863
+ const normalized = normalize_projection_triplet(next_projection, all_entry_elements)
1887
1864
  if (normalized) projection_elements_override = normalized
1888
1865
  }
1889
1866
 
1890
1867
  function apply_projection_preset(preset_elements: string[]): void {
1891
- const normalized = normalize_projection_triplet(
1892
- preset_elements,
1893
- all_entry_elements,
1894
- )
1868
+ const normalized = normalize_projection_triplet(preset_elements, all_entry_elements)
1895
1869
  if (normalized) projection_elements_override = normalized
1896
1870
  }
1897
1871
 
@@ -1968,19 +1942,21 @@
1968
1942
  },
1969
1943
  {
1970
1944
  label: `View`,
1971
- on_download: () =>
1972
- export_view_json_file(current_view_settings(), export_basename),
1945
+ on_download: () => export_view_json_file(current_view_settings(), export_basename),
1973
1946
  },
1974
1947
  {
1975
1948
  label: `GLB`,
1976
1949
  on_download: () =>
1977
- export_glb_file({
1978
- hull_geometry: colored_hull_geometry,
1979
- hull_opacity: color_mode === `none` ? 0.25 : 0.4,
1980
- edge_geometry,
1981
- formula_meshes: formula_mesh_data,
1982
- formula_edges: draw_formula_lines ? formula_edge_data : [],
1983
- }, export_basename),
1950
+ export_glb_file(
1951
+ {
1952
+ hull_geometry: colored_hull_geometry,
1953
+ hull_opacity: color_mode === `none` ? 0.25 : 0.4,
1954
+ edge_geometry,
1955
+ formula_meshes: formula_mesh_data,
1956
+ formula_edges: draw_formula_lines ? formula_edge_data : [],
1957
+ },
1958
+ export_basename,
1959
+ ),
1984
1960
  },
1985
1961
  ],
1986
1962
  },
@@ -1997,10 +1973,12 @@
1997
1973
  const pointer = hover_info?.pointer
1998
1974
  if (!pointer) return { x: 4, y: 4 }
1999
1975
  return constrain_tooltip_position(
2000
- pointer.x, pointer.y,
1976
+ pointer.x,
1977
+ pointer.y,
2001
1978
  tooltip_el?.offsetWidth ?? 200,
2002
1979
  tooltip_el?.offsetHeight ?? 100,
2003
- container_width, container_height,
1980
+ container_width,
1981
+ container_height,
2004
1982
  { offset: 0 },
2005
1983
  )
2006
1984
  })
@@ -2018,12 +1996,25 @@
2018
1996
  hover_info = null
2019
1997
  }
2020
1998
 
1999
+ function stop_phase_pointer_event(raw_event: unknown): void {
2000
+ if (!raw_event || typeof raw_event !== `object`) return
2001
+
2002
+ const event = raw_event as { nativeEvent?: unknown; stopPropagation?: () => void }
2003
+ event.stopPropagation?.()
2004
+
2005
+ const native_event = event.nativeEvent
2006
+ if (!native_event || typeof native_event !== `object`) return
2007
+ const native_pointer_event = native_event as { stopPropagation?: () => void }
2008
+ native_pointer_event.stopPropagation?.()
2009
+ }
2010
+
2021
2011
  function handle_phase_hover(domain_data: HoverMeshData, raw_event: unknown): void {
2022
2012
  if (locked_hover_formula && locked_hover_formula !== domain_data.formula) return
2023
2013
  set_hover_info(domain_data, raw_event)
2024
2014
  }
2025
2015
 
2026
2016
  function toggle_phase_lock(domain_data: HoverMeshData, raw_event: unknown): void {
2017
+ stop_phase_pointer_event(raw_event)
2027
2018
  if (locked_hover_formula === domain_data.formula) {
2028
2019
  clear_hover_lock()
2029
2020
  return
@@ -2053,20 +2044,15 @@
2053
2044
  role="application"
2054
2045
  tabindex="0"
2055
2046
  onkeydown={(event) => {
2056
- if (
2057
- event.target instanceof HTMLInputElement ||
2058
- event.target instanceof HTMLSelectElement
2059
- ) return
2047
+ if (event.target instanceof HTMLInputElement || event.target instanceof HTMLSelectElement)
2048
+ return
2060
2049
  if (event.key === `Escape`) clear_hover_lock()
2061
2050
  else if (event.key === `c`) cycle_color_mode()
2062
2051
  else if (event.key === `f` && fullscreen_toggle) toggle_fullscreen(wrapper)
2063
2052
  }}
2064
2053
  onpointerdown={(event) => {
2065
2054
  const target = event.target
2066
- if (
2067
- locked_hover_formula &&
2068
- (target === wrapper || target instanceof HTMLCanvasElement)
2069
- ) {
2055
+ if (locked_hover_formula && (target === wrapper || target instanceof HTMLCanvasElement)) {
2070
2056
  clear_hover_lock()
2071
2057
  }
2072
2058
  }}
@@ -2102,11 +2088,7 @@
2102
2088
  </div>
2103
2089
  <label class="overlay-search">
2104
2090
  Search:
2105
- <input
2106
- type="text"
2107
- placeholder="Formula filter"
2108
- bind:value={formula_filter_query}
2109
- />
2091
+ <input type="text" placeholder="Formula filter" bind:value={formula_filter_query} />
2110
2092
  </label>
2111
2093
  <div class="formula-list">
2112
2094
  {#if filtered_formulas.length === 0}
@@ -2117,14 +2099,14 @@
2117
2099
  <label>
2118
2100
  <input
2119
2101
  type="checkbox"
2120
- checked={formulas_to_draw.includes(formula)}
2102
+ checked={formula_overlay_idx !== -1}
2121
2103
  onchange={() => toggle_formula_selection(formula)}
2122
2104
  />
2123
2105
  <span
2124
2106
  class="formula-color-dot"
2125
2107
  style:background={formula_colors[
2126
2108
  (formula_overlay_idx >= 0 ? formula_overlay_idx : formula_idx) %
2127
- formula_colors.length
2109
+ formula_colors.length
2128
2110
  ]}
2129
2111
  ></span>
2130
2112
  {get_electro_neg_formula(formula, true, ``, `.3~s`)}
@@ -2231,8 +2213,7 @@
2231
2213
  <input
2232
2214
  type="checkbox"
2233
2215
  checked={draw_formula_meshes}
2234
- onchange={() =>
2235
- overrides.set(`draw_formula_meshes`, !draw_formula_meshes)}
2216
+ onchange={() => overrides.set(`draw_formula_meshes`, !draw_formula_meshes)}
2236
2217
  /> Meshes
2237
2218
  </label>
2238
2219
  <label>
@@ -2252,7 +2233,7 @@
2252
2233
  step="0.1"
2253
2234
  value={element_padding}
2254
2235
  oninput={(event) =>
2255
- overrides.set(`element_padding`, Number(event.currentTarget.value))}
2236
+ overrides.set(`element_padding`, Number(event.currentTarget.value))}
2256
2237
  />
2257
2238
  </label>
2258
2239
  <label>
@@ -2263,7 +2244,7 @@
2263
2244
  step="1"
2264
2245
  value={default_min_limit}
2265
2246
  oninput={(event) =>
2266
- overrides.set(`default_min_limit`, Number(event.currentTarget.value))}
2247
+ overrides.set(`default_min_limit`, Number(event.currentTarget.value))}
2267
2248
  />
2268
2249
  </label>
2269
2250
  </div>
@@ -2273,7 +2254,7 @@
2273
2254
  id="chempot-color-mode"
2274
2255
  value={color_mode}
2275
2256
  onchange={(event) =>
2276
- overrides.set(`color_mode`, event.currentTarget.value as ChemPotColorMode)}
2257
+ overrides.set(`color_mode`, event.currentTarget.value as ChemPotColorMode)}
2277
2258
  >
2278
2259
  {#each CHEMPOT_COLOR_MODE_OPTIONS as [value, label] (value)}
2279
2260
  <option {value}>{label}</option>
@@ -2287,10 +2268,7 @@
2287
2268
  id="chempot-color-scale"
2288
2269
  value={color_scale}
2289
2270
  onchange={(event) =>
2290
- overrides.set(
2291
- `color_scale`,
2292
- event.currentTarget.value as D3InterpolateName,
2293
- )}
2271
+ overrides.set(`color_scale`, event.currentTarget.value as D3InterpolateName)}
2294
2272
  >
2295
2273
  {#each CHEMPOT_COLOR_SCALE_OPTIONS as [value, label] (value)}
2296
2274
  <option {value}>{label}</option>
@@ -2300,8 +2278,7 @@
2300
2278
  <input
2301
2279
  type="checkbox"
2302
2280
  checked={reverse_color_scale}
2303
- onchange={() =>
2304
- overrides.set(`reverse_color_scale`, !reverse_color_scale)}
2281
+ onchange={() => overrides.set(`reverse_color_scale`, !reverse_color_scale)}
2305
2282
  /> Rev
2306
2283
  </label>
2307
2284
  </div>
@@ -2314,312 +2291,300 @@
2314
2291
  {/if}
2315
2292
  </section>
2316
2293
  {#if show_temperature_slider && temperature !== undefined}
2317
- <TemperatureSlider
2318
- class="chempot-temp-slider"
2319
- {available_temperatures}
2320
- bind:temperature
2321
- />
2294
+ <TemperatureSlider class="chempot-temp-slider" {available_temperatures} bind:temperature />
2322
2295
  {/if}
2323
2296
  <div class="canvas-clip">
2324
- {#if diagram_computing}
2325
- <div class="computing-state">
2326
- <Spinner text="Computing chemical potential domains..." style="--spinner-size: 1.2em" />
2327
- </div>
2328
- {:else if !diagram_data}
2329
- <div class="error-state" role="alert" aria-live="polite">
2330
- <p>Cannot compute chemical potential diagram.</p>
2331
- <p>Need at least 2 elements with elemental reference entries.</p>
2332
- </div>
2333
- {:else if mounted && typeof WebGLRenderingContext !== `undefined`}
2334
- <Canvas
2335
- createRenderer={(cvs) =>
2336
- new THREE.WebGLRenderer({
2337
- canvas: cvs,
2338
- alpha: true,
2339
- antialias: true,
2340
- preserveDrawingBuffer: true,
2341
- })}
2342
- >
2343
- <ChemPotScene3D>
2344
- {#if camera_projection === `orthographic`}
2345
- <!-- Orthographic camera matching pymatgen's projection style -->
2346
- <T.OrthographicCamera
2347
- makeDefault
2348
- position={camera_position}
2349
- zoom={orthographic_zoom}
2350
- near={0.1}
2351
- far={data_extent * 10}
2352
- >
2353
- <extras.OrbitControls
2354
- bind:ref={orbit_controls_ref}
2355
- enableRotate
2356
- enableZoom
2357
- enablePan
2358
- autoRotate={auto_rotate > 0}
2359
- autoRotateSpeed={auto_rotate}
2360
- target={camera_target}
2361
- />
2362
- </T.OrthographicCamera>
2363
- {:else}
2364
- <T.PerspectiveCamera
2365
- makeDefault
2366
- position={camera_position}
2367
- fov={50}
2368
- near={0.1}
2369
- far={data_extent * 10}
2370
- >
2371
- <extras.OrbitControls
2372
- bind:ref={orbit_controls_ref}
2373
- enableRotate
2374
- enableZoom
2375
- enablePan
2376
- autoRotate={auto_rotate > 0}
2377
- autoRotateSpeed={auto_rotate}
2378
- target={camera_target}
2379
- />
2380
- </T.PerspectiveCamera>
2381
- {/if}
2297
+ {#if diagram_computing}
2298
+ <div class="computing-state">
2299
+ <Spinner
2300
+ text="Computing chemical potential domains..."
2301
+ style="--spinner-size: 1.2em"
2302
+ />
2303
+ </div>
2304
+ {:else if !diagram_data}
2305
+ <div class="error-state" role="alert" aria-live="polite">
2306
+ <p>Cannot compute chemical potential diagram.</p>
2307
+ <p>Need at least 2 elements with elemental reference entries.</p>
2308
+ </div>
2309
+ {:else if mounted && typeof WebGLRenderingContext !== `undefined`}
2310
+ <Canvas
2311
+ createRenderer={(cvs) =>
2312
+ new THREE.WebGLRenderer({
2313
+ canvas: cvs,
2314
+ alpha: true,
2315
+ antialias: true,
2316
+ preserveDrawingBuffer: true,
2317
+ })}
2318
+ >
2319
+ <ChemPotScene3D>
2320
+ {#if camera_projection === `orthographic`}
2321
+ <!-- Orthographic camera matching pymatgen's projection style -->
2322
+ <T.OrthographicCamera
2323
+ makeDefault
2324
+ position={camera_position}
2325
+ zoom={orthographic_zoom}
2326
+ near={0.1}
2327
+ far={data_extent * 10}
2328
+ >
2329
+ <extras.OrbitControls
2330
+ bind:ref={orbit_controls_ref}
2331
+ enableRotate
2332
+ enableZoom
2333
+ enablePan
2334
+ autoRotate={auto_rotate > 0}
2335
+ autoRotateSpeed={auto_rotate}
2336
+ target={camera_target}
2337
+ />
2338
+ </T.OrthographicCamera>
2339
+ {:else}
2340
+ <T.PerspectiveCamera
2341
+ makeDefault
2342
+ position={camera_position}
2343
+ fov={50}
2344
+ near={0.1}
2345
+ far={data_extent * 10}
2346
+ >
2347
+ <extras.OrbitControls
2348
+ bind:ref={orbit_controls_ref}
2349
+ enableRotate
2350
+ enableZoom
2351
+ enablePan
2352
+ autoRotate={auto_rotate > 0}
2353
+ autoRotateSpeed={auto_rotate}
2354
+ target={camera_target}
2355
+ />
2356
+ </T.PerspectiveCamera>
2357
+ {/if}
2382
2358
 
2383
- <!-- Ambient light for visibility -->
2384
- <T.AmbientLight intensity={0.8} />
2385
- <T.DirectionalLight position={[1, 1, 1]} intensity={0.5} />
2359
+ <!-- Ambient light for visibility -->
2360
+ <T.AmbientLight intensity={0.8} />
2361
+ <T.DirectionalLight position={[1, 1, 1]} intensity={0.5} />
2386
2362
 
2387
- <!-- Vertex-colored hull for both plain and colored modes.
2363
+ <!-- Vertex-colored hull for both plain and colored modes.
2388
2364
  {#key domain_colors} forces Threlte to re-create the mesh whenever
2389
2365
  colors change (covers color_mode, color_scale, and data updates),
2390
2366
  since on-demand rendering won't detect mutated vertex color buffers. -->
2391
- {#if colored_hull_geometry}
2392
- {#key domain_colors}
2393
- <T.Mesh geometry={colored_hull_geometry}>
2367
+ {#if colored_hull_geometry}
2368
+ {#key domain_colors}
2369
+ <T.Mesh geometry={colored_hull_geometry}>
2370
+ <T.MeshBasicMaterial
2371
+ vertexColors
2372
+ transparent
2373
+ opacity={color_mode === `none` ? 0.25 : 0.4}
2374
+ side={THREE.DoubleSide}
2375
+ polygonOffset
2376
+ polygonOffsetFactor={1}
2377
+ polygonOffsetUnits={1}
2378
+ />
2379
+ </T.Mesh>
2380
+ {/key}
2381
+ {/if}
2382
+
2383
+ <!-- Domain boundary edges (wireframe on top of opaque fills) -->
2384
+ <T.LineSegments geometry={edge_geometry}>
2385
+ <T.LineBasicMaterial color={0x333333} linewidth={1} />
2386
+ </T.LineSegments>
2387
+
2388
+ <!-- Invisible pick meshes for per-phase hover tooltip -->
2389
+ {#each hover_mesh_data as domain_hover (domain_hover.formula)}
2390
+ <T.Mesh
2391
+ geometry={domain_hover.geometry}
2392
+ onpointerenter={(event: unknown) => handle_phase_hover(domain_hover, event)}
2393
+ onpointermove={(event: unknown) => handle_phase_hover(domain_hover, event)}
2394
+ onpointerdown={(event: unknown) => toggle_phase_lock(domain_hover, event)}
2395
+ onpointerleave={() => {
2396
+ if (!locked_hover_formula && hover_info?.formula === domain_hover.formula) {
2397
+ hover_info = null
2398
+ }
2399
+ }}
2400
+ >
2394
2401
  <T.MeshBasicMaterial
2395
- vertexColors
2396
2402
  transparent
2397
- opacity={color_mode === `none` ? 0.25 : 0.4}
2403
+ opacity={0}
2398
2404
  side={THREE.DoubleSide}
2399
- polygonOffset
2400
- polygonOffsetFactor={1}
2401
- polygonOffsetUnits={1}
2405
+ depthWrite={false}
2402
2406
  />
2403
2407
  </T.Mesh>
2404
- {/key}
2405
- {/if}
2408
+ {/each}
2406
2409
 
2407
- <!-- Domain boundary edges (wireframe on top of opaque fills) -->
2408
- <T.LineSegments geometry={edge_geometry}>
2409
- <T.LineBasicMaterial color={0x333333} linewidth={1} />
2410
- </T.LineSegments>
2411
-
2412
- <!-- Invisible pick meshes for per-phase hover tooltip -->
2413
- {#each hover_mesh_data as domain_hover (domain_hover.formula)}
2414
- <T.Mesh
2415
- geometry={domain_hover.geometry}
2416
- onpointerenter={(event: unknown) => handle_phase_hover(domain_hover, event)}
2417
- onpointermove={(event: unknown) => handle_phase_hover(domain_hover, event)}
2418
- onpointerdown={(event: unknown) => toggle_phase_lock(domain_hover, event)}
2419
- onpointerleave={() => {
2420
- if (
2421
- !locked_hover_formula &&
2422
- hover_info?.formula === domain_hover.formula
2423
- ) {
2424
- hover_info = null
2425
- }
2426
- }}
2427
- >
2428
- <T.MeshBasicMaterial
2429
- transparent
2430
- opacity={0}
2431
- side={THREE.DoubleSide}
2432
- depthWrite={false}
2433
- />
2434
- </T.Mesh>
2435
- {/each}
2436
-
2437
- <!-- Formula overlay meshes (semi-transparent colored fill) -->
2438
- {#each formula_mesh_data as { geometry, color }, mesh_idx (mesh_idx)}
2439
- <T.Mesh {geometry}>
2440
- <T.MeshBasicMaterial
2441
- color={new THREE.Color(color)}
2442
- transparent
2443
- opacity={0.13}
2444
- side={THREE.DoubleSide}
2445
- depthWrite={false}
2446
- />
2447
- </T.Mesh>
2448
- {/each}
2449
-
2450
- <!-- Formula overlay edges (colored, thicker) -->
2451
- {#if draw_formula_lines}
2452
- {#each formula_edge_data as { geometry, color }, edge_idx (edge_idx)}
2453
- <T.LineSegments {geometry}>
2454
- <T.LineBasicMaterial color={new THREE.Color(color)} linewidth={2} />
2455
- </T.LineSegments>
2410
+ <!-- Formula overlay meshes (semi-transparent colored fill) -->
2411
+ {#each formula_mesh_data as { geometry, color }, mesh_idx (mesh_idx)}
2412
+ <T.Mesh {geometry}>
2413
+ <T.MeshBasicMaterial
2414
+ color={new THREE.Color(color)}
2415
+ transparent
2416
+ opacity={0.13}
2417
+ side={THREE.DoubleSide}
2418
+ depthWrite={false}
2419
+ />
2420
+ </T.Mesh>
2456
2421
  {/each}
2457
- {/if}
2458
2422
 
2459
- {#each projection_planes as plane (`${plane.key}-${projection_opacity}`)}
2460
- <T.Mesh position={plane.pos} rotation={plane.rot}>
2461
- <T.PlaneGeometry args={plane.size} />
2462
- <T.MeshBasicMaterial
2463
- color={plane.color}
2464
- opacity={projection_opacity}
2465
- transparent
2466
- side={THREE.DoubleSide}
2467
- depthWrite={false}
2468
- />
2469
- </T.Mesh>
2470
- {/each}
2423
+ <!-- Formula overlay edges (colored, thicker) -->
2424
+ {#if draw_formula_lines}
2425
+ {#each formula_edge_data as { geometry, color }, edge_idx (edge_idx)}
2426
+ <T.LineSegments {geometry}>
2427
+ <T.LineBasicMaterial color={new THREE.Color(color)} linewidth={2} />
2428
+ </T.LineSegments>
2429
+ {/each}
2430
+ {/if}
2471
2431
 
2472
- {#if display.show_bounding_box}
2473
- <T.LineSegments geometry={bounding_box_geometry}>
2474
- <T.LineBasicMaterial color="#666" opacity={0.6} transparent />
2475
- </T.LineSegments>
2476
- {/if}
2432
+ {#each projection_planes as plane (`${plane.key}-${projection_opacity}`)}
2433
+ <T.Mesh position={plane.pos} rotation={plane.rot}>
2434
+ <T.PlaneGeometry args={plane.size} />
2435
+ <T.MeshBasicMaterial
2436
+ color={plane.color}
2437
+ opacity={projection_opacity}
2438
+ transparent
2439
+ side={THREE.DoubleSide}
2440
+ depthWrite={false}
2441
+ />
2442
+ </T.Mesh>
2443
+ {/each}
2477
2444
 
2478
- <!-- Axes, ticks, grid lines, and labels -->
2479
- {#each grid_config as gc (gc.axis)}
2480
- {#if display.show_axes}
2481
- <!-- Main axis line -->
2482
- <T.Line geometry={gc.line_geom}>
2483
- <T.LineBasicMaterial color={gc.color} linewidth={2} />
2484
- </T.Line>
2485
- <!-- Tick marks -->
2486
- {#each gc.tick_geoms as tick_geom, tdx (tdx)}
2487
- <T.Line geometry={tick_geom}>
2488
- <T.LineBasicMaterial color={gc.color} />
2489
- </T.Line>
2490
- {/each}
2445
+ {#if display.show_bounding_box}
2446
+ <T.LineSegments geometry={bounding_box_geometry}>
2447
+ <T.LineBasicMaterial color="#666" opacity={0.6} transparent />
2448
+ </T.LineSegments>
2491
2449
  {/if}
2492
- {#if display.show_grid}
2493
- <!-- Grid lines -->
2494
- {#each gc.grid_geoms as grid_geom, gdx (gdx)}
2495
- <T.Line geometry={grid_geom}>
2496
- <T.LineBasicMaterial color="#888" opacity={0.3} transparent />
2450
+
2451
+ <!-- Axes, ticks, grid lines, and labels -->
2452
+ {#each grid_config as gc (gc.axis)}
2453
+ {#if display.show_axes}
2454
+ <!-- Main axis line -->
2455
+ <T.Line geometry={gc.line_geom}>
2456
+ <T.LineBasicMaterial color={gc.color} linewidth={2} />
2497
2457
  </T.Line>
2498
- {/each}
2499
- {/if}
2500
- {#if display.show_axis_labels}
2501
- <!-- Tick labels (billboarded, always face camera) -->
2502
- {#each gc.tick_labels as tick, tick_idx (tick_idx)}
2458
+ <!-- Tick marks -->
2459
+ {#each gc.tick_geoms as tick_geom, tdx (tdx)}
2460
+ <T.Line geometry={tick_geom}>
2461
+ <T.LineBasicMaterial color={gc.color} />
2462
+ </T.Line>
2463
+ {/each}
2464
+ {/if}
2465
+ {#if display.show_grid}
2466
+ <!-- Grid lines -->
2467
+ {#each gc.grid_geoms as grid_geom, gdx (gdx)}
2468
+ <T.Line geometry={grid_geom}>
2469
+ <T.LineBasicMaterial color="#888" opacity={0.3} transparent />
2470
+ </T.Line>
2471
+ {/each}
2472
+ {/if}
2473
+ {#if display.show_axis_labels}
2474
+ <!-- Tick labels (billboarded, always face camera) -->
2475
+ {#each gc.tick_labels as tick, tick_idx (tick_idx)}
2476
+ <extras.HTML position={tick.pos} center portal={wrapper} zIndexRange={[1, 0]}>
2477
+ <span class="tick-label axis-tick-label">{tick.text}</span>
2478
+ </extras.HTML>
2479
+ {/each}
2480
+ <!-- Axis label -->
2503
2481
  <extras.HTML
2504
- position={tick.pos}
2482
+ position={gc.label_pos}
2505
2483
  center
2506
2484
  portal={wrapper}
2507
2485
  zIndexRange={[1, 0]}
2508
2486
  >
2509
- <span class="tick-label axis-tick-label">{tick.text}</span>
2487
+ <span class="axis-label" style:color={gc.color}>{@html gc.label}</span>
2488
+ </extras.HTML>
2489
+ {/if}
2490
+ {/each}
2491
+
2492
+ <!-- Domain labels -->
2493
+ {#if label_stable}
2494
+ {#each visible_domain_labels as domain (domain.formula)}
2495
+ <extras.HTML
2496
+ position={domain.position}
2497
+ center
2498
+ portal={wrapper}
2499
+ zIndexRange={[5, 5]}
2500
+ >
2501
+ <span
2502
+ class="domain-label"
2503
+ style:font-size="{(domain.label_font_size * zoom_scale).toFixed(1)}px"
2504
+ >
2505
+ {#each formula_label_segments(domain.formula) as segment}
2506
+ <span class:formula-subscript={segment.subscript}>{segment.text}</span>
2507
+ {/each}
2508
+ </span>
2510
2509
  </extras.HTML>
2511
2510
  {/each}
2512
- <!-- Axis label -->
2513
- <extras.HTML
2514
- position={gc.label_pos}
2515
- center
2516
- portal={wrapper}
2517
- zIndexRange={[1, 0]}
2518
- >
2519
- <span class="axis-label" style:color={gc.color}>{@html gc.label}</span>
2520
- </extras.HTML>
2521
2511
  {/if}
2522
- {/each}
2523
-
2524
- <!-- Domain labels -->
2525
- {#if label_stable}
2526
- {#each visible_domain_labels as domain (domain.formula)}
2527
- <extras.HTML
2528
- position={domain.position}
2529
- center
2530
- portal={wrapper}
2531
- zIndexRange={[5, 5]}
2532
- >
2533
- <span
2534
- class="domain-label"
2535
- style:font-size="{(domain.label_font_size * zoom_scale).toFixed(1)}px"
2536
- >
2537
- {#each formula_label_segments(domain.formula) as segment}
2538
- <span class:formula-subscript={segment.subscript}>{segment.text}</span>
2539
- {/each}
2540
- </span>
2541
- </extras.HTML>
2512
+ </ChemPotScene3D>
2513
+ </Canvas>
2514
+ <!-- Color bar for continuous modes -->
2515
+ {#if color_mode !== `none` && color_mode !== `arity` && color_range}
2516
+ {@const color_bar_config = get_chempot_color_bar_config(
2517
+ color_scale,
2518
+ reverse_color_scale,
2519
+ )}
2520
+ <ColorBar
2521
+ title={color_range.label}
2522
+ range={[color_range.min, color_range.max]}
2523
+ color_scale_fn={color_bar_config.color_scale_fn}
2524
+ color_scale_domain={color_bar_config.color_scale_domain}
2525
+ wrapper_style="position: absolute; bottom: 16px; left: 1em; width: 200px; z-index: 10;"
2526
+ bar_style="height: 12px;"
2527
+ title_style="margin-bottom: 4px;"
2528
+ />
2529
+ {/if}
2530
+ <!-- Categorical legend for arity mode -->
2531
+ {#if color_mode === `arity`}
2532
+ <div class="arity-legend">
2533
+ {#each arity_legend_labels as label, idx (label)}
2534
+ <span>
2535
+ <span style:background={arity_colors[idx]}></span>
2536
+ {label}
2537
+ </span>
2542
2538
  {/each}
2543
- {/if}
2544
- </ChemPotScene3D>
2545
- </Canvas>
2546
- <!-- Color bar for continuous modes -->
2547
- {#if color_mode !== `none` && color_mode !== `arity` && color_range}
2548
- {@const color_bar_config = get_chempot_color_bar_config(
2549
- color_scale,
2550
- reverse_color_scale,
2551
- )}
2552
- <ColorBar
2553
- title={color_range.label}
2554
- range={[color_range.min, color_range.max]}
2555
- color_scale_fn={color_bar_config.color_scale_fn}
2556
- color_scale_domain={color_bar_config.color_scale_domain}
2557
- wrapper_style="position: absolute; bottom: 16px; left: 1em; width: 200px; z-index: 10;"
2558
- bar_style="height: 12px;"
2559
- title_style="margin-bottom: 4px;"
2560
- />
2561
- {/if}
2562
- <!-- Categorical legend for arity mode -->
2563
- {#if color_mode === `arity`}
2564
- <div class="arity-legend">
2565
- {#each arity_legend_labels as label, idx (label)}
2566
- <span>
2567
- <span style:background={arity_colors[idx]}></span>
2568
- {label}
2569
- </span>
2570
- {/each}
2571
- </div>
2572
- {/if}
2573
- {/if}
2574
- {#if render_local_tooltip && show_tooltip && hover_info?.view === `3d`}
2575
- <aside
2576
- bind:this={tooltip_el}
2577
- class="phase-tooltip"
2578
- style:left="{tooltip_pos.x}px"
2579
- style:top="{tooltip_pos.y}px"
2580
- >
2581
- <h4>
2582
- {#each formula_label_segments(hover_info.formula) as segment}
2583
- <span class:formula-subscript={segment.subscript}>{segment.text}</span>
2584
- {/each}
2585
- </h4>
2586
- {#if locked_hover_formula === hover_info.formula}
2587
- <p>Pinned · Press Esc to unlock</p>
2539
+ </div>
2588
2540
  {/if}
2589
- <p>
2590
- Vertices: {hover_info.n_vertices} · Edges: {hover_info.n_edges} · Points:
2591
- {hover_info.n_points}
2592
- </p>
2593
- <p>
2594
- Entries: {hover_info.matching_entry_count}
2595
- {#if hover_info.min_energy_per_atom !== null &&
2596
- hover_info.max_energy_per_atom !== null}
2597
- · E/atom: {format_num(hover_info.min_energy_per_atom, `.4~g`)}
2598
- to {format_num(hover_info.max_energy_per_atom, `.4~g`)} eV
2541
+ {/if}
2542
+ {#if render_local_tooltip && show_tooltip && hover_info?.view === `3d`}
2543
+ <aside
2544
+ bind:this={tooltip_el}
2545
+ class="phase-tooltip"
2546
+ style:left="{tooltip_pos.x}px"
2547
+ style:top="{tooltip_pos.y}px"
2548
+ >
2549
+ <h4>
2550
+ {#each formula_label_segments(hover_info.formula) as segment}
2551
+ <span class:formula-subscript={segment.subscript}>{segment.text}</span>
2552
+ {/each}
2553
+ </h4>
2554
+ {#if locked_hover_formula === hover_info.formula}
2555
+ <p>Pinned · Press Esc to unlock</p>
2599
2556
  {/if}
2600
- </p>
2601
- {#if tooltip_detail_level === `detailed`}
2602
- <h5 id="axis-ranges">Axis ranges</h5>
2603
- {#each hover_info.axis_ranges as axis_range (axis_range.element)}
2604
- <p>
2605
- {axis_range.element}: {format_num(axis_range.min_val, `.4~g`)} to
2606
- {format_num(axis_range.max_val, `.4~g`)} eV
2607
- </p>
2608
- {/each}
2609
2557
  <p>
2610
- Centroid: ({
2611
- hover_info.ann_loc.map((value) => format_num(value, `.3~g`)).join(
2612
- `, `,
2613
- )
2614
- })
2558
+ Vertices: {hover_info.n_vertices} · Edges: {hover_info.n_edges} · Points:
2559
+ {hover_info.n_points}
2615
2560
  </p>
2616
- {#if hover_info.touches_limits.length > 0}
2617
- <h5 id="touches-bounds">Touches bounds</h5>
2618
- <p>{hover_info.touches_limits.join(`, `)}</p>
2561
+ <p>
2562
+ Entries: {hover_info.matching_entry_count}
2563
+ {#if hover_info.min_energy_per_atom !== null && hover_info.max_energy_per_atom !== null}
2564
+ · E/atom: {format_num(hover_info.min_energy_per_atom, `.4~g`)}
2565
+ to {format_num(hover_info.max_energy_per_atom, `.4~g`)} eV
2566
+ {/if}
2567
+ </p>
2568
+ {#if tooltip_detail_level === `detailed`}
2569
+ <h5 id="axis-ranges">Axis ranges</h5>
2570
+ {#each hover_info.axis_ranges as axis_range (axis_range.element)}
2571
+ <p>
2572
+ {axis_range.element}: {format_num(axis_range.min_val, `.4~g`)} to
2573
+ {format_num(axis_range.max_val, `.4~g`)} eV
2574
+ </p>
2575
+ {/each}
2576
+ <p>
2577
+ Centroid: ({hover_info.ann_loc
2578
+ .map((value) => format_num(value, `.3~g`))
2579
+ .join(`, `)})
2580
+ </p>
2581
+ {#if hover_info.touches_limits.length > 0}
2582
+ <h5 id="touches-bounds">Touches bounds</h5>
2583
+ <p>{hover_info.touches_limits.join(`, `)}</p>
2584
+ {/if}
2619
2585
  {/if}
2620
- {/if}
2621
- </aside>
2622
- {/if}
2586
+ </aside>
2587
+ {/if}
2623
2588
  </div>
2624
2589
  </div>
2625
2590
 
@@ -2708,8 +2673,10 @@
2708
2673
  }
2709
2674
  .chempot-diagram-3d :global(.projection-controls .pane-row) {
2710
2675
  display: grid;
2711
- grid-template-columns:
2712
- auto minmax(4.5em, 1fr) auto minmax(4.5em, 1fr) auto minmax(4.5em, 1fr);
2676
+ grid-template-columns: auto minmax(4.5em, 1fr) auto minmax(4.5em, 1fr) auto minmax(
2677
+ 4.5em,
2678
+ 1fr
2679
+ );
2713
2680
  align-items: center;
2714
2681
  gap: 3pt;
2715
2682
  }
@@ -2849,10 +2816,7 @@
2849
2816
  .phase-tooltip {
2850
2817
  position: absolute;
2851
2818
  max-width: min(32rem, 92vw);
2852
- background: var(
2853
- --tooltip-bg,
2854
- light-dark(rgba(255, 255, 255, 0.95), rgba(0, 0, 0, 0.9))
2855
- );
2819
+ background: var(--tooltip-bg, light-dark(rgba(255, 255, 255, 0.95), rgba(0, 0, 0, 0.9)));
2856
2820
  color: var(--tooltip-text, var(--text-color, #222));
2857
2821
  border: 1px solid color-mix(in srgb, currentColor 18%, transparent);
2858
2822
  border-radius: 6px;