matterviz 0.4.1 → 0.4.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/EmptyState.svelte +10 -4
- package/dist/FilePicker.svelte +48 -60
- package/dist/Icon.svelte +7 -4
- package/dist/MillerIndexInput.svelte +2 -2
- package/dist/api/optimade.js +10 -7
- package/dist/app.css +68 -0
- package/dist/brillouin/BrillouinZone.svelte +90 -91
- package/dist/brillouin/BrillouinZone.svelte.d.ts +5 -7
- package/dist/brillouin/BrillouinZoneControls.svelte +3 -6
- package/dist/brillouin/BrillouinZoneExportPane.svelte +18 -14
- package/dist/brillouin/BrillouinZoneInfoPane.svelte +6 -10
- package/dist/brillouin/BrillouinZoneScene.svelte +46 -68
- package/dist/brillouin/BrillouinZoneScene.svelte.d.ts +1 -1
- package/dist/brillouin/compute.js +10 -16
- package/dist/brillouin/geometry.js +2 -2
- package/dist/chempot-diagram/ChemPotDiagram.svelte +48 -50
- package/dist/chempot-diagram/ChemPotDiagram2D.svelte +61 -169
- package/dist/chempot-diagram/ChemPotDiagram2D.svelte.d.ts +1 -1
- package/dist/chempot-diagram/ChemPotDiagram3D.svelte +559 -755
- package/dist/chempot-diagram/ChemPotDiagram3D.svelte.d.ts +1 -1
- package/dist/chempot-diagram/async-compute.svelte.js +13 -14
- package/dist/chempot-diagram/color.d.ts +21 -1
- package/dist/chempot-diagram/color.js +70 -1
- package/dist/chempot-diagram/compute.d.ts +7 -0
- package/dist/chempot-diagram/compute.js +85 -26
- package/dist/chempot-diagram/controls-state.svelte.js +1 -1
- package/dist/chempot-diagram/export.js +1 -6
- package/dist/chempot-diagram/temperature.js +9 -10
- package/dist/colors/index.d.ts +0 -4
- package/dist/colors/index.js +19 -20
- package/dist/composition/BarChart.svelte +30 -26
- package/dist/composition/BubbleChart.svelte +17 -17
- package/dist/composition/Composition.svelte +10 -19
- package/dist/composition/Formula.svelte +20 -27
- package/dist/composition/FormulaFilter.svelte +115 -184
- package/dist/composition/PieChart.svelte +55 -41
- package/dist/composition/format.js +7 -9
- package/dist/composition/index.d.ts +2 -0
- package/dist/composition/index.js +14 -0
- package/dist/composition/parse.d.ts +2 -2
- package/dist/composition/parse.js +61 -115
- package/dist/constants.d.ts +0 -1
- package/dist/constants.js +17 -26
- package/dist/convex-hull/ConvexHull.svelte +12 -15
- package/dist/convex-hull/ConvexHull.svelte.d.ts +1 -1
- package/dist/convex-hull/ConvexHull2D.svelte +93 -94
- package/dist/convex-hull/ConvexHull2D.svelte.d.ts +1 -1
- package/dist/convex-hull/ConvexHull3D.svelte +127 -186
- package/dist/convex-hull/ConvexHull3D.svelte.d.ts +1 -1
- package/dist/convex-hull/ConvexHull4D.svelte +131 -180
- package/dist/convex-hull/ConvexHull4D.svelte.d.ts +1 -1
- package/dist/convex-hull/ConvexHullChrome.svelte +36 -40
- package/dist/convex-hull/ConvexHullControls.svelte +46 -48
- package/dist/convex-hull/ConvexHullStats.svelte +193 -195
- package/dist/convex-hull/ConvexHullTooltip.svelte +5 -12
- package/dist/convex-hull/GasPressureControls.svelte +5 -12
- package/dist/convex-hull/StructurePopup.svelte +18 -22
- package/dist/convex-hull/StructurePopup.svelte.d.ts +2 -0
- package/dist/convex-hull/TemperatureSlider.svelte +4 -10
- package/dist/convex-hull/canvas-interactions.svelte.js +2 -1
- package/dist/convex-hull/gas-thermodynamics.js +21 -53
- package/dist/convex-hull/helpers.d.ts +8 -10
- package/dist/convex-hull/helpers.js +37 -43
- package/dist/convex-hull/hull-state.svelte.d.ts +1 -1
- package/dist/convex-hull/thermodynamics.js +37 -44
- package/dist/coordination/CoordinationBarPlot.svelte +49 -53
- package/dist/coordination/CoordinationBarPlot.svelte.d.ts +1 -1
- package/dist/coordination/calc-coordination.d.ts +1 -1
- package/dist/coordination/calc-coordination.js +28 -25
- package/dist/element/BohrAtom.svelte +5 -9
- package/dist/element/ElementHeading.svelte +4 -1
- package/dist/element/ElementPhoto.svelte +11 -9
- package/dist/element/ElementStats.svelte +12 -10
- package/dist/element/ElementTile.svelte +44 -67
- package/dist/element/Nucleus.svelte +4 -2
- package/dist/element/data.d.ts +3 -2
- package/dist/element/data.js +5 -1
- package/dist/element/helpers.d.ts +4 -0
- package/dist/element/helpers.js +18 -0
- package/dist/element/index.d.ts +2 -5
- package/dist/element/index.js +4 -19
- package/dist/feedback/DragOverlay.svelte +5 -5
- package/dist/feedback/DragOverlay.svelte.d.ts +2 -2
- package/dist/feedback/StatusMessage.svelte +7 -4
- package/dist/fermi-surface/FermiSlice.svelte +21 -18
- package/dist/fermi-surface/FermiSurface.svelte +35 -44
- package/dist/fermi-surface/FermiSurface.svelte.d.ts +7 -13
- package/dist/fermi-surface/FermiSurfaceControls.svelte +6 -20
- package/dist/fermi-surface/FermiSurfaceControls.svelte.d.ts +1 -1
- package/dist/fermi-surface/FermiSurfaceScene.svelte +64 -136
- package/dist/fermi-surface/FermiSurfaceScene.svelte.d.ts +1 -1
- package/dist/fermi-surface/FermiSurfaceTooltip.svelte +9 -6
- package/dist/fermi-surface/compute.js +25 -58
- package/dist/fermi-surface/parse.js +54 -88
- package/dist/file-viewer/JsonBrowser.svelte +1043 -0
- package/dist/file-viewer/JsonBrowser.svelte.d.ts +9 -0
- package/dist/file-viewer/PlotPanel.svelte +350 -0
- package/dist/file-viewer/PlotPanel.svelte.d.ts +9 -0
- package/dist/file-viewer/TrajectoryWithDos.svelte +30 -0
- package/dist/file-viewer/TrajectoryWithDos.svelte.d.ts +10 -0
- package/dist/file-viewer/detect.d.ts +11 -0
- package/dist/file-viewer/detect.js +381 -0
- package/dist/file-viewer/eligibility.d.ts +4 -0
- package/dist/file-viewer/eligibility.js +53 -0
- package/dist/file-viewer/host-protocol.d.ts +50 -0
- package/dist/file-viewer/host-transfer.d.ts +25 -0
- package/dist/file-viewer/host-transfer.js +42 -0
- package/dist/file-viewer/index.d.ts +5 -0
- package/dist/file-viewer/index.js +5 -0
- package/dist/file-viewer/main.d.ts +44 -0
- package/dist/file-viewer/main.js +535 -0
- package/dist/file-viewer/parse.d.ts +9 -0
- package/dist/file-viewer/parse.js +170 -0
- package/dist/file-viewer/plot-utils.d.ts +24 -0
- package/dist/file-viewer/plot-utils.js +191 -0
- package/dist/file-viewer/types.d.ts +4 -0
- package/dist/file-viewer/types.js +5 -0
- package/dist/heatmap-matrix/HeatmapMatrix.svelte +153 -219
- package/dist/heatmap-matrix/HeatmapMatrix.svelte.d.ts +2 -2
- package/dist/heatmap-matrix/HeatmapMatrixControls.svelte +9 -7
- package/dist/heatmap-matrix/HeatmapMatrixControls.svelte.d.ts +1 -1
- package/dist/heatmap-matrix/index.d.ts +5 -0
- package/dist/icons.d.ts +4 -0
- package/dist/icons.js +4 -0
- package/dist/index.d.ts +2 -2
- package/dist/index.js +1 -1
- package/dist/io/ExportPane.svelte +11 -7
- package/dist/io/decompress.d.ts +4 -1
- package/dist/io/decompress.js +24 -36
- package/dist/io/export.d.ts +11 -4
- package/dist/io/export.js +75 -19
- package/dist/io/fetch.d.ts +0 -3
- package/dist/io/fetch.js +0 -11
- package/dist/io/file-drop.js +60 -35
- package/dist/io/index.d.ts +0 -1
- package/dist/io/index.js +2 -9
- package/dist/io/is-binary.d.ts +9 -0
- package/dist/io/is-binary.js +45 -1
- package/dist/io/url-drop.d.ts +2 -0
- package/dist/io/url-drop.js +40 -40
- package/dist/isosurface/Isosurface.svelte +700 -215
- package/dist/isosurface/Isosurface.svelte.d.ts +7 -1
- package/dist/isosurface/IsosurfaceControls.svelte +590 -116
- package/dist/isosurface/IsosurfaceControls.svelte.d.ts +1 -1
- package/dist/isosurface/VolumeSlice.svelte +224 -0
- package/dist/isosurface/VolumeSlice.svelte.d.ts +28 -0
- package/dist/isosurface/coloring.d.ts +20 -0
- package/dist/isosurface/coloring.js +118 -0
- package/dist/isosurface/geometry-worker-types.d.ts +38 -0
- package/dist/isosurface/geometry.worker.d.ts +1 -0
- package/dist/isosurface/geometry.worker.js +59 -0
- package/dist/isosurface/grid.d.ts +10 -0
- package/dist/isosurface/grid.js +31 -0
- package/dist/isosurface/index.d.ts +4 -0
- package/dist/isosurface/index.js +4 -0
- package/dist/isosurface/parse-vaspwave.d.ts +3 -0
- package/dist/isosurface/parse-vaspwave.js +138 -0
- package/dist/isosurface/parse.js +6 -6
- package/dist/isosurface/profile.d.ts +12 -0
- package/dist/isosurface/profile.js +19 -0
- package/dist/isosurface/sampling.d.ts +34 -0
- package/dist/isosurface/sampling.js +408 -0
- package/dist/isosurface/slice-rendering.d.ts +13 -0
- package/dist/isosurface/slice-rendering.js +79 -0
- package/dist/isosurface/slice.d.ts +22 -2
- package/dist/isosurface/slice.js +200 -116
- package/dist/isosurface/types.d.ts +24 -1
- package/dist/isosurface/types.js +120 -8
- package/dist/json-path.d.ts +4 -0
- package/dist/json-path.js +89 -0
- package/dist/labels.d.ts +6 -2
- package/dist/labels.js +44 -14
- package/dist/layout/FullscreenButton.svelte +2 -1
- package/dist/layout/FullscreenToggle.svelte +10 -4
- package/dist/layout/InfoCard.svelte +8 -21
- package/dist/layout/InfoTag.svelte +1 -3
- package/dist/layout/NumberRangeInput.svelte +46 -0
- package/dist/layout/NumberRangeInput.svelte.d.ts +12 -0
- package/dist/layout/PropertyFilter.svelte +2 -6
- package/dist/layout/SettingsSection.svelte +57 -62
- package/dist/layout/SettingsSection.svelte.d.ts +6 -7
- package/dist/layout/SubpageGrid.svelte +3 -1
- package/dist/layout/ViewerChrome.svelte +16 -11
- package/dist/layout/ViewerChrome.svelte.d.ts +2 -1
- package/dist/layout/fullscreen.js +3 -5
- package/dist/layout/fullscreen.svelte.js +1 -2
- package/dist/layout/index.d.ts +1 -0
- package/dist/layout/index.js +1 -0
- package/dist/layout/json-tree/JsonNode.svelte +22 -59
- package/dist/layout/json-tree/JsonTree.svelte +101 -172
- package/dist/layout/json-tree/JsonValue.svelte +9 -32
- package/dist/layout/json-tree/utils.d.ts +0 -3
- package/dist/layout/json-tree/utils.js +50 -188
- package/dist/marching-cubes.d.ts +8 -1
- package/dist/marching-cubes.js +115 -48
- package/dist/math.d.ts +5 -2
- package/dist/math.js +48 -38
- package/dist/overlays/ContextMenu.svelte +19 -34
- package/dist/overlays/CopyButton.svelte +11 -5
- package/dist/overlays/DragControlTab.svelte +6 -1
- package/dist/overlays/DraggablePane.svelte +110 -74
- package/dist/overlays/DraggablePane.svelte.d.ts +2 -1
- package/dist/overlays/GlassChip.svelte +32 -0
- package/dist/overlays/GlassChip.svelte.d.ts +8 -0
- package/dist/overlays/InfoPaneCards.svelte +11 -23
- package/dist/overlays/index.d.ts +7 -0
- package/dist/overlays/index.js +26 -0
- package/dist/overlays/portal.d.ts +2 -0
- package/dist/overlays/portal.js +14 -0
- package/dist/periodic-table/PeriodicTable.svelte +113 -145
- package/dist/periodic-table/PeriodicTable.svelte.d.ts +5 -3
- package/dist/periodic-table/PeriodicTableControls.svelte +37 -115
- package/dist/periodic-table/TableInset.svelte +9 -4
- package/dist/phase-diagram/IsobaricBinaryPhaseDiagram.svelte +68 -105
- package/dist/phase-diagram/IsobaricBinaryPhaseDiagram.svelte.d.ts +6 -8
- package/dist/phase-diagram/PhaseDiagramControls.svelte +70 -94
- package/dist/phase-diagram/PhaseDiagramControls.svelte.d.ts +1 -1
- package/dist/phase-diagram/PhaseDiagramEditorPane.svelte +2 -1
- package/dist/phase-diagram/PhaseDiagramExportPane.svelte +12 -12
- package/dist/phase-diagram/PhaseDiagramTooltip.svelte +54 -58
- package/dist/phase-diagram/TdbInfoPanel.svelte +21 -15
- package/dist/phase-diagram/build-diagram.js +4 -9
- package/dist/phase-diagram/diagram-input.d.ts +1 -2
- package/dist/phase-diagram/parse.js +15 -15
- package/dist/phase-diagram/svg-to-diagram.js +28 -27
- package/dist/phase-diagram/utils.js +2 -3
- package/dist/plot/bar/BarPlot.svelte +461 -426
- package/dist/plot/bar/BarPlot.svelte.d.ts +2 -0
- package/dist/plot/bar/BarPlotControls.svelte +1 -3
- package/dist/plot/bar/BarPlotControls.svelte.d.ts +4 -6
- package/dist/plot/bar/SpacegroupBarPlot.svelte +46 -77
- package/dist/plot/bar/data.d.ts +5 -4
- package/dist/plot/bar/data.js +2 -1
- package/dist/plot/box/BoxPlot.svelte +322 -226
- package/dist/plot/box/BoxPlot.svelte.d.ts +2 -0
- package/dist/plot/box/Violin.svelte.d.ts +1 -0
- package/dist/plot/box/box-plot.js +1 -1
- package/dist/plot/core/auto-place.d.ts +1 -1
- package/dist/plot/core/auto-place.js +2 -2
- package/dist/plot/core/axis-utils.d.ts +12 -7
- package/dist/plot/core/axis-utils.js +48 -48
- package/dist/plot/core/components/AxisLabel.svelte +82 -20
- package/dist/plot/core/components/AxisLabel.svelte.d.ts +1 -0
- package/dist/plot/core/components/ColorBar.svelte +101 -106
- package/dist/plot/core/components/ColorScaleSelect.svelte +1 -1
- package/dist/plot/core/components/FillArea.svelte +10 -17
- package/dist/plot/core/components/HierarchyControls.svelte +249 -0
- package/dist/plot/{sunburst/SunburstControls.svelte.d.ts → core/components/HierarchyControls.svelte.d.ts} +12 -8
- package/dist/plot/core/components/InteractiveAxisLabel.svelte +1 -1
- package/dist/plot/core/components/InteractiveAxisLabel.svelte.d.ts +1 -1
- package/dist/plot/core/components/Line.svelte +18 -9
- package/dist/plot/core/components/Line.svelte.d.ts +2 -0
- package/dist/plot/core/components/PlotAxis.svelte +40 -17
- package/dist/plot/core/components/PlotControls.svelte +65 -41
- package/dist/plot/core/components/PlotLegend.svelte +31 -35
- package/dist/plot/core/components/PlotMarginals.svelte +616 -0
- package/dist/plot/core/components/PlotMarginals.svelte.d.ts +15 -0
- package/dist/plot/core/components/PlotTooltip.svelte +1 -1
- package/dist/plot/core/components/PortalSelect.svelte +4 -8
- package/dist/plot/core/components/ReferenceLine.svelte +27 -24
- package/dist/plot/core/components/ReferenceLine3D.svelte +54 -57
- package/dist/plot/core/components/ReferencePlane.svelte +7 -8
- package/dist/plot/core/components/ZeroLines.svelte +4 -8
- package/dist/plot/core/components/ZoomRect.svelte +1 -2
- package/dist/plot/core/components/index.d.ts +1 -0
- package/dist/plot/core/components/index.js +1 -0
- package/dist/plot/core/data-cleaning-signal.d.ts +46 -0
- package/dist/plot/core/data-cleaning-signal.js +467 -0
- package/dist/plot/core/data-cleaning.d.ts +2 -42
- package/dist/plot/core/data-cleaning.js +27 -474
- package/dist/plot/core/data-transform.d.ts +1 -2
- package/dist/plot/core/data-transform.js +9 -15
- package/dist/plot/core/fill-utils.d.ts +3 -1
- package/dist/plot/core/fill-utils.js +28 -6
- package/dist/plot/core/index.d.ts +1 -0
- package/dist/plot/core/index.js +1 -0
- package/dist/plot/core/interactions.js +0 -2
- package/dist/plot/core/layout.d.ts +15 -6
- package/dist/plot/core/layout.js +57 -38
- package/dist/plot/core/marginals.d.ts +170 -0
- package/dist/plot/core/marginals.js +436 -0
- package/dist/plot/core/pan-zoom.svelte.d.ts +2 -4
- package/dist/plot/core/pan-zoom.svelte.js +34 -17
- package/dist/plot/core/placed-tween.svelte.d.ts +3 -0
- package/dist/plot/core/placed-tween.svelte.js +68 -21
- package/dist/plot/core/reference-line.js +1 -1
- package/dist/plot/core/scales.d.ts +23 -0
- package/dist/plot/core/scales.js +39 -13
- package/dist/plot/core/svg.js +0 -1
- package/dist/plot/core/types/fills.d.ts +101 -0
- package/dist/plot/core/types/fills.js +15 -0
- package/dist/plot/core/types/plot-3d.d.ts +87 -0
- package/dist/plot/core/types/plot-3d.js +4 -0
- package/dist/plot/core/types/reference-lines.d.ts +140 -0
- package/dist/plot/core/types/reference-lines.js +9 -0
- package/dist/plot/core/types.d.ts +29 -324
- package/dist/plot/core/types.js +23 -20
- package/dist/plot/core/utils/hierarchy-chart.d.ts +52 -0
- package/dist/plot/core/utils/hierarchy-chart.js +191 -0
- package/dist/plot/core/utils/hierarchy-labels.d.ts +20 -0
- package/dist/plot/core/utils/hierarchy-labels.js +100 -0
- package/dist/plot/core/utils/label-placement.js +2 -2
- package/dist/plot/histogram/Histogram.svelte +314 -340
- package/dist/plot/histogram/Histogram.svelte.d.ts +7 -7
- package/dist/plot/histogram/HistogramControls.svelte +30 -28
- package/dist/plot/histogram/histogram.d.ts +31 -0
- package/dist/plot/histogram/histogram.js +70 -0
- package/dist/plot/histogram/index.d.ts +1 -0
- package/dist/plot/histogram/index.js +1 -0
- package/dist/plot/index.d.ts +1 -0
- package/dist/plot/index.js +1 -0
- package/dist/plot/sankey/Sankey.svelte +78 -69
- package/dist/plot/sankey/Sankey.svelte.d.ts +2 -2
- package/dist/plot/sankey/SankeyControls.svelte +22 -16
- package/dist/plot/sankey/sankey.js +13 -9
- package/dist/plot/scatter/BinnedScatterPlot.svelte +311 -141
- package/dist/plot/scatter/BinnedScatterPlot.svelte.d.ts +7 -0
- package/dist/plot/scatter/ElementScatter.svelte +4 -1
- package/dist/plot/scatter/ScatterPlot.svelte +517 -410
- package/dist/plot/scatter/ScatterPlot.svelte.d.ts +2 -0
- package/dist/plot/scatter/ScatterPlotControls.svelte +18 -19
- package/dist/plot/scatter/ScatterPlotControls.svelte.d.ts +1 -1
- package/dist/plot/scatter/ScatterPoint.svelte +16 -9
- package/dist/plot/scatter/adaptive-density.d.ts +1 -1
- package/dist/plot/scatter/adaptive-density.js +36 -20
- package/dist/plot/scatter/binned-scatter-types.d.ts +3 -2
- package/dist/plot/scatter/binned-scatter-types.js +6 -1
- package/dist/plot/scatter/scatter-data.d.ts +1 -1
- package/dist/plot/scatter/scatter-data.js +8 -7
- package/dist/plot/scatter-3d/ScatterPlot3D.svelte +25 -34
- package/dist/plot/scatter-3d/ScatterPlot3D.svelte.d.ts +2 -2
- package/dist/plot/scatter-3d/ScatterPlot3DControls.svelte +8 -5
- package/dist/plot/scatter-3d/ScatterPlot3DScene.svelte +113 -116
- package/dist/plot/scatter-3d/ScatterPlot3DScene.svelte.d.ts +2 -2
- package/dist/plot/scatter-3d/Surface3D.svelte +4 -13
- package/dist/plot/sunburst/Sunburst.svelte +269 -347
- package/dist/plot/sunburst/Sunburst.svelte.d.ts +2 -2
- package/dist/plot/sunburst/index.d.ts +1 -1
- package/dist/plot/sunburst/index.js +2 -1
- package/dist/plot/sunburst/render.d.ts +2 -2
- package/dist/plot/sunburst/render.js +47 -22
- package/dist/plot/sunburst/sunburst.d.ts +5 -1
- package/dist/plot/sunburst/sunburst.js +10 -3
- package/dist/plot/treemap/Treemap.svelte +1022 -0
- package/dist/plot/treemap/Treemap.svelte.d.ts +90 -0
- package/dist/plot/treemap/index.d.ts +4 -0
- package/dist/plot/treemap/index.js +4 -0
- package/dist/plot/treemap/labels.d.ts +38 -0
- package/dist/plot/treemap/labels.js +80 -0
- package/dist/plot/treemap/treemap.d.ts +28 -0
- package/dist/plot/treemap/treemap.js +102 -0
- package/dist/rdf/RdfPlot.svelte +37 -59
- package/dist/rdf/RdfPlot.svelte.d.ts +1 -1
- package/dist/rdf/calc-rdf.js +63 -52
- package/dist/rdf/index.d.ts +0 -1
- package/dist/sanitize.js +85 -27
- package/dist/scene/SceneCamera.svelte +1 -1
- package/dist/scene/SceneCamera.svelte.d.ts +1 -1
- package/dist/scene/bind-renderer.svelte.js +14 -6
- package/dist/scene/index.d.ts +1 -2
- package/dist/scene/index.js +1 -1
- package/dist/scene/{props.js → props.svelte.js} +15 -1
- package/dist/settings.d.ts +19 -9
- package/dist/settings.js +229 -525
- package/dist/spectral/Bands.svelte +207 -221
- package/dist/spectral/BandsAndDos.svelte +11 -9
- package/dist/spectral/BrillouinBandsDos.svelte +19 -42
- package/dist/spectral/Dos.svelte +92 -93
- package/dist/spectral/helpers.d.ts +3 -3
- package/dist/spectral/helpers.js +65 -140
- package/dist/state.svelte.js +5 -18
- package/dist/structure/Arrow.svelte +5 -18
- package/dist/structure/ArrowInstances.svelte +160 -0
- package/dist/structure/ArrowInstances.svelte.d.ts +16 -0
- package/dist/structure/AtomLegend.svelte +120 -85
- package/dist/structure/AtomLegend.svelte.d.ts +2 -3
- package/dist/structure/Bond.svelte +31 -23
- package/dist/structure/CanvasTooltip.svelte +15 -3
- package/dist/structure/CellSelect.svelte +45 -35
- package/dist/structure/Cylinder.svelte +24 -40
- package/dist/structure/InstancedAtoms.svelte +114 -0
- package/dist/structure/InstancedAtoms.svelte.d.ts +15 -0
- package/dist/structure/Lattice.svelte +85 -149
- package/dist/structure/SiteLabels.svelte +122 -0
- package/dist/structure/SiteLabels.svelte.d.ts +18 -0
- package/dist/structure/Structure.svelte +636 -504
- package/dist/structure/Structure.svelte.d.ts +4 -2
- package/dist/structure/StructureCarousel.svelte +637 -0
- package/dist/structure/StructureCarousel.svelte.d.ts +19 -0
- package/dist/structure/StructureControls.svelte +165 -425
- package/dist/structure/StructureControls.svelte.d.ts +1 -1
- package/dist/structure/StructureExportPane.svelte +17 -21
- package/dist/structure/StructureInfoPane.svelte +128 -133
- package/dist/structure/StructureInfoPane.svelte.d.ts +1 -1
- package/dist/structure/StructureScene.svelte +535 -578
- package/dist/structure/StructureScene.svelte.d.ts +6 -2
- package/dist/structure/StructureViewport.svelte +451 -0
- package/dist/structure/StructureViewport.svelte.d.ts +65 -0
- package/dist/structure/atom-label-placement.d.ts +16 -12
- package/dist/structure/atom-label-placement.js +70 -37
- package/dist/structure/atom-properties.d.ts +2 -0
- package/dist/structure/atom-properties.js +105 -38
- package/dist/structure/bond-order-perception.js +3 -8
- package/dist/structure/bonding.d.ts +9 -3
- package/dist/structure/bonding.js +95 -46
- package/dist/structure/edit-history.d.ts +6 -0
- package/dist/structure/edit-history.js +27 -0
- package/dist/structure/export.d.ts +1 -0
- package/dist/structure/export.js +89 -105
- package/dist/structure/format-detect.d.ts +1 -0
- package/dist/structure/format-detect.js +20 -0
- package/dist/structure/geometry.d.ts +9 -0
- package/dist/structure/geometry.js +27 -0
- package/dist/structure/index.d.ts +16 -1
- package/dist/structure/index.js +15 -10
- package/dist/structure/measure.d.ts +1 -1
- package/dist/structure/measure.js +6 -12
- package/dist/structure/parse.d.ts +2 -1
- package/dist/structure/parse.js +272 -313
- package/dist/structure/partial-occupancy.js +10 -5
- package/dist/structure/pbc.js +85 -107
- package/dist/structure/polyhedra.d.ts +0 -1
- package/dist/structure/polyhedra.js +7 -21
- package/dist/structure/prop-groups.d.ts +85 -0
- package/dist/structure/prop-groups.js +18 -0
- package/dist/structure/supercell.d.ts +1 -2
- package/dist/structure/supercell.js +7 -13
- package/dist/symmetry/SymmetryElements.svelte +11 -15
- package/dist/symmetry/SymmetryStats.svelte +55 -71
- package/dist/symmetry/WyckoffTable.svelte +10 -28
- package/dist/symmetry/cell-transform.js +6 -14
- package/dist/symmetry/index.d.ts +1 -0
- package/dist/symmetry/index.js +13 -10
- package/dist/symmetry/spacegroups.js +3 -2
- package/dist/table/HeatmapTable.svelte +1142 -447
- package/dist/table/HeatmapTable.svelte.d.ts +12 -2
- package/dist/table/ToggleMenu.svelte +168 -53
- package/dist/table/ToggleMenu.svelte.d.ts +1 -1
- package/dist/table/index.d.ts +21 -6
- package/dist/table/index.js +34 -21
- package/dist/theme/ThemeControl.svelte +16 -8
- package/dist/theme/embedded.d.ts +18 -0
- package/dist/theme/embedded.js +206 -0
- package/dist/theme/index.d.ts +5 -5
- package/dist/theme/index.js +5 -12
- package/dist/theme/themes.mjs +44 -66
- package/dist/tooltip/KCoords.svelte +4 -1
- package/dist/tooltip/TooltipContent.svelte +3 -6
- package/dist/tooltip/TooltipContent.svelte.d.ts +1 -1
- package/dist/tooltip/index.d.ts +8 -1
- package/dist/trajectory/Trajectory.svelte +613 -386
- package/dist/trajectory/Trajectory.svelte.d.ts +1 -1
- package/dist/trajectory/TrajectoryError.svelte +12 -74
- package/dist/trajectory/TrajectoryExportPane.svelte +14 -32
- package/dist/trajectory/TrajectoryInfoPane.svelte +127 -164
- package/dist/trajectory/TrajectoryInfoPane.svelte.d.ts +2 -1
- package/dist/trajectory/extract.js +61 -49
- package/dist/trajectory/format-detect.d.ts +2 -0
- package/dist/trajectory/format-detect.js +17 -13
- package/dist/trajectory/frame-reader.d.ts +2 -0
- package/dist/trajectory/frame-reader.js +35 -32
- package/dist/trajectory/helpers.d.ts +2 -0
- package/dist/trajectory/helpers.js +34 -56
- package/dist/trajectory/index.d.ts +1 -0
- package/dist/trajectory/index.js +5 -8
- package/dist/trajectory/parse/ase.js +1 -1
- package/dist/trajectory/parse/h5-utils.d.ts +13 -0
- package/dist/trajectory/parse/h5-utils.js +109 -0
- package/dist/trajectory/parse/hdf5.d.ts +1 -1
- package/dist/trajectory/parse/hdf5.js +116 -106
- package/dist/trajectory/parse/index.d.ts +6 -6
- package/dist/trajectory/parse/index.js +25 -33
- package/dist/trajectory/parse/lammps.js +8 -12
- package/dist/trajectory/parse/vasp.js +10 -7
- package/dist/trajectory/parse/vaspout-electronic.d.ts +13 -0
- package/dist/trajectory/parse/vaspout-electronic.js +207 -0
- package/dist/trajectory/parse/vaspout-h5.d.ts +4 -0
- package/dist/trajectory/parse/vaspout-h5.js +281 -0
- package/dist/trajectory/parse/xyz.js +59 -9
- package/dist/trajectory/plotting.d.ts +8 -9
- package/dist/trajectory/plotting.js +113 -64
- package/dist/utils.d.ts +3 -0
- package/dist/utils.js +7 -0
- package/dist/xrd/XrdPlot.svelte +79 -118
- package/dist/xrd/broadening.js +2 -1
- package/dist/xrd/calc-xrd.js +24 -62
- package/dist/xrd/parse.d.ts +0 -1
- package/dist/xrd/parse.js +69 -95
- package/package.json +94 -34
- package/readme.md +6 -5
- package/dist/api/mp.d.ts +0 -6
- package/dist/api/mp.js +0 -22
- package/dist/plot/sunburst/SunburstControls.svelte +0 -200
- package/dist/scene/types.d.ts +0 -26
- package/dist/tooltip/types.d.ts +0 -8
- package/dist/trajectory/constants.d.ts +0 -6
- package/dist/trajectory/constants.js +0 -11
- /package/dist/{scene/types.js → file-viewer/host-protocol.js} +0 -0
- /package/dist/{tooltip/types.js → isosurface/geometry-worker-types.js} +0 -0
|
@@ -9,22 +9,20 @@
|
|
|
9
9
|
import type { ExportSection } from '../io'
|
|
10
10
|
import ExportPane from '../io/ExportPane.svelte'
|
|
11
11
|
import { format_num } from '../labels'
|
|
12
|
-
import {
|
|
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
|
-
|
|
25
|
-
|
|
26
|
-
rects_overlap,
|
|
27
|
-
} from '../plot/core/layout'
|
|
23
|
+
import { page_visibility } from '../scene'
|
|
24
|
+
import { sanitize_html } from '../sanitize'
|
|
25
|
+
import { constrain_tooltip_position, pad_rect, rects_overlap } from '../plot/core/layout'
|
|
28
26
|
import type {
|
|
29
27
|
AxisConfig3D,
|
|
30
28
|
CameraProjection3D,
|
|
@@ -42,7 +40,7 @@
|
|
|
42
40
|
import { ConvexGeometry } from 'three/examples/jsm/geometries/ConvexGeometry.js'
|
|
43
41
|
import { compute_chempot_async } from './async-compute.svelte'
|
|
44
42
|
import ChemPotScene3D from './ChemPotScene3D.svelte'
|
|
45
|
-
import { get_chempot_color_bar_config,
|
|
43
|
+
import { ARITY_COLORS, get_chempot_color_bar_config, get_domain_color_data } from './color'
|
|
46
44
|
import {
|
|
47
45
|
CHEMPOT_COLOR_MODE_OPTIONS,
|
|
48
46
|
CHEMPOT_COLOR_SCALE_OPTIONS,
|
|
@@ -60,12 +58,10 @@
|
|
|
60
58
|
import {
|
|
61
59
|
apply_element_padding,
|
|
62
60
|
bbox_diagonal,
|
|
63
|
-
best_form_energy_for_formula,
|
|
64
61
|
build_axis_ranges,
|
|
65
62
|
dedup_points,
|
|
66
|
-
formula_key_from_composition,
|
|
67
63
|
get_3d_domain_simplexes_and_ann_loc,
|
|
68
|
-
|
|
64
|
+
get_energy_stats_by_formula,
|
|
69
65
|
get_min_entries_and_el_refs,
|
|
70
66
|
get_ternary_combinations,
|
|
71
67
|
get_visible_domain_labels,
|
|
@@ -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(
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
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(() => {
|
|
185
|
-
|
|
186
|
-
|
|
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
|
-
?
|
|
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,25 +263,20 @@
|
|
|
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),
|
|
257
270
|
)
|
|
258
271
|
|
|
259
|
-
const all_entry_elements = $derived.by(() =>
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
),
|
|
268
|
-
).sort()
|
|
269
|
-
)
|
|
272
|
+
const all_entry_elements = $derived.by(() => {
|
|
273
|
+
const elements = projection_source_entries.flatMap((entry) =>
|
|
274
|
+
Object.entries(entry.composition)
|
|
275
|
+
.filter(([, amount]) => amount > 0)
|
|
276
|
+
.map(([element]) => element),
|
|
277
|
+
)
|
|
278
|
+
return Array.from(new SvelteSet(elements)).sort()
|
|
279
|
+
})
|
|
270
280
|
const has_multinary_system = $derived(all_entry_elements.length > 3)
|
|
271
281
|
let projection_elements_override = $state<string[] | null>(null)
|
|
272
282
|
const config_projection_elements = $derived(
|
|
@@ -274,22 +284,18 @@
|
|
|
274
284
|
)
|
|
275
285
|
const projection_elements = $derived.by(() => {
|
|
276
286
|
if (all_entry_elements.length < 3) return []
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
if (config_projection_elements) return config_projection_elements
|
|
286
|
-
return all_entry_elements.slice(0, 3)
|
|
287
|
+
// User-picked projection axes only apply to multinary (4+ element) systems
|
|
288
|
+
const override_projection = has_multinary_system
|
|
289
|
+
? normalize_projection_triplet(
|
|
290
|
+
projection_elements_override ?? undefined,
|
|
291
|
+
all_entry_elements,
|
|
292
|
+
)
|
|
293
|
+
: null
|
|
294
|
+
return override_projection ?? config_projection_elements ?? all_entry_elements.slice(0, 3)
|
|
287
295
|
})
|
|
288
296
|
const effective_config = $derived({
|
|
289
297
|
...config,
|
|
290
|
-
elements: projection_elements.length === 3
|
|
291
|
-
? projection_elements
|
|
292
|
-
: config.elements,
|
|
298
|
+
elements: projection_elements.length === 3 ? projection_elements : config.elements,
|
|
293
299
|
formal_chempots,
|
|
294
300
|
label_stable,
|
|
295
301
|
element_padding,
|
|
@@ -319,7 +325,9 @@
|
|
|
319
325
|
diagram_data = null
|
|
320
326
|
diagram_computing = false
|
|
321
327
|
})
|
|
322
|
-
return () => {
|
|
328
|
+
return () => {
|
|
329
|
+
cancelled = true
|
|
330
|
+
}
|
|
323
331
|
})
|
|
324
332
|
|
|
325
333
|
const plot_elements = $derived(diagram_data?.elements ?? projection_elements)
|
|
@@ -348,15 +356,11 @@
|
|
|
348
356
|
})
|
|
349
357
|
const current_projection_key = $derived(plot_elements.join(`|`))
|
|
350
358
|
let formula_filter_query = $state(``)
|
|
351
|
-
const available_formulas = $derived.
|
|
352
|
-
Object.keys(diagram_data?.domains ?? {}).sort()
|
|
353
|
-
)
|
|
359
|
+
const available_formulas = $derived(Object.keys(diagram_data?.domains ?? {}).sort())
|
|
354
360
|
const filtered_formulas = $derived.by(() => {
|
|
355
361
|
const query = formula_filter_query.trim().toLowerCase()
|
|
356
362
|
if (!query) return available_formulas
|
|
357
|
-
return available_formulas.filter((formula) =>
|
|
358
|
-
formula.toLowerCase().includes(query)
|
|
359
|
-
)
|
|
363
|
+
return available_formulas.filter((formula) => formula.toLowerCase().includes(query))
|
|
360
364
|
})
|
|
361
365
|
|
|
362
366
|
// Process domains for rendering
|
|
@@ -374,51 +378,49 @@
|
|
|
374
378
|
info: ChemPotHoverInfo3D
|
|
375
379
|
}
|
|
376
380
|
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
+
const domain_annotation_cache = new Map<string, number[]>()
|
|
382
|
+
|
|
383
|
+
function get_domain_ann_loc(points_3d: number[][]): number[] {
|
|
384
|
+
if (points_3d.length >= 3) {
|
|
385
|
+
const cache_key = points_3d.map((point) => point.join(`,`)).join(`;`)
|
|
386
|
+
const cached = domain_annotation_cache.get(cache_key)
|
|
387
|
+
if (cached) return cached
|
|
388
|
+
const ann_loc = get_3d_domain_simplexes_and_ann_loc(points_3d).ann_loc
|
|
389
|
+
domain_annotation_cache.set(cache_key, ann_loc)
|
|
390
|
+
return ann_loc
|
|
391
|
+
}
|
|
392
|
+
return points_3d[0].map(
|
|
393
|
+
(_, col_idx) =>
|
|
394
|
+
points_3d.reduce((sum, point) => sum + point[col_idx], 0) / points_3d.length,
|
|
395
|
+
)
|
|
381
396
|
}
|
|
382
|
-
type NumericColorMode = Exclude<ChemPotColorMode, `none` | `arity`>
|
|
383
397
|
|
|
384
398
|
const render_domains = $derived.by((): DomainRenderData[] => {
|
|
385
399
|
if (!diagram_data || plot_elements.length < 2) return []
|
|
386
400
|
|
|
387
401
|
const dim = diagram_data.elements.length
|
|
388
402
|
const indices = Array.from({ length: dim }, (_, idx) => idx)
|
|
389
|
-
const new_lims =
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
403
|
+
const new_lims =
|
|
404
|
+
element_padding > 0
|
|
405
|
+
? apply_element_padding(
|
|
406
|
+
diagram_data.domains,
|
|
407
|
+
indices,
|
|
408
|
+
element_padding,
|
|
409
|
+
default_min_limit,
|
|
410
|
+
)
|
|
411
|
+
: null
|
|
397
412
|
|
|
398
413
|
const result: DomainRenderData[] = []
|
|
399
414
|
for (const [formula, pts] of Object.entries(diagram_data.domains)) {
|
|
400
415
|
const padded = new_lims
|
|
401
|
-
? pad_domain_points(
|
|
402
|
-
pts,
|
|
403
|
-
indices,
|
|
404
|
-
new_lims,
|
|
405
|
-
default_min_limit,
|
|
406
|
-
element_padding,
|
|
407
|
-
)
|
|
416
|
+
? pad_domain_points(pts, indices, new_lims, default_min_limit, element_padding)
|
|
408
417
|
: pts
|
|
409
418
|
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
419
|
result.push({
|
|
418
420
|
formula,
|
|
419
421
|
points_3d: padded,
|
|
420
|
-
ann_loc,
|
|
421
|
-
is_draw_formula:
|
|
422
|
+
ann_loc: get_domain_ann_loc(padded),
|
|
423
|
+
is_draw_formula: formulas_to_draw.includes(formula),
|
|
422
424
|
label_font_size: bbox_diagonal(padded),
|
|
423
425
|
})
|
|
424
426
|
}
|
|
@@ -431,129 +433,26 @@
|
|
|
431
433
|
return result
|
|
432
434
|
})
|
|
433
435
|
|
|
434
|
-
const entry_energy_stats_by_formula = $derived
|
|
435
|
-
()
|
|
436
|
-
const stats_by_formula = new SvelteMap<string, FormulaEnergyStats>()
|
|
437
|
-
for (const entry of temp_filtered_entries) {
|
|
438
|
-
const formula_key = formula_key_from_composition(entry.composition)
|
|
439
|
-
const energy_per_atom = get_energy_per_atom(entry)
|
|
440
|
-
const existing = stats_by_formula.get(formula_key)
|
|
441
|
-
if (!existing) {
|
|
442
|
-
stats_by_formula.set(formula_key, {
|
|
443
|
-
matching_entry_count: 1,
|
|
444
|
-
min_energy_per_atom: energy_per_atom,
|
|
445
|
-
max_energy_per_atom: energy_per_atom,
|
|
446
|
-
})
|
|
447
|
-
continue
|
|
448
|
-
}
|
|
449
|
-
stats_by_formula.set(formula_key, {
|
|
450
|
-
matching_entry_count: existing.matching_entry_count + 1,
|
|
451
|
-
min_energy_per_atom: Math.min(
|
|
452
|
-
existing.min_energy_per_atom ?? energy_per_atom,
|
|
453
|
-
energy_per_atom,
|
|
454
|
-
),
|
|
455
|
-
max_energy_per_atom: Math.max(
|
|
456
|
-
existing.max_energy_per_atom ?? energy_per_atom,
|
|
457
|
-
energy_per_atom,
|
|
458
|
-
),
|
|
459
|
-
})
|
|
460
|
-
}
|
|
461
|
-
return stats_by_formula
|
|
462
|
-
},
|
|
436
|
+
const entry_energy_stats_by_formula = $derived(
|
|
437
|
+
get_energy_stats_by_formula(temp_filtered_entries),
|
|
463
438
|
)
|
|
464
439
|
|
|
465
440
|
// === Region coloring ===
|
|
466
|
-
// Categorical palette for arity mode (element count)
|
|
467
|
-
const arity_colors = [`#3498db`, `#2ecc71`, `#e67e22`, `#9b59b6`] as const
|
|
468
|
-
|
|
469
441
|
// Original (non-renormalized) elemental references for formation energy computation.
|
|
470
442
|
// diagram_data.el_refs may be renormalized to zero when formal_chempots is true,
|
|
471
443
|
// 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
|
-
)
|
|
475
|
-
|
|
476
|
-
const color_mode_labels: Record<NumericColorMode, string> = {
|
|
477
|
-
energy: `Energy per atom (eV)`,
|
|
478
|
-
formation_energy: `Formation energy (eV/atom)`,
|
|
479
|
-
entries: `Entry count`,
|
|
480
|
-
}
|
|
481
|
-
function get_numeric_color_value(
|
|
482
|
-
formula: string,
|
|
483
|
-
active_color_mode: NumericColorMode,
|
|
484
|
-
): number | null {
|
|
485
|
-
if (active_color_mode === `energy`) {
|
|
486
|
-
return entry_energy_stats_by_formula.get(formula)?.min_energy_per_atom ?? null
|
|
487
|
-
}
|
|
488
|
-
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
|
|
494
|
-
}
|
|
495
|
-
return entry_energy_stats_by_formula.get(formula)?.matching_entry_count ?? 0
|
|
496
|
-
}
|
|
497
|
-
const domain_color_values = $derived.by(
|
|
498
|
-
(): { value_by_formula: SvelteMap<string, number>; values: number[] } | null => {
|
|
499
|
-
if (color_mode === `none` || color_mode === `arity`) return null
|
|
500
|
-
const active_color_mode = color_mode as NumericColorMode
|
|
501
|
-
const value_by_formula = new SvelteMap<string, number>()
|
|
502
|
-
const values: number[] = []
|
|
503
|
-
for (const domain of render_domains) {
|
|
504
|
-
const value = get_numeric_color_value(domain.formula, active_color_mode)
|
|
505
|
-
if (value == null || !Number.isFinite(value)) continue
|
|
506
|
-
values.push(value)
|
|
507
|
-
value_by_formula.set(domain.formula, value)
|
|
508
|
-
}
|
|
509
|
-
return { value_by_formula, values }
|
|
510
|
-
},
|
|
511
|
-
)
|
|
512
|
-
|
|
513
|
-
// Per-domain color map keyed by formula
|
|
514
|
-
const domain_colors = $derived.by((): SvelteMap<string, string> => {
|
|
515
|
-
const colors = new SvelteMap<string, string>()
|
|
516
|
-
if (color_mode === `none`) return colors
|
|
444
|
+
const raw_el_refs = $derived(get_min_entries_and_el_refs(temp_filtered_entries).el_refs)
|
|
517
445
|
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
colors.set(domain.formula, arity_colors[Math.max(0, idx)])
|
|
523
|
-
}
|
|
524
|
-
return colors
|
|
525
|
-
}
|
|
526
|
-
const values_payload = domain_color_values
|
|
527
|
-
const scale = make_chempot_color_scale(
|
|
528
|
-
values_payload?.values ?? [],
|
|
446
|
+
const { colors: domain_colors, color_range } = $derived(
|
|
447
|
+
get_domain_color_data({
|
|
448
|
+
formulas: render_domains.map((domain) => domain.formula),
|
|
449
|
+
color_mode,
|
|
529
450
|
color_scale,
|
|
530
451
|
reverse_color_scale,
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
}
|
|
536
|
-
return colors
|
|
537
|
-
})
|
|
538
|
-
|
|
539
|
-
// 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
|
-
},
|
|
452
|
+
entries: temp_filtered_entries,
|
|
453
|
+
el_refs: raw_el_refs,
|
|
454
|
+
energy_stats: entry_energy_stats_by_formula,
|
|
455
|
+
}),
|
|
557
456
|
)
|
|
558
457
|
|
|
559
458
|
const arity_legend_labels = $derived.by((): string[] => {
|
|
@@ -574,9 +473,12 @@
|
|
|
574
473
|
const render_axis_scale = $derived.by((): Vec3 => {
|
|
575
474
|
const points = render_domains.flatMap((domain) => domain.points_3d)
|
|
576
475
|
if (points.length === 0) return [1, 1, 1]
|
|
577
|
-
let min0 = Infinity,
|
|
578
|
-
|
|
579
|
-
let
|
|
476
|
+
let min0 = Infinity,
|
|
477
|
+
max0 = -Infinity
|
|
478
|
+
let min1 = Infinity,
|
|
479
|
+
max1 = -Infinity
|
|
480
|
+
let min2 = Infinity,
|
|
481
|
+
max2 = -Infinity
|
|
580
482
|
for (const point of points) {
|
|
581
483
|
if (point[0] < min0) min0 = point[0]
|
|
582
484
|
if (point[0] > max0) max0 = point[0]
|
|
@@ -596,10 +498,7 @@
|
|
|
596
498
|
]
|
|
597
499
|
})
|
|
598
500
|
|
|
599
|
-
|
|
600
|
-
const [scale_x, scale_y, scale_z] = render_axis_scale
|
|
601
|
-
return [point[1] * scale_x, point[2] * scale_y, point[0] * scale_z]
|
|
602
|
-
}
|
|
501
|
+
const to_render_xyz = (point: number[]): Vec3 => swiz(point[0], point[1], point[2])
|
|
603
502
|
|
|
604
503
|
// Compute data center and extent for camera positioning (in swizzled coords)
|
|
605
504
|
const { data_center, data_extent } = $derived.by(() => {
|
|
@@ -616,11 +515,7 @@
|
|
|
616
515
|
sum_z += z_val
|
|
617
516
|
}
|
|
618
517
|
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
|
-
)
|
|
518
|
+
const center = new THREE.Vector3(sum_x / n_points, sum_y / n_points, sum_z / n_points)
|
|
624
519
|
// Compute max distance from center
|
|
625
520
|
let max_dist = 0
|
|
626
521
|
for (const point of points) {
|
|
@@ -635,30 +530,22 @@
|
|
|
635
530
|
data_center.y + data_extent,
|
|
636
531
|
data_center.z + data_extent,
|
|
637
532
|
])
|
|
638
|
-
const default_camera_target = $derived<Vec3>([
|
|
639
|
-
data_center.x,
|
|
640
|
-
data_center.y,
|
|
641
|
-
data_center.z,
|
|
642
|
-
])
|
|
533
|
+
const default_camera_target = $derived<Vec3>([data_center.x, data_center.y, data_center.z])
|
|
643
534
|
const default_orthographic_zoom = $derived(
|
|
644
535
|
Math.min(render_width, render_height) / (data_extent * 1.6),
|
|
645
536
|
)
|
|
646
537
|
let camera_position_override = $state<Vec3 | null>(null)
|
|
647
538
|
let camera_target_override = $state<Vec3 | null>(null)
|
|
648
539
|
let orthographic_zoom_override = $state<number | null>(null)
|
|
649
|
-
const camera_position = $derived(
|
|
650
|
-
|
|
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
|
-
)
|
|
540
|
+
const camera_position = $derived(camera_position_override ?? default_camera_position)
|
|
541
|
+
const camera_target = $derived(camera_target_override ?? default_camera_target)
|
|
542
|
+
const orthographic_zoom = $derived(orthographic_zoom_override ?? default_orthographic_zoom)
|
|
658
543
|
// Label scale factor: zoom relative to default, so labels grow/shrink with zoom
|
|
659
544
|
// Labels scale sub-linearly with zoom so they grow but don't dominate when zoomed in
|
|
660
545
|
const zoom_scale = $derived(
|
|
661
|
-
default_orthographic_zoom > 0
|
|
546
|
+
default_orthographic_zoom > 0
|
|
547
|
+
? Math.sqrt(orthographic_zoom / default_orthographic_zoom)
|
|
548
|
+
: 1,
|
|
662
549
|
)
|
|
663
550
|
let last_data_center: Vec3 | null = null
|
|
664
551
|
let last_data_extent: number | null = null
|
|
@@ -667,14 +554,16 @@
|
|
|
667
554
|
// Each domain in a chem pot diagram is a convex polygon/polyhedron. We project
|
|
668
555
|
// to 2D (trying all 3 axis-aligned planes) and use the best projection's
|
|
669
556
|
// convex hull boundary. This reliably handles both flat and 3D domains.
|
|
670
|
-
function get_domain_edges(
|
|
671
|
-
pts: number[][],
|
|
672
|
-
): [number[], number[]][] {
|
|
557
|
+
function get_domain_edges(pts: number[][]): [number[], number[]][] {
|
|
673
558
|
const unique = dedup_3d(pts)
|
|
674
559
|
if (unique.length < 2) return []
|
|
675
560
|
if (unique.length === 2) return [[unique[0], unique[1]]]
|
|
676
561
|
if (unique.length === 3) {
|
|
677
|
-
return [
|
|
562
|
+
return [
|
|
563
|
+
[unique[0], unique[1]],
|
|
564
|
+
[unique[1], unique[2]],
|
|
565
|
+
[unique[0], unique[2]],
|
|
566
|
+
]
|
|
678
567
|
}
|
|
679
568
|
return get_2d_hull_edges(unique)
|
|
680
569
|
}
|
|
@@ -694,9 +583,7 @@
|
|
|
694
583
|
// (largest non-degenerate hull area). Unioning multiple projections can add
|
|
695
584
|
// non-physical diagonals for nearly coplanar domains.
|
|
696
585
|
// Called only from get_domain_edges with 4+ unique points
|
|
697
|
-
function get_2d_hull_edges(
|
|
698
|
-
pts: number[][],
|
|
699
|
-
): [number[], number[]][] {
|
|
586
|
+
function get_2d_hull_edges(pts: number[][]): [number[], number[]][] {
|
|
700
587
|
let selected_hull: Vec2[] = []
|
|
701
588
|
let selected_coord_to_idx: SvelteMap<string, number> | null = null
|
|
702
589
|
let selected_hull_area = -1
|
|
@@ -706,15 +593,20 @@
|
|
|
706
593
|
|
|
707
594
|
// Skip this projection if points collapse to a line (near-zero range in
|
|
708
595
|
// either projected axis). This avoids spurious edges from edge-on views.
|
|
709
|
-
let min0 = Infinity,
|
|
596
|
+
let min0 = Infinity,
|
|
597
|
+
max0 = -Infinity,
|
|
598
|
+
min1 = Infinity,
|
|
599
|
+
max1 = -Infinity
|
|
710
600
|
for (const pt of pts) {
|
|
711
|
-
const v0 = pt[axes[0]],
|
|
601
|
+
const v0 = pt[axes[0]],
|
|
602
|
+
v1 = pt[axes[1]]
|
|
712
603
|
if (v0 < min0) min0 = v0
|
|
713
604
|
if (v0 > max0) max0 = v0
|
|
714
605
|
if (v1 < min1) min1 = v1
|
|
715
606
|
if (v1 > max1) max1 = v1
|
|
716
607
|
}
|
|
717
|
-
const range0 = max0 - min0,
|
|
608
|
+
const range0 = max0 - min0,
|
|
609
|
+
range1 = max1 - min1
|
|
718
610
|
const max_2d_range = Math.max(range0, range1)
|
|
719
611
|
if (max_2d_range < 1e-6 || Math.min(range0, range1) < max_2d_range * 0.01) {
|
|
720
612
|
continue
|
|
@@ -751,18 +643,8 @@
|
|
|
751
643
|
const point_b_idx = selected_coord_to_idx.get(
|
|
752
644
|
`${point_b[0].toFixed(6)},${point_b[1].toFixed(6)}`,
|
|
753
645
|
)
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
point_b_idx >= pts.length
|
|
757
|
-
) {
|
|
758
|
-
console.warn(`get_2d_hull_edges: invalid edge`, {
|
|
759
|
-
point_a,
|
|
760
|
-
point_b,
|
|
761
|
-
point_a_idx,
|
|
762
|
-
point_b_idx,
|
|
763
|
-
})
|
|
764
|
-
continue
|
|
765
|
-
}
|
|
646
|
+
// Hull vertices come from pts_2d, so lookups always succeed
|
|
647
|
+
if (point_a_idx == null || point_b_idx == null) continue
|
|
766
648
|
edges.push([pts[point_a_idx], pts[point_b_idx]])
|
|
767
649
|
}
|
|
768
650
|
|
|
@@ -846,7 +728,9 @@
|
|
|
846
728
|
const n_verts = pos.count
|
|
847
729
|
const n_faces = n_verts / 3
|
|
848
730
|
// Hull centroid for orienting face normals outward
|
|
849
|
-
let hx = 0,
|
|
731
|
+
let hx = 0,
|
|
732
|
+
hy = 0,
|
|
733
|
+
hz = 0
|
|
850
734
|
for (let vert_idx = 0; vert_idx < n_verts; vert_idx++) {
|
|
851
735
|
hx += pos.getX(vert_idx)
|
|
852
736
|
hy += pos.getY(vert_idx)
|
|
@@ -900,7 +784,9 @@
|
|
|
900
784
|
const centroids = render_domains
|
|
901
785
|
.filter((domain) => !domain.is_draw_formula && domain.points_3d.length > 0)
|
|
902
786
|
.map((domain) => {
|
|
903
|
-
let sx = 0,
|
|
787
|
+
let sx = 0,
|
|
788
|
+
sy = 0,
|
|
789
|
+
sz = 0
|
|
904
790
|
for (const pt of domain.points_3d) {
|
|
905
791
|
const [x_val, y_val, z_val] = to_render_xyz(pt)
|
|
906
792
|
sx += x_val
|
|
@@ -908,7 +794,12 @@
|
|
|
908
794
|
sz += z_val
|
|
909
795
|
}
|
|
910
796
|
const n_points = domain.points_3d.length
|
|
911
|
-
return {
|
|
797
|
+
return {
|
|
798
|
+
formula: domain.formula,
|
|
799
|
+
cx: sx / n_points,
|
|
800
|
+
cy: sy / n_points,
|
|
801
|
+
cz: sz / n_points,
|
|
802
|
+
}
|
|
912
803
|
})
|
|
913
804
|
|
|
914
805
|
// Assign each face to the nearest domain centroid
|
|
@@ -938,9 +829,9 @@
|
|
|
938
829
|
const tol = 1e-3
|
|
939
830
|
const round = (val: number): number => Math.round(val / tol)
|
|
940
831
|
const vkey = (vert_idx: number): string =>
|
|
941
|
-
`${round(pos.getX(vert_idx))},${round(pos.getY(vert_idx))},${
|
|
942
|
-
|
|
943
|
-
}`
|
|
832
|
+
`${round(pos.getX(vert_idx))},${round(pos.getY(vert_idx))},${round(
|
|
833
|
+
pos.getZ(vert_idx),
|
|
834
|
+
)}`
|
|
944
835
|
// Compute face normals
|
|
945
836
|
const normals: Vec3[] = []
|
|
946
837
|
for (let face_idx = 0; face_idx < n_faces; face_idx++) {
|
|
@@ -962,13 +853,11 @@
|
|
|
962
853
|
for (let face_idx = 0; face_idx < n_faces; face_idx++) {
|
|
963
854
|
const base = face_idx * 3
|
|
964
855
|
const keys = [vkey(base), vkey(base + 1), vkey(base + 2)]
|
|
965
|
-
for (
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
]
|
|
971
|
-
) {
|
|
856
|
+
for (const ek of [
|
|
857
|
+
edge_key(keys[0], keys[1]),
|
|
858
|
+
edge_key(keys[1], keys[2]),
|
|
859
|
+
edge_key(keys[0], keys[2]),
|
|
860
|
+
]) {
|
|
972
861
|
const list = edge_faces.get(ek)
|
|
973
862
|
if (list) list.push(face_idx)
|
|
974
863
|
else edge_faces.set(ek, [face_idx])
|
|
@@ -984,13 +873,15 @@
|
|
|
984
873
|
return node
|
|
985
874
|
}
|
|
986
875
|
const union = (a_idx: number, b_idx: number): void => {
|
|
987
|
-
const ra = find(a_idx),
|
|
876
|
+
const ra = find(a_idx),
|
|
877
|
+
rb = find(b_idx)
|
|
988
878
|
if (ra !== rb) parent[ra] = rb
|
|
989
879
|
}
|
|
990
880
|
for (const pair of edge_faces.values()) {
|
|
991
881
|
if (pair.length !== 2) continue
|
|
992
882
|
const [fa, fb] = pair
|
|
993
|
-
const na = normals[fa],
|
|
883
|
+
const na = normals[fa],
|
|
884
|
+
nb = normals[fb]
|
|
994
885
|
if (Math.abs(na[0] * nb[0] + na[1] * nb[1] + na[2] * nb[2]) > 1 - tol) {
|
|
995
886
|
union(fa, fb)
|
|
996
887
|
}
|
|
@@ -1057,23 +948,21 @@
|
|
|
1057
948
|
return geom
|
|
1058
949
|
})
|
|
1059
950
|
|
|
951
|
+
const domain_label = (domain: DomainRenderData) => ({
|
|
952
|
+
formula: domain.formula,
|
|
953
|
+
position: swiz(domain.ann_loc[0], domain.ann_loc[1], domain.ann_loc[2]),
|
|
954
|
+
label_font_size: domain.label_font_size,
|
|
955
|
+
})
|
|
956
|
+
|
|
1060
957
|
const visible_domain_labels = $derived.by(() => {
|
|
1061
958
|
if (!hull_base_geometry || face_domain_map.length === 0) {
|
|
1062
|
-
return render_domains.map(
|
|
1063
|
-
formula: domain.formula,
|
|
1064
|
-
position: swiz(domain.ann_loc[0], domain.ann_loc[1], domain.ann_loc[2]),
|
|
1065
|
-
label_font_size: domain.label_font_size,
|
|
1066
|
-
}))
|
|
959
|
+
return render_domains.map(domain_label)
|
|
1067
960
|
}
|
|
1068
961
|
|
|
1069
962
|
const pos = hull_base_geometry.getAttribute(`position`)
|
|
1070
963
|
const pinned_labels = render_domains
|
|
1071
964
|
.filter((domain) => domain.is_draw_formula)
|
|
1072
|
-
.map(
|
|
1073
|
-
formula: domain.formula,
|
|
1074
|
-
position: swiz(domain.ann_loc[0], domain.ann_loc[1], domain.ann_loc[2]),
|
|
1075
|
-
label_font_size: domain.label_font_size,
|
|
1076
|
-
}))
|
|
965
|
+
.map(domain_label)
|
|
1077
966
|
const font_size_by_formula = new SvelteMap(
|
|
1078
967
|
render_domains.map((domain) => [domain.formula, domain.label_font_size]),
|
|
1079
968
|
)
|
|
@@ -1085,16 +974,24 @@
|
|
|
1085
974
|
)
|
|
1086
975
|
})
|
|
1087
976
|
|
|
1088
|
-
|
|
1089
|
-
|
|
1090
|
-
|
|
1091
|
-
|
|
977
|
+
// Register an effect that disposes the given geometries whenever they are
|
|
978
|
+
// recomputed or the component unmounts.
|
|
979
|
+
function dispose_on_change(
|
|
980
|
+
get_geometries: () => (THREE.BufferGeometry | null | undefined)[],
|
|
981
|
+
): void {
|
|
982
|
+
$effect(() => {
|
|
983
|
+
const geometries = get_geometries()
|
|
984
|
+
return () => {
|
|
985
|
+
for (const geometry of geometries) geometry?.dispose()
|
|
986
|
+
}
|
|
987
|
+
})
|
|
988
|
+
}
|
|
1092
989
|
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
|
|
990
|
+
dispose_on_change(() => [hull_base_geometry])
|
|
991
|
+
// Don't dispose colored hull if it's the same object as hull_base_geometry (no clone made)
|
|
992
|
+
dispose_on_change(() =>
|
|
993
|
+
colored_hull_geometry !== hull_base_geometry ? [colored_hull_geometry] : [],
|
|
994
|
+
)
|
|
1098
995
|
|
|
1099
996
|
// Domains on the outer surface (used by the "Surface" formula overlay quick-select).
|
|
1100
997
|
const surface_formulas = $derived.by((): SvelteSet<string> => {
|
|
@@ -1140,15 +1037,9 @@
|
|
|
1140
1037
|
|
|
1141
1038
|
const controls_series = $derived<DataSeries3D[]>([
|
|
1142
1039
|
{
|
|
1143
|
-
x: render_domains.flatMap((domain) =>
|
|
1144
|
-
|
|
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
|
-
),
|
|
1040
|
+
x: render_domains.flatMap((domain) => domain.points_3d.map((point) => point[1])),
|
|
1041
|
+
y: render_domains.flatMap((domain) => domain.points_3d.map((point) => point[2])),
|
|
1042
|
+
z: render_domains.flatMap((domain) => domain.points_3d.map((point) => point[0])),
|
|
1152
1043
|
label: `domains`,
|
|
1153
1044
|
},
|
|
1154
1045
|
])
|
|
@@ -1159,8 +1050,7 @@
|
|
|
1159
1050
|
const result: { geometry: THREE.BufferGeometry; color: string }[] = []
|
|
1160
1051
|
for (const domain of render_domains) {
|
|
1161
1052
|
if (!domain.is_draw_formula) continue
|
|
1162
|
-
const color_idx = formulas_to_draw.indexOf(domain.formula) %
|
|
1163
|
-
formula_colors.length
|
|
1053
|
+
const color_idx = formulas_to_draw.indexOf(domain.formula) % formula_colors.length
|
|
1164
1054
|
const swizzled = domain.points_3d.map((point) => to_render_xyz(point))
|
|
1165
1055
|
const positions: number[] = []
|
|
1166
1056
|
for (const [pa, pb] of get_domain_edges(swizzled)) {
|
|
@@ -1179,8 +1069,7 @@
|
|
|
1179
1069
|
if (!draw_formula_meshes) return result
|
|
1180
1070
|
for (const domain of render_domains) {
|
|
1181
1071
|
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
|
|
1072
|
+
const color_idx = formulas_to_draw.indexOf(domain.formula) % formula_colors.length
|
|
1184
1073
|
const unique = dedup_3d(domain.points_3d)
|
|
1185
1074
|
if (unique.length < 4) continue
|
|
1186
1075
|
const vectors = unique.map((pt) => to_vec3(pt))
|
|
@@ -1194,10 +1083,7 @@
|
|
|
1194
1083
|
return result
|
|
1195
1084
|
})
|
|
1196
1085
|
|
|
1197
|
-
function get_touches_limits(
|
|
1198
|
-
points_3d: number[][],
|
|
1199
|
-
lims: Vec2[],
|
|
1200
|
-
): string[] {
|
|
1086
|
+
function get_touches_limits(points_3d: number[][], lims: Vec2[]): string[] {
|
|
1201
1087
|
const limit_tol = 1e-3
|
|
1202
1088
|
const touches_limits: string[] = []
|
|
1203
1089
|
for (
|
|
@@ -1207,11 +1093,11 @@
|
|
|
1207
1093
|
) {
|
|
1208
1094
|
const [axis_min, axis_max] = lims[axis_idx]
|
|
1209
1095
|
const axis_name = plot_elements[axis_idx] ?? `axis_${axis_idx}`
|
|
1210
|
-
const touches_min = points_3d.some(
|
|
1211
|
-
Math.abs(point[axis_idx] - axis_min) < limit_tol
|
|
1096
|
+
const touches_min = points_3d.some(
|
|
1097
|
+
(point) => Math.abs(point[axis_idx] - axis_min) < limit_tol,
|
|
1212
1098
|
)
|
|
1213
|
-
const touches_max = points_3d.some(
|
|
1214
|
-
Math.abs(point[axis_idx] - axis_max) < limit_tol
|
|
1099
|
+
const touches_max = points_3d.some(
|
|
1100
|
+
(point) => Math.abs(point[axis_idx] - axis_max) < limit_tol,
|
|
1215
1101
|
)
|
|
1216
1102
|
if (touches_min) touches_limits.push(`${axis_name} lower bound`)
|
|
1217
1103
|
if (touches_max) touches_limits.push(`${axis_name} upper bound`)
|
|
@@ -1269,9 +1155,7 @@
|
|
|
1269
1155
|
const vertex_owners = new SvelteMap<string, string[]>()
|
|
1270
1156
|
for (const domain of render_domains) {
|
|
1271
1157
|
for (const pt of domain.points_3d) {
|
|
1272
|
-
const key = pt.map((val) => (Math.round(val / tol) * tol).toFixed(4)).join(
|
|
1273
|
-
`,`,
|
|
1274
|
-
)
|
|
1158
|
+
const key = pt.map((val) => (Math.round(val / tol) * tol).toFixed(4)).join(`,`)
|
|
1275
1159
|
const owners = vertex_owners.get(key)
|
|
1276
1160
|
if (owners) {
|
|
1277
1161
|
if (!owners.includes(domain.formula)) owners.push(domain.formula)
|
|
@@ -1344,46 +1228,12 @@
|
|
|
1344
1228
|
return result
|
|
1345
1229
|
})
|
|
1346
1230
|
|
|
1347
|
-
|
|
1348
|
-
|
|
1349
|
-
|
|
1350
|
-
|
|
1351
|
-
|
|
1352
|
-
|
|
1353
|
-
geometries: (THREE.BufferGeometry | null | undefined)[],
|
|
1354
|
-
): void {
|
|
1355
|
-
for (const geometry of geometries) dispose_geometry(geometry)
|
|
1356
|
-
}
|
|
1357
|
-
|
|
1358
|
-
$effect(() => {
|
|
1359
|
-
const geometry = edge_geometry
|
|
1360
|
-
return () => dispose_geometry(geometry)
|
|
1361
|
-
})
|
|
1362
|
-
|
|
1363
|
-
$effect(() => {
|
|
1364
|
-
const geometry = occlusion_hull_geometry
|
|
1365
|
-
return () => dispose_geometry(geometry)
|
|
1366
|
-
})
|
|
1367
|
-
|
|
1368
|
-
$effect(() => {
|
|
1369
|
-
const geometry = bounding_box_geometry
|
|
1370
|
-
return () => dispose_geometry(geometry)
|
|
1371
|
-
})
|
|
1372
|
-
|
|
1373
|
-
$effect(() => {
|
|
1374
|
-
const geometries = formula_edge_data.map((data) => data.geometry)
|
|
1375
|
-
return () => dispose_geometries(geometries)
|
|
1376
|
-
})
|
|
1377
|
-
|
|
1378
|
-
$effect(() => {
|
|
1379
|
-
const geometries = formula_mesh_data.map((data) => data.geometry)
|
|
1380
|
-
return () => dispose_geometries(geometries)
|
|
1381
|
-
})
|
|
1382
|
-
|
|
1383
|
-
$effect(() => {
|
|
1384
|
-
const geometries = hover_mesh_data.map((data) => data.geometry)
|
|
1385
|
-
return () => dispose_geometries(geometries)
|
|
1386
|
-
})
|
|
1231
|
+
dispose_on_change(() => [edge_geometry])
|
|
1232
|
+
dispose_on_change(() => [occlusion_hull_geometry])
|
|
1233
|
+
dispose_on_change(() => [bounding_box_geometry])
|
|
1234
|
+
dispose_on_change(() => formula_edge_data.map((data) => data.geometry))
|
|
1235
|
+
dispose_on_change(() => formula_mesh_data.map((data) => data.geometry))
|
|
1236
|
+
dispose_on_change(() => hover_mesh_data.map((data) => data.geometry))
|
|
1387
1237
|
|
|
1388
1238
|
// === Grid, axes, ticks (matching ScatterPlot3D style) ===
|
|
1389
1239
|
|
|
@@ -1440,8 +1290,8 @@
|
|
|
1440
1290
|
// Niced ranges (from ticks) padded so the grid extends beyond the diagram.
|
|
1441
1291
|
// For horizontal axes (0,1): pad both sides.
|
|
1442
1292
|
// For vertical axis (2): use actual data range and round min down to an integer.
|
|
1443
|
-
const niced_range = $derived
|
|
1444
|
-
|
|
1293
|
+
const niced_range = $derived(
|
|
1294
|
+
[0, 1, 2].map((axis): Vec2 => {
|
|
1445
1295
|
const ticks = data_ticks[axis]
|
|
1446
1296
|
const lo = ticks[0]
|
|
1447
1297
|
const hi = ticks.at(-1) ?? lo
|
|
@@ -1451,14 +1301,11 @@
|
|
|
1451
1301
|
return [Math.floor(min_data), hi]
|
|
1452
1302
|
}
|
|
1453
1303
|
return [lo - step, hi + step]
|
|
1454
|
-
})
|
|
1455
|
-
|
|
1304
|
+
}),
|
|
1305
|
+
)
|
|
1456
1306
|
|
|
1457
1307
|
// Helper to create a line geometry from two Vec3 arrays
|
|
1458
|
-
function make_line_geom(
|
|
1459
|
-
start: Vec3,
|
|
1460
|
-
end: Vec3,
|
|
1461
|
-
): THREE.BufferGeometry {
|
|
1308
|
+
function make_line_geom(start: Vec3, end: Vec3): THREE.BufferGeometry {
|
|
1462
1309
|
const geom = new THREE.BufferGeometry()
|
|
1463
1310
|
geom.setAttribute(
|
|
1464
1311
|
`position`,
|
|
@@ -1506,11 +1353,12 @@
|
|
|
1506
1353
|
return [0, 1, 2].map((axis) => {
|
|
1507
1354
|
const ticks = data_ticks[axis]
|
|
1508
1355
|
const color = axis_colors[axis]
|
|
1509
|
-
const label =
|
|
1510
|
-
|
|
1511
|
-
|
|
1512
|
-
|
|
1513
|
-
|
|
1356
|
+
const label =
|
|
1357
|
+
axis === 0
|
|
1358
|
+
? z_axis.label || chem_axis_label(0)
|
|
1359
|
+
: axis === 1
|
|
1360
|
+
? x_axis.label || chem_axis_label(1)
|
|
1361
|
+
: y_axis.label || chem_axis_label(2)
|
|
1514
1362
|
|
|
1515
1363
|
const tick_geoms: THREE.BufferGeometry[] = []
|
|
1516
1364
|
const grid_geoms: THREE.BufferGeometry[] = []
|
|
@@ -1530,16 +1378,14 @@
|
|
|
1530
1378
|
back[2] + out_y * tick_label_dist,
|
|
1531
1379
|
)
|
|
1532
1380
|
for (const val of ticks) {
|
|
1533
|
-
tick_geoms.push(
|
|
1534
|
-
|
|
1535
|
-
|
|
1536
|
-
|
|
1537
|
-
|
|
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])),
|
|
1381
|
+
tick_geoms.push(
|
|
1382
|
+
make_line_geom(
|
|
1383
|
+
swiz(val, back[1], back[2]),
|
|
1384
|
+
swiz(val, back[1], back[2] + out_y * tick_size),
|
|
1385
|
+
),
|
|
1542
1386
|
)
|
|
1387
|
+
grid_geoms.push(make_line_geom(swiz(val, r1[0], back[2]), swiz(val, r1[1], back[2])))
|
|
1388
|
+
grid_geoms.push(make_line_geom(swiz(val, back[1], r2[0]), swiz(val, back[1], r2[1])))
|
|
1543
1389
|
tick_labels.push({
|
|
1544
1390
|
pos: swiz(
|
|
1545
1391
|
val,
|
|
@@ -1560,16 +1406,14 @@
|
|
|
1560
1406
|
back[2] + out_y * tick_label_dist,
|
|
1561
1407
|
)
|
|
1562
1408
|
for (const val of ticks) {
|
|
1563
|
-
tick_geoms.push(
|
|
1564
|
-
|
|
1565
|
-
|
|
1566
|
-
|
|
1567
|
-
|
|
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])),
|
|
1409
|
+
tick_geoms.push(
|
|
1410
|
+
make_line_geom(
|
|
1411
|
+
swiz(back[0], val, back[2]),
|
|
1412
|
+
swiz(back[0], val, back[2] + out_y * tick_size),
|
|
1413
|
+
),
|
|
1572
1414
|
)
|
|
1415
|
+
grid_geoms.push(make_line_geom(swiz(r0[0], val, back[2]), swiz(r0[1], val, back[2])))
|
|
1416
|
+
grid_geoms.push(make_line_geom(swiz(back[0], val, r2[0]), swiz(back[0], val, r2[1])))
|
|
1573
1417
|
tick_labels.push({
|
|
1574
1418
|
pos: swiz(back[0], val, back[2] + out_y * tick_label_dist),
|
|
1575
1419
|
text: format_num(val, `.3~g`),
|
|
@@ -1586,16 +1430,14 @@
|
|
|
1586
1430
|
outer_end(r2) + outer_direction(r2) * axis_label_dist,
|
|
1587
1431
|
)
|
|
1588
1432
|
for (const val of ticks) {
|
|
1589
|
-
tick_geoms.push(
|
|
1590
|
-
|
|
1591
|
-
|
|
1592
|
-
|
|
1593
|
-
|
|
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)),
|
|
1433
|
+
tick_geoms.push(
|
|
1434
|
+
make_line_geom(
|
|
1435
|
+
swiz(back[0], back[1], val),
|
|
1436
|
+
swiz(back[0], back[1] + out_x * tick_size, val),
|
|
1437
|
+
),
|
|
1598
1438
|
)
|
|
1439
|
+
grid_geoms.push(make_line_geom(swiz(r0[0], back[1], val), swiz(r0[1], back[1], val)))
|
|
1440
|
+
grid_geoms.push(make_line_geom(swiz(back[0], r1[0], val), swiz(back[0], r1[1], val)))
|
|
1599
1441
|
tick_labels.push({
|
|
1600
1442
|
pos: swiz(back[0], back[1] + out_x * tick_label_dist, val),
|
|
1601
1443
|
text: format_num(val, `.3~g`),
|
|
@@ -1623,21 +1465,17 @@
|
|
|
1623
1465
|
|
|
1624
1466
|
function update_label_occlusion(): void {
|
|
1625
1467
|
if (!wrapper) return
|
|
1626
|
-
const tick_labels = Array.from(
|
|
1627
|
-
wrapper.querySelectorAll<HTMLElement>(`.axis-tick-label`),
|
|
1628
|
-
)
|
|
1468
|
+
const tick_labels = Array.from(wrapper.querySelectorAll<HTMLElement>(`.axis-tick-label`))
|
|
1629
1469
|
tick_labels_occluded = false
|
|
1630
1470
|
for (const tick_label of tick_labels) {
|
|
1631
1471
|
tick_label.style.visibility = ``
|
|
1632
1472
|
}
|
|
1633
|
-
const domain_rects = Array.from(
|
|
1634
|
-
|
|
1635
|
-
|
|
1636
|
-
.filter((domain_label) => {
|
|
1637
|
-
const style = getComputedStyle(domain_label)
|
|
1473
|
+
const domain_rects = Array.from(wrapper.querySelectorAll<HTMLElement>(`.domain-label`))
|
|
1474
|
+
.filter((label_el) => {
|
|
1475
|
+
const style = getComputedStyle(label_el)
|
|
1638
1476
|
return style.display !== `none` && style.visibility !== `hidden`
|
|
1639
1477
|
})
|
|
1640
|
-
.map((
|
|
1478
|
+
.map((label_el) => pad_rect(label_el.getBoundingClientRect(), 1))
|
|
1641
1479
|
if (domain_rects.length === 0) return
|
|
1642
1480
|
|
|
1643
1481
|
for (const tick_label of tick_labels) {
|
|
@@ -1700,11 +1538,7 @@
|
|
|
1700
1538
|
}
|
|
1701
1539
|
const controls_target = controls?.target
|
|
1702
1540
|
if (controls_target) {
|
|
1703
|
-
camera_target_override = [
|
|
1704
|
-
controls_target.x,
|
|
1705
|
-
controls_target.y,
|
|
1706
|
-
controls_target.z,
|
|
1707
|
-
]
|
|
1541
|
+
camera_target_override = [controls_target.x, controls_target.y, controls_target.z]
|
|
1708
1542
|
}
|
|
1709
1543
|
}
|
|
1710
1544
|
|
|
@@ -1769,28 +1603,20 @@
|
|
|
1769
1603
|
bg_css_var: `--chempot-3d-bg-fullscreen`,
|
|
1770
1604
|
})
|
|
1771
1605
|
|
|
1772
|
-
|
|
1773
|
-
|
|
1774
|
-
|
|
1775
|
-
|
|
1776
|
-
|
|
1777
|
-
|
|
1778
|
-
|
|
1779
|
-
}
|
|
1780
|
-
for (const line_geometry of grid_item.grid_geoms) {
|
|
1781
|
-
dispose_geometry(line_geometry)
|
|
1782
|
-
}
|
|
1783
|
-
}
|
|
1784
|
-
}
|
|
1785
|
-
})
|
|
1606
|
+
dispose_on_change(() =>
|
|
1607
|
+
grid_config.flatMap((grid_item) => [
|
|
1608
|
+
grid_item.line_geom,
|
|
1609
|
+
...grid_item.tick_geoms,
|
|
1610
|
+
...grid_item.grid_geoms,
|
|
1611
|
+
]),
|
|
1612
|
+
)
|
|
1786
1613
|
|
|
1787
1614
|
const projection_planes = $derived.by(() => {
|
|
1788
1615
|
const projections = display.projections
|
|
1789
1616
|
if (!projections) return []
|
|
1790
1617
|
const [r0, r1, r2] = niced_range
|
|
1791
|
-
const
|
|
1792
|
-
const s1 = (
|
|
1793
|
-
const s2 = (r2[1] - r2[0]) * (display.projection_scale ?? 0.5)
|
|
1618
|
+
const projection_scale = display.projection_scale ?? 0.5
|
|
1619
|
+
const [s0, s1, s2] = niced_range.map(([lo, hi]) => (hi - lo) * projection_scale)
|
|
1794
1620
|
const planes: {
|
|
1795
1621
|
key: string
|
|
1796
1622
|
pos: Vec3
|
|
@@ -1880,18 +1706,12 @@
|
|
|
1880
1706
|
next_projection[current_owner_idx] = next_projection[axis_idx]
|
|
1881
1707
|
}
|
|
1882
1708
|
next_projection[axis_idx] = element
|
|
1883
|
-
const normalized = normalize_projection_triplet(
|
|
1884
|
-
next_projection,
|
|
1885
|
-
all_entry_elements,
|
|
1886
|
-
)
|
|
1709
|
+
const normalized = normalize_projection_triplet(next_projection, all_entry_elements)
|
|
1887
1710
|
if (normalized) projection_elements_override = normalized
|
|
1888
1711
|
}
|
|
1889
1712
|
|
|
1890
1713
|
function apply_projection_preset(preset_elements: string[]): void {
|
|
1891
|
-
const normalized = normalize_projection_triplet(
|
|
1892
|
-
preset_elements,
|
|
1893
|
-
all_entry_elements,
|
|
1894
|
-
)
|
|
1714
|
+
const normalized = normalize_projection_triplet(preset_elements, all_entry_elements)
|
|
1895
1715
|
if (normalized) projection_elements_override = normalized
|
|
1896
1716
|
}
|
|
1897
1717
|
|
|
@@ -1968,19 +1788,21 @@
|
|
|
1968
1788
|
},
|
|
1969
1789
|
{
|
|
1970
1790
|
label: `View`,
|
|
1971
|
-
on_download: () =>
|
|
1972
|
-
export_view_json_file(current_view_settings(), export_basename),
|
|
1791
|
+
on_download: () => export_view_json_file(current_view_settings(), export_basename),
|
|
1973
1792
|
},
|
|
1974
1793
|
{
|
|
1975
1794
|
label: `GLB`,
|
|
1976
1795
|
on_download: () =>
|
|
1977
|
-
export_glb_file(
|
|
1978
|
-
|
|
1979
|
-
|
|
1980
|
-
|
|
1981
|
-
|
|
1982
|
-
|
|
1983
|
-
|
|
1796
|
+
export_glb_file(
|
|
1797
|
+
{
|
|
1798
|
+
hull_geometry: colored_hull_geometry,
|
|
1799
|
+
hull_opacity: color_mode === `none` ? 0.25 : 0.4,
|
|
1800
|
+
edge_geometry,
|
|
1801
|
+
formula_meshes: formula_mesh_data,
|
|
1802
|
+
formula_edges: draw_formula_lines ? formula_edge_data : [],
|
|
1803
|
+
},
|
|
1804
|
+
export_basename,
|
|
1805
|
+
),
|
|
1984
1806
|
},
|
|
1985
1807
|
],
|
|
1986
1808
|
},
|
|
@@ -1997,10 +1819,12 @@
|
|
|
1997
1819
|
const pointer = hover_info?.pointer
|
|
1998
1820
|
if (!pointer) return { x: 4, y: 4 }
|
|
1999
1821
|
return constrain_tooltip_position(
|
|
2000
|
-
pointer.x,
|
|
1822
|
+
pointer.x,
|
|
1823
|
+
pointer.y,
|
|
2001
1824
|
tooltip_el?.offsetWidth ?? 200,
|
|
2002
1825
|
tooltip_el?.offsetHeight ?? 100,
|
|
2003
|
-
container_width,
|
|
1826
|
+
container_width,
|
|
1827
|
+
container_height,
|
|
2004
1828
|
{ offset: 0 },
|
|
2005
1829
|
)
|
|
2006
1830
|
})
|
|
@@ -2018,12 +1842,22 @@
|
|
|
2018
1842
|
hover_info = null
|
|
2019
1843
|
}
|
|
2020
1844
|
|
|
1845
|
+
function stop_phase_pointer_event(raw_event: unknown): void {
|
|
1846
|
+
const event = raw_event as
|
|
1847
|
+
| { nativeEvent?: { stopPropagation?: () => void }; stopPropagation?: () => void }
|
|
1848
|
+
| null
|
|
1849
|
+
| undefined
|
|
1850
|
+
event?.stopPropagation?.()
|
|
1851
|
+
event?.nativeEvent?.stopPropagation?.()
|
|
1852
|
+
}
|
|
1853
|
+
|
|
2021
1854
|
function handle_phase_hover(domain_data: HoverMeshData, raw_event: unknown): void {
|
|
2022
1855
|
if (locked_hover_formula && locked_hover_formula !== domain_data.formula) return
|
|
2023
1856
|
set_hover_info(domain_data, raw_event)
|
|
2024
1857
|
}
|
|
2025
1858
|
|
|
2026
1859
|
function toggle_phase_lock(domain_data: HoverMeshData, raw_event: unknown): void {
|
|
1860
|
+
stop_phase_pointer_event(raw_event)
|
|
2027
1861
|
if (locked_hover_formula === domain_data.formula) {
|
|
2028
1862
|
clear_hover_lock()
|
|
2029
1863
|
return
|
|
@@ -2053,20 +1887,15 @@
|
|
|
2053
1887
|
role="application"
|
|
2054
1888
|
tabindex="0"
|
|
2055
1889
|
onkeydown={(event) => {
|
|
2056
|
-
if (
|
|
2057
|
-
|
|
2058
|
-
event.target instanceof HTMLSelectElement
|
|
2059
|
-
) return
|
|
1890
|
+
if (event.target instanceof HTMLInputElement || event.target instanceof HTMLSelectElement)
|
|
1891
|
+
return
|
|
2060
1892
|
if (event.key === `Escape`) clear_hover_lock()
|
|
2061
1893
|
else if (event.key === `c`) cycle_color_mode()
|
|
2062
1894
|
else if (event.key === `f` && fullscreen_toggle) toggle_fullscreen(wrapper)
|
|
2063
1895
|
}}
|
|
2064
1896
|
onpointerdown={(event) => {
|
|
2065
1897
|
const target = event.target
|
|
2066
|
-
if (
|
|
2067
|
-
locked_hover_formula &&
|
|
2068
|
-
(target === wrapper || target instanceof HTMLCanvasElement)
|
|
2069
|
-
) {
|
|
1898
|
+
if (locked_hover_formula && (target === wrapper || target instanceof HTMLCanvasElement)) {
|
|
2070
1899
|
clear_hover_lock()
|
|
2071
1900
|
}
|
|
2072
1901
|
}}
|
|
@@ -2102,11 +1931,7 @@
|
|
|
2102
1931
|
</div>
|
|
2103
1932
|
<label class="overlay-search">
|
|
2104
1933
|
Search:
|
|
2105
|
-
<input
|
|
2106
|
-
type="text"
|
|
2107
|
-
placeholder="Formula filter"
|
|
2108
|
-
bind:value={formula_filter_query}
|
|
2109
|
-
/>
|
|
1934
|
+
<input type="text" placeholder="Formula filter" bind:value={formula_filter_query} />
|
|
2110
1935
|
</label>
|
|
2111
1936
|
<div class="formula-list">
|
|
2112
1937
|
{#if filtered_formulas.length === 0}
|
|
@@ -2117,14 +1942,14 @@
|
|
|
2117
1942
|
<label>
|
|
2118
1943
|
<input
|
|
2119
1944
|
type="checkbox"
|
|
2120
|
-
checked={
|
|
1945
|
+
checked={formula_overlay_idx !== -1}
|
|
2121
1946
|
onchange={() => toggle_formula_selection(formula)}
|
|
2122
1947
|
/>
|
|
2123
1948
|
<span
|
|
2124
1949
|
class="formula-color-dot"
|
|
2125
1950
|
style:background={formula_colors[
|
|
2126
1951
|
(formula_overlay_idx >= 0 ? formula_overlay_idx : formula_idx) %
|
|
2127
|
-
|
|
1952
|
+
formula_colors.length
|
|
2128
1953
|
]}
|
|
2129
1954
|
></span>
|
|
2130
1955
|
{get_electro_neg_formula(formula, true, ``, `.3~s`)}
|
|
@@ -2231,8 +2056,7 @@
|
|
|
2231
2056
|
<input
|
|
2232
2057
|
type="checkbox"
|
|
2233
2058
|
checked={draw_formula_meshes}
|
|
2234
|
-
onchange={() =>
|
|
2235
|
-
overrides.set(`draw_formula_meshes`, !draw_formula_meshes)}
|
|
2059
|
+
onchange={() => overrides.set(`draw_formula_meshes`, !draw_formula_meshes)}
|
|
2236
2060
|
/> Meshes
|
|
2237
2061
|
</label>
|
|
2238
2062
|
<label>
|
|
@@ -2252,7 +2076,7 @@
|
|
|
2252
2076
|
step="0.1"
|
|
2253
2077
|
value={element_padding}
|
|
2254
2078
|
oninput={(event) =>
|
|
2255
|
-
|
|
2079
|
+
overrides.set(`element_padding`, Number(event.currentTarget.value))}
|
|
2256
2080
|
/>
|
|
2257
2081
|
</label>
|
|
2258
2082
|
<label>
|
|
@@ -2263,7 +2087,7 @@
|
|
|
2263
2087
|
step="1"
|
|
2264
2088
|
value={default_min_limit}
|
|
2265
2089
|
oninput={(event) =>
|
|
2266
|
-
|
|
2090
|
+
overrides.set(`default_min_limit`, Number(event.currentTarget.value))}
|
|
2267
2091
|
/>
|
|
2268
2092
|
</label>
|
|
2269
2093
|
</div>
|
|
@@ -2273,7 +2097,7 @@
|
|
|
2273
2097
|
id="chempot-color-mode"
|
|
2274
2098
|
value={color_mode}
|
|
2275
2099
|
onchange={(event) =>
|
|
2276
|
-
|
|
2100
|
+
overrides.set(`color_mode`, event.currentTarget.value as ChemPotColorMode)}
|
|
2277
2101
|
>
|
|
2278
2102
|
{#each CHEMPOT_COLOR_MODE_OPTIONS as [value, label] (value)}
|
|
2279
2103
|
<option {value}>{label}</option>
|
|
@@ -2287,10 +2111,7 @@
|
|
|
2287
2111
|
id="chempot-color-scale"
|
|
2288
2112
|
value={color_scale}
|
|
2289
2113
|
onchange={(event) =>
|
|
2290
|
-
|
|
2291
|
-
`color_scale`,
|
|
2292
|
-
event.currentTarget.value as D3InterpolateName,
|
|
2293
|
-
)}
|
|
2114
|
+
overrides.set(`color_scale`, event.currentTarget.value as D3InterpolateName)}
|
|
2294
2115
|
>
|
|
2295
2116
|
{#each CHEMPOT_COLOR_SCALE_OPTIONS as [value, label] (value)}
|
|
2296
2117
|
<option {value}>{label}</option>
|
|
@@ -2300,8 +2121,7 @@
|
|
|
2300
2121
|
<input
|
|
2301
2122
|
type="checkbox"
|
|
2302
2123
|
checked={reverse_color_scale}
|
|
2303
|
-
onchange={() =>
|
|
2304
|
-
overrides.set(`reverse_color_scale`, !reverse_color_scale)}
|
|
2124
|
+
onchange={() => overrides.set(`reverse_color_scale`, !reverse_color_scale)}
|
|
2305
2125
|
/> Rev
|
|
2306
2126
|
</label>
|
|
2307
2127
|
</div>
|
|
@@ -2314,312 +2134,297 @@
|
|
|
2314
2134
|
{/if}
|
|
2315
2135
|
</section>
|
|
2316
2136
|
{#if show_temperature_slider && temperature !== undefined}
|
|
2317
|
-
<TemperatureSlider
|
|
2318
|
-
class="chempot-temp-slider"
|
|
2319
|
-
{available_temperatures}
|
|
2320
|
-
bind:temperature
|
|
2321
|
-
/>
|
|
2137
|
+
<TemperatureSlider class="chempot-temp-slider" {available_temperatures} bind:temperature />
|
|
2322
2138
|
{/if}
|
|
2323
2139
|
<div class="canvas-clip">
|
|
2324
|
-
|
|
2325
|
-
|
|
2326
|
-
|
|
2327
|
-
|
|
2328
|
-
|
|
2329
|
-
|
|
2330
|
-
|
|
2331
|
-
|
|
2332
|
-
|
|
2333
|
-
|
|
2334
|
-
|
|
2335
|
-
|
|
2336
|
-
|
|
2337
|
-
|
|
2338
|
-
|
|
2339
|
-
|
|
2340
|
-
|
|
2341
|
-
|
|
2342
|
-
|
|
2343
|
-
|
|
2344
|
-
|
|
2345
|
-
|
|
2346
|
-
|
|
2347
|
-
|
|
2348
|
-
|
|
2349
|
-
|
|
2350
|
-
|
|
2351
|
-
|
|
2352
|
-
|
|
2353
|
-
|
|
2354
|
-
|
|
2355
|
-
|
|
2356
|
-
|
|
2357
|
-
|
|
2358
|
-
|
|
2359
|
-
|
|
2360
|
-
|
|
2361
|
-
|
|
2362
|
-
|
|
2363
|
-
|
|
2364
|
-
|
|
2365
|
-
|
|
2366
|
-
|
|
2367
|
-
|
|
2368
|
-
|
|
2369
|
-
|
|
2370
|
-
|
|
2371
|
-
|
|
2372
|
-
|
|
2373
|
-
|
|
2374
|
-
|
|
2375
|
-
|
|
2376
|
-
|
|
2377
|
-
|
|
2378
|
-
|
|
2379
|
-
|
|
2380
|
-
</T.PerspectiveCamera>
|
|
2381
|
-
{/if}
|
|
2140
|
+
{#if diagram_computing}
|
|
2141
|
+
<div class="computing-state">
|
|
2142
|
+
<Spinner
|
|
2143
|
+
text="Computing chemical potential domains..."
|
|
2144
|
+
style="--spinner-size: 1.2em"
|
|
2145
|
+
/>
|
|
2146
|
+
</div>
|
|
2147
|
+
{:else if !diagram_data}
|
|
2148
|
+
<div class="error-state" role="alert" aria-live="polite">
|
|
2149
|
+
<p>Cannot compute chemical potential diagram.</p>
|
|
2150
|
+
<p>Need at least 2 elements with elemental reference entries.</p>
|
|
2151
|
+
</div>
|
|
2152
|
+
{:else if mounted && typeof WebGLRenderingContext !== `undefined`}
|
|
2153
|
+
{#snippet orbit_controls()}
|
|
2154
|
+
<extras.OrbitControls
|
|
2155
|
+
bind:ref={orbit_controls_ref}
|
|
2156
|
+
enableRotate
|
|
2157
|
+
enableZoom
|
|
2158
|
+
enablePan
|
|
2159
|
+
autoRotate={auto_rotate > 0 && page_visibility.visible}
|
|
2160
|
+
autoRotateSpeed={auto_rotate}
|
|
2161
|
+
target={camera_target}
|
|
2162
|
+
/>
|
|
2163
|
+
{/snippet}
|
|
2164
|
+
<Canvas
|
|
2165
|
+
createRenderer={(cvs) =>
|
|
2166
|
+
new THREE.WebGLRenderer({
|
|
2167
|
+
canvas: cvs,
|
|
2168
|
+
alpha: true,
|
|
2169
|
+
antialias: true,
|
|
2170
|
+
preserveDrawingBuffer: true,
|
|
2171
|
+
})}
|
|
2172
|
+
>
|
|
2173
|
+
<ChemPotScene3D>
|
|
2174
|
+
{#if camera_projection === `orthographic`}
|
|
2175
|
+
<!-- Orthographic camera matching pymatgen's projection style -->
|
|
2176
|
+
<T.OrthographicCamera
|
|
2177
|
+
makeDefault
|
|
2178
|
+
position={camera_position}
|
|
2179
|
+
zoom={orthographic_zoom}
|
|
2180
|
+
near={0.1}
|
|
2181
|
+
far={data_extent * 10}
|
|
2182
|
+
>
|
|
2183
|
+
{@render orbit_controls()}
|
|
2184
|
+
</T.OrthographicCamera>
|
|
2185
|
+
{:else}
|
|
2186
|
+
<T.PerspectiveCamera
|
|
2187
|
+
makeDefault
|
|
2188
|
+
position={camera_position}
|
|
2189
|
+
fov={50}
|
|
2190
|
+
near={0.1}
|
|
2191
|
+
far={data_extent * 10}
|
|
2192
|
+
>
|
|
2193
|
+
{@render orbit_controls()}
|
|
2194
|
+
</T.PerspectiveCamera>
|
|
2195
|
+
{/if}
|
|
2382
2196
|
|
|
2383
|
-
|
|
2384
|
-
|
|
2385
|
-
|
|
2197
|
+
<!-- Ambient light for visibility -->
|
|
2198
|
+
<T.AmbientLight intensity={0.8} />
|
|
2199
|
+
<T.DirectionalLight position={[1, 1, 1]} intensity={0.5} />
|
|
2386
2200
|
|
|
2387
|
-
|
|
2201
|
+
<!-- Vertex-colored hull for both plain and colored modes.
|
|
2388
2202
|
{#key domain_colors} forces Threlte to re-create the mesh whenever
|
|
2389
2203
|
colors change (covers color_mode, color_scale, and data updates),
|
|
2390
2204
|
since on-demand rendering won't detect mutated vertex color buffers. -->
|
|
2391
|
-
|
|
2392
|
-
|
|
2393
|
-
|
|
2205
|
+
{#if colored_hull_geometry}
|
|
2206
|
+
{#key domain_colors}
|
|
2207
|
+
<T.Mesh geometry={colored_hull_geometry}>
|
|
2208
|
+
<T.MeshBasicMaterial
|
|
2209
|
+
vertexColors
|
|
2210
|
+
transparent
|
|
2211
|
+
opacity={color_mode === `none` ? 0.25 : 0.4}
|
|
2212
|
+
side={THREE.DoubleSide}
|
|
2213
|
+
polygonOffset
|
|
2214
|
+
polygonOffsetFactor={1}
|
|
2215
|
+
polygonOffsetUnits={1}
|
|
2216
|
+
/>
|
|
2217
|
+
</T.Mesh>
|
|
2218
|
+
{/key}
|
|
2219
|
+
{/if}
|
|
2220
|
+
|
|
2221
|
+
<!-- Domain boundary edges (wireframe on top of opaque fills) -->
|
|
2222
|
+
<T.LineSegments geometry={edge_geometry}>
|
|
2223
|
+
<T.LineBasicMaterial color={0x333333} linewidth={1} />
|
|
2224
|
+
</T.LineSegments>
|
|
2225
|
+
|
|
2226
|
+
<!-- Invisible pick meshes for per-phase hover tooltip -->
|
|
2227
|
+
{#each hover_mesh_data as domain_hover (domain_hover.formula)}
|
|
2228
|
+
<T.Mesh
|
|
2229
|
+
geometry={domain_hover.geometry}
|
|
2230
|
+
onpointerenter={(event: unknown) => handle_phase_hover(domain_hover, event)}
|
|
2231
|
+
onpointermove={(event: unknown) => handle_phase_hover(domain_hover, event)}
|
|
2232
|
+
onpointerdown={(event: unknown) => toggle_phase_lock(domain_hover, event)}
|
|
2233
|
+
onpointerleave={() => {
|
|
2234
|
+
if (!locked_hover_formula && hover_info?.formula === domain_hover.formula) {
|
|
2235
|
+
hover_info = null
|
|
2236
|
+
}
|
|
2237
|
+
}}
|
|
2238
|
+
>
|
|
2394
2239
|
<T.MeshBasicMaterial
|
|
2395
|
-
vertexColors
|
|
2396
2240
|
transparent
|
|
2397
|
-
opacity={
|
|
2241
|
+
opacity={0}
|
|
2398
2242
|
side={THREE.DoubleSide}
|
|
2399
|
-
|
|
2400
|
-
polygonOffsetFactor={1}
|
|
2401
|
-
polygonOffsetUnits={1}
|
|
2243
|
+
depthWrite={false}
|
|
2402
2244
|
/>
|
|
2403
2245
|
</T.Mesh>
|
|
2404
|
-
{/
|
|
2405
|
-
{/if}
|
|
2246
|
+
{/each}
|
|
2406
2247
|
|
|
2407
|
-
|
|
2408
|
-
|
|
2409
|
-
|
|
2410
|
-
|
|
2411
|
-
|
|
2412
|
-
|
|
2413
|
-
|
|
2414
|
-
|
|
2415
|
-
|
|
2416
|
-
|
|
2417
|
-
|
|
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>
|
|
2248
|
+
<!-- Formula overlay meshes (semi-transparent colored fill) -->
|
|
2249
|
+
{#each formula_mesh_data as { geometry, color }, mesh_idx (mesh_idx)}
|
|
2250
|
+
<T.Mesh {geometry}>
|
|
2251
|
+
<T.MeshBasicMaterial
|
|
2252
|
+
color={new THREE.Color(color)}
|
|
2253
|
+
transparent
|
|
2254
|
+
opacity={0.13}
|
|
2255
|
+
side={THREE.DoubleSide}
|
|
2256
|
+
depthWrite={false}
|
|
2257
|
+
/>
|
|
2258
|
+
</T.Mesh>
|
|
2456
2259
|
{/each}
|
|
2457
|
-
{/if}
|
|
2458
2260
|
|
|
2459
|
-
|
|
2460
|
-
|
|
2461
|
-
|
|
2462
|
-
|
|
2463
|
-
|
|
2464
|
-
|
|
2465
|
-
|
|
2466
|
-
|
|
2467
|
-
depthWrite={false}
|
|
2468
|
-
/>
|
|
2469
|
-
</T.Mesh>
|
|
2470
|
-
{/each}
|
|
2261
|
+
<!-- Formula overlay edges (colored, thicker) -->
|
|
2262
|
+
{#if draw_formula_lines}
|
|
2263
|
+
{#each formula_edge_data as { geometry, color }, edge_idx (edge_idx)}
|
|
2264
|
+
<T.LineSegments {geometry}>
|
|
2265
|
+
<T.LineBasicMaterial color={new THREE.Color(color)} linewidth={2} />
|
|
2266
|
+
</T.LineSegments>
|
|
2267
|
+
{/each}
|
|
2268
|
+
{/if}
|
|
2471
2269
|
|
|
2472
|
-
|
|
2473
|
-
|
|
2474
|
-
|
|
2475
|
-
|
|
2476
|
-
|
|
2270
|
+
{#each projection_planes as plane (`${plane.key}-${projection_opacity}`)}
|
|
2271
|
+
<T.Mesh position={plane.pos} rotation={plane.rot}>
|
|
2272
|
+
<T.PlaneGeometry args={plane.size} />
|
|
2273
|
+
<T.MeshBasicMaterial
|
|
2274
|
+
color={plane.color}
|
|
2275
|
+
opacity={projection_opacity}
|
|
2276
|
+
transparent
|
|
2277
|
+
side={THREE.DoubleSide}
|
|
2278
|
+
depthWrite={false}
|
|
2279
|
+
/>
|
|
2280
|
+
</T.Mesh>
|
|
2281
|
+
{/each}
|
|
2477
2282
|
|
|
2478
|
-
|
|
2479
|
-
|
|
2480
|
-
|
|
2481
|
-
|
|
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}
|
|
2283
|
+
{#if display.show_bounding_box}
|
|
2284
|
+
<T.LineSegments geometry={bounding_box_geometry}>
|
|
2285
|
+
<T.LineBasicMaterial color="#666" opacity={0.6} transparent />
|
|
2286
|
+
</T.LineSegments>
|
|
2491
2287
|
{/if}
|
|
2492
|
-
|
|
2493
|
-
|
|
2494
|
-
|
|
2495
|
-
|
|
2496
|
-
|
|
2288
|
+
|
|
2289
|
+
<!-- Axes, ticks, grid lines, and labels -->
|
|
2290
|
+
{#each grid_config as gc (gc.axis)}
|
|
2291
|
+
{#if display.show_axes}
|
|
2292
|
+
<!-- Main axis line -->
|
|
2293
|
+
<T.Line geometry={gc.line_geom}>
|
|
2294
|
+
<T.LineBasicMaterial color={gc.color} linewidth={2} />
|
|
2497
2295
|
</T.Line>
|
|
2498
|
-
|
|
2499
|
-
|
|
2500
|
-
|
|
2501
|
-
|
|
2502
|
-
|
|
2296
|
+
<!-- Tick marks -->
|
|
2297
|
+
{#each gc.tick_geoms as tick_geom, tdx (tdx)}
|
|
2298
|
+
<T.Line geometry={tick_geom}>
|
|
2299
|
+
<T.LineBasicMaterial color={gc.color} />
|
|
2300
|
+
</T.Line>
|
|
2301
|
+
{/each}
|
|
2302
|
+
{/if}
|
|
2303
|
+
{#if display.show_grid}
|
|
2304
|
+
<!-- Grid lines -->
|
|
2305
|
+
{#each gc.grid_geoms as grid_geom, gdx (gdx)}
|
|
2306
|
+
<T.Line geometry={grid_geom}>
|
|
2307
|
+
<T.LineBasicMaterial color="#888" opacity={0.3} transparent />
|
|
2308
|
+
</T.Line>
|
|
2309
|
+
{/each}
|
|
2310
|
+
{/if}
|
|
2311
|
+
{#if display.show_axis_labels}
|
|
2312
|
+
<!-- Tick labels (billboarded, always face camera) -->
|
|
2313
|
+
{#each gc.tick_labels as tick, tick_idx (tick_idx)}
|
|
2314
|
+
<extras.HTML position={tick.pos} center portal={wrapper} zIndexRange={[1, 0]}>
|
|
2315
|
+
<span class="tick-label axis-tick-label">{tick.text}</span>
|
|
2316
|
+
</extras.HTML>
|
|
2317
|
+
{/each}
|
|
2318
|
+
<!-- Axis label -->
|
|
2503
2319
|
<extras.HTML
|
|
2504
|
-
position={
|
|
2320
|
+
position={gc.label_pos}
|
|
2505
2321
|
center
|
|
2506
2322
|
portal={wrapper}
|
|
2507
2323
|
zIndexRange={[1, 0]}
|
|
2508
2324
|
>
|
|
2509
|
-
<span class="
|
|
2325
|
+
<span class="axis-label" style:color={gc.color}
|
|
2326
|
+
>{@html sanitize_html(gc.label)}</span
|
|
2327
|
+
>
|
|
2328
|
+
</extras.HTML>
|
|
2329
|
+
{/if}
|
|
2330
|
+
{/each}
|
|
2331
|
+
|
|
2332
|
+
<!-- Domain labels -->
|
|
2333
|
+
{#if label_stable}
|
|
2334
|
+
{#each visible_domain_labels as domain (domain.formula)}
|
|
2335
|
+
<extras.HTML
|
|
2336
|
+
position={domain.position}
|
|
2337
|
+
center
|
|
2338
|
+
portal={wrapper}
|
|
2339
|
+
zIndexRange={[5, 5]}
|
|
2340
|
+
>
|
|
2341
|
+
<span
|
|
2342
|
+
class="domain-label"
|
|
2343
|
+
style:font-size="{(domain.label_font_size * zoom_scale).toFixed(1)}px"
|
|
2344
|
+
>
|
|
2345
|
+
{#each formula_label_segments(domain.formula) as segment}
|
|
2346
|
+
<span class:formula-subscript={segment.subscript}>{segment.text}</span>
|
|
2347
|
+
{/each}
|
|
2348
|
+
</span>
|
|
2510
2349
|
</extras.HTML>
|
|
2511
2350
|
{/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
2351
|
{/if}
|
|
2522
|
-
|
|
2523
|
-
|
|
2524
|
-
|
|
2525
|
-
|
|
2526
|
-
|
|
2527
|
-
|
|
2528
|
-
|
|
2529
|
-
|
|
2530
|
-
|
|
2531
|
-
|
|
2532
|
-
|
|
2533
|
-
|
|
2534
|
-
|
|
2535
|
-
|
|
2536
|
-
|
|
2537
|
-
|
|
2538
|
-
|
|
2539
|
-
|
|
2540
|
-
|
|
2541
|
-
|
|
2352
|
+
</ChemPotScene3D>
|
|
2353
|
+
</Canvas>
|
|
2354
|
+
<!-- Color bar for continuous modes -->
|
|
2355
|
+
{#if color_range}
|
|
2356
|
+
{@const color_bar_config = get_chempot_color_bar_config(
|
|
2357
|
+
color_scale,
|
|
2358
|
+
reverse_color_scale,
|
|
2359
|
+
)}
|
|
2360
|
+
<ColorBar
|
|
2361
|
+
title={color_range.label}
|
|
2362
|
+
range={[color_range.min, color_range.max]}
|
|
2363
|
+
color_scale_fn={color_bar_config.color_scale_fn}
|
|
2364
|
+
color_scale_domain={color_bar_config.color_scale_domain}
|
|
2365
|
+
wrapper_style="position: absolute; bottom: 16px; left: 1em; width: 200px; z-index: 10;"
|
|
2366
|
+
bar_style="height: 12px;"
|
|
2367
|
+
title_style="margin-bottom: 4px;"
|
|
2368
|
+
/>
|
|
2369
|
+
{/if}
|
|
2370
|
+
<!-- Categorical legend for arity mode -->
|
|
2371
|
+
{#if color_mode === `arity`}
|
|
2372
|
+
<div class="arity-legend">
|
|
2373
|
+
{#each arity_legend_labels as label, idx (label)}
|
|
2374
|
+
<span>
|
|
2375
|
+
<span style:background={ARITY_COLORS[idx]}></span>
|
|
2376
|
+
{label}
|
|
2377
|
+
</span>
|
|
2542
2378
|
{/each}
|
|
2543
|
-
|
|
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>
|
|
2379
|
+
</div>
|
|
2588
2380
|
{/if}
|
|
2589
|
-
|
|
2590
|
-
|
|
2591
|
-
|
|
2592
|
-
|
|
2593
|
-
|
|
2594
|
-
|
|
2595
|
-
{
|
|
2596
|
-
|
|
2597
|
-
|
|
2598
|
-
|
|
2381
|
+
{/if}
|
|
2382
|
+
{#if render_local_tooltip && show_tooltip && hover_info?.view === `3d`}
|
|
2383
|
+
<aside
|
|
2384
|
+
bind:this={tooltip_el}
|
|
2385
|
+
class="phase-tooltip"
|
|
2386
|
+
style:left="{tooltip_pos.x}px"
|
|
2387
|
+
style:top="{tooltip_pos.y}px"
|
|
2388
|
+
>
|
|
2389
|
+
<h4>
|
|
2390
|
+
{#each formula_label_segments(hover_info.formula) as segment}
|
|
2391
|
+
<span class:formula-subscript={segment.subscript}>{segment.text}</span>
|
|
2392
|
+
{/each}
|
|
2393
|
+
</h4>
|
|
2394
|
+
{#if locked_hover_formula === hover_info.formula}
|
|
2395
|
+
<p>Pinned · Press Esc to unlock</p>
|
|
2599
2396
|
{/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
2397
|
<p>
|
|
2610
|
-
|
|
2611
|
-
|
|
2612
|
-
|
|
2613
|
-
|
|
2614
|
-
}
|
|
2398
|
+
Vertices: {hover_info.n_vertices} · Edges: {hover_info.n_edges} · Points:
|
|
2399
|
+
{hover_info.n_points}
|
|
2400
|
+
</p>
|
|
2401
|
+
<p>
|
|
2402
|
+
Entries: {hover_info.matching_entry_count}
|
|
2403
|
+
{#if hover_info.min_energy_per_atom !== null && hover_info.max_energy_per_atom !== null}
|
|
2404
|
+
· E/atom: {format_num(hover_info.min_energy_per_atom, `.4~g`)}
|
|
2405
|
+
to {format_num(hover_info.max_energy_per_atom, `.4~g`)} eV
|
|
2406
|
+
{/if}
|
|
2615
2407
|
</p>
|
|
2616
|
-
{#if
|
|
2617
|
-
<h5 id="
|
|
2618
|
-
|
|
2408
|
+
{#if tooltip_detail_level === `detailed`}
|
|
2409
|
+
<h5 id="axis-ranges">Axis ranges</h5>
|
|
2410
|
+
{#each hover_info.axis_ranges as axis_range (axis_range.element)}
|
|
2411
|
+
<p>
|
|
2412
|
+
{axis_range.element}: {format_num(axis_range.min_val, `.4~g`)} to
|
|
2413
|
+
{format_num(axis_range.max_val, `.4~g`)} eV
|
|
2414
|
+
</p>
|
|
2415
|
+
{/each}
|
|
2416
|
+
<p>
|
|
2417
|
+
Centroid: ({hover_info.ann_loc
|
|
2418
|
+
.map((value) => format_num(value, `.3~g`))
|
|
2419
|
+
.join(`, `)})
|
|
2420
|
+
</p>
|
|
2421
|
+
{#if hover_info.touches_limits.length > 0}
|
|
2422
|
+
<h5 id="touches-bounds">Touches bounds</h5>
|
|
2423
|
+
<p>{hover_info.touches_limits.join(`, `)}</p>
|
|
2424
|
+
{/if}
|
|
2619
2425
|
{/if}
|
|
2620
|
-
|
|
2621
|
-
|
|
2622
|
-
{/if}
|
|
2426
|
+
</aside>
|
|
2427
|
+
{/if}
|
|
2623
2428
|
</div>
|
|
2624
2429
|
</div>
|
|
2625
2430
|
|
|
@@ -2708,8 +2513,10 @@
|
|
|
2708
2513
|
}
|
|
2709
2514
|
.chempot-diagram-3d :global(.projection-controls .pane-row) {
|
|
2710
2515
|
display: grid;
|
|
2711
|
-
grid-template-columns:
|
|
2712
|
-
|
|
2516
|
+
grid-template-columns: auto minmax(4.5em, 1fr) auto minmax(4.5em, 1fr) auto minmax(
|
|
2517
|
+
4.5em,
|
|
2518
|
+
1fr
|
|
2519
|
+
);
|
|
2713
2520
|
align-items: center;
|
|
2714
2521
|
gap: 3pt;
|
|
2715
2522
|
}
|
|
@@ -2849,10 +2656,7 @@
|
|
|
2849
2656
|
.phase-tooltip {
|
|
2850
2657
|
position: absolute;
|
|
2851
2658
|
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
|
-
);
|
|
2659
|
+
background: var(--tooltip-bg, light-dark(rgba(255, 255, 255, 0.95), rgba(0, 0, 0, 0.9)));
|
|
2856
2660
|
color: var(--tooltip-text, var(--text-color, #222));
|
|
2857
2661
|
border: 1px solid color-mix(in srgb, currentColor 18%, transparent);
|
|
2858
2662
|
border-radius: 6px;
|