matterviz 0.4.0 → 0.4.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/EmptyState.svelte +10 -4
- package/dist/FilePicker.svelte +12 -14
- package/dist/Icon.svelte +7 -4
- package/dist/MillerIndexInput.svelte +2 -2
- package/dist/app.css +53 -0
- package/dist/brillouin/BrillouinZone.svelte +132 -219
- package/dist/brillouin/BrillouinZone.svelte.d.ts +9 -20
- package/dist/brillouin/BrillouinZoneControls.svelte +3 -6
- package/dist/brillouin/BrillouinZoneExportPane.svelte +47 -96
- package/dist/brillouin/BrillouinZoneExportPane.svelte.d.ts +1 -1
- package/dist/brillouin/BrillouinZoneInfoPane.svelte +15 -42
- package/dist/brillouin/BrillouinZoneInfoPane.svelte.d.ts +2 -3
- package/dist/brillouin/BrillouinZoneScene.svelte +63 -230
- package/dist/brillouin/BrillouinZoneScene.svelte.d.ts +3 -23
- package/dist/brillouin/ReciprocalVectors.svelte +39 -0
- package/dist/brillouin/ReciprocalVectors.svelte.d.ts +9 -0
- package/dist/brillouin/compute.d.ts +2 -0
- package/dist/brillouin/compute.js +80 -77
- package/dist/brillouin/geometry.d.ts +8 -0
- package/dist/brillouin/geometry.js +57 -0
- package/dist/brillouin/index.d.ts +2 -0
- package/dist/brillouin/index.js +2 -0
- package/dist/brillouin/types.d.ts +2 -2
- package/dist/chempot-diagram/ChemPotDiagram.svelte +33 -38
- package/dist/chempot-diagram/ChemPotDiagram.svelte.d.ts +1 -1
- package/dist/chempot-diagram/ChemPotDiagram2D.svelte +143 -246
- package/dist/chempot-diagram/ChemPotDiagram2D.svelte.d.ts +4 -1
- package/dist/chempot-diagram/ChemPotDiagram3D.svelte +652 -976
- package/dist/chempot-diagram/ChemPotDiagram3D.svelte.d.ts +7 -1
- package/dist/chempot-diagram/async-compute.svelte.js +1 -1
- package/dist/chempot-diagram/color.d.ts +3 -6
- package/dist/chempot-diagram/color.js +5 -5
- package/dist/chempot-diagram/compute.d.ts +3 -3
- package/dist/chempot-diagram/compute.js +3 -1
- package/dist/chempot-diagram/controls-state.svelte.d.ts +10 -0
- package/dist/chempot-diagram/controls-state.svelte.js +42 -0
- package/dist/chempot-diagram/export.d.ts +47 -0
- package/dist/chempot-diagram/export.js +133 -0
- package/dist/chempot-diagram/index.d.ts +1 -0
- package/dist/chempot-diagram/index.js +1 -0
- package/dist/chempot-diagram/pointer.d.ts +0 -10
- package/dist/chempot-diagram/pointer.js +4 -4
- package/dist/chempot-diagram/types.d.ts +3 -3
- package/dist/colors/index.d.ts +0 -4
- package/dist/colors/index.js +21 -22
- package/dist/composition/BarChart.svelte +37 -31
- package/dist/composition/BubbleChart.svelte +17 -17
- package/dist/composition/Composition.svelte +7 -11
- package/dist/composition/Formula.svelte +18 -25
- package/dist/composition/FormulaFilter.svelte +96 -98
- package/dist/composition/PieChart.svelte +60 -46
- package/dist/composition/chem-sys.js +3 -2
- package/dist/composition/format.js +4 -3
- package/dist/composition/index.d.ts +2 -0
- package/dist/composition/index.js +14 -0
- package/dist/composition/parse.d.ts +2 -3
- package/dist/composition/parse.js +27 -28
- package/dist/constants.js +11 -9
- package/dist/controls.d.ts +1 -0
- package/dist/controls.js +0 -1
- package/dist/convex-hull/ConvexHull.svelte +20 -25
- package/dist/convex-hull/ConvexHull.svelte.d.ts +1 -4
- package/dist/convex-hull/ConvexHull2D.svelte +176 -256
- package/dist/convex-hull/ConvexHull2D.svelte.d.ts +1 -1
- package/dist/convex-hull/ConvexHull3D.svelte +269 -804
- package/dist/convex-hull/ConvexHull3D.svelte.d.ts +1 -1
- package/dist/convex-hull/ConvexHull4D.svelte +236 -755
- package/dist/convex-hull/ConvexHull4D.svelte.d.ts +1 -1
- package/dist/convex-hull/ConvexHullChrome.svelte +264 -0
- package/dist/convex-hull/ConvexHullChrome.svelte.d.ts +30 -0
- package/dist/convex-hull/ConvexHullControls.svelte +128 -49
- package/dist/convex-hull/ConvexHullControls.svelte.d.ts +7 -6
- package/dist/convex-hull/ConvexHullInfoPane.svelte +18 -5
- package/dist/convex-hull/ConvexHullInfoPane.svelte.d.ts +6 -5
- package/dist/convex-hull/ConvexHullStats.svelte +210 -351
- package/dist/convex-hull/ConvexHullStats.svelte.d.ts +3 -1
- package/dist/convex-hull/ConvexHullTooltip.svelte +16 -14
- package/dist/convex-hull/ConvexHullTooltip.svelte.d.ts +2 -1
- package/dist/convex-hull/GasPressureControls.svelte +5 -12
- package/dist/convex-hull/StructurePopup.svelte +17 -21
- package/dist/convex-hull/StructurePopup.svelte.d.ts +2 -0
- package/dist/convex-hull/TemperatureSlider.svelte +4 -10
- package/dist/convex-hull/barycentric-coords.d.ts +2 -4
- package/dist/convex-hull/barycentric-coords.js +6 -33
- package/dist/convex-hull/canvas-interactions.svelte.d.ts +79 -0
- package/dist/convex-hull/canvas-interactions.svelte.js +279 -0
- package/dist/convex-hull/helpers.d.ts +47 -17
- package/dist/convex-hull/helpers.js +186 -101
- package/dist/convex-hull/hull-state.svelte.d.ts +44 -0
- package/dist/convex-hull/hull-state.svelte.js +124 -0
- package/dist/convex-hull/index.d.ts +9 -7
- package/dist/convex-hull/index.js +7 -2
- package/dist/convex-hull/thermodynamics.js +109 -937
- package/dist/convex-hull/types.d.ts +12 -4
- package/dist/convex-hull/types.js +12 -0
- package/dist/coordination/CoordinationBarPlot.svelte +41 -43
- 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 +6 -8
- 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 +24 -29
- package/dist/element/ElementTile.svelte.d.ts +1 -1
- package/dist/element/Nucleus.svelte +4 -2
- package/dist/element/data.d.ts +1 -2
- package/dist/element/helpers.d.ts +4 -0
- package/dist/element/helpers.js +18 -0
- package/dist/element/index.d.ts +1 -0
- package/dist/element/index.js +3 -0
- package/dist/feedback/DragOverlay.svelte +5 -3
- package/dist/feedback/DragOverlay.svelte.d.ts +2 -1
- package/dist/feedback/StatusMessage.svelte +20 -7
- package/dist/fermi-surface/FermiSlice.svelte +21 -18
- package/dist/fermi-surface/FermiSurface.svelte +78 -165
- package/dist/fermi-surface/FermiSurface.svelte.d.ts +9 -20
- package/dist/fermi-surface/FermiSurfaceControls.svelte +6 -20
- package/dist/fermi-surface/FermiSurfaceScene.svelte +93 -272
- package/dist/fermi-surface/FermiSurfaceScene.svelte.d.ts +3 -23
- package/dist/fermi-surface/FermiSurfaceTooltip.svelte +9 -6
- package/dist/fermi-surface/compute.js +14 -13
- package/dist/fermi-surface/export.js +4 -15
- package/dist/fermi-surface/index.d.ts +0 -1
- package/dist/fermi-surface/index.js +0 -1
- package/dist/fermi-surface/parse.d.ts +1 -1
- package/dist/fermi-surface/parse.js +84 -97
- package/dist/fermi-surface/types.d.ts +2 -2
- package/dist/heatmap-matrix/HeatmapMatrix.svelte +161 -185
- package/dist/heatmap-matrix/HeatmapMatrix.svelte.d.ts +6 -5
- package/dist/heatmap-matrix/HeatmapMatrixControls.svelte +12 -9
- package/dist/heatmap-matrix/HeatmapMatrixControls.svelte.d.ts +5 -5
- package/dist/heatmap-matrix/index.d.ts +8 -2
- package/dist/icons.d.ts +4 -0
- package/dist/icons.js +4 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/io/ExportPane.svelte +170 -0
- package/dist/io/ExportPane.svelte.d.ts +17 -0
- package/dist/io/decompress.d.ts +2 -1
- package/dist/io/decompress.js +22 -36
- package/dist/io/export.d.ts +9 -1
- package/dist/io/export.js +37 -29
- package/dist/io/fetch.d.ts +2 -4
- package/dist/io/fetch.js +0 -11
- package/dist/io/file-drop.d.ts +7 -0
- package/dist/io/file-drop.js +13 -0
- package/dist/io/index.d.ts +1 -0
- package/dist/io/index.js +3 -0
- package/dist/io/is-binary.d.ts +9 -0
- package/dist/io/is-binary.js +45 -1
- package/dist/io/types.d.ts +13 -0
- package/dist/io/url-drop.js +13 -25
- package/dist/isosurface/Isosurface.svelte +17 -23
- package/dist/isosurface/IsosurfaceControls.svelte +37 -42
- package/dist/isosurface/parse-vaspwave.d.ts +3 -0
- package/dist/isosurface/parse-vaspwave.js +138 -0
- package/dist/isosurface/parse.js +50 -48
- package/dist/labels.d.ts +6 -2
- package/dist/labels.js +44 -14
- package/dist/layout/FullscreenButton.svelte +34 -0
- package/dist/layout/FullscreenButton.svelte.d.ts +10 -0
- package/dist/layout/FullscreenToggle.svelte +12 -12
- package/dist/layout/InfoCard.svelte +7 -18
- 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 +21 -17
- package/dist/layout/SubpageGrid.svelte +3 -1
- package/dist/layout/ViewerChrome.svelte +115 -0
- package/dist/layout/ViewerChrome.svelte.d.ts +18 -0
- package/dist/layout/fullscreen.d.ts +4 -0
- package/dist/layout/fullscreen.js +3 -5
- package/dist/layout/fullscreen.svelte.d.ts +8 -0
- package/dist/layout/fullscreen.svelte.js +36 -0
- package/dist/layout/index.d.ts +4 -0
- package/dist/layout/index.js +4 -0
- package/dist/layout/json-tree/JsonNode.svelte +8 -11
- package/dist/layout/json-tree/JsonTree.svelte +53 -77
- package/dist/layout/json-tree/JsonValue.svelte +7 -15
- package/dist/layout/json-tree/utils.js +14 -23
- package/dist/math.d.ts +9 -3
- package/dist/math.js +37 -21
- package/dist/overlays/ContextMenu.svelte +4 -2
- package/dist/overlays/CopyButton.svelte +11 -5
- package/dist/overlays/DragControlTab.svelte +6 -1
- package/dist/overlays/DraggablePane.svelte +81 -26
- package/dist/overlays/DraggablePane.svelte.d.ts +1 -0
- package/dist/overlays/GlassChip.svelte +30 -0
- package/dist/overlays/GlassChip.svelte.d.ts +8 -0
- package/dist/overlays/InfoPaneCards.svelte +11 -23
- package/dist/overlays/index.d.ts +11 -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 +115 -146
- package/dist/periodic-table/PeriodicTable.svelte.d.ts +5 -3
- package/dist/periodic-table/PeriodicTableControls.svelte +11 -63
- package/dist/periodic-table/TableInset.svelte +9 -4
- package/dist/phase-diagram/IsobaricBinaryPhaseDiagram.svelte +50 -71
- package/dist/phase-diagram/IsobaricBinaryPhaseDiagram.svelte.d.ts +6 -8
- package/dist/phase-diagram/PhaseDiagramControls.svelte +73 -96
- package/dist/phase-diagram/PhaseDiagramControls.svelte.d.ts +4 -3
- package/dist/phase-diagram/PhaseDiagramEditorPane.svelte +4 -2
- package/dist/phase-diagram/PhaseDiagramEditorPane.svelte.d.ts +2 -3
- package/dist/phase-diagram/PhaseDiagramExportPane.svelte +49 -134
- package/dist/phase-diagram/PhaseDiagramExportPane.svelte.d.ts +3 -4
- package/dist/phase-diagram/PhaseDiagramTooltip.svelte +54 -58
- package/dist/phase-diagram/TdbInfoPanel.svelte +21 -15
- package/dist/phase-diagram/build-diagram.js +3 -3
- package/dist/phase-diagram/colors.js +1 -1
- package/dist/phase-diagram/diagram-input.d.ts +1 -2
- package/dist/phase-diagram/parse.d.ts +2 -1
- package/dist/phase-diagram/parse.js +15 -15
- package/dist/phase-diagram/svg-to-diagram.js +21 -15
- package/dist/phase-diagram/utils.js +2 -3
- package/dist/plot/bar/BarPlot.svelte +494 -692
- package/dist/plot/bar/BarPlot.svelte.d.ts +9 -15
- package/dist/plot/bar/BarPlotControls.svelte +1 -3
- package/dist/plot/bar/BarPlotControls.svelte.d.ts +5 -7
- package/dist/plot/bar/SpacegroupBarPlot.svelte +31 -37
- package/dist/plot/bar/data.d.ts +5 -4
- package/dist/plot/bar/data.js +2 -1
- package/dist/plot/box/BoxPlot.svelte +361 -439
- package/dist/plot/box/BoxPlot.svelte.d.ts +6 -3
- package/dist/plot/box/BoxPlotControls.svelte.d.ts +1 -1
- package/dist/plot/box/Violin.svelte.d.ts +2 -1
- package/dist/plot/box/box-plot.d.ts +3 -2
- package/dist/plot/box/box-plot.js +6 -3
- package/dist/plot/box/kde.d.ts +2 -1
- package/dist/plot/box/kde.js +4 -4
- package/dist/plot/core/auto-place.d.ts +1 -1
- package/dist/plot/core/auto-place.js +5 -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 +106 -111
- package/dist/plot/core/components/ColorBar.svelte.d.ts +5 -4
- 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 +21 -11
- package/dist/plot/core/components/Line.svelte.d.ts +5 -2
- package/dist/plot/core/components/PlotAxis.svelte +42 -18
- package/dist/plot/core/components/PlotAxis.svelte.d.ts +2 -1
- package/dist/plot/core/components/PlotControls.svelte +65 -41
- package/dist/plot/core/components/PlotControls.svelte.d.ts +1 -1
- 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 +56 -59
- package/dist/plot/core/components/ReferenceLine3D.svelte.d.ts +4 -4
- package/dist/plot/core/components/ReferencePlane.svelte +9 -10
- package/dist/plot/core/components/ReferencePlane.svelte.d.ts +4 -4
- 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 +29 -476
- package/dist/plot/core/data-transform.js +9 -5
- package/dist/plot/core/fill-utils.d.ts +7 -4
- package/dist/plot/core/fill-utils.js +34 -9
- package/dist/plot/core/index.d.ts +1 -0
- package/dist/plot/core/index.js +1 -0
- package/dist/plot/core/interactions.d.ts +5 -1
- package/dist/plot/core/interactions.js +14 -2
- package/dist/plot/core/layout.d.ts +3 -1
- package/dist/plot/core/layout.js +22 -13
- 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 +35 -0
- package/dist/plot/core/pan-zoom.svelte.js +221 -0
- package/dist/plot/core/placed-tween.svelte.d.ts +21 -0
- package/dist/plot/core/placed-tween.svelte.js +68 -0
- package/dist/plot/core/reference-line.d.ts +10 -10
- package/dist/plot/core/reference-line.js +7 -7
- package/dist/plot/core/scales.d.ts +40 -25
- package/dist/plot/core/scales.js +49 -21
- package/dist/plot/core/svg.d.ts +2 -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 +47 -331
- package/dist/plot/core/types.js +23 -20
- package/dist/plot/core/utils/hierarchy-chart.d.ts +51 -0
- package/dist/plot/core/utils/hierarchy-chart.js +179 -0
- package/dist/plot/core/utils/hierarchy-labels.d.ts +20 -0
- package/dist/plot/core/utils/hierarchy-labels.js +99 -0
- package/dist/plot/core/utils/label-placement.d.ts +1 -1
- package/dist/plot/core/utils/label-placement.js +5 -5
- package/dist/plot/core/utils.d.ts +2 -1
- package/dist/plot/histogram/Histogram.svelte +373 -631
- package/dist/plot/histogram/Histogram.svelte.d.ts +7 -7
- package/dist/plot/histogram/HistogramControls.svelte +30 -28
- package/dist/plot/histogram/HistogramControls.svelte.d.ts +1 -1
- 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 +79 -73
- package/dist/plot/sankey/Sankey.svelte.d.ts +3 -3
- package/dist/plot/sankey/SankeyControls.svelte +22 -16
- package/dist/plot/sankey/sankey.js +3 -1
- package/dist/plot/scatter/BinnedScatterPlot.svelte +264 -112
- package/dist/plot/scatter/BinnedScatterPlot.svelte.d.ts +11 -4
- package/dist/plot/scatter/ElementScatter.svelte +4 -1
- package/dist/plot/scatter/ScatterPlot.svelte +623 -821
- package/dist/plot/scatter/ScatterPlot.svelte.d.ts +9 -15
- 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/binned-scatter-types.d.ts +6 -12
- package/dist/plot/scatter/binned-scatter-types.js +6 -1
- package/dist/plot/scatter/index.d.ts +1 -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 +40 -60
- package/dist/plot/scatter-3d/ScatterPlot3D.svelte.d.ts +6 -14
- package/dist/plot/scatter-3d/ScatterPlot3DControls.svelte +17 -15
- package/dist/plot/scatter-3d/ScatterPlot3DControls.svelte.d.ts +5 -5
- package/dist/plot/scatter-3d/ScatterPlot3DScene.svelte +232 -234
- package/dist/plot/scatter-3d/ScatterPlot3DScene.svelte.d.ts +5 -14
- package/dist/plot/scatter-3d/Surface3D.svelte +9 -17
- package/dist/plot/scatter-3d/Surface3D.svelte.d.ts +4 -3
- package/dist/plot/sunburst/Sunburst.svelte +256 -338
- package/dist/plot/sunburst/Sunburst.svelte.d.ts +4 -3
- 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 +14 -4
- package/dist/plot/treemap/Treemap.svelte +907 -0
- package/dist/plot/treemap/Treemap.svelte.d.ts +84 -0
- package/dist/plot/treemap/index.d.ts +3 -0
- package/dist/plot/treemap/index.js +4 -0
- package/dist/plot/treemap/treemap.d.ts +26 -0
- package/dist/plot/treemap/treemap.js +99 -0
- package/dist/rdf/RdfPlot.svelte +22 -26
- package/dist/rdf/RdfPlot.svelte.d.ts +1 -1
- package/dist/rdf/calc-rdf.js +4 -8
- package/dist/sanitize.js +14 -3
- package/dist/scene/SceneCamera.svelte +62 -0
- package/dist/scene/SceneCamera.svelte.d.ts +19 -0
- package/dist/scene/bind-renderer.svelte.d.ts +2 -0
- package/dist/scene/bind-renderer.svelte.js +22 -0
- package/dist/scene/index.d.ts +4 -0
- package/dist/scene/index.js +5 -0
- package/dist/scene/props.js +52 -0
- package/dist/scene/types.d.ts +26 -0
- package/dist/scene/types.js +1 -0
- package/dist/settings.d.ts +33 -11
- package/dist/settings.js +136 -51
- package/dist/spectral/Bands.svelte +231 -237
- package/dist/spectral/Bands.svelte.d.ts +3 -2
- package/dist/spectral/BandsAndDos.svelte +29 -29
- package/dist/spectral/BrillouinBandsDos.svelte +21 -29
- package/dist/spectral/Dos.svelte +75 -77
- package/dist/spectral/Dos.svelte.d.ts +2 -1
- package/dist/spectral/helpers.d.ts +9 -9
- package/dist/spectral/helpers.js +66 -70
- package/dist/state.svelte.d.ts +0 -7
- package/dist/state.svelte.js +5 -24
- package/dist/structure/Arrow.svelte +6 -21
- package/dist/structure/ArrowInstances.svelte +160 -0
- package/dist/structure/ArrowInstances.svelte.d.ts +16 -0
- package/dist/structure/AtomLegend.svelte +115 -75
- package/dist/structure/AtomLegend.svelte.d.ts +1 -1
- package/dist/structure/Bond.svelte +31 -23
- package/dist/structure/CanvasTooltip.svelte +16 -3
- package/dist/structure/CellSelect.svelte +22 -29
- package/dist/structure/CellSelect.svelte.d.ts +2 -1
- 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 +725 -735
- package/dist/structure/Structure.svelte.d.ts +8 -16
- package/dist/structure/StructureCarousel.svelte +630 -0
- package/dist/structure/StructureCarousel.svelte.d.ts +19 -0
- package/dist/structure/StructureControls.svelte +298 -325
- package/dist/structure/StructureControls.svelte.d.ts +5 -3
- package/dist/structure/StructureExportPane.svelte +62 -168
- package/dist/structure/StructureExportPane.svelte.d.ts +4 -5
- package/dist/structure/StructureInfoPane.svelte +77 -69
- package/dist/structure/StructureInfoPane.svelte.d.ts +6 -6
- package/dist/structure/StructureScene.svelte +758 -600
- package/dist/structure/StructureScene.svelte.d.ts +24 -20
- package/dist/structure/StructureViewport.svelte +386 -0
- package/dist/structure/StructureViewport.svelte.d.ts +63 -0
- package/dist/structure/atom-label-placement.d.ts +18 -0
- package/dist/structure/atom-label-placement.js +115 -0
- package/dist/structure/atom-properties.d.ts +3 -1
- package/dist/structure/atom-properties.js +115 -54
- package/dist/structure/bond-order-perception.js +2 -4
- package/dist/structure/bonding.d.ts +12 -2
- package/dist/structure/bonding.js +172 -73
- package/dist/structure/edit-history.d.ts +6 -0
- package/dist/structure/edit-history.js +27 -0
- package/dist/structure/export.d.ts +25 -4
- package/dist/structure/export.js +103 -153
- package/dist/structure/format-detect.d.ts +1 -0
- package/dist/structure/format-detect.js +22 -0
- package/dist/structure/geometry.d.ts +9 -0
- package/dist/structure/geometry.js +27 -0
- package/dist/structure/index.d.ts +18 -1
- package/dist/structure/index.js +15 -2
- package/dist/structure/measure.d.ts +1 -1
- package/dist/structure/measure.js +6 -12
- package/dist/structure/parse.d.ts +5 -3
- package/dist/structure/parse.js +551 -567
- package/dist/structure/partial-occupancy.d.ts +0 -1
- package/dist/structure/partial-occupancy.js +5 -3
- package/dist/structure/pbc.d.ts +1 -1
- package/dist/structure/pbc.js +204 -51
- package/dist/structure/polyhedra.d.ts +40 -0
- package/dist/structure/polyhedra.js +587 -0
- package/dist/structure/site.d.ts +4 -0
- package/dist/structure/site.js +1 -0
- package/dist/structure/supercell.d.ts +1 -2
- package/dist/structure/supercell.js +10 -15
- package/dist/structure/validation.js +5 -6
- package/dist/symmetry/SymmetryElementControls.svelte +69 -0
- package/dist/symmetry/SymmetryElementControls.svelte.d.ts +9 -0
- package/dist/symmetry/SymmetryElements.svelte +350 -0
- package/dist/symmetry/SymmetryElements.svelte.d.ts +24 -0
- package/dist/symmetry/SymmetryStats.svelte +142 -49
- package/dist/symmetry/WyckoffTable.svelte +58 -16
- package/dist/symmetry/WyckoffTable.svelte.d.ts +3 -0
- package/dist/symmetry/cell-transform.js +8 -14
- package/dist/symmetry/index.d.ts +15 -4
- package/dist/symmetry/index.js +308 -81
- package/dist/symmetry/spacegroups.d.ts +5 -1
- package/dist/symmetry/spacegroups.js +18 -3
- package/dist/symmetry/symmetry-elements.d.ts +33 -0
- package/dist/symmetry/symmetry-elements.js +521 -0
- package/dist/symmetry/wyckoff-db.d.ts +9 -0
- package/dist/symmetry/wyckoff-db.js +87 -0
- package/dist/table/HeatmapTable.svelte +1104 -378
- package/dist/table/HeatmapTable.svelte.d.ts +12 -2
- package/dist/table/ToggleMenu.svelte +5 -12
- 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/index.d.ts +1 -5
- package/dist/theme/index.js +4 -10
- package/dist/theme/themes.mjs +14 -7
- package/dist/tooltip/KCoords.svelte +4 -1
- package/dist/tooltip/TooltipContent.svelte +2 -5
- package/dist/trajectory/Trajectory.svelte +556 -352
- package/dist/trajectory/Trajectory.svelte.d.ts +10 -22
- package/dist/trajectory/TrajectoryError.svelte +11 -8
- package/dist/trajectory/TrajectoryExportPane.svelte +28 -54
- package/dist/trajectory/TrajectoryExportPane.svelte.d.ts +4 -5
- package/dist/trajectory/TrajectoryInfoPane.svelte +88 -99
- package/dist/trajectory/TrajectoryInfoPane.svelte.d.ts +3 -2
- package/dist/trajectory/constants.js +6 -2
- package/dist/trajectory/extract.js +73 -71
- package/dist/trajectory/format-detect.d.ts +0 -1
- package/dist/trajectory/format-detect.js +13 -17
- package/dist/trajectory/frame-reader.d.ts +2 -1
- package/dist/trajectory/frame-reader.js +74 -136
- package/dist/trajectory/helpers.d.ts +12 -2
- package/dist/trajectory/helpers.js +68 -37
- package/dist/trajectory/index.d.ts +1 -0
- package/dist/trajectory/index.js +3 -0
- package/dist/trajectory/parse/ase.d.ts +9 -1
- package/dist/trajectory/parse/ase.js +47 -32
- package/dist/trajectory/parse/diagnostics.d.ts +3 -0
- package/dist/trajectory/parse/diagnostics.js +14 -0
- 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 +3 -4
- package/dist/trajectory/parse/index.js +68 -119
- package/dist/trajectory/parse/lammps.d.ts +0 -2
- package/dist/trajectory/parse/lammps.js +14 -16
- package/dist/trajectory/parse/pymatgen.d.ts +2 -0
- package/dist/trajectory/parse/pymatgen.js +74 -0
- package/dist/trajectory/parse/vasp.js +13 -9
- 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 +5 -0
- package/dist/trajectory/parse/vaspout-h5.js +284 -0
- package/dist/trajectory/parse/xyz.d.ts +9 -21
- package/dist/trajectory/parse/xyz.js +38 -39
- package/dist/trajectory/plotting.d.ts +8 -10
- package/dist/trajectory/plotting.js +102 -127
- package/dist/utils.d.ts +4 -0
- package/dist/utils.js +8 -1
- package/dist/xrd/XrdPlot.svelte +56 -85
- package/dist/xrd/broadening.d.ts +2 -1
- package/dist/xrd/broadening.js +2 -1
- package/dist/xrd/calc-xrd.js +8 -15
- package/dist/xrd/index.d.ts +2 -2
- package/dist/xrd/parse.d.ts +0 -1
- package/dist/xrd/parse.js +56 -73
- package/package.json +77 -36
- package/dist/api/mp.d.ts +0 -6
- package/dist/api/mp.js +0 -22
- package/dist/element/data.json +0 -11864
- package/dist/fermi-surface/marching-cubes.d.ts +0 -2
- package/dist/fermi-surface/marching-cubes.js +0 -2
- package/dist/plot/core/hover-lock.svelte.d.ts +0 -14
- package/dist/plot/core/hover-lock.svelte.js +0 -45
- package/dist/plot/sunburst/SunburstControls.svelte +0 -200
- package/dist/structure/label-placement.d.ts +0 -14
- package/dist/structure/label-placement.js +0 -72
|
@@ -6,23 +6,21 @@
|
|
|
6
6
|
import TemperatureSlider from '../convex-hull/TemperatureSlider.svelte'
|
|
7
7
|
import type { PhaseData } from '../convex-hull/types'
|
|
8
8
|
import Spinner from '../feedback/Spinner.svelte'
|
|
9
|
-
import
|
|
9
|
+
import type { ExportSection } from '../io'
|
|
10
|
+
import ExportPane from '../io/ExportPane.svelte'
|
|
10
11
|
import { format_num } from '../labels'
|
|
11
|
-
import { set_fullscreen_bg, SettingsSection, toggle_fullscreen } from '../layout'
|
|
12
|
-
import type { Vec2, Vec3 } from '../math'
|
|
13
12
|
import {
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
} from '../
|
|
13
|
+
FullscreenButton,
|
|
14
|
+
type FullscreenToggleProp,
|
|
15
|
+
SettingsSection,
|
|
16
|
+
toggle_fullscreen,
|
|
17
|
+
} from '../layout'
|
|
18
|
+
import { sync_fullscreen } from '../layout/fullscreen.svelte'
|
|
19
|
+
import type { Vec2, Vec3 } from '../math'
|
|
20
|
+
import { convex_hull_2d, cross_3d, merge_coplanar_triangles, normalize_vec } from '../math'
|
|
19
21
|
import DraggablePane from '../overlays/DraggablePane.svelte'
|
|
20
22
|
import { ColorBar, ScatterPlot3DControls } from '../plot'
|
|
21
|
-
import {
|
|
22
|
-
constrain_tooltip_position,
|
|
23
|
-
pad_rect,
|
|
24
|
-
rects_overlap,
|
|
25
|
-
} from '../plot/core/layout'
|
|
23
|
+
import { constrain_tooltip_position, pad_rect, rects_overlap } from '../plot/core/layout'
|
|
26
24
|
import type {
|
|
27
25
|
AxisConfig3D,
|
|
28
26
|
CameraProjection3D,
|
|
@@ -32,15 +30,29 @@
|
|
|
32
30
|
import { Canvas, T } from '@threlte/core'
|
|
33
31
|
import * as extras from '@threlte/extras'
|
|
34
32
|
import { scaleLinear } from 'd3-scale'
|
|
33
|
+
import type { Snippet } from 'svelte'
|
|
35
34
|
import { onDestroy, onMount, untrack } from 'svelte'
|
|
36
35
|
import { SvelteMap, SvelteSet } from 'svelte/reactivity'
|
|
37
36
|
import * as THREE from 'three'
|
|
38
37
|
import type { OrbitControls } from 'three/examples/jsm/controls/OrbitControls.js'
|
|
39
|
-
import { GLTFExporter } from 'three/examples/jsm/exporters/GLTFExporter.js'
|
|
40
38
|
import { ConvexGeometry } from 'three/examples/jsm/geometries/ConvexGeometry.js'
|
|
41
39
|
import { compute_chempot_async } from './async-compute.svelte'
|
|
42
40
|
import ChemPotScene3D from './ChemPotScene3D.svelte'
|
|
43
41
|
import { get_chempot_color_bar_config, make_chempot_color_scale } from './color'
|
|
42
|
+
import {
|
|
43
|
+
CHEMPOT_COLOR_MODE_OPTIONS,
|
|
44
|
+
CHEMPOT_COLOR_SCALE_OPTIONS,
|
|
45
|
+
create_chempot_overrides,
|
|
46
|
+
} from './controls-state.svelte'
|
|
47
|
+
import {
|
|
48
|
+
export_glb_file,
|
|
49
|
+
export_json_file,
|
|
50
|
+
export_png_file,
|
|
51
|
+
export_svg_file,
|
|
52
|
+
export_view_json_file,
|
|
53
|
+
get_json_string,
|
|
54
|
+
get_view_settings,
|
|
55
|
+
} from './export'
|
|
44
56
|
import {
|
|
45
57
|
apply_element_padding,
|
|
46
58
|
bbox_diagonal,
|
|
@@ -85,6 +97,11 @@
|
|
|
85
97
|
max_interpolation_gap = CHEMPOT_DEFAULTS.max_interpolation_gap,
|
|
86
98
|
hover_info = $bindable<ChemPotHoverInfo | null>(null),
|
|
87
99
|
render_local_tooltip = true,
|
|
100
|
+
wrapper = $bindable(),
|
|
101
|
+
fullscreen = $bindable(false),
|
|
102
|
+
fullscreen_toggle = true,
|
|
103
|
+
controls_open = $bindable(false),
|
|
104
|
+
export_pane_open = $bindable(false),
|
|
88
105
|
}: {
|
|
89
106
|
entries: PhaseData[]
|
|
90
107
|
config?: ChemPotDiagramConfig
|
|
@@ -95,62 +112,51 @@
|
|
|
95
112
|
max_interpolation_gap?: number
|
|
96
113
|
hover_info?: ChemPotHoverInfo | null
|
|
97
114
|
render_local_tooltip?: boolean
|
|
115
|
+
// bindable: top-level wrapper element
|
|
116
|
+
wrapper?: HTMLDivElement
|
|
117
|
+
// bindable: fullscreen state
|
|
118
|
+
fullscreen?: boolean
|
|
119
|
+
// show/hide the fullscreen button (or custom snippet to render it)
|
|
120
|
+
fullscreen_toggle?: FullscreenToggleProp
|
|
121
|
+
// bindable: whether the controls pane is currently open
|
|
122
|
+
controls_open?: boolean
|
|
123
|
+
// bindable: whether the export pane is currently open
|
|
124
|
+
export_pane_open?: boolean
|
|
98
125
|
} = $props()
|
|
99
126
|
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
)
|
|
117
|
-
const default_min_limit = $derived(
|
|
118
|
-
default_min_limit_override ??
|
|
119
|
-
(config.default_min_limit ?? CHEMPOT_DEFAULTS.default_min_limit),
|
|
120
|
-
)
|
|
121
|
-
let formulas_to_draw_override = $state<string[] | null>(null)
|
|
122
|
-
const formulas_to_draw = $derived(
|
|
123
|
-
formulas_to_draw_override ?? (config.formulas_to_draw ?? []),
|
|
124
|
-
)
|
|
125
|
-
const draw_formula_meshes = $derived(
|
|
126
|
-
draw_formula_meshes_override ??
|
|
127
|
-
(config.draw_formula_meshes ?? CHEMPOT_DEFAULTS.draw_formula_meshes),
|
|
128
|
-
)
|
|
129
|
-
const draw_formula_lines = $derived(
|
|
130
|
-
draw_formula_lines_override ??
|
|
131
|
-
(config.draw_formula_lines ?? CHEMPOT_DEFAULTS.draw_formula_lines),
|
|
132
|
-
)
|
|
133
|
-
let color_mode_override = $state<ChemPotColorMode | null>(null)
|
|
134
|
-
let color_scale_override = $state<D3InterpolateName | null>(null)
|
|
135
|
-
let reverse_color_scale_override = $state<boolean | null>(null)
|
|
136
|
-
const color_mode = $derived(
|
|
137
|
-
color_mode_override ?? (config.color_mode ?? `arity`),
|
|
138
|
-
)
|
|
139
|
-
const color_scale = $derived(
|
|
140
|
-
color_scale_override ?? (config.color_scale ?? CHEMPOT_DEFAULTS.color_scale),
|
|
141
|
-
)
|
|
142
|
-
const reverse_color_scale = $derived(
|
|
143
|
-
reverse_color_scale_override ??
|
|
144
|
-
(config.reverse_color_scale ?? CHEMPOT_DEFAULTS.reverse_color_scale),
|
|
127
|
+
// Control overrides (override ?? config ?? default, cleared by Reset)
|
|
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: [] },
|
|
145
143
|
)
|
|
144
|
+
const formal_chempots = $derived(overrides.resolve(`formal_chempots`))
|
|
145
|
+
const label_stable = $derived(overrides.resolve(`label_stable`))
|
|
146
|
+
const element_padding = $derived(overrides.resolve(`element_padding`))
|
|
147
|
+
const default_min_limit = $derived(overrides.resolve(`default_min_limit`))
|
|
148
|
+
const formulas_to_draw = $derived(overrides.resolve(`formulas_to_draw`))
|
|
149
|
+
const draw_formula_meshes = $derived(overrides.resolve(`draw_formula_meshes`))
|
|
150
|
+
const draw_formula_lines = $derived(overrides.resolve(`draw_formula_lines`))
|
|
151
|
+
const color_mode = $derived(overrides.resolve(`color_mode`))
|
|
152
|
+
const color_scale = $derived(overrides.resolve(`color_scale`))
|
|
153
|
+
const reverse_color_scale = $derived(overrides.resolve(`reverse_color_scale`))
|
|
146
154
|
const show_tooltip = $derived(config.show_tooltip ?? CHEMPOT_DEFAULTS.show_tooltip)
|
|
147
155
|
const tooltip_detail_level = $derived(
|
|
148
156
|
config.tooltip_detail_level ?? CHEMPOT_DEFAULTS.tooltip_detail_level,
|
|
149
157
|
)
|
|
150
158
|
const formula_colors = $derived(
|
|
151
|
-
config.formula_colors?.length
|
|
152
|
-
? config.formula_colors
|
|
153
|
-
: CHEMPOT_DEFAULTS.formula_colors,
|
|
159
|
+
config.formula_colors?.length ? config.formula_colors : CHEMPOT_DEFAULTS.formula_colors,
|
|
154
160
|
)
|
|
155
161
|
|
|
156
162
|
const formula_label_segments = (formula: string): FormulaLabelSegment[] =>
|
|
@@ -167,33 +173,44 @@
|
|
|
167
173
|
return deduped
|
|
168
174
|
}
|
|
169
175
|
|
|
170
|
-
let wrapper = $state<HTMLDivElement>()
|
|
171
|
-
let fullscreen = $state(false)
|
|
172
|
-
let export_pane_open = $state(false)
|
|
173
176
|
let formula_picker_open = $state(false)
|
|
174
|
-
let controls_open = $state(false)
|
|
175
177
|
|
|
176
178
|
// Mutual exclusion: only one pane open at a time.
|
|
177
179
|
// Separate effects so each reacts to its own pane opening independently —
|
|
178
180
|
// a single $derived ternary would create priority ordering where opening
|
|
179
181
|
// a "lower" pane while a "higher" one is open fails silently.
|
|
180
|
-
$effect(() => {
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
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
|
+
})
|
|
185
200
|
let container_width = $state(0)
|
|
186
201
|
let container_height = $state(0)
|
|
187
202
|
const base_aspect_ratio = $derived(height > 0 && width > 0 ? height / width : 1)
|
|
188
203
|
const render_width = $derived(container_width > 0 ? container_width : width)
|
|
189
204
|
const render_height = $derived(
|
|
190
205
|
fullscreen
|
|
191
|
-
?
|
|
206
|
+
? container_height > 0
|
|
207
|
+
? container_height
|
|
208
|
+
: height
|
|
192
209
|
: Math.round(render_width * base_aspect_ratio),
|
|
193
210
|
)
|
|
194
211
|
|
|
195
212
|
let mounted = $state(false)
|
|
196
|
-
onMount(() => mounted = true)
|
|
213
|
+
onMount(() => (mounted = true))
|
|
197
214
|
let orbit_controls_ref = $state<OrbitControls | undefined>(undefined)
|
|
198
215
|
// Backside tracking: axes/ticks/labels render on the far side from the camera
|
|
199
216
|
// back[i] = backside data coordinate value for data axis i
|
|
@@ -246,9 +263,7 @@
|
|
|
246
263
|
if (next_temperature !== temperature) temperature = next_temperature
|
|
247
264
|
})
|
|
248
265
|
|
|
249
|
-
const show_temperature_slider = $derived(
|
|
250
|
-
has_temp_data && available_temperatures.length > 0,
|
|
251
|
-
)
|
|
266
|
+
const show_temperature_slider = $derived(has_temp_data && available_temperatures.length > 0)
|
|
252
267
|
|
|
253
268
|
const projection_source_entries = $derived(
|
|
254
269
|
get_projection_source_entries(entries, temp_filtered_entries),
|
|
@@ -260,10 +275,10 @@
|
|
|
260
275
|
projection_source_entries.flatMap((entry) =>
|
|
261
276
|
Object.entries(entry.composition)
|
|
262
277
|
.filter(([, amount]) => amount > 0)
|
|
263
|
-
.map(([element]) => element)
|
|
278
|
+
.map(([element]) => element),
|
|
264
279
|
),
|
|
265
280
|
),
|
|
266
|
-
).sort()
|
|
281
|
+
).sort(),
|
|
267
282
|
)
|
|
268
283
|
const has_multinary_system = $derived(all_entry_elements.length > 3)
|
|
269
284
|
let projection_elements_override = $state<string[] | null>(null)
|
|
@@ -285,9 +300,7 @@
|
|
|
285
300
|
})
|
|
286
301
|
const effective_config = $derived({
|
|
287
302
|
...config,
|
|
288
|
-
elements: projection_elements.length === 3
|
|
289
|
-
? projection_elements
|
|
290
|
-
: config.elements,
|
|
303
|
+
elements: projection_elements.length === 3 ? projection_elements : config.elements,
|
|
291
304
|
formal_chempots,
|
|
292
305
|
label_stable,
|
|
293
306
|
element_padding,
|
|
@@ -317,7 +330,9 @@
|
|
|
317
330
|
diagram_data = null
|
|
318
331
|
diagram_computing = false
|
|
319
332
|
})
|
|
320
|
-
return () => {
|
|
333
|
+
return () => {
|
|
334
|
+
cancelled = true
|
|
335
|
+
}
|
|
321
336
|
})
|
|
322
337
|
|
|
323
338
|
const plot_elements = $derived(diagram_data?.elements ?? projection_elements)
|
|
@@ -346,15 +361,11 @@
|
|
|
346
361
|
})
|
|
347
362
|
const current_projection_key = $derived(plot_elements.join(`|`))
|
|
348
363
|
let formula_filter_query = $state(``)
|
|
349
|
-
const available_formulas = $derived.by(() =>
|
|
350
|
-
Object.keys(diagram_data?.domains ?? {}).sort()
|
|
351
|
-
)
|
|
364
|
+
const available_formulas = $derived.by(() => Object.keys(diagram_data?.domains ?? {}).sort())
|
|
352
365
|
const filtered_formulas = $derived.by(() => {
|
|
353
366
|
const query = formula_filter_query.trim().toLowerCase()
|
|
354
367
|
if (!query) return available_formulas
|
|
355
|
-
return available_formulas.filter((formula) =>
|
|
356
|
-
formula.toLowerCase().includes(query)
|
|
357
|
-
)
|
|
368
|
+
return available_formulas.filter((formula) => formula.toLowerCase().includes(query))
|
|
358
369
|
})
|
|
359
370
|
|
|
360
371
|
// Process domains for rendering
|
|
@@ -378,45 +389,49 @@
|
|
|
378
389
|
max_energy_per_atom: number | null
|
|
379
390
|
}
|
|
380
391
|
type NumericColorMode = Exclude<ChemPotColorMode, `none` | `arity`>
|
|
392
|
+
const domain_annotation_cache = new Map<string, number[]>()
|
|
393
|
+
|
|
394
|
+
function get_domain_ann_loc(points_3d: number[][]): number[] {
|
|
395
|
+
if (points_3d.length >= 3) {
|
|
396
|
+
const cache_key = points_3d.map((point) => point.join(`,`)).join(`;`)
|
|
397
|
+
const cached = domain_annotation_cache.get(cache_key)
|
|
398
|
+
if (cached) return cached
|
|
399
|
+
const ann_loc = get_3d_domain_simplexes_and_ann_loc(points_3d).ann_loc
|
|
400
|
+
domain_annotation_cache.set(cache_key, ann_loc)
|
|
401
|
+
return ann_loc
|
|
402
|
+
}
|
|
403
|
+
return points_3d[0].map(
|
|
404
|
+
(_, col_idx) =>
|
|
405
|
+
points_3d.reduce((sum, point) => sum + point[col_idx], 0) / points_3d.length,
|
|
406
|
+
)
|
|
407
|
+
}
|
|
381
408
|
|
|
382
409
|
const render_domains = $derived.by((): DomainRenderData[] => {
|
|
383
410
|
if (!diagram_data || plot_elements.length < 2) return []
|
|
384
411
|
|
|
385
412
|
const dim = diagram_data.elements.length
|
|
386
413
|
const indices = Array.from({ length: dim }, (_, idx) => idx)
|
|
387
|
-
const new_lims =
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
414
|
+
const new_lims =
|
|
415
|
+
element_padding > 0
|
|
416
|
+
? apply_element_padding(
|
|
417
|
+
diagram_data.domains,
|
|
418
|
+
indices,
|
|
419
|
+
element_padding,
|
|
420
|
+
default_min_limit,
|
|
421
|
+
)
|
|
422
|
+
: null
|
|
395
423
|
|
|
396
424
|
const result: DomainRenderData[] = []
|
|
397
425
|
for (const [formula, pts] of Object.entries(diagram_data.domains)) {
|
|
398
426
|
const padded = new_lims
|
|
399
|
-
? pad_domain_points(
|
|
400
|
-
pts,
|
|
401
|
-
indices,
|
|
402
|
-
new_lims,
|
|
403
|
-
default_min_limit,
|
|
404
|
-
element_padding,
|
|
405
|
-
)
|
|
427
|
+
? pad_domain_points(pts, indices, new_lims, default_min_limit, element_padding)
|
|
406
428
|
: pts
|
|
407
429
|
if (padded.length < 2) continue
|
|
408
|
-
const is_draw = formulas_to_draw.includes(formula)
|
|
409
|
-
const centroid = padded[0].map((_, col_idx) =>
|
|
410
|
-
padded.reduce((sum, point) => sum + point[col_idx], 0) / padded.length
|
|
411
|
-
)
|
|
412
|
-
const ann_loc = padded.length >= 3
|
|
413
|
-
? get_3d_domain_simplexes_and_ann_loc(padded).ann_loc
|
|
414
|
-
: centroid
|
|
415
430
|
result.push({
|
|
416
431
|
formula,
|
|
417
432
|
points_3d: padded,
|
|
418
|
-
ann_loc,
|
|
419
|
-
is_draw_formula:
|
|
433
|
+
ann_loc: get_domain_ann_loc(padded),
|
|
434
|
+
is_draw_formula: formulas_to_draw.includes(formula),
|
|
420
435
|
label_font_size: bbox_diagonal(padded),
|
|
421
436
|
})
|
|
422
437
|
}
|
|
@@ -467,9 +482,7 @@
|
|
|
467
482
|
// Original (non-renormalized) elemental references for formation energy computation.
|
|
468
483
|
// diagram_data.el_refs may be renormalized to zero when formal_chempots is true,
|
|
469
484
|
// so we compute our own from the raw entries to get true DFT reference energies.
|
|
470
|
-
const raw_el_refs = $derived(
|
|
471
|
-
get_min_entries_and_el_refs(temp_filtered_entries).el_refs,
|
|
472
|
-
)
|
|
485
|
+
const raw_el_refs = $derived(get_min_entries_and_el_refs(temp_filtered_entries).el_refs)
|
|
473
486
|
|
|
474
487
|
const color_mode_labels: Record<NumericColorMode, string> = {
|
|
475
488
|
energy: `Energy per atom (eV)`,
|
|
@@ -484,11 +497,7 @@
|
|
|
484
497
|
return entry_energy_stats_by_formula.get(formula)?.min_energy_per_atom ?? null
|
|
485
498
|
}
|
|
486
499
|
if (active_color_mode === `formation_energy`) {
|
|
487
|
-
return best_form_energy_for_formula(
|
|
488
|
-
temp_filtered_entries,
|
|
489
|
-
formula,
|
|
490
|
-
raw_el_refs,
|
|
491
|
-
) ?? null
|
|
500
|
+
return best_form_energy_for_formula(temp_filtered_entries, formula, raw_el_refs) ?? null
|
|
492
501
|
}
|
|
493
502
|
return entry_energy_stats_by_formula.get(formula)?.matching_entry_count ?? 0
|
|
494
503
|
}
|
|
@@ -535,24 +544,22 @@
|
|
|
535
544
|
})
|
|
536
545
|
|
|
537
546
|
// Range and label for the color bar (null for none/arity which are categorical)
|
|
538
|
-
const color_range = $derived.by(
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
},
|
|
555
|
-
)
|
|
547
|
+
const color_range = $derived.by((): { min: number; max: number; label: string } | null => {
|
|
548
|
+
const values = domain_color_values?.values ?? []
|
|
549
|
+
if (values.length === 0) return null
|
|
550
|
+
let lo = values[0],
|
|
551
|
+
hi = values[0]
|
|
552
|
+
for (let idx = 1; idx < values.length; idx++) {
|
|
553
|
+
if (values[idx] < lo) lo = values[idx]
|
|
554
|
+
if (values[idx] > hi) hi = values[idx]
|
|
555
|
+
}
|
|
556
|
+
return {
|
|
557
|
+
min: lo,
|
|
558
|
+
max: Math.max(hi, lo + 1e-6),
|
|
559
|
+
label:
|
|
560
|
+
color_mode === `none` || color_mode === `arity` ? `` : color_mode_labels[color_mode],
|
|
561
|
+
}
|
|
562
|
+
})
|
|
556
563
|
|
|
557
564
|
const arity_legend_labels = $derived.by((): string[] => {
|
|
558
565
|
let has_four_plus_regions = false
|
|
@@ -572,9 +579,12 @@
|
|
|
572
579
|
const render_axis_scale = $derived.by((): Vec3 => {
|
|
573
580
|
const points = render_domains.flatMap((domain) => domain.points_3d)
|
|
574
581
|
if (points.length === 0) return [1, 1, 1]
|
|
575
|
-
let min0 = Infinity,
|
|
576
|
-
|
|
577
|
-
let
|
|
582
|
+
let min0 = Infinity,
|
|
583
|
+
max0 = -Infinity
|
|
584
|
+
let min1 = Infinity,
|
|
585
|
+
max1 = -Infinity
|
|
586
|
+
let min2 = Infinity,
|
|
587
|
+
max2 = -Infinity
|
|
578
588
|
for (const point of points) {
|
|
579
589
|
if (point[0] < min0) min0 = point[0]
|
|
580
590
|
if (point[0] > max0) max0 = point[0]
|
|
@@ -614,11 +624,7 @@
|
|
|
614
624
|
sum_z += z_val
|
|
615
625
|
}
|
|
616
626
|
const n_points = points.length
|
|
617
|
-
const center = new THREE.Vector3(
|
|
618
|
-
sum_x / n_points,
|
|
619
|
-
sum_y / n_points,
|
|
620
|
-
sum_z / n_points,
|
|
621
|
-
)
|
|
627
|
+
const center = new THREE.Vector3(sum_x / n_points, sum_y / n_points, sum_z / n_points)
|
|
622
628
|
// Compute max distance from center
|
|
623
629
|
let max_dist = 0
|
|
624
630
|
for (const point of points) {
|
|
@@ -633,30 +639,22 @@
|
|
|
633
639
|
data_center.y + data_extent,
|
|
634
640
|
data_center.z + data_extent,
|
|
635
641
|
])
|
|
636
|
-
const default_camera_target = $derived<Vec3>([
|
|
637
|
-
data_center.x,
|
|
638
|
-
data_center.y,
|
|
639
|
-
data_center.z,
|
|
640
|
-
])
|
|
642
|
+
const default_camera_target = $derived<Vec3>([data_center.x, data_center.y, data_center.z])
|
|
641
643
|
const default_orthographic_zoom = $derived(
|
|
642
644
|
Math.min(render_width, render_height) / (data_extent * 1.6),
|
|
643
645
|
)
|
|
644
646
|
let camera_position_override = $state<Vec3 | null>(null)
|
|
645
647
|
let camera_target_override = $state<Vec3 | null>(null)
|
|
646
648
|
let orthographic_zoom_override = $state<number | null>(null)
|
|
647
|
-
const camera_position = $derived(
|
|
648
|
-
|
|
649
|
-
)
|
|
650
|
-
const camera_target = $derived(
|
|
651
|
-
camera_target_override ?? default_camera_target,
|
|
652
|
-
)
|
|
653
|
-
const orthographic_zoom = $derived(
|
|
654
|
-
orthographic_zoom_override ?? default_orthographic_zoom,
|
|
655
|
-
)
|
|
649
|
+
const camera_position = $derived(camera_position_override ?? default_camera_position)
|
|
650
|
+
const camera_target = $derived(camera_target_override ?? default_camera_target)
|
|
651
|
+
const orthographic_zoom = $derived(orthographic_zoom_override ?? default_orthographic_zoom)
|
|
656
652
|
// Label scale factor: zoom relative to default, so labels grow/shrink with zoom
|
|
657
653
|
// Labels scale sub-linearly with zoom so they grow but don't dominate when zoomed in
|
|
658
654
|
const zoom_scale = $derived(
|
|
659
|
-
default_orthographic_zoom > 0
|
|
655
|
+
default_orthographic_zoom > 0
|
|
656
|
+
? Math.sqrt(orthographic_zoom / default_orthographic_zoom)
|
|
657
|
+
: 1,
|
|
660
658
|
)
|
|
661
659
|
let last_data_center: Vec3 | null = null
|
|
662
660
|
let last_data_extent: number | null = null
|
|
@@ -665,14 +663,16 @@
|
|
|
665
663
|
// Each domain in a chem pot diagram is a convex polygon/polyhedron. We project
|
|
666
664
|
// to 2D (trying all 3 axis-aligned planes) and use the best projection's
|
|
667
665
|
// convex hull boundary. This reliably handles both flat and 3D domains.
|
|
668
|
-
function get_domain_edges(
|
|
669
|
-
pts: number[][],
|
|
670
|
-
): [number[], number[]][] {
|
|
666
|
+
function get_domain_edges(pts: number[][]): [number[], number[]][] {
|
|
671
667
|
const unique = dedup_3d(pts)
|
|
672
668
|
if (unique.length < 2) return []
|
|
673
669
|
if (unique.length === 2) return [[unique[0], unique[1]]]
|
|
674
670
|
if (unique.length === 3) {
|
|
675
|
-
return [
|
|
671
|
+
return [
|
|
672
|
+
[unique[0], unique[1]],
|
|
673
|
+
[unique[1], unique[2]],
|
|
674
|
+
[unique[0], unique[2]],
|
|
675
|
+
]
|
|
676
676
|
}
|
|
677
677
|
return get_2d_hull_edges(unique)
|
|
678
678
|
}
|
|
@@ -692,9 +692,7 @@
|
|
|
692
692
|
// (largest non-degenerate hull area). Unioning multiple projections can add
|
|
693
693
|
// non-physical diagonals for nearly coplanar domains.
|
|
694
694
|
// Called only from get_domain_edges with 4+ unique points
|
|
695
|
-
function get_2d_hull_edges(
|
|
696
|
-
pts: number[][],
|
|
697
|
-
): [number[], number[]][] {
|
|
695
|
+
function get_2d_hull_edges(pts: number[][]): [number[], number[]][] {
|
|
698
696
|
let selected_hull: Vec2[] = []
|
|
699
697
|
let selected_coord_to_idx: SvelteMap<string, number> | null = null
|
|
700
698
|
let selected_hull_area = -1
|
|
@@ -704,15 +702,20 @@
|
|
|
704
702
|
|
|
705
703
|
// Skip this projection if points collapse to a line (near-zero range in
|
|
706
704
|
// either projected axis). This avoids spurious edges from edge-on views.
|
|
707
|
-
let min0 = Infinity,
|
|
705
|
+
let min0 = Infinity,
|
|
706
|
+
max0 = -Infinity,
|
|
707
|
+
min1 = Infinity,
|
|
708
|
+
max1 = -Infinity
|
|
708
709
|
for (const pt of pts) {
|
|
709
|
-
const v0 = pt[axes[0]],
|
|
710
|
+
const v0 = pt[axes[0]],
|
|
711
|
+
v1 = pt[axes[1]]
|
|
710
712
|
if (v0 < min0) min0 = v0
|
|
711
713
|
if (v0 > max0) max0 = v0
|
|
712
714
|
if (v1 < min1) min1 = v1
|
|
713
715
|
if (v1 > max1) max1 = v1
|
|
714
716
|
}
|
|
715
|
-
const range0 = max0 - min0,
|
|
717
|
+
const range0 = max0 - min0,
|
|
718
|
+
range1 = max1 - min1
|
|
716
719
|
const max_2d_range = Math.max(range0, range1)
|
|
717
720
|
if (max_2d_range < 1e-6 || Math.min(range0, range1) < max_2d_range * 0.01) {
|
|
718
721
|
continue
|
|
@@ -750,7 +753,9 @@
|
|
|
750
753
|
`${point_b[0].toFixed(6)},${point_b[1].toFixed(6)}`,
|
|
751
754
|
)
|
|
752
755
|
if (
|
|
753
|
-
point_a_idx == null ||
|
|
756
|
+
point_a_idx == null ||
|
|
757
|
+
point_b_idx == null ||
|
|
758
|
+
point_a_idx >= pts.length ||
|
|
754
759
|
point_b_idx >= pts.length
|
|
755
760
|
) {
|
|
756
761
|
console.warn(`get_2d_hull_edges: invalid edge`, {
|
|
@@ -797,7 +802,7 @@
|
|
|
797
802
|
for (const [pa, pb] of get_domain_edges(swizzled)) {
|
|
798
803
|
const ka = pa.map((coord) => coord.toFixed(4)).join(`,`)
|
|
799
804
|
const kb = pb.map((coord) => coord.toFixed(4)).join(`,`)
|
|
800
|
-
const key = ka
|
|
805
|
+
const key = edge_key(ka, kb)
|
|
801
806
|
if (seen.has(key)) continue
|
|
802
807
|
seen.add(key)
|
|
803
808
|
positions.push(pa[0], pa[1], pa[2], pb[0], pb[1], pb[2])
|
|
@@ -844,7 +849,9 @@
|
|
|
844
849
|
const n_verts = pos.count
|
|
845
850
|
const n_faces = n_verts / 3
|
|
846
851
|
// Hull centroid for orienting face normals outward
|
|
847
|
-
let hx = 0,
|
|
852
|
+
let hx = 0,
|
|
853
|
+
hy = 0,
|
|
854
|
+
hz = 0
|
|
848
855
|
for (let vert_idx = 0; vert_idx < n_verts; vert_idx++) {
|
|
849
856
|
hx += pos.getX(vert_idx)
|
|
850
857
|
hy += pos.getY(vert_idx)
|
|
@@ -898,7 +905,9 @@
|
|
|
898
905
|
const centroids = render_domains
|
|
899
906
|
.filter((domain) => !domain.is_draw_formula && domain.points_3d.length > 0)
|
|
900
907
|
.map((domain) => {
|
|
901
|
-
let sx = 0,
|
|
908
|
+
let sx = 0,
|
|
909
|
+
sy = 0,
|
|
910
|
+
sz = 0
|
|
902
911
|
for (const pt of domain.points_3d) {
|
|
903
912
|
const [x_val, y_val, z_val] = to_render_xyz(pt)
|
|
904
913
|
sx += x_val
|
|
@@ -906,7 +915,12 @@
|
|
|
906
915
|
sz += z_val
|
|
907
916
|
}
|
|
908
917
|
const n_points = domain.points_3d.length
|
|
909
|
-
return {
|
|
918
|
+
return {
|
|
919
|
+
formula: domain.formula,
|
|
920
|
+
cx: sx / n_points,
|
|
921
|
+
cy: sy / n_points,
|
|
922
|
+
cz: sz / n_points,
|
|
923
|
+
}
|
|
910
924
|
})
|
|
911
925
|
|
|
912
926
|
// Assign each face to the nearest domain centroid
|
|
@@ -934,11 +948,11 @@
|
|
|
934
948
|
// coplanar neighbors, then assign each group to its most-common domain.
|
|
935
949
|
if (n_faces > 1) {
|
|
936
950
|
const tol = 1e-3
|
|
937
|
-
const round = (
|
|
951
|
+
const round = (val: number): number => Math.round(val / tol)
|
|
938
952
|
const vkey = (vert_idx: number): string =>
|
|
939
|
-
`${round(pos.getX(vert_idx))},${round(pos.getY(vert_idx))},${
|
|
940
|
-
|
|
941
|
-
}`
|
|
953
|
+
`${round(pos.getX(vert_idx))},${round(pos.getY(vert_idx))},${round(
|
|
954
|
+
pos.getZ(vert_idx),
|
|
955
|
+
)}`
|
|
942
956
|
// Compute face normals
|
|
943
957
|
const normals: Vec3[] = []
|
|
944
958
|
for (let face_idx = 0; face_idx < n_faces; face_idx++) {
|
|
@@ -960,13 +974,11 @@
|
|
|
960
974
|
for (let face_idx = 0; face_idx < n_faces; face_idx++) {
|
|
961
975
|
const base = face_idx * 3
|
|
962
976
|
const keys = [vkey(base), vkey(base + 1), vkey(base + 2)]
|
|
963
|
-
for (
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
]
|
|
969
|
-
) {
|
|
977
|
+
for (const ek of [
|
|
978
|
+
edge_key(keys[0], keys[1]),
|
|
979
|
+
edge_key(keys[1], keys[2]),
|
|
980
|
+
edge_key(keys[0], keys[2]),
|
|
981
|
+
]) {
|
|
970
982
|
const list = edge_faces.get(ek)
|
|
971
983
|
if (list) list.push(face_idx)
|
|
972
984
|
else edge_faces.set(ek, [face_idx])
|
|
@@ -974,21 +986,23 @@
|
|
|
974
986
|
}
|
|
975
987
|
// Union-find for coplanar adjacent faces
|
|
976
988
|
const parent = Array.from({ length: n_faces }, (_, idx) => idx)
|
|
977
|
-
const find = (
|
|
978
|
-
while (parent[
|
|
979
|
-
parent[
|
|
980
|
-
|
|
989
|
+
const find = (node: number): number => {
|
|
990
|
+
while (parent[node] !== node) {
|
|
991
|
+
parent[node] = parent[parent[node]]
|
|
992
|
+
node = parent[node]
|
|
981
993
|
}
|
|
982
|
-
return
|
|
994
|
+
return node
|
|
983
995
|
}
|
|
984
996
|
const union = (a_idx: number, b_idx: number): void => {
|
|
985
|
-
const ra = find(a_idx),
|
|
997
|
+
const ra = find(a_idx),
|
|
998
|
+
rb = find(b_idx)
|
|
986
999
|
if (ra !== rb) parent[ra] = rb
|
|
987
1000
|
}
|
|
988
1001
|
for (const pair of edge_faces.values()) {
|
|
989
1002
|
if (pair.length !== 2) continue
|
|
990
1003
|
const [fa, fb] = pair
|
|
991
|
-
const na = normals[fa],
|
|
1004
|
+
const na = normals[fa],
|
|
1005
|
+
nb = normals[fb]
|
|
992
1006
|
if (Math.abs(na[0] * nb[0] + na[1] * nb[1] + na[2] * nb[2]) > 1 - tol) {
|
|
993
1007
|
union(fa, fb)
|
|
994
1008
|
}
|
|
@@ -1138,15 +1152,9 @@
|
|
|
1138
1152
|
|
|
1139
1153
|
const controls_series = $derived<DataSeries3D[]>([
|
|
1140
1154
|
{
|
|
1141
|
-
x: render_domains.flatMap((domain) =>
|
|
1142
|
-
|
|
1143
|
-
),
|
|
1144
|
-
y: render_domains.flatMap((domain) =>
|
|
1145
|
-
domain.points_3d.map((point) => point[2])
|
|
1146
|
-
),
|
|
1147
|
-
z: render_domains.flatMap((domain) =>
|
|
1148
|
-
domain.points_3d.map((point) => point[0])
|
|
1149
|
-
),
|
|
1155
|
+
x: render_domains.flatMap((domain) => domain.points_3d.map((point) => point[1])),
|
|
1156
|
+
y: render_domains.flatMap((domain) => domain.points_3d.map((point) => point[2])),
|
|
1157
|
+
z: render_domains.flatMap((domain) => domain.points_3d.map((point) => point[0])),
|
|
1150
1158
|
label: `domains`,
|
|
1151
1159
|
},
|
|
1152
1160
|
])
|
|
@@ -1157,8 +1165,7 @@
|
|
|
1157
1165
|
const result: { geometry: THREE.BufferGeometry; color: string }[] = []
|
|
1158
1166
|
for (const domain of render_domains) {
|
|
1159
1167
|
if (!domain.is_draw_formula) continue
|
|
1160
|
-
const color_idx = formulas_to_draw.indexOf(domain.formula) %
|
|
1161
|
-
formula_colors.length
|
|
1168
|
+
const color_idx = formulas_to_draw.indexOf(domain.formula) % formula_colors.length
|
|
1162
1169
|
const swizzled = domain.points_3d.map((point) => to_render_xyz(point))
|
|
1163
1170
|
const positions: number[] = []
|
|
1164
1171
|
for (const [pa, pb] of get_domain_edges(swizzled)) {
|
|
@@ -1177,8 +1184,7 @@
|
|
|
1177
1184
|
if (!draw_formula_meshes) return result
|
|
1178
1185
|
for (const domain of render_domains) {
|
|
1179
1186
|
if (!domain.is_draw_formula || domain.points_3d.length < 4) continue
|
|
1180
|
-
const color_idx = formulas_to_draw.indexOf(domain.formula) %
|
|
1181
|
-
formula_colors.length
|
|
1187
|
+
const color_idx = formulas_to_draw.indexOf(domain.formula) % formula_colors.length
|
|
1182
1188
|
const unique = dedup_3d(domain.points_3d)
|
|
1183
1189
|
if (unique.length < 4) continue
|
|
1184
1190
|
const vectors = unique.map((pt) => to_vec3(pt))
|
|
@@ -1192,10 +1198,7 @@
|
|
|
1192
1198
|
return result
|
|
1193
1199
|
})
|
|
1194
1200
|
|
|
1195
|
-
function get_touches_limits(
|
|
1196
|
-
points_3d: number[][],
|
|
1197
|
-
lims: [number, number][],
|
|
1198
|
-
): string[] {
|
|
1201
|
+
function get_touches_limits(points_3d: number[][], lims: Vec2[]): string[] {
|
|
1199
1202
|
const limit_tol = 1e-3
|
|
1200
1203
|
const touches_limits: string[] = []
|
|
1201
1204
|
for (
|
|
@@ -1205,11 +1208,11 @@
|
|
|
1205
1208
|
) {
|
|
1206
1209
|
const [axis_min, axis_max] = lims[axis_idx]
|
|
1207
1210
|
const axis_name = plot_elements[axis_idx] ?? `axis_${axis_idx}`
|
|
1208
|
-
const touches_min = points_3d.some(
|
|
1209
|
-
Math.abs(point[axis_idx] - axis_min) < limit_tol
|
|
1211
|
+
const touches_min = points_3d.some(
|
|
1212
|
+
(point) => Math.abs(point[axis_idx] - axis_min) < limit_tol,
|
|
1210
1213
|
)
|
|
1211
|
-
const touches_max = points_3d.some(
|
|
1212
|
-
Math.abs(point[axis_idx] - axis_max) < limit_tol
|
|
1214
|
+
const touches_max = points_3d.some(
|
|
1215
|
+
(point) => Math.abs(point[axis_idx] - axis_max) < limit_tol,
|
|
1213
1216
|
)
|
|
1214
1217
|
if (touches_min) touches_limits.push(`${axis_name} lower bound`)
|
|
1215
1218
|
if (touches_max) touches_limits.push(`${axis_name} upper bound`)
|
|
@@ -1267,9 +1270,7 @@
|
|
|
1267
1270
|
const vertex_owners = new SvelteMap<string, string[]>()
|
|
1268
1271
|
for (const domain of render_domains) {
|
|
1269
1272
|
for (const pt of domain.points_3d) {
|
|
1270
|
-
const key = pt.map((val) => (Math.round(val / tol) * tol).toFixed(4)).join(
|
|
1271
|
-
`,`,
|
|
1272
|
-
)
|
|
1273
|
+
const key = pt.map((val) => (Math.round(val / tol) * tol).toFixed(4)).join(`,`)
|
|
1273
1274
|
const owners = vertex_owners.get(key)
|
|
1274
1275
|
if (owners) {
|
|
1275
1276
|
if (!owners.includes(domain.formula)) owners.push(domain.formula)
|
|
@@ -1347,9 +1348,7 @@
|
|
|
1347
1348
|
geometry.dispose()
|
|
1348
1349
|
}
|
|
1349
1350
|
|
|
1350
|
-
function dispose_geometries(
|
|
1351
|
-
geometries: (THREE.BufferGeometry | null | undefined)[],
|
|
1352
|
-
): void {
|
|
1351
|
+
function dispose_geometries(geometries: (THREE.BufferGeometry | null | undefined)[]): void {
|
|
1353
1352
|
for (const geometry of geometries) dispose_geometry(geometry)
|
|
1354
1353
|
}
|
|
1355
1354
|
|
|
@@ -1453,10 +1452,7 @@
|
|
|
1453
1452
|
})
|
|
1454
1453
|
|
|
1455
1454
|
// Helper to create a line geometry from two Vec3 arrays
|
|
1456
|
-
function make_line_geom(
|
|
1457
|
-
start: Vec3,
|
|
1458
|
-
end: Vec3,
|
|
1459
|
-
): THREE.BufferGeometry {
|
|
1455
|
+
function make_line_geom(start: Vec3, end: Vec3): THREE.BufferGeometry {
|
|
1460
1456
|
const geom = new THREE.BufferGeometry()
|
|
1461
1457
|
geom.setAttribute(
|
|
1462
1458
|
`position`,
|
|
@@ -1486,10 +1482,10 @@
|
|
|
1486
1482
|
// Place axis label just past the outer end of the axis (the end closer to 0).
|
|
1487
1483
|
// In isometric 3D, the end near 0 projects outward at the front edge of the
|
|
1488
1484
|
// bounding box, while the negative end projects inward toward the center.
|
|
1489
|
-
const outer_end = (range:
|
|
1485
|
+
const outer_end = (range: Vec2): number =>
|
|
1490
1486
|
Math.abs(range[0]) <= Math.abs(range[1]) ? range[0] : range[1]
|
|
1491
1487
|
// Direction from range center toward outer end (to extend the label beyond the grid)
|
|
1492
|
-
const outer_direction = (range:
|
|
1488
|
+
const outer_direction = (range: Vec2): number => {
|
|
1493
1489
|
const end = outer_end(range)
|
|
1494
1490
|
const mid = (range[0] + range[1]) / 2
|
|
1495
1491
|
return end >= mid ? 1 : -1
|
|
@@ -1504,11 +1500,12 @@
|
|
|
1504
1500
|
return [0, 1, 2].map((axis) => {
|
|
1505
1501
|
const ticks = data_ticks[axis]
|
|
1506
1502
|
const color = axis_colors[axis]
|
|
1507
|
-
const label =
|
|
1508
|
-
|
|
1509
|
-
|
|
1510
|
-
|
|
1511
|
-
|
|
1503
|
+
const label =
|
|
1504
|
+
axis === 0
|
|
1505
|
+
? z_axis.label || chem_axis_label(0)
|
|
1506
|
+
: axis === 1
|
|
1507
|
+
? x_axis.label || chem_axis_label(1)
|
|
1508
|
+
: y_axis.label || chem_axis_label(2)
|
|
1512
1509
|
|
|
1513
1510
|
const tick_geoms: THREE.BufferGeometry[] = []
|
|
1514
1511
|
const grid_geoms: THREE.BufferGeometry[] = []
|
|
@@ -1528,16 +1525,14 @@
|
|
|
1528
1525
|
back[2] + out_y * tick_label_dist,
|
|
1529
1526
|
)
|
|
1530
1527
|
for (const val of ticks) {
|
|
1531
|
-
tick_geoms.push(
|
|
1532
|
-
|
|
1533
|
-
|
|
1534
|
-
|
|
1535
|
-
|
|
1536
|
-
make_line_geom(swiz(val, r1[0], back[2]), swiz(val, r1[1], back[2])),
|
|
1537
|
-
)
|
|
1538
|
-
grid_geoms.push(
|
|
1539
|
-
make_line_geom(swiz(val, back[1], r2[0]), swiz(val, back[1], r2[1])),
|
|
1528
|
+
tick_geoms.push(
|
|
1529
|
+
make_line_geom(
|
|
1530
|
+
swiz(val, back[1], back[2]),
|
|
1531
|
+
swiz(val, back[1], back[2] + out_y * tick_size),
|
|
1532
|
+
),
|
|
1540
1533
|
)
|
|
1534
|
+
grid_geoms.push(make_line_geom(swiz(val, r1[0], back[2]), swiz(val, r1[1], back[2])))
|
|
1535
|
+
grid_geoms.push(make_line_geom(swiz(val, back[1], r2[0]), swiz(val, back[1], r2[1])))
|
|
1541
1536
|
tick_labels.push({
|
|
1542
1537
|
pos: swiz(
|
|
1543
1538
|
val,
|
|
@@ -1558,16 +1553,14 @@
|
|
|
1558
1553
|
back[2] + out_y * tick_label_dist,
|
|
1559
1554
|
)
|
|
1560
1555
|
for (const val of ticks) {
|
|
1561
|
-
tick_geoms.push(
|
|
1562
|
-
|
|
1563
|
-
|
|
1564
|
-
|
|
1565
|
-
|
|
1566
|
-
make_line_geom(swiz(r0[0], val, back[2]), swiz(r0[1], val, back[2])),
|
|
1567
|
-
)
|
|
1568
|
-
grid_geoms.push(
|
|
1569
|
-
make_line_geom(swiz(back[0], val, r2[0]), swiz(back[0], val, r2[1])),
|
|
1556
|
+
tick_geoms.push(
|
|
1557
|
+
make_line_geom(
|
|
1558
|
+
swiz(back[0], val, back[2]),
|
|
1559
|
+
swiz(back[0], val, back[2] + out_y * tick_size),
|
|
1560
|
+
),
|
|
1570
1561
|
)
|
|
1562
|
+
grid_geoms.push(make_line_geom(swiz(r0[0], val, back[2]), swiz(r0[1], val, back[2])))
|
|
1563
|
+
grid_geoms.push(make_line_geom(swiz(back[0], val, r2[0]), swiz(back[0], val, r2[1])))
|
|
1571
1564
|
tick_labels.push({
|
|
1572
1565
|
pos: swiz(back[0], val, back[2] + out_y * tick_label_dist),
|
|
1573
1566
|
text: format_num(val, `.3~g`),
|
|
@@ -1584,16 +1577,14 @@
|
|
|
1584
1577
|
outer_end(r2) + outer_direction(r2) * axis_label_dist,
|
|
1585
1578
|
)
|
|
1586
1579
|
for (const val of ticks) {
|
|
1587
|
-
tick_geoms.push(
|
|
1588
|
-
|
|
1589
|
-
|
|
1590
|
-
|
|
1591
|
-
|
|
1592
|
-
make_line_geom(swiz(r0[0], back[1], val), swiz(r0[1], back[1], val)),
|
|
1593
|
-
)
|
|
1594
|
-
grid_geoms.push(
|
|
1595
|
-
make_line_geom(swiz(back[0], r1[0], val), swiz(back[0], r1[1], val)),
|
|
1580
|
+
tick_geoms.push(
|
|
1581
|
+
make_line_geom(
|
|
1582
|
+
swiz(back[0], back[1], val),
|
|
1583
|
+
swiz(back[0], back[1] + out_x * tick_size, val),
|
|
1584
|
+
),
|
|
1596
1585
|
)
|
|
1586
|
+
grid_geoms.push(make_line_geom(swiz(r0[0], back[1], val), swiz(r0[1], back[1], val)))
|
|
1587
|
+
grid_geoms.push(make_line_geom(swiz(back[0], r1[0], val), swiz(back[0], r1[1], val)))
|
|
1597
1588
|
tick_labels.push({
|
|
1598
1589
|
pos: swiz(back[0], back[1] + out_x * tick_label_dist, val),
|
|
1599
1590
|
text: format_num(val, `.3~g`),
|
|
@@ -1621,16 +1612,12 @@
|
|
|
1621
1612
|
|
|
1622
1613
|
function update_label_occlusion(): void {
|
|
1623
1614
|
if (!wrapper) return
|
|
1624
|
-
const tick_labels = Array.from(
|
|
1625
|
-
wrapper.querySelectorAll<HTMLElement>(`.axis-tick-label`),
|
|
1626
|
-
)
|
|
1615
|
+
const tick_labels = Array.from(wrapper.querySelectorAll<HTMLElement>(`.axis-tick-label`))
|
|
1627
1616
|
tick_labels_occluded = false
|
|
1628
1617
|
for (const tick_label of tick_labels) {
|
|
1629
1618
|
tick_label.style.visibility = ``
|
|
1630
1619
|
}
|
|
1631
|
-
const domain_rects = Array.from(
|
|
1632
|
-
wrapper.querySelectorAll<HTMLElement>(`.domain-label`),
|
|
1633
|
-
)
|
|
1620
|
+
const domain_rects = Array.from(wrapper.querySelectorAll<HTMLElement>(`.domain-label`))
|
|
1634
1621
|
.filter((domain_label) => {
|
|
1635
1622
|
const style = getComputedStyle(domain_label)
|
|
1636
1623
|
return style.display !== `none` && style.visibility !== `hidden`
|
|
@@ -1698,11 +1685,7 @@
|
|
|
1698
1685
|
}
|
|
1699
1686
|
const controls_target = controls?.target
|
|
1700
1687
|
if (controls_target) {
|
|
1701
|
-
camera_target_override = [
|
|
1702
|
-
controls_target.x,
|
|
1703
|
-
controls_target.y,
|
|
1704
|
-
controls_target.z,
|
|
1705
|
-
]
|
|
1688
|
+
camera_target_override = [controls_target.x, controls_target.y, controls_target.z]
|
|
1706
1689
|
}
|
|
1707
1690
|
}
|
|
1708
1691
|
|
|
@@ -1759,8 +1742,12 @@
|
|
|
1759
1742
|
schedule_label_occlusion_update()
|
|
1760
1743
|
})
|
|
1761
1744
|
|
|
1762
|
-
|
|
1763
|
-
|
|
1745
|
+
// Drive the browser Fullscreen API from the bindable `fullscreen` prop (parent-controllable), keep it in sync with Esc/external exits
|
|
1746
|
+
sync_fullscreen({
|
|
1747
|
+
get_wrapper: () => wrapper,
|
|
1748
|
+
get_fullscreen: () => fullscreen,
|
|
1749
|
+
set_fullscreen: (val) => (fullscreen = val),
|
|
1750
|
+
bg_css_var: `--chempot-3d-bg-fullscreen`,
|
|
1764
1751
|
})
|
|
1765
1752
|
|
|
1766
1753
|
$effect(() => {
|
|
@@ -1782,14 +1769,13 @@
|
|
|
1782
1769
|
const projections = display.projections
|
|
1783
1770
|
if (!projections) return []
|
|
1784
1771
|
const [r0, r1, r2] = niced_range
|
|
1785
|
-
const
|
|
1786
|
-
const s1 = (
|
|
1787
|
-
const s2 = (r2[1] - r2[0]) * (display.projection_scale ?? 0.5)
|
|
1772
|
+
const projection_scale = display.projection_scale ?? 0.5
|
|
1773
|
+
const [s0, s1, s2] = niced_range.map(([lo, hi]) => (hi - lo) * projection_scale)
|
|
1788
1774
|
const planes: {
|
|
1789
1775
|
key: string
|
|
1790
1776
|
pos: Vec3
|
|
1791
1777
|
rot: Vec3
|
|
1792
|
-
size:
|
|
1778
|
+
size: Vec2
|
|
1793
1779
|
color: string
|
|
1794
1780
|
}[] = []
|
|
1795
1781
|
if (projections.xy) {
|
|
@@ -1860,17 +1846,8 @@
|
|
|
1860
1846
|
})
|
|
1861
1847
|
|
|
1862
1848
|
function reset_controls(): void {
|
|
1863
|
-
|
|
1864
|
-
label_stable_override = null
|
|
1865
|
-
element_padding_override = null
|
|
1866
|
-
default_min_limit_override = null
|
|
1867
|
-
draw_formula_meshes_override = null
|
|
1868
|
-
draw_formula_lines_override = null
|
|
1869
|
-
color_mode_override = null
|
|
1870
|
-
color_scale_override = null
|
|
1871
|
-
reverse_color_scale_override = null
|
|
1849
|
+
overrides.reset()
|
|
1872
1850
|
projection_elements_override = null
|
|
1873
|
-
formulas_to_draw_override = null
|
|
1874
1851
|
formula_filter_query = ``
|
|
1875
1852
|
}
|
|
1876
1853
|
|
|
@@ -1883,18 +1860,12 @@
|
|
|
1883
1860
|
next_projection[current_owner_idx] = next_projection[axis_idx]
|
|
1884
1861
|
}
|
|
1885
1862
|
next_projection[axis_idx] = element
|
|
1886
|
-
const normalized = normalize_projection_triplet(
|
|
1887
|
-
next_projection,
|
|
1888
|
-
all_entry_elements,
|
|
1889
|
-
)
|
|
1863
|
+
const normalized = normalize_projection_triplet(next_projection, all_entry_elements)
|
|
1890
1864
|
if (normalized) projection_elements_override = normalized
|
|
1891
1865
|
}
|
|
1892
1866
|
|
|
1893
1867
|
function apply_projection_preset(preset_elements: string[]): void {
|
|
1894
|
-
const normalized = normalize_projection_triplet(
|
|
1895
|
-
preset_elements,
|
|
1896
|
-
all_entry_elements,
|
|
1897
|
-
)
|
|
1868
|
+
const normalized = normalize_projection_triplet(preset_elements, all_entry_elements)
|
|
1898
1869
|
if (normalized) projection_elements_override = normalized
|
|
1899
1870
|
}
|
|
1900
1871
|
|
|
@@ -1902,270 +1873,96 @@
|
|
|
1902
1873
|
const selected_formulas = new SvelteSet(formulas_to_draw)
|
|
1903
1874
|
if (selected_formulas.has(formula)) selected_formulas.delete(formula)
|
|
1904
1875
|
else selected_formulas.add(formula)
|
|
1905
|
-
|
|
1876
|
+
overrides.set(`formulas_to_draw`, [...selected_formulas])
|
|
1906
1877
|
}
|
|
1907
1878
|
|
|
1908
1879
|
function select_surface_formulas(): void {
|
|
1909
|
-
|
|
1910
|
-
|
|
1911
|
-
|
|
1880
|
+
overrides.set(
|
|
1881
|
+
`formulas_to_draw`,
|
|
1882
|
+
render_domains
|
|
1883
|
+
.filter((domain) => surface_formulas.has(domain.formula))
|
|
1884
|
+
.map((domain) => domain.formula),
|
|
1885
|
+
)
|
|
1912
1886
|
}
|
|
1913
1887
|
|
|
1914
1888
|
function select_neighbor_formulas(): void {
|
|
1915
1889
|
if (hover_info?.view !== `3d`) return
|
|
1916
1890
|
const neighbors = domain_neighbors.get(hover_info.formula) ?? []
|
|
1917
|
-
|
|
1918
|
-
}
|
|
1919
|
-
|
|
1920
|
-
function download_blob(blob: Blob, filename: string): void {
|
|
1921
|
-
const url = URL.createObjectURL(blob)
|
|
1922
|
-
const link = document.createElement(`a`)
|
|
1923
|
-
link.href = url
|
|
1924
|
-
link.download = filename
|
|
1925
|
-
link.click()
|
|
1926
|
-
URL.revokeObjectURL(url)
|
|
1891
|
+
overrides.set(`formulas_to_draw`, [hover_info.formula, ...neighbors])
|
|
1927
1892
|
}
|
|
1928
1893
|
|
|
1929
1894
|
let png_dpi = $state(150)
|
|
1930
1895
|
const export_basename = $derived(`chempot-${plot_elements.join(`-`)}`)
|
|
1931
1896
|
|
|
1932
|
-
|
|
1933
|
-
|
|
1934
|
-
const view_camera_target = orbit_controls_ref?.target
|
|
1935
|
-
return {
|
|
1897
|
+
const current_view_settings = (): Record<string, unknown> =>
|
|
1898
|
+
get_view_settings({
|
|
1936
1899
|
elements: plot_elements,
|
|
1937
1900
|
camera_projection,
|
|
1938
1901
|
auto_rotate,
|
|
1939
1902
|
color_mode,
|
|
1940
1903
|
color_scale,
|
|
1941
1904
|
reverse_color_scale,
|
|
1942
|
-
camera_position:
|
|
1943
|
-
|
|
1944
|
-
|
|
1945
|
-
camera_target: view_camera_target
|
|
1946
|
-
? [view_camera_target.x, view_camera_target.y, view_camera_target.z]
|
|
1947
|
-
: null,
|
|
1948
|
-
}
|
|
1949
|
-
}
|
|
1950
|
-
|
|
1951
|
-
interface OverlayTextItem {
|
|
1952
|
-
x: number
|
|
1953
|
-
y: number
|
|
1954
|
-
text: string
|
|
1955
|
-
font: string
|
|
1956
|
-
font_size: string
|
|
1957
|
-
font_family: string
|
|
1958
|
-
font_weight: string
|
|
1959
|
-
color: string
|
|
1960
|
-
}
|
|
1961
|
-
function get_overlay_text_items(canvas_rect: DOMRect): OverlayTextItem[] {
|
|
1962
|
-
if (!wrapper) return []
|
|
1963
|
-
const text_items: OverlayTextItem[] = []
|
|
1964
|
-
for (
|
|
1965
|
-
const element of wrapper.querySelectorAll(
|
|
1966
|
-
`.tick-label, .axis-label, .domain-label`,
|
|
1967
|
-
)
|
|
1968
|
-
) {
|
|
1969
|
-
const html_element = element as HTMLElement
|
|
1970
|
-
const style = getComputedStyle(html_element)
|
|
1971
|
-
if (style.display === `none` || style.visibility === `hidden`) continue
|
|
1972
|
-
const element_rect = html_element.getBoundingClientRect()
|
|
1973
|
-
text_items.push({
|
|
1974
|
-
x: element_rect.left + element_rect.width / 2 - canvas_rect.left,
|
|
1975
|
-
y: element_rect.top + element_rect.height / 2 - canvas_rect.top,
|
|
1976
|
-
text: html_element.textContent ?? ``,
|
|
1977
|
-
font: style.font || `${style.fontSize} ${style.fontFamily}`,
|
|
1978
|
-
font_size: style.fontSize || `11px`,
|
|
1979
|
-
font_family: style.fontFamily || `sans-serif`,
|
|
1980
|
-
font_weight: style.fontWeight || `400`,
|
|
1981
|
-
color: style.color || `#333`,
|
|
1982
|
-
})
|
|
1983
|
-
}
|
|
1984
|
-
return text_items
|
|
1985
|
-
}
|
|
1986
|
-
|
|
1987
|
-
function export_png_file(): void {
|
|
1988
|
-
if (!wrapper) return
|
|
1989
|
-
const gl_canvas = wrapper.querySelector(`canvas`)
|
|
1990
|
-
if (!(gl_canvas instanceof HTMLCanvasElement)) return
|
|
1991
|
-
|
|
1992
|
-
// Composite WebGL canvas + HTML overlay labels into a single image
|
|
1993
|
-
const rect = gl_canvas.getBoundingClientRect()
|
|
1994
|
-
const scale = Math.min(png_dpi / 72, 10)
|
|
1995
|
-
const out = document.createElement(`canvas`)
|
|
1996
|
-
out.width = Math.round(rect.width * scale)
|
|
1997
|
-
out.height = Math.round(rect.height * scale)
|
|
1998
|
-
const ctx = out.getContext(`2d`)
|
|
1999
|
-
if (!ctx) return
|
|
2000
|
-
ctx.scale(scale, scale)
|
|
2001
|
-
|
|
2002
|
-
// Draw the WebGL canvas as background
|
|
2003
|
-
ctx.drawImage(gl_canvas, 0, 0, rect.width, rect.height)
|
|
2004
|
-
|
|
2005
|
-
// Draw all HTML overlay text (tick labels, axis labels, domain labels)
|
|
2006
|
-
for (const text_item of get_overlay_text_items(rect)) {
|
|
2007
|
-
ctx.font = text_item.font
|
|
2008
|
-
ctx.fillStyle = text_item.color
|
|
2009
|
-
ctx.textAlign = `center`
|
|
2010
|
-
ctx.textBaseline = `middle`
|
|
2011
|
-
ctx.fillText(text_item.text, text_item.x, text_item.y)
|
|
2012
|
-
}
|
|
2013
|
-
|
|
2014
|
-
out.toBlob((blob) => {
|
|
2015
|
-
if (!blob) return
|
|
2016
|
-
download_blob(blob, `${export_basename}.png`)
|
|
2017
|
-
}, `image/png`)
|
|
2018
|
-
}
|
|
2019
|
-
|
|
2020
|
-
const xml_escape = (text: string): string =>
|
|
2021
|
-
text
|
|
2022
|
-
.replaceAll(`&`, `&`)
|
|
2023
|
-
.replaceAll(`<`, `<`)
|
|
2024
|
-
.replaceAll(`>`, `>`)
|
|
2025
|
-
.replaceAll(`"`, `"`)
|
|
2026
|
-
.replaceAll(`'`, `'`)
|
|
2027
|
-
|
|
2028
|
-
function export_svg_file(): void {
|
|
2029
|
-
if (!wrapper) return
|
|
2030
|
-
const gl_canvas = wrapper.querySelector(`canvas`)
|
|
2031
|
-
if (!(gl_canvas instanceof HTMLCanvasElement)) return
|
|
2032
|
-
const canvas_rect = gl_canvas.getBoundingClientRect()
|
|
2033
|
-
if (canvas_rect.width === 0 || canvas_rect.height === 0) return
|
|
2034
|
-
const png_data_url = gl_canvas.toDataURL(`image/png`)
|
|
2035
|
-
const text_nodes = get_overlay_text_items(canvas_rect).map((text_item) =>
|
|
2036
|
-
`<text x="${text_item.x.toFixed(2)}" y="${
|
|
2037
|
-
text_item.y.toFixed(2)
|
|
2038
|
-
}" text-anchor="middle" dominant-baseline="central" fill="${
|
|
2039
|
-
xml_escape(text_item.color)
|
|
2040
|
-
}" font-size="${xml_escape(text_item.font_size)}" font-family="${
|
|
2041
|
-
xml_escape(text_item.font_family)
|
|
2042
|
-
}" font-weight="${xml_escape(text_item.font_weight)}">${
|
|
2043
|
-
xml_escape(text_item.text)
|
|
2044
|
-
}</text>`
|
|
2045
|
-
)
|
|
2046
|
-
const metadata = xml_escape(JSON.stringify(get_view_settings()))
|
|
2047
|
-
const svg = [
|
|
2048
|
-
`<?xml version="1.0" encoding="UTF-8"?>`,
|
|
2049
|
-
`<svg xmlns="http://www.w3.org/2000/svg" width="${canvas_rect.width}" height="${canvas_rect.height}" viewBox="0 0 ${canvas_rect.width} ${canvas_rect.height}">`,
|
|
2050
|
-
`<metadata>${metadata}</metadata>`,
|
|
2051
|
-
`<image href="${png_data_url}" x="0" y="0" width="${canvas_rect.width}" height="${canvas_rect.height}" />`,
|
|
2052
|
-
...text_nodes,
|
|
2053
|
-
`</svg>`,
|
|
2054
|
-
].join(``)
|
|
2055
|
-
download_blob(
|
|
2056
|
-
new Blob([svg], { type: `image/svg+xml` }),
|
|
2057
|
-
`${export_basename}.svg`,
|
|
2058
|
-
)
|
|
2059
|
-
}
|
|
2060
|
-
|
|
2061
|
-
function export_view_json_file(): void {
|
|
2062
|
-
const json_text = JSON.stringify(get_view_settings(), null, 2)
|
|
2063
|
-
download_blob(
|
|
2064
|
-
new Blob([json_text], { type: `application/json` }),
|
|
2065
|
-
`${export_basename}-view.json`,
|
|
2066
|
-
)
|
|
2067
|
-
}
|
|
2068
|
-
|
|
2069
|
-
function export_glb_file(): void {
|
|
2070
|
-
const gltf_exporter = new GLTFExporter()
|
|
2071
|
-
const export_root = new THREE.Group()
|
|
2072
|
-
if (colored_hull_geometry) {
|
|
2073
|
-
export_root.add(
|
|
2074
|
-
new THREE.Mesh(
|
|
2075
|
-
colored_hull_geometry.clone(),
|
|
2076
|
-
new THREE.MeshBasicMaterial({
|
|
2077
|
-
vertexColors: true,
|
|
2078
|
-
transparent: true,
|
|
2079
|
-
opacity: color_mode === `none` ? 0.25 : 0.4,
|
|
2080
|
-
side: THREE.DoubleSide,
|
|
2081
|
-
}),
|
|
2082
|
-
),
|
|
2083
|
-
)
|
|
2084
|
-
}
|
|
2085
|
-
export_root.add(
|
|
2086
|
-
new THREE.LineSegments(
|
|
2087
|
-
edge_geometry.clone(),
|
|
2088
|
-
new THREE.LineBasicMaterial({ color: 0x333333 }),
|
|
2089
|
-
),
|
|
2090
|
-
)
|
|
2091
|
-
for (const { geometry, color } of formula_mesh_data) {
|
|
2092
|
-
export_root.add(
|
|
2093
|
-
new THREE.Mesh(
|
|
2094
|
-
geometry.clone(),
|
|
2095
|
-
new THREE.MeshBasicMaterial({
|
|
2096
|
-
color: new THREE.Color(color),
|
|
2097
|
-
transparent: true,
|
|
2098
|
-
opacity: 0.13,
|
|
2099
|
-
side: THREE.DoubleSide,
|
|
2100
|
-
}),
|
|
2101
|
-
),
|
|
2102
|
-
)
|
|
2103
|
-
}
|
|
2104
|
-
if (draw_formula_lines) {
|
|
2105
|
-
for (const { geometry, color } of formula_edge_data) {
|
|
2106
|
-
export_root.add(
|
|
2107
|
-
new THREE.LineSegments(
|
|
2108
|
-
geometry.clone(),
|
|
2109
|
-
new THREE.LineBasicMaterial({ color: new THREE.Color(color) }),
|
|
2110
|
-
),
|
|
2111
|
-
)
|
|
2112
|
-
}
|
|
2113
|
-
}
|
|
2114
|
-
gltf_exporter.parse(
|
|
2115
|
-
export_root,
|
|
2116
|
-
(result) => {
|
|
2117
|
-
if (!(result instanceof ArrayBuffer)) return
|
|
2118
|
-
download_blob(
|
|
2119
|
-
new Blob([result], { type: `model/gltf-binary` }),
|
|
2120
|
-
`${export_basename}.glb`,
|
|
2121
|
-
)
|
|
2122
|
-
},
|
|
2123
|
-
(err) => {
|
|
2124
|
-
console.error(`Failed to export GLB:`, err)
|
|
2125
|
-
},
|
|
2126
|
-
{ binary: true, onlyVisible: false },
|
|
2127
|
-
)
|
|
2128
|
-
}
|
|
2129
|
-
|
|
2130
|
-
const get_json_string = (): string =>
|
|
2131
|
-
JSON.stringify(
|
|
2132
|
-
{
|
|
2133
|
-
elements: diagram_data?.elements ?? [],
|
|
2134
|
-
domains: render_domains.map((domain) => ({
|
|
2135
|
-
formula: domain.formula,
|
|
2136
|
-
points_3d: domain.points_3d,
|
|
2137
|
-
})),
|
|
2138
|
-
lims: diagram_data?.lims ?? [],
|
|
2139
|
-
view: get_view_settings(),
|
|
2140
|
-
},
|
|
2141
|
-
null,
|
|
2142
|
-
2,
|
|
2143
|
-
)
|
|
1905
|
+
camera_position: orbit_controls_ref?.object?.position ?? null,
|
|
1906
|
+
camera_target: orbit_controls_ref?.target ?? null,
|
|
1907
|
+
})
|
|
2144
1908
|
|
|
2145
|
-
|
|
2146
|
-
|
|
2147
|
-
|
|
2148
|
-
|
|
2149
|
-
|
|
2150
|
-
|
|
1909
|
+
const export_json_payload = (): Record<string, unknown> => ({
|
|
1910
|
+
elements: diagram_data?.elements ?? [],
|
|
1911
|
+
domains: render_domains.map((domain) => ({
|
|
1912
|
+
formula: domain.formula,
|
|
1913
|
+
points_3d: domain.points_3d,
|
|
1914
|
+
})),
|
|
1915
|
+
lims: diagram_data?.lims ?? [],
|
|
1916
|
+
view: current_view_settings(),
|
|
1917
|
+
})
|
|
2151
1918
|
|
|
2152
|
-
|
|
2153
|
-
|
|
2154
|
-
|
|
2155
|
-
|
|
2156
|
-
|
|
2157
|
-
|
|
2158
|
-
|
|
2159
|
-
|
|
2160
|
-
|
|
2161
|
-
|
|
2162
|
-
|
|
2163
|
-
|
|
2164
|
-
|
|
2165
|
-
|
|
1919
|
+
const export_sections = $derived<ExportSection[]>([
|
|
1920
|
+
{
|
|
1921
|
+
title: `Export Image`,
|
|
1922
|
+
items: [
|
|
1923
|
+
{
|
|
1924
|
+
label: `SVG`,
|
|
1925
|
+
on_download: () =>
|
|
1926
|
+
export_svg_file(wrapper, export_basename, current_view_settings()),
|
|
1927
|
+
},
|
|
1928
|
+
{
|
|
1929
|
+
label: `PNG`,
|
|
1930
|
+
show_dpi: true,
|
|
1931
|
+
on_download: () => export_png_file(wrapper, export_basename, png_dpi),
|
|
1932
|
+
},
|
|
1933
|
+
],
|
|
1934
|
+
},
|
|
1935
|
+
{
|
|
1936
|
+
title: `Export Data`,
|
|
1937
|
+
items: [
|
|
1938
|
+
{
|
|
1939
|
+
label: `JSON`,
|
|
1940
|
+
on_download: () => export_json_file(export_json_payload(), export_basename),
|
|
1941
|
+
copy_text: () => get_json_string(export_json_payload()),
|
|
1942
|
+
},
|
|
1943
|
+
{
|
|
1944
|
+
label: `View`,
|
|
1945
|
+
on_download: () => export_view_json_file(current_view_settings(), export_basename),
|
|
1946
|
+
},
|
|
1947
|
+
{
|
|
1948
|
+
label: `GLB`,
|
|
1949
|
+
on_download: () =>
|
|
1950
|
+
export_glb_file(
|
|
1951
|
+
{
|
|
1952
|
+
hull_geometry: colored_hull_geometry,
|
|
1953
|
+
hull_opacity: color_mode === `none` ? 0.25 : 0.4,
|
|
1954
|
+
edge_geometry,
|
|
1955
|
+
formula_meshes: formula_mesh_data,
|
|
1956
|
+
formula_edges: draw_formula_lines ? formula_edge_data : [],
|
|
1957
|
+
},
|
|
1958
|
+
export_basename,
|
|
1959
|
+
),
|
|
1960
|
+
},
|
|
1961
|
+
],
|
|
1962
|
+
},
|
|
1963
|
+
])
|
|
2166
1964
|
|
|
2167
1965
|
onDestroy(() => {
|
|
2168
|
-
if (copy_timeout_id !== null) clearTimeout(copy_timeout_id)
|
|
2169
1966
|
if (label_occlusion_frame !== null) cancelAnimationFrame(label_occlusion_frame)
|
|
2170
1967
|
})
|
|
2171
1968
|
|
|
@@ -2176,10 +1973,12 @@
|
|
|
2176
1973
|
const pointer = hover_info?.pointer
|
|
2177
1974
|
if (!pointer) return { x: 4, y: 4 }
|
|
2178
1975
|
return constrain_tooltip_position(
|
|
2179
|
-
pointer.x,
|
|
1976
|
+
pointer.x,
|
|
1977
|
+
pointer.y,
|
|
2180
1978
|
tooltip_el?.offsetWidth ?? 200,
|
|
2181
1979
|
tooltip_el?.offsetHeight ?? 100,
|
|
2182
|
-
container_width,
|
|
1980
|
+
container_width,
|
|
1981
|
+
container_height,
|
|
2183
1982
|
{ offset: 0 },
|
|
2184
1983
|
)
|
|
2185
1984
|
})
|
|
@@ -2197,12 +1996,25 @@
|
|
|
2197
1996
|
hover_info = null
|
|
2198
1997
|
}
|
|
2199
1998
|
|
|
1999
|
+
function stop_phase_pointer_event(raw_event: unknown): void {
|
|
2000
|
+
if (!raw_event || typeof raw_event !== `object`) return
|
|
2001
|
+
|
|
2002
|
+
const event = raw_event as { nativeEvent?: unknown; stopPropagation?: () => void }
|
|
2003
|
+
event.stopPropagation?.()
|
|
2004
|
+
|
|
2005
|
+
const native_event = event.nativeEvent
|
|
2006
|
+
if (!native_event || typeof native_event !== `object`) return
|
|
2007
|
+
const native_pointer_event = native_event as { stopPropagation?: () => void }
|
|
2008
|
+
native_pointer_event.stopPropagation?.()
|
|
2009
|
+
}
|
|
2010
|
+
|
|
2200
2011
|
function handle_phase_hover(domain_data: HoverMeshData, raw_event: unknown): void {
|
|
2201
2012
|
if (locked_hover_formula && locked_hover_formula !== domain_data.formula) return
|
|
2202
2013
|
set_hover_info(domain_data, raw_event)
|
|
2203
2014
|
}
|
|
2204
2015
|
|
|
2205
2016
|
function toggle_phase_lock(domain_data: HoverMeshData, raw_event: unknown): void {
|
|
2017
|
+
stop_phase_pointer_event(raw_event)
|
|
2206
2018
|
if (locked_hover_formula === domain_data.formula) {
|
|
2207
2019
|
clear_hover_lock()
|
|
2208
2020
|
return
|
|
@@ -2212,25 +2024,13 @@
|
|
|
2212
2024
|
}
|
|
2213
2025
|
|
|
2214
2026
|
// Color mode cycling (keyboard shortcut 'c')
|
|
2215
|
-
const color_modes
|
|
2216
|
-
`none`,
|
|
2217
|
-
`energy`,
|
|
2218
|
-
`formation_energy`,
|
|
2219
|
-
`arity`,
|
|
2220
|
-
`entries`,
|
|
2221
|
-
]
|
|
2027
|
+
const color_modes = CHEMPOT_COLOR_MODE_OPTIONS.map(([value]) => value)
|
|
2222
2028
|
function cycle_color_mode(): void {
|
|
2223
2029
|
const idx = color_modes.indexOf(color_mode)
|
|
2224
|
-
|
|
2030
|
+
overrides.set(`color_mode`, color_modes[(idx + 1) % color_modes.length])
|
|
2225
2031
|
}
|
|
2226
2032
|
</script>
|
|
2227
2033
|
|
|
2228
|
-
<svelte:document
|
|
2229
|
-
onfullscreenchange={() => {
|
|
2230
|
-
fullscreen = document.fullscreenElement === wrapper
|
|
2231
|
-
}}
|
|
2232
|
-
/>
|
|
2233
|
-
|
|
2234
2034
|
<!-- svelte-ignore a11y_no_noninteractive_element_interactions -->
|
|
2235
2035
|
<!-- svelte-ignore a11y_no_noninteractive_tabindex -->
|
|
2236
2036
|
<div
|
|
@@ -2244,91 +2044,30 @@
|
|
|
2244
2044
|
role="application"
|
|
2245
2045
|
tabindex="0"
|
|
2246
2046
|
onkeydown={(event) => {
|
|
2247
|
-
if (
|
|
2248
|
-
|
|
2249
|
-
event.target instanceof HTMLSelectElement
|
|
2250
|
-
) return
|
|
2047
|
+
if (event.target instanceof HTMLInputElement || event.target instanceof HTMLSelectElement)
|
|
2048
|
+
return
|
|
2251
2049
|
if (event.key === `Escape`) clear_hover_lock()
|
|
2252
2050
|
else if (event.key === `c`) cycle_color_mode()
|
|
2253
|
-
else if (event.key === `f`) toggle_fullscreen(wrapper)
|
|
2051
|
+
else if (event.key === `f` && fullscreen_toggle) toggle_fullscreen(wrapper)
|
|
2254
2052
|
}}
|
|
2255
2053
|
onpointerdown={(event) => {
|
|
2256
2054
|
const target = event.target
|
|
2257
|
-
if (
|
|
2258
|
-
locked_hover_formula &&
|
|
2259
|
-
(target === wrapper || target instanceof HTMLCanvasElement)
|
|
2260
|
-
) {
|
|
2055
|
+
if (locked_hover_formula && (target === wrapper || target instanceof HTMLCanvasElement)) {
|
|
2261
2056
|
clear_hover_lock()
|
|
2262
2057
|
}
|
|
2263
2058
|
}}
|
|
2264
2059
|
>
|
|
2265
2060
|
<section>
|
|
2266
|
-
<
|
|
2267
|
-
bind:
|
|
2268
|
-
|
|
2269
|
-
|
|
2061
|
+
<ExportPane
|
|
2062
|
+
bind:export_pane_open
|
|
2063
|
+
bind:png_dpi
|
|
2064
|
+
sections={export_sections}
|
|
2270
2065
|
pane_props={{ class: `chempot-export-pane` }}
|
|
2271
2066
|
toggle_props={{
|
|
2272
2067
|
class: `chempot-export-toggle`,
|
|
2273
2068
|
title: `Export chemical potential diagram`,
|
|
2274
2069
|
}}
|
|
2275
|
-
|
|
2276
|
-
<h4 id="export-image">Export Image</h4>
|
|
2277
|
-
<div class="export-row">
|
|
2278
|
-
<label>
|
|
2279
|
-
SVG
|
|
2280
|
-
<button type="button" onclick={export_svg_file} title="SVG snapshot export">
|
|
2281
|
-
⬇
|
|
2282
|
-
</button>
|
|
2283
|
-
</label>
|
|
2284
|
-
<label>
|
|
2285
|
-
PNG
|
|
2286
|
-
<button type="button" onclick={export_png_file} title="PNG ({png_dpi} DPI)">
|
|
2287
|
-
⬇
|
|
2288
|
-
</button>
|
|
2289
|
-
(DPI: <input
|
|
2290
|
-
type="number"
|
|
2291
|
-
min={50}
|
|
2292
|
-
max={500}
|
|
2293
|
-
bind:value={png_dpi}
|
|
2294
|
-
title="Export resolution in dots per inch"
|
|
2295
|
-
style="margin: 0 0 0 2pt"
|
|
2296
|
-
/>)
|
|
2297
|
-
</label>
|
|
2298
|
-
</div>
|
|
2299
|
-
<h4 id="export-data">Export Data</h4>
|
|
2300
|
-
<div class="export-row">
|
|
2301
|
-
<label>
|
|
2302
|
-
JSON
|
|
2303
|
-
<button type="button" onclick={export_json_file} aria-label="Download JSON">
|
|
2304
|
-
⬇
|
|
2305
|
-
</button>
|
|
2306
|
-
<button
|
|
2307
|
-
type="button"
|
|
2308
|
-
onclick={copy_json}
|
|
2309
|
-
aria-label="Copy JSON to clipboard"
|
|
2310
|
-
>
|
|
2311
|
-
{copy_status ? `✅` : `📋`}
|
|
2312
|
-
</button>
|
|
2313
|
-
</label>
|
|
2314
|
-
<label>
|
|
2315
|
-
View
|
|
2316
|
-
<button
|
|
2317
|
-
type="button"
|
|
2318
|
-
onclick={export_view_json_file}
|
|
2319
|
-
aria-label="Download view JSON"
|
|
2320
|
-
>
|
|
2321
|
-
⬇
|
|
2322
|
-
</button>
|
|
2323
|
-
</label>
|
|
2324
|
-
<label>
|
|
2325
|
-
GLB
|
|
2326
|
-
<button type="button" onclick={export_glb_file} aria-label="Download GLB">
|
|
2327
|
-
⬇
|
|
2328
|
-
</button>
|
|
2329
|
-
</label>
|
|
2330
|
-
</div>
|
|
2331
|
-
</DraggablePane>
|
|
2070
|
+
/>
|
|
2332
2071
|
<DraggablePane
|
|
2333
2072
|
bind:show={formula_picker_open}
|
|
2334
2073
|
open_icon="Cross"
|
|
@@ -2341,7 +2080,7 @@
|
|
|
2341
2080
|
>
|
|
2342
2081
|
<h4 id="formula-overlays">Formula Overlays</h4>
|
|
2343
2082
|
<div class="overlay-actions">
|
|
2344
|
-
<button type="button" onclick={() =>
|
|
2083
|
+
<button type="button" onclick={() => overrides.set(`formulas_to_draw`, [])}>
|
|
2345
2084
|
Clear
|
|
2346
2085
|
</button>
|
|
2347
2086
|
<button type="button" onclick={select_surface_formulas}>Surface</button>
|
|
@@ -2349,11 +2088,7 @@
|
|
|
2349
2088
|
</div>
|
|
2350
2089
|
<label class="overlay-search">
|
|
2351
2090
|
Search:
|
|
2352
|
-
<input
|
|
2353
|
-
type="text"
|
|
2354
|
-
placeholder="Formula filter"
|
|
2355
|
-
bind:value={formula_filter_query}
|
|
2356
|
-
/>
|
|
2091
|
+
<input type="text" placeholder="Formula filter" bind:value={formula_filter_query} />
|
|
2357
2092
|
</label>
|
|
2358
2093
|
<div class="formula-list">
|
|
2359
2094
|
{#if filtered_formulas.length === 0}
|
|
@@ -2364,14 +2099,14 @@
|
|
|
2364
2099
|
<label>
|
|
2365
2100
|
<input
|
|
2366
2101
|
type="checkbox"
|
|
2367
|
-
checked={
|
|
2102
|
+
checked={formula_overlay_idx !== -1}
|
|
2368
2103
|
onchange={() => toggle_formula_selection(formula)}
|
|
2369
2104
|
/>
|
|
2370
2105
|
<span
|
|
2371
2106
|
class="formula-color-dot"
|
|
2372
2107
|
style:background={formula_colors[
|
|
2373
2108
|
(formula_overlay_idx >= 0 ? formula_overlay_idx : formula_idx) %
|
|
2374
|
-
|
|
2109
|
+
formula_colors.length
|
|
2375
2110
|
]}
|
|
2376
2111
|
></span>
|
|
2377
2112
|
{get_electro_neg_formula(formula, true, ``, `.3~s`)}
|
|
@@ -2464,36 +2199,28 @@
|
|
|
2464
2199
|
<input
|
|
2465
2200
|
type="checkbox"
|
|
2466
2201
|
checked={formal_chempots}
|
|
2467
|
-
onchange={() =>
|
|
2468
|
-
formal_chempots_override = !formal_chempots
|
|
2469
|
-
}}
|
|
2202
|
+
onchange={() => overrides.set(`formal_chempots`, !formal_chempots)}
|
|
2470
2203
|
/> Formal
|
|
2471
2204
|
</label>
|
|
2472
2205
|
<label>
|
|
2473
2206
|
<input
|
|
2474
2207
|
type="checkbox"
|
|
2475
2208
|
checked={label_stable}
|
|
2476
|
-
onchange={() =>
|
|
2477
|
-
label_stable_override = !label_stable
|
|
2478
|
-
}}
|
|
2209
|
+
onchange={() => overrides.set(`label_stable`, !label_stable)}
|
|
2479
2210
|
/> Labels
|
|
2480
2211
|
</label>
|
|
2481
2212
|
<label>
|
|
2482
2213
|
<input
|
|
2483
2214
|
type="checkbox"
|
|
2484
2215
|
checked={draw_formula_meshes}
|
|
2485
|
-
onchange={() =>
|
|
2486
|
-
draw_formula_meshes_override = !draw_formula_meshes
|
|
2487
|
-
}}
|
|
2216
|
+
onchange={() => overrides.set(`draw_formula_meshes`, !draw_formula_meshes)}
|
|
2488
2217
|
/> Meshes
|
|
2489
2218
|
</label>
|
|
2490
2219
|
<label>
|
|
2491
2220
|
<input
|
|
2492
2221
|
type="checkbox"
|
|
2493
2222
|
checked={draw_formula_lines}
|
|
2494
|
-
onchange={() =>
|
|
2495
|
-
draw_formula_lines_override = !draw_formula_lines
|
|
2496
|
-
}}
|
|
2223
|
+
onchange={() => overrides.set(`draw_formula_lines`, !draw_formula_lines)}
|
|
2497
2224
|
/> Lines
|
|
2498
2225
|
</label>
|
|
2499
2226
|
</div>
|
|
@@ -2505,9 +2232,8 @@
|
|
|
2505
2232
|
min="0"
|
|
2506
2233
|
step="0.1"
|
|
2507
2234
|
value={element_padding}
|
|
2508
|
-
oninput={(event) =>
|
|
2509
|
-
|
|
2510
|
-
}}
|
|
2235
|
+
oninput={(event) =>
|
|
2236
|
+
overrides.set(`element_padding`, Number(event.currentTarget.value))}
|
|
2511
2237
|
/>
|
|
2512
2238
|
</label>
|
|
2513
2239
|
<label>
|
|
@@ -2517,11 +2243,8 @@
|
|
|
2517
2243
|
max="0"
|
|
2518
2244
|
step="1"
|
|
2519
2245
|
value={default_min_limit}
|
|
2520
|
-
oninput={(event) =>
|
|
2521
|
-
|
|
2522
|
-
event.currentTarget.value,
|
|
2523
|
-
)
|
|
2524
|
-
}}
|
|
2246
|
+
oninput={(event) =>
|
|
2247
|
+
overrides.set(`default_min_limit`, Number(event.currentTarget.value))}
|
|
2525
2248
|
/>
|
|
2526
2249
|
</label>
|
|
2527
2250
|
</div>
|
|
@@ -2530,16 +2253,12 @@
|
|
|
2530
2253
|
<select
|
|
2531
2254
|
id="chempot-color-mode"
|
|
2532
2255
|
value={color_mode}
|
|
2533
|
-
onchange={(event) =>
|
|
2534
|
-
|
|
2535
|
-
.value as ChemPotColorMode
|
|
2536
|
-
}}
|
|
2256
|
+
onchange={(event) =>
|
|
2257
|
+
overrides.set(`color_mode`, event.currentTarget.value as ChemPotColorMode)}
|
|
2537
2258
|
>
|
|
2538
|
-
|
|
2539
|
-
|
|
2540
|
-
|
|
2541
|
-
<option value="arity">Element count</option>
|
|
2542
|
-
<option value="entries">Entry count</option>
|
|
2259
|
+
{#each CHEMPOT_COLOR_MODE_OPTIONS as [value, label] (value)}
|
|
2260
|
+
<option {value}>{label}</option>
|
|
2261
|
+
{/each}
|
|
2543
2262
|
</select>
|
|
2544
2263
|
</div>
|
|
2545
2264
|
{#if color_mode !== `none` && color_mode !== `arity`}
|
|
@@ -2548,27 +2267,18 @@
|
|
|
2548
2267
|
<select
|
|
2549
2268
|
id="chempot-color-scale"
|
|
2550
2269
|
value={color_scale}
|
|
2551
|
-
onchange={(event) =>
|
|
2552
|
-
|
|
2553
|
-
.value as D3InterpolateName
|
|
2554
|
-
}}
|
|
2270
|
+
onchange={(event) =>
|
|
2271
|
+
overrides.set(`color_scale`, event.currentTarget.value as D3InterpolateName)}
|
|
2555
2272
|
>
|
|
2556
|
-
|
|
2557
|
-
|
|
2558
|
-
|
|
2559
|
-
<option value="interpolateMagma">Magma</option>
|
|
2560
|
-
<option value="interpolateCividis">Cividis</option>
|
|
2561
|
-
<option value="interpolateTurbo">Turbo</option>
|
|
2562
|
-
<option value="interpolateRdYlBu">RdYlBu</option>
|
|
2563
|
-
<option value="interpolateSpectral">Spectral</option>
|
|
2273
|
+
{#each CHEMPOT_COLOR_SCALE_OPTIONS as [value, label] (value)}
|
|
2274
|
+
<option {value}>{label}</option>
|
|
2275
|
+
{/each}
|
|
2564
2276
|
</select>
|
|
2565
2277
|
<label>
|
|
2566
2278
|
<input
|
|
2567
2279
|
type="checkbox"
|
|
2568
2280
|
checked={reverse_color_scale}
|
|
2569
|
-
onchange={() =>
|
|
2570
|
-
reverse_color_scale_override = !reverse_color_scale
|
|
2571
|
-
}}
|
|
2281
|
+
onchange={() => overrides.set(`reverse_color_scale`, !reverse_color_scale)}
|
|
2572
2282
|
/> Rev
|
|
2573
2283
|
</label>
|
|
2574
2284
|
</div>
|
|
@@ -2576,321 +2286,305 @@
|
|
|
2576
2286
|
</SettingsSection>
|
|
2577
2287
|
</ScatterPlot3DControls>
|
|
2578
2288
|
|
|
2579
|
-
|
|
2580
|
-
|
|
2581
|
-
|
|
2582
|
-
title="{fullscreen ? `Exit` : `Enter`} fullscreen"
|
|
2583
|
-
>
|
|
2584
|
-
<Icon icon="{fullscreen ? `Exit` : ``}Fullscreen" />
|
|
2585
|
-
</button>
|
|
2289
|
+
{#if fullscreen_toggle}
|
|
2290
|
+
<FullscreenButton {fullscreen} toggle={fullscreen_toggle} {wrapper} />
|
|
2291
|
+
{/if}
|
|
2586
2292
|
</section>
|
|
2587
2293
|
{#if show_temperature_slider && temperature !== undefined}
|
|
2588
|
-
<TemperatureSlider
|
|
2589
|
-
class="chempot-temp-slider"
|
|
2590
|
-
{available_temperatures}
|
|
2591
|
-
bind:temperature
|
|
2592
|
-
/>
|
|
2294
|
+
<TemperatureSlider class="chempot-temp-slider" {available_temperatures} bind:temperature />
|
|
2593
2295
|
{/if}
|
|
2594
2296
|
<div class="canvas-clip">
|
|
2595
|
-
|
|
2596
|
-
|
|
2597
|
-
|
|
2598
|
-
|
|
2599
|
-
|
|
2600
|
-
|
|
2601
|
-
|
|
2602
|
-
|
|
2603
|
-
|
|
2604
|
-
|
|
2605
|
-
|
|
2606
|
-
|
|
2607
|
-
|
|
2608
|
-
|
|
2609
|
-
|
|
2610
|
-
|
|
2611
|
-
|
|
2612
|
-
|
|
2613
|
-
|
|
2614
|
-
|
|
2615
|
-
|
|
2616
|
-
|
|
2617
|
-
|
|
2618
|
-
|
|
2619
|
-
|
|
2620
|
-
|
|
2621
|
-
|
|
2622
|
-
|
|
2623
|
-
|
|
2624
|
-
|
|
2625
|
-
|
|
2626
|
-
|
|
2627
|
-
|
|
2628
|
-
|
|
2629
|
-
|
|
2630
|
-
|
|
2631
|
-
|
|
2632
|
-
|
|
2633
|
-
|
|
2634
|
-
|
|
2635
|
-
|
|
2636
|
-
|
|
2637
|
-
|
|
2638
|
-
|
|
2639
|
-
|
|
2640
|
-
|
|
2641
|
-
|
|
2642
|
-
|
|
2643
|
-
|
|
2644
|
-
|
|
2645
|
-
|
|
2646
|
-
|
|
2647
|
-
|
|
2648
|
-
|
|
2649
|
-
|
|
2650
|
-
|
|
2651
|
-
|
|
2652
|
-
|
|
2297
|
+
{#if diagram_computing}
|
|
2298
|
+
<div class="computing-state">
|
|
2299
|
+
<Spinner
|
|
2300
|
+
text="Computing chemical potential domains..."
|
|
2301
|
+
style="--spinner-size: 1.2em"
|
|
2302
|
+
/>
|
|
2303
|
+
</div>
|
|
2304
|
+
{:else if !diagram_data}
|
|
2305
|
+
<div class="error-state" role="alert" aria-live="polite">
|
|
2306
|
+
<p>Cannot compute chemical potential diagram.</p>
|
|
2307
|
+
<p>Need at least 2 elements with elemental reference entries.</p>
|
|
2308
|
+
</div>
|
|
2309
|
+
{:else if mounted && typeof WebGLRenderingContext !== `undefined`}
|
|
2310
|
+
<Canvas
|
|
2311
|
+
createRenderer={(cvs) =>
|
|
2312
|
+
new THREE.WebGLRenderer({
|
|
2313
|
+
canvas: cvs,
|
|
2314
|
+
alpha: true,
|
|
2315
|
+
antialias: true,
|
|
2316
|
+
preserveDrawingBuffer: true,
|
|
2317
|
+
})}
|
|
2318
|
+
>
|
|
2319
|
+
<ChemPotScene3D>
|
|
2320
|
+
{#if camera_projection === `orthographic`}
|
|
2321
|
+
<!-- Orthographic camera matching pymatgen's projection style -->
|
|
2322
|
+
<T.OrthographicCamera
|
|
2323
|
+
makeDefault
|
|
2324
|
+
position={camera_position}
|
|
2325
|
+
zoom={orthographic_zoom}
|
|
2326
|
+
near={0.1}
|
|
2327
|
+
far={data_extent * 10}
|
|
2328
|
+
>
|
|
2329
|
+
<extras.OrbitControls
|
|
2330
|
+
bind:ref={orbit_controls_ref}
|
|
2331
|
+
enableRotate
|
|
2332
|
+
enableZoom
|
|
2333
|
+
enablePan
|
|
2334
|
+
autoRotate={auto_rotate > 0}
|
|
2335
|
+
autoRotateSpeed={auto_rotate}
|
|
2336
|
+
target={camera_target}
|
|
2337
|
+
/>
|
|
2338
|
+
</T.OrthographicCamera>
|
|
2339
|
+
{:else}
|
|
2340
|
+
<T.PerspectiveCamera
|
|
2341
|
+
makeDefault
|
|
2342
|
+
position={camera_position}
|
|
2343
|
+
fov={50}
|
|
2344
|
+
near={0.1}
|
|
2345
|
+
far={data_extent * 10}
|
|
2346
|
+
>
|
|
2347
|
+
<extras.OrbitControls
|
|
2348
|
+
bind:ref={orbit_controls_ref}
|
|
2349
|
+
enableRotate
|
|
2350
|
+
enableZoom
|
|
2351
|
+
enablePan
|
|
2352
|
+
autoRotate={auto_rotate > 0}
|
|
2353
|
+
autoRotateSpeed={auto_rotate}
|
|
2354
|
+
target={camera_target}
|
|
2355
|
+
/>
|
|
2356
|
+
</T.PerspectiveCamera>
|
|
2357
|
+
{/if}
|
|
2653
2358
|
|
|
2654
|
-
|
|
2655
|
-
|
|
2656
|
-
|
|
2359
|
+
<!-- Ambient light for visibility -->
|
|
2360
|
+
<T.AmbientLight intensity={0.8} />
|
|
2361
|
+
<T.DirectionalLight position={[1, 1, 1]} intensity={0.5} />
|
|
2657
2362
|
|
|
2658
|
-
|
|
2363
|
+
<!-- Vertex-colored hull for both plain and colored modes.
|
|
2659
2364
|
{#key domain_colors} forces Threlte to re-create the mesh whenever
|
|
2660
2365
|
colors change (covers color_mode, color_scale, and data updates),
|
|
2661
2366
|
since on-demand rendering won't detect mutated vertex color buffers. -->
|
|
2662
|
-
|
|
2663
|
-
|
|
2664
|
-
|
|
2367
|
+
{#if colored_hull_geometry}
|
|
2368
|
+
{#key domain_colors}
|
|
2369
|
+
<T.Mesh geometry={colored_hull_geometry}>
|
|
2370
|
+
<T.MeshBasicMaterial
|
|
2371
|
+
vertexColors
|
|
2372
|
+
transparent
|
|
2373
|
+
opacity={color_mode === `none` ? 0.25 : 0.4}
|
|
2374
|
+
side={THREE.DoubleSide}
|
|
2375
|
+
polygonOffset
|
|
2376
|
+
polygonOffsetFactor={1}
|
|
2377
|
+
polygonOffsetUnits={1}
|
|
2378
|
+
/>
|
|
2379
|
+
</T.Mesh>
|
|
2380
|
+
{/key}
|
|
2381
|
+
{/if}
|
|
2382
|
+
|
|
2383
|
+
<!-- Domain boundary edges (wireframe on top of opaque fills) -->
|
|
2384
|
+
<T.LineSegments geometry={edge_geometry}>
|
|
2385
|
+
<T.LineBasicMaterial color={0x333333} linewidth={1} />
|
|
2386
|
+
</T.LineSegments>
|
|
2387
|
+
|
|
2388
|
+
<!-- Invisible pick meshes for per-phase hover tooltip -->
|
|
2389
|
+
{#each hover_mesh_data as domain_hover (domain_hover.formula)}
|
|
2390
|
+
<T.Mesh
|
|
2391
|
+
geometry={domain_hover.geometry}
|
|
2392
|
+
onpointerenter={(event: unknown) => handle_phase_hover(domain_hover, event)}
|
|
2393
|
+
onpointermove={(event: unknown) => handle_phase_hover(domain_hover, event)}
|
|
2394
|
+
onpointerdown={(event: unknown) => toggle_phase_lock(domain_hover, event)}
|
|
2395
|
+
onpointerleave={() => {
|
|
2396
|
+
if (!locked_hover_formula && hover_info?.formula === domain_hover.formula) {
|
|
2397
|
+
hover_info = null
|
|
2398
|
+
}
|
|
2399
|
+
}}
|
|
2400
|
+
>
|
|
2665
2401
|
<T.MeshBasicMaterial
|
|
2666
|
-
vertexColors
|
|
2667
2402
|
transparent
|
|
2668
|
-
opacity={
|
|
2403
|
+
opacity={0}
|
|
2669
2404
|
side={THREE.DoubleSide}
|
|
2670
|
-
|
|
2671
|
-
polygonOffsetFactor={1}
|
|
2672
|
-
polygonOffsetUnits={1}
|
|
2405
|
+
depthWrite={false}
|
|
2673
2406
|
/>
|
|
2674
2407
|
</T.Mesh>
|
|
2675
|
-
{/
|
|
2676
|
-
{/if}
|
|
2408
|
+
{/each}
|
|
2677
2409
|
|
|
2678
|
-
|
|
2679
|
-
|
|
2680
|
-
|
|
2681
|
-
|
|
2682
|
-
|
|
2683
|
-
|
|
2684
|
-
|
|
2685
|
-
|
|
2686
|
-
|
|
2687
|
-
|
|
2688
|
-
|
|
2689
|
-
onpointerdown={(event: unknown) => toggle_phase_lock(domain_hover, event)}
|
|
2690
|
-
onpointerleave={() => {
|
|
2691
|
-
if (
|
|
2692
|
-
!locked_hover_formula &&
|
|
2693
|
-
hover_info?.formula === domain_hover.formula
|
|
2694
|
-
) {
|
|
2695
|
-
hover_info = null
|
|
2696
|
-
}
|
|
2697
|
-
}}
|
|
2698
|
-
>
|
|
2699
|
-
<T.MeshBasicMaterial
|
|
2700
|
-
transparent
|
|
2701
|
-
opacity={0}
|
|
2702
|
-
side={THREE.DoubleSide}
|
|
2703
|
-
depthWrite={false}
|
|
2704
|
-
/>
|
|
2705
|
-
</T.Mesh>
|
|
2706
|
-
{/each}
|
|
2707
|
-
|
|
2708
|
-
<!-- Formula overlay meshes (semi-transparent colored fill) -->
|
|
2709
|
-
{#each formula_mesh_data as { geometry, color }, mesh_idx (mesh_idx)}
|
|
2710
|
-
<T.Mesh {geometry}>
|
|
2711
|
-
<T.MeshBasicMaterial
|
|
2712
|
-
color={new THREE.Color(color)}
|
|
2713
|
-
transparent
|
|
2714
|
-
opacity={0.13}
|
|
2715
|
-
side={THREE.DoubleSide}
|
|
2716
|
-
depthWrite={false}
|
|
2717
|
-
/>
|
|
2718
|
-
</T.Mesh>
|
|
2719
|
-
{/each}
|
|
2720
|
-
|
|
2721
|
-
<!-- Formula overlay edges (colored, thicker) -->
|
|
2722
|
-
{#if draw_formula_lines}
|
|
2723
|
-
{#each formula_edge_data as { geometry, color }, edge_idx (edge_idx)}
|
|
2724
|
-
<T.LineSegments {geometry}>
|
|
2725
|
-
<T.LineBasicMaterial color={new THREE.Color(color)} linewidth={2} />
|
|
2726
|
-
</T.LineSegments>
|
|
2410
|
+
<!-- Formula overlay meshes (semi-transparent colored fill) -->
|
|
2411
|
+
{#each formula_mesh_data as { geometry, color }, mesh_idx (mesh_idx)}
|
|
2412
|
+
<T.Mesh {geometry}>
|
|
2413
|
+
<T.MeshBasicMaterial
|
|
2414
|
+
color={new THREE.Color(color)}
|
|
2415
|
+
transparent
|
|
2416
|
+
opacity={0.13}
|
|
2417
|
+
side={THREE.DoubleSide}
|
|
2418
|
+
depthWrite={false}
|
|
2419
|
+
/>
|
|
2420
|
+
</T.Mesh>
|
|
2727
2421
|
{/each}
|
|
2728
|
-
{/if}
|
|
2729
2422
|
|
|
2730
|
-
|
|
2731
|
-
|
|
2732
|
-
|
|
2733
|
-
|
|
2734
|
-
|
|
2735
|
-
|
|
2736
|
-
|
|
2737
|
-
|
|
2738
|
-
depthWrite={false}
|
|
2739
|
-
/>
|
|
2740
|
-
</T.Mesh>
|
|
2741
|
-
{/each}
|
|
2423
|
+
<!-- Formula overlay edges (colored, thicker) -->
|
|
2424
|
+
{#if draw_formula_lines}
|
|
2425
|
+
{#each formula_edge_data as { geometry, color }, edge_idx (edge_idx)}
|
|
2426
|
+
<T.LineSegments {geometry}>
|
|
2427
|
+
<T.LineBasicMaterial color={new THREE.Color(color)} linewidth={2} />
|
|
2428
|
+
</T.LineSegments>
|
|
2429
|
+
{/each}
|
|
2430
|
+
{/if}
|
|
2742
2431
|
|
|
2743
|
-
|
|
2744
|
-
|
|
2745
|
-
|
|
2746
|
-
|
|
2747
|
-
|
|
2432
|
+
{#each projection_planes as plane (`${plane.key}-${projection_opacity}`)}
|
|
2433
|
+
<T.Mesh position={plane.pos} rotation={plane.rot}>
|
|
2434
|
+
<T.PlaneGeometry args={plane.size} />
|
|
2435
|
+
<T.MeshBasicMaterial
|
|
2436
|
+
color={plane.color}
|
|
2437
|
+
opacity={projection_opacity}
|
|
2438
|
+
transparent
|
|
2439
|
+
side={THREE.DoubleSide}
|
|
2440
|
+
depthWrite={false}
|
|
2441
|
+
/>
|
|
2442
|
+
</T.Mesh>
|
|
2443
|
+
{/each}
|
|
2748
2444
|
|
|
2749
|
-
|
|
2750
|
-
|
|
2751
|
-
|
|
2752
|
-
|
|
2753
|
-
<T.Line geometry={gc.line_geom}>
|
|
2754
|
-
<T.LineBasicMaterial color={gc.color} linewidth={2} />
|
|
2755
|
-
</T.Line>
|
|
2756
|
-
<!-- Tick marks -->
|
|
2757
|
-
{#each gc.tick_geoms as tick_geom, tdx (tdx)}
|
|
2758
|
-
<T.Line geometry={tick_geom}>
|
|
2759
|
-
<T.LineBasicMaterial color={gc.color} />
|
|
2760
|
-
</T.Line>
|
|
2761
|
-
{/each}
|
|
2445
|
+
{#if display.show_bounding_box}
|
|
2446
|
+
<T.LineSegments geometry={bounding_box_geometry}>
|
|
2447
|
+
<T.LineBasicMaterial color="#666" opacity={0.6} transparent />
|
|
2448
|
+
</T.LineSegments>
|
|
2762
2449
|
{/if}
|
|
2763
|
-
|
|
2764
|
-
|
|
2765
|
-
|
|
2766
|
-
|
|
2767
|
-
|
|
2450
|
+
|
|
2451
|
+
<!-- Axes, ticks, grid lines, and labels -->
|
|
2452
|
+
{#each grid_config as gc (gc.axis)}
|
|
2453
|
+
{#if display.show_axes}
|
|
2454
|
+
<!-- Main axis line -->
|
|
2455
|
+
<T.Line geometry={gc.line_geom}>
|
|
2456
|
+
<T.LineBasicMaterial color={gc.color} linewidth={2} />
|
|
2768
2457
|
</T.Line>
|
|
2769
|
-
|
|
2770
|
-
|
|
2771
|
-
|
|
2772
|
-
|
|
2773
|
-
|
|
2458
|
+
<!-- Tick marks -->
|
|
2459
|
+
{#each gc.tick_geoms as tick_geom, tdx (tdx)}
|
|
2460
|
+
<T.Line geometry={tick_geom}>
|
|
2461
|
+
<T.LineBasicMaterial color={gc.color} />
|
|
2462
|
+
</T.Line>
|
|
2463
|
+
{/each}
|
|
2464
|
+
{/if}
|
|
2465
|
+
{#if display.show_grid}
|
|
2466
|
+
<!-- Grid lines -->
|
|
2467
|
+
{#each gc.grid_geoms as grid_geom, gdx (gdx)}
|
|
2468
|
+
<T.Line geometry={grid_geom}>
|
|
2469
|
+
<T.LineBasicMaterial color="#888" opacity={0.3} transparent />
|
|
2470
|
+
</T.Line>
|
|
2471
|
+
{/each}
|
|
2472
|
+
{/if}
|
|
2473
|
+
{#if display.show_axis_labels}
|
|
2474
|
+
<!-- Tick labels (billboarded, always face camera) -->
|
|
2475
|
+
{#each gc.tick_labels as tick, tick_idx (tick_idx)}
|
|
2476
|
+
<extras.HTML position={tick.pos} center portal={wrapper} zIndexRange={[1, 0]}>
|
|
2477
|
+
<span class="tick-label axis-tick-label">{tick.text}</span>
|
|
2478
|
+
</extras.HTML>
|
|
2479
|
+
{/each}
|
|
2480
|
+
<!-- Axis label -->
|
|
2774
2481
|
<extras.HTML
|
|
2775
|
-
position={
|
|
2482
|
+
position={gc.label_pos}
|
|
2776
2483
|
center
|
|
2777
2484
|
portal={wrapper}
|
|
2778
2485
|
zIndexRange={[1, 0]}
|
|
2779
2486
|
>
|
|
2780
|
-
<span class="
|
|
2487
|
+
<span class="axis-label" style:color={gc.color}>{@html gc.label}</span>
|
|
2488
|
+
</extras.HTML>
|
|
2489
|
+
{/if}
|
|
2490
|
+
{/each}
|
|
2491
|
+
|
|
2492
|
+
<!-- Domain labels -->
|
|
2493
|
+
{#if label_stable}
|
|
2494
|
+
{#each visible_domain_labels as domain (domain.formula)}
|
|
2495
|
+
<extras.HTML
|
|
2496
|
+
position={domain.position}
|
|
2497
|
+
center
|
|
2498
|
+
portal={wrapper}
|
|
2499
|
+
zIndexRange={[5, 5]}
|
|
2500
|
+
>
|
|
2501
|
+
<span
|
|
2502
|
+
class="domain-label"
|
|
2503
|
+
style:font-size="{(domain.label_font_size * zoom_scale).toFixed(1)}px"
|
|
2504
|
+
>
|
|
2505
|
+
{#each formula_label_segments(domain.formula) as segment}
|
|
2506
|
+
<span class:formula-subscript={segment.subscript}>{segment.text}</span>
|
|
2507
|
+
{/each}
|
|
2508
|
+
</span>
|
|
2781
2509
|
</extras.HTML>
|
|
2782
2510
|
{/each}
|
|
2783
|
-
<!-- Axis label -->
|
|
2784
|
-
<extras.HTML
|
|
2785
|
-
position={gc.label_pos}
|
|
2786
|
-
center
|
|
2787
|
-
portal={wrapper}
|
|
2788
|
-
zIndexRange={[1, 0]}
|
|
2789
|
-
>
|
|
2790
|
-
<span class="axis-label" style:color={gc.color}>{@html gc.label}</span>
|
|
2791
|
-
</extras.HTML>
|
|
2792
2511
|
{/if}
|
|
2793
|
-
|
|
2794
|
-
|
|
2795
|
-
|
|
2796
|
-
|
|
2797
|
-
|
|
2798
|
-
|
|
2799
|
-
|
|
2800
|
-
|
|
2801
|
-
|
|
2802
|
-
|
|
2803
|
-
|
|
2804
|
-
|
|
2805
|
-
|
|
2806
|
-
|
|
2807
|
-
|
|
2808
|
-
|
|
2809
|
-
|
|
2810
|
-
|
|
2811
|
-
|
|
2812
|
-
|
|
2512
|
+
</ChemPotScene3D>
|
|
2513
|
+
</Canvas>
|
|
2514
|
+
<!-- Color bar for continuous modes -->
|
|
2515
|
+
{#if color_mode !== `none` && color_mode !== `arity` && color_range}
|
|
2516
|
+
{@const color_bar_config = get_chempot_color_bar_config(
|
|
2517
|
+
color_scale,
|
|
2518
|
+
reverse_color_scale,
|
|
2519
|
+
)}
|
|
2520
|
+
<ColorBar
|
|
2521
|
+
title={color_range.label}
|
|
2522
|
+
range={[color_range.min, color_range.max]}
|
|
2523
|
+
color_scale_fn={color_bar_config.color_scale_fn}
|
|
2524
|
+
color_scale_domain={color_bar_config.color_scale_domain}
|
|
2525
|
+
wrapper_style="position: absolute; bottom: 16px; left: 1em; width: 200px; z-index: 10;"
|
|
2526
|
+
bar_style="height: 12px;"
|
|
2527
|
+
title_style="margin-bottom: 4px;"
|
|
2528
|
+
/>
|
|
2529
|
+
{/if}
|
|
2530
|
+
<!-- Categorical legend for arity mode -->
|
|
2531
|
+
{#if color_mode === `arity`}
|
|
2532
|
+
<div class="arity-legend">
|
|
2533
|
+
{#each arity_legend_labels as label, idx (label)}
|
|
2534
|
+
<span>
|
|
2535
|
+
<span style:background={arity_colors[idx]}></span>
|
|
2536
|
+
{label}
|
|
2537
|
+
</span>
|
|
2813
2538
|
{/each}
|
|
2814
|
-
|
|
2815
|
-
</ChemPotScene3D>
|
|
2816
|
-
</Canvas>
|
|
2817
|
-
<!-- Color bar for continuous modes -->
|
|
2818
|
-
{#if color_mode !== `none` && color_mode !== `arity` && color_range}
|
|
2819
|
-
{@const color_bar_config = get_chempot_color_bar_config(
|
|
2820
|
-
color_scale,
|
|
2821
|
-
reverse_color_scale,
|
|
2822
|
-
)}
|
|
2823
|
-
<ColorBar
|
|
2824
|
-
title={color_range.label}
|
|
2825
|
-
range={[color_range.min, color_range.max]}
|
|
2826
|
-
color_scale_fn={color_bar_config.color_scale_fn}
|
|
2827
|
-
color_scale_domain={color_bar_config.color_scale_domain}
|
|
2828
|
-
wrapper_style="position: absolute; bottom: 16px; left: 1em; width: 200px; z-index: 10;"
|
|
2829
|
-
bar_style="height: 12px;"
|
|
2830
|
-
title_style="margin-bottom: 4px;"
|
|
2831
|
-
/>
|
|
2832
|
-
{/if}
|
|
2833
|
-
<!-- Categorical legend for arity mode -->
|
|
2834
|
-
{#if color_mode === `arity`}
|
|
2835
|
-
<div class="arity-legend">
|
|
2836
|
-
{#each arity_legend_labels as label, idx (label)}
|
|
2837
|
-
<span>
|
|
2838
|
-
<span style:background={arity_colors[idx]}></span>
|
|
2839
|
-
{label}
|
|
2840
|
-
</span>
|
|
2841
|
-
{/each}
|
|
2842
|
-
</div>
|
|
2843
|
-
{/if}
|
|
2844
|
-
{/if}
|
|
2845
|
-
{#if render_local_tooltip && show_tooltip && hover_info?.view === `3d`}
|
|
2846
|
-
<aside
|
|
2847
|
-
bind:this={tooltip_el}
|
|
2848
|
-
class="phase-tooltip"
|
|
2849
|
-
style:left="{tooltip_pos.x}px"
|
|
2850
|
-
style:top="{tooltip_pos.y}px"
|
|
2851
|
-
>
|
|
2852
|
-
<h4>
|
|
2853
|
-
{#each formula_label_segments(hover_info.formula) as segment}
|
|
2854
|
-
<span class:formula-subscript={segment.subscript}>{segment.text}</span>
|
|
2855
|
-
{/each}
|
|
2856
|
-
</h4>
|
|
2857
|
-
{#if locked_hover_formula === hover_info.formula}
|
|
2858
|
-
<p>Pinned · Press Esc to unlock</p>
|
|
2539
|
+
</div>
|
|
2859
2540
|
{/if}
|
|
2860
|
-
|
|
2861
|
-
|
|
2862
|
-
|
|
2863
|
-
|
|
2864
|
-
|
|
2865
|
-
|
|
2866
|
-
{
|
|
2867
|
-
|
|
2868
|
-
|
|
2869
|
-
|
|
2541
|
+
{/if}
|
|
2542
|
+
{#if render_local_tooltip && show_tooltip && hover_info?.view === `3d`}
|
|
2543
|
+
<aside
|
|
2544
|
+
bind:this={tooltip_el}
|
|
2545
|
+
class="phase-tooltip"
|
|
2546
|
+
style:left="{tooltip_pos.x}px"
|
|
2547
|
+
style:top="{tooltip_pos.y}px"
|
|
2548
|
+
>
|
|
2549
|
+
<h4>
|
|
2550
|
+
{#each formula_label_segments(hover_info.formula) as segment}
|
|
2551
|
+
<span class:formula-subscript={segment.subscript}>{segment.text}</span>
|
|
2552
|
+
{/each}
|
|
2553
|
+
</h4>
|
|
2554
|
+
{#if locked_hover_formula === hover_info.formula}
|
|
2555
|
+
<p>Pinned · Press Esc to unlock</p>
|
|
2870
2556
|
{/if}
|
|
2871
|
-
</p>
|
|
2872
|
-
{#if tooltip_detail_level === `detailed`}
|
|
2873
|
-
<h5 id="axis-ranges">Axis ranges</h5>
|
|
2874
|
-
{#each hover_info.axis_ranges as axis_range (axis_range.element)}
|
|
2875
|
-
<p>
|
|
2876
|
-
{axis_range.element}: {format_num(axis_range.min_val, `.4~g`)} to
|
|
2877
|
-
{format_num(axis_range.max_val, `.4~g`)} eV
|
|
2878
|
-
</p>
|
|
2879
|
-
{/each}
|
|
2880
2557
|
<p>
|
|
2881
|
-
|
|
2882
|
-
|
|
2883
|
-
|
|
2884
|
-
|
|
2885
|
-
}
|
|
2558
|
+
Vertices: {hover_info.n_vertices} · Edges: {hover_info.n_edges} · Points:
|
|
2559
|
+
{hover_info.n_points}
|
|
2560
|
+
</p>
|
|
2561
|
+
<p>
|
|
2562
|
+
Entries: {hover_info.matching_entry_count}
|
|
2563
|
+
{#if hover_info.min_energy_per_atom !== null && hover_info.max_energy_per_atom !== null}
|
|
2564
|
+
· E/atom: {format_num(hover_info.min_energy_per_atom, `.4~g`)}
|
|
2565
|
+
to {format_num(hover_info.max_energy_per_atom, `.4~g`)} eV
|
|
2566
|
+
{/if}
|
|
2886
2567
|
</p>
|
|
2887
|
-
{#if
|
|
2888
|
-
<h5 id="
|
|
2889
|
-
|
|
2568
|
+
{#if tooltip_detail_level === `detailed`}
|
|
2569
|
+
<h5 id="axis-ranges">Axis ranges</h5>
|
|
2570
|
+
{#each hover_info.axis_ranges as axis_range (axis_range.element)}
|
|
2571
|
+
<p>
|
|
2572
|
+
{axis_range.element}: {format_num(axis_range.min_val, `.4~g`)} to
|
|
2573
|
+
{format_num(axis_range.max_val, `.4~g`)} eV
|
|
2574
|
+
</p>
|
|
2575
|
+
{/each}
|
|
2576
|
+
<p>
|
|
2577
|
+
Centroid: ({hover_info.ann_loc
|
|
2578
|
+
.map((value) => format_num(value, `.3~g`))
|
|
2579
|
+
.join(`, `)})
|
|
2580
|
+
</p>
|
|
2581
|
+
{#if hover_info.touches_limits.length > 0}
|
|
2582
|
+
<h5 id="touches-bounds">Touches bounds</h5>
|
|
2583
|
+
<p>{hover_info.touches_limits.join(`, `)}</p>
|
|
2584
|
+
{/if}
|
|
2890
2585
|
{/if}
|
|
2891
|
-
|
|
2892
|
-
|
|
2893
|
-
{/if}
|
|
2586
|
+
</aside>
|
|
2587
|
+
{/if}
|
|
2894
2588
|
</div>
|
|
2895
2589
|
</div>
|
|
2896
2590
|
|
|
@@ -2963,23 +2657,6 @@
|
|
|
2963
2657
|
gap: 4pt;
|
|
2964
2658
|
font-size: 0.9em;
|
|
2965
2659
|
}
|
|
2966
|
-
.chempot-diagram-3d :global(.export-row) {
|
|
2967
|
-
display: flex;
|
|
2968
|
-
flex-wrap: wrap;
|
|
2969
|
-
gap: 4pt 10pt;
|
|
2970
|
-
margin: 0 0 4pt;
|
|
2971
|
-
}
|
|
2972
|
-
.chempot-diagram-3d :global(.export-row > label) {
|
|
2973
|
-
margin: 0;
|
|
2974
|
-
}
|
|
2975
|
-
.chempot-diagram-3d :global(.export-row button) {
|
|
2976
|
-
width: 1.4em;
|
|
2977
|
-
height: 1.4em;
|
|
2978
|
-
padding: 0;
|
|
2979
|
-
display: inline-flex;
|
|
2980
|
-
align-items: center;
|
|
2981
|
-
justify-content: center;
|
|
2982
|
-
}
|
|
2983
2660
|
.chempot-diagram-3d :global(.chempot-checks) {
|
|
2984
2661
|
display: flex;
|
|
2985
2662
|
flex-wrap: wrap;
|
|
@@ -2996,8 +2673,10 @@
|
|
|
2996
2673
|
}
|
|
2997
2674
|
.chempot-diagram-3d :global(.projection-controls .pane-row) {
|
|
2998
2675
|
display: grid;
|
|
2999
|
-
grid-template-columns:
|
|
3000
|
-
|
|
2676
|
+
grid-template-columns: auto minmax(4.5em, 1fr) auto minmax(4.5em, 1fr) auto minmax(
|
|
2677
|
+
4.5em,
|
|
2678
|
+
1fr
|
|
2679
|
+
);
|
|
3001
2680
|
align-items: center;
|
|
3002
2681
|
gap: 3pt;
|
|
3003
2682
|
}
|
|
@@ -3137,10 +2816,7 @@
|
|
|
3137
2816
|
.phase-tooltip {
|
|
3138
2817
|
position: absolute;
|
|
3139
2818
|
max-width: min(32rem, 92vw);
|
|
3140
|
-
background: var(
|
|
3141
|
-
--tooltip-bg,
|
|
3142
|
-
light-dark(rgba(255, 255, 255, 0.95), rgba(0, 0, 0, 0.9))
|
|
3143
|
-
);
|
|
2819
|
+
background: var(--tooltip-bg, light-dark(rgba(255, 255, 255, 0.95), rgba(0, 0, 0, 0.9)));
|
|
3144
2820
|
color: var(--tooltip-text, var(--text-color, #222));
|
|
3145
2821
|
border: 1px solid color-mix(in srgb, currentColor 18%, transparent);
|
|
3146
2822
|
border-radius: 6px;
|