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
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
2
|
import type { D3InterpolateName } from '../colors'
|
|
3
|
+
import { clamp01 } from '../utils'
|
|
3
4
|
import {
|
|
4
5
|
add_alpha,
|
|
5
6
|
AXIS_COLORS,
|
|
@@ -13,17 +14,16 @@
|
|
|
13
14
|
import type { FormulaLabelSegment } from '../composition/format'
|
|
14
15
|
import { normalize_show_controls } from '../controls'
|
|
15
16
|
import { sanitize_html } from '../sanitize'
|
|
16
|
-
import {
|
|
17
|
-
import Icon from '../Icon.svelte'
|
|
17
|
+
import { Spinner } from '../feedback'
|
|
18
18
|
import { format_num } from '../labels'
|
|
19
|
+
import { to_radians, type Point3D, type Vec2, type Vec3 } from '../math'
|
|
20
|
+
import { ColorBar } from '../plot'
|
|
19
21
|
import {
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
import { ColorBar, PlotTooltip } from '../plot'
|
|
26
|
-
import { centered_rect, pad_rect, rects_overlap, rect_within_rect } from '../plot/core/layout'
|
|
22
|
+
centered_rect,
|
|
23
|
+
pad_rect,
|
|
24
|
+
rects_overlap,
|
|
25
|
+
rect_within_rect,
|
|
26
|
+
} from '../plot/core/layout'
|
|
27
27
|
import type { Rect } from '../plot/core/layout'
|
|
28
28
|
import { create_pulse_animation } from '../effects.svelte'
|
|
29
29
|
import { DEFAULTS } from '../settings'
|
|
@@ -40,39 +40,41 @@
|
|
|
40
40
|
get_triangle_vertical_edges,
|
|
41
41
|
TRIANGLE_VERTICES,
|
|
42
42
|
} from './barycentric-coords'
|
|
43
|
-
import
|
|
44
|
-
import
|
|
45
|
-
import ConvexHullTooltip from './ConvexHullTooltip.svelte'
|
|
43
|
+
import { create_canvas_interactions } from './canvas-interactions.svelte'
|
|
44
|
+
import ConvexHullChrome from './ConvexHullChrome.svelte'
|
|
46
45
|
import GasPressureControls from './GasPressureControls.svelte'
|
|
47
46
|
import * as helpers from './helpers'
|
|
47
|
+
import { create_hull_data_pipeline } from './hull-state.svelte'
|
|
48
48
|
import type { BaseConvexHullProps, Hull3DProps } from './index'
|
|
49
49
|
import { CONVEX_HULL_STYLE, default_controls, default_hull_config } from './index'
|
|
50
|
-
import StructurePopup from './StructurePopup.svelte'
|
|
51
50
|
import TemperatureSlider from './TemperatureSlider.svelte'
|
|
52
51
|
import * as thermo from './thermodynamics'
|
|
53
52
|
import type {
|
|
54
53
|
ConvexHullEntry,
|
|
55
54
|
ConvexHullTriangle,
|
|
56
55
|
HighlightStyle,
|
|
57
|
-
HoverData3D,
|
|
58
56
|
HullFaceColorMode,
|
|
59
57
|
LabelPlacement,
|
|
60
58
|
} from './types'
|
|
61
59
|
import { compute_hull_stability } from './helpers'
|
|
60
|
+
import { MAGNETIC_ORDERING_CATEGORY } from './types'
|
|
62
61
|
|
|
63
62
|
let {
|
|
64
63
|
entries = [],
|
|
65
64
|
controls = {},
|
|
66
65
|
config = {},
|
|
66
|
+
show_controls,
|
|
67
67
|
on_point_click,
|
|
68
68
|
on_point_hover,
|
|
69
69
|
fullscreen = $bindable(DEFAULTS.convex_hull.ternary.fullscreen),
|
|
70
|
-
|
|
70
|
+
fullscreen_toggle = true,
|
|
71
71
|
enable_info_pane = true,
|
|
72
72
|
wrapper = $bindable(),
|
|
73
73
|
label_threshold = 50,
|
|
74
74
|
show_stable = $bindable(DEFAULTS.convex_hull.ternary.show_stable),
|
|
75
75
|
show_unstable = $bindable(DEFAULTS.convex_hull.ternary.show_unstable),
|
|
76
|
+
entry_category = MAGNETIC_ORDERING_CATEGORY,
|
|
77
|
+
hidden_categories = $bindable([]),
|
|
76
78
|
show_hull_faces = $bindable(DEFAULTS.convex_hull.ternary.show_hull_faces),
|
|
77
79
|
hull_face_opacity = $bindable(DEFAULTS.convex_hull.ternary.hull_face_opacity),
|
|
78
80
|
hull_face_color_mode = $bindable(
|
|
@@ -80,11 +82,9 @@
|
|
|
80
82
|
),
|
|
81
83
|
element_colors = vesta_hex,
|
|
82
84
|
color_mode = $bindable(DEFAULTS.convex_hull.ternary.color_mode),
|
|
83
|
-
color_scale = $bindable(
|
|
84
|
-
DEFAULTS.convex_hull.ternary.color_scale as D3InterpolateName,
|
|
85
|
-
),
|
|
85
|
+
color_scale = $bindable(DEFAULTS.convex_hull.ternary.color_scale as D3InterpolateName),
|
|
86
86
|
info_pane_open = $bindable(DEFAULTS.convex_hull.ternary.info_pane_open),
|
|
87
|
-
|
|
87
|
+
controls_open = $bindable(DEFAULTS.convex_hull.ternary.legend_pane_open),
|
|
88
88
|
max_hull_dist_show_phases = $bindable(
|
|
89
89
|
DEFAULTS.convex_hull.ternary.max_hull_dist_show_phases,
|
|
90
90
|
),
|
|
@@ -92,9 +92,7 @@
|
|
|
92
92
|
DEFAULTS.convex_hull.ternary.max_hull_dist_show_labels,
|
|
93
93
|
),
|
|
94
94
|
show_stable_labels = $bindable(DEFAULTS.convex_hull.ternary.show_stable_labels),
|
|
95
|
-
show_unstable_labels = $bindable(
|
|
96
|
-
DEFAULTS.convex_hull.ternary.show_unstable_labels,
|
|
97
|
-
),
|
|
95
|
+
show_unstable_labels = $bindable(DEFAULTS.convex_hull.ternary.show_unstable_labels),
|
|
98
96
|
on_file_drop,
|
|
99
97
|
enable_click_selection = true,
|
|
100
98
|
enable_structure_preview = true,
|
|
@@ -114,12 +112,13 @@
|
|
|
114
112
|
children,
|
|
115
113
|
tooltip,
|
|
116
114
|
...rest
|
|
117
|
-
}: BaseConvexHullProps<ConvexHullEntry> &
|
|
118
|
-
|
|
119
|
-
|
|
115
|
+
}: BaseConvexHullProps<ConvexHullEntry> &
|
|
116
|
+
Hull3DProps & {
|
|
117
|
+
highlight_style?: HighlightStyle
|
|
118
|
+
} = $props()
|
|
120
119
|
|
|
121
120
|
const merged_controls = $derived({ ...default_controls, ...controls })
|
|
122
|
-
const controls_config = $derived(normalize_show_controls(
|
|
121
|
+
const controls_config = $derived(normalize_show_controls(show_controls))
|
|
123
122
|
const merged_config = $derived({
|
|
124
123
|
...default_hull_config,
|
|
125
124
|
...config,
|
|
@@ -127,100 +126,43 @@
|
|
|
127
126
|
margin: { t: 40, r: 40, b: 60, l: 60, ...config.margin },
|
|
128
127
|
})
|
|
129
128
|
|
|
130
|
-
//
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
)
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
)
|
|
153
|
-
|
|
154
|
-
// Gas-dependent chemical potential support (corrections based on T, P)
|
|
155
|
-
// Default to DEFAULT_GAS_TEMP (room temperature) when no temperature specified
|
|
156
|
-
const {
|
|
157
|
-
entries: gas_corrected_entries,
|
|
158
|
-
analysis: gas_analysis,
|
|
159
|
-
merged_config: merged_gas_config,
|
|
160
|
-
} = $derived(
|
|
161
|
-
helpers.get_gas_corrected_entries(
|
|
162
|
-
temp_filtered_entries,
|
|
163
|
-
gas_config,
|
|
164
|
-
gas_pressures,
|
|
165
|
-
temperature ?? helpers.DEFAULT_GAS_TEMP,
|
|
166
|
-
),
|
|
167
|
-
)
|
|
168
|
-
|
|
169
|
-
let { // Compute energy mode information
|
|
170
|
-
has_precomputed_e_form,
|
|
171
|
-
has_precomputed_hull,
|
|
172
|
-
can_compute_e_form,
|
|
173
|
-
can_compute_hull,
|
|
174
|
-
energy_mode,
|
|
175
|
-
unary_refs,
|
|
176
|
-
} = $derived(
|
|
177
|
-
helpers.compute_energy_mode_info(
|
|
178
|
-
gas_corrected_entries,
|
|
179
|
-
thermo.find_lowest_energy_unary_refs,
|
|
180
|
-
energy_source_mode,
|
|
181
|
-
),
|
|
182
|
-
)
|
|
183
|
-
|
|
184
|
-
const effective_entries = $derived(
|
|
185
|
-
helpers.get_effective_entries(
|
|
186
|
-
gas_corrected_entries,
|
|
187
|
-
energy_mode,
|
|
188
|
-
unary_refs,
|
|
189
|
-
thermo.compute_e_form_per_atom,
|
|
190
|
-
),
|
|
191
|
-
)
|
|
192
|
-
|
|
193
|
-
// Process convex hull data with unified PhaseData interface using effective entries
|
|
194
|
-
const pd_data = $derived(thermo.process_hull_entries(effective_entries))
|
|
195
|
-
|
|
196
|
-
// Pre-compute polymorph stats once for O(1) tooltip lookups
|
|
197
|
-
const polymorph_stats_map = $derived(
|
|
198
|
-
helpers.compute_all_polymorph_stats(effective_entries),
|
|
199
|
-
)
|
|
200
|
-
|
|
201
|
-
const elements = $derived.by(() => {
|
|
202
|
-
if (pd_data.elements.length > 3) {
|
|
203
|
-
console.error(
|
|
204
|
-
`ConvexHull3D: Dataset contains ${pd_data.elements.length} elements, but ternary diagrams require exactly 3. Found: [${
|
|
205
|
-
pd_data.elements.join(`, `)
|
|
206
|
-
}]`,
|
|
207
|
-
)
|
|
208
|
-
return []
|
|
209
|
-
}
|
|
210
|
-
|
|
211
|
-
return pd_data.elements
|
|
129
|
+
// Shared reactive data pipeline (temperature → gas → energy mode → hull data → threshold)
|
|
130
|
+
// Explicit generic breaks the circular type inference through the all_enriched_entries thunk
|
|
131
|
+
const hull_data = create_hull_data_pipeline<ConvexHullEntry>({
|
|
132
|
+
dim: 3,
|
|
133
|
+
entries: () => entries,
|
|
134
|
+
temperature: () => temperature,
|
|
135
|
+
interpolate_temperature: () => interpolate_temperature,
|
|
136
|
+
max_interpolation_gap: () => max_interpolation_gap,
|
|
137
|
+
gas_config: () => gas_config,
|
|
138
|
+
gas_pressures: () => gas_pressures,
|
|
139
|
+
energy_source_mode: () => energy_source_mode,
|
|
140
|
+
all_enriched_entries: () => all_enriched_entries,
|
|
141
|
+
max_hull_dist_show_phases: () => max_hull_dist_show_phases,
|
|
142
|
+
show_stable: () => show_stable,
|
|
143
|
+
show_unstable: () => show_unstable,
|
|
144
|
+
entry_category: () => entry_category,
|
|
145
|
+
hidden_categories: () => hidden_categories,
|
|
146
|
+
keep_plot_entry: helpers.entry_within_hull_dist,
|
|
147
|
+
set_temperature: (next_temp) => (temperature = next_temp),
|
|
148
|
+
set_max_hull_dist_show_phases: (value) => (max_hull_dist_show_phases = value),
|
|
149
|
+
set_stable_entries: (value) => (stable_entries = value),
|
|
150
|
+
set_unstable_entries: (value) => (unstable_entries = value),
|
|
212
151
|
})
|
|
152
|
+
const has_temp_data = $derived(hull_data.has_temp_data)
|
|
153
|
+
const gas_analysis = $derived(hull_data.gas_analysis)
|
|
154
|
+
const merged_gas_config = $derived(hull_data.merged_gas_config)
|
|
155
|
+
const pd_data = $derived(hull_data.pd_data)
|
|
156
|
+
const elements = $derived(hull_data.elements)
|
|
157
|
+
const plot_entries = $derived(hull_data.plot_entries)
|
|
158
|
+
const visible_entries = $derived(hull_data.visible_entries)
|
|
213
159
|
|
|
214
160
|
// 1) Raw 3D coordinates (formation-energy z), independent of hull state
|
|
215
161
|
const coords_entries = $derived.by(() => {
|
|
216
162
|
if (elements.length !== 3) return []
|
|
217
163
|
try {
|
|
218
164
|
// Pass precomputed el_refs to avoid recomputing in error diagnostics
|
|
219
|
-
const coords = get_ternary_3d_coordinates(
|
|
220
|
-
pd_data.entries,
|
|
221
|
-
elements,
|
|
222
|
-
pd_data.el_refs,
|
|
223
|
-
)
|
|
165
|
+
const coords = get_ternary_3d_coordinates(pd_data.entries, elements, pd_data.el_refs)
|
|
224
166
|
return coords
|
|
225
167
|
} catch (error) {
|
|
226
168
|
console.error(`Error computing ternary coordinates:`, error)
|
|
@@ -250,59 +192,20 @@
|
|
|
250
192
|
// Enrich coords with e_above_hull from cached hull model (before filtering)
|
|
251
193
|
const all_enriched_entries = $derived.by(() => {
|
|
252
194
|
if (coords_entries.length === 0) return []
|
|
253
|
-
if (energy_mode !== `on-the-fly`) return coords_entries
|
|
195
|
+
if (hull_data.energy_mode !== `on-the-fly`) return coords_entries
|
|
254
196
|
const pts = coords_entries.map(({ x, y, z }) => ({ x, y, z }))
|
|
255
197
|
const raw_dists = thermo.compute_e_above_hull_for_points(pts, hull_model)
|
|
198
|
+
// non-finite distance (no covering hull face) -> unknown, handled by compute_hull_stability
|
|
256
199
|
return coords_entries.map((entry, idx) => ({
|
|
257
|
-
...entry,
|
|
200
|
+
...entry,
|
|
201
|
+
...compute_hull_stability(raw_dists[idx], entry.exclude_from_hull),
|
|
258
202
|
}))
|
|
259
203
|
})
|
|
260
204
|
|
|
261
|
-
// Auto threshold: show all for few entries, use default for many, interpolate between
|
|
262
|
-
const max_hull_dist_in_data = $derived(
|
|
263
|
-
helpers.calc_max_hull_dist_in_data(all_enriched_entries),
|
|
264
|
-
)
|
|
265
|
-
const auto_default_threshold = $derived(helpers.compute_auto_hull_dist_threshold(
|
|
266
|
-
all_enriched_entries.length,
|
|
267
|
-
max_hull_dist_in_data,
|
|
268
|
-
DEFAULTS.convex_hull.ternary.max_hull_dist_show_phases,
|
|
269
|
-
))
|
|
270
|
-
|
|
271
|
-
const next_auto_threshold = helpers.auto_threshold_reset(
|
|
272
|
-
DEFAULTS.convex_hull.ternary.max_hull_dist_show_phases,
|
|
273
|
-
)
|
|
274
|
-
$effect(() => {
|
|
275
|
-
max_hull_dist_show_phases = next_auto_threshold(
|
|
276
|
-
entries,
|
|
277
|
-
max_hull_dist_show_phases,
|
|
278
|
-
auto_default_threshold,
|
|
279
|
-
) ?? max_hull_dist_show_phases
|
|
280
|
-
})
|
|
281
|
-
|
|
282
|
-
// Filter by threshold; visibility is a view predicate, not entry state.
|
|
283
|
-
const plot_entries = $derived(
|
|
284
|
-
all_enriched_entries.filter((entry) =>
|
|
285
|
-
(entry.e_above_hull ?? 0) <= max_hull_dist_show_phases
|
|
286
|
-
),
|
|
287
|
-
)
|
|
288
|
-
const visible_entries = $derived(helpers.visible_entries(
|
|
289
|
-
plot_entries,
|
|
290
|
-
show_stable,
|
|
291
|
-
show_unstable,
|
|
292
|
-
))
|
|
293
|
-
|
|
294
|
-
$effect(() => {
|
|
295
|
-
stable_entries = plot_entries.filter(helpers.entry_is_stable)
|
|
296
|
-
unstable_entries = plot_entries.filter(helpers.entry_is_unstable)
|
|
297
|
-
})
|
|
298
|
-
|
|
299
205
|
// Canvas rendering
|
|
300
206
|
let canvas: HTMLCanvasElement | undefined = undefined
|
|
301
207
|
let ctx: CanvasRenderingContext2D | null = null
|
|
302
208
|
|
|
303
|
-
// Performance optimization
|
|
304
|
-
let frame_id = 0
|
|
305
|
-
|
|
306
209
|
const camera_default = {
|
|
307
210
|
elevation: DEFAULTS.convex_hull.ternary.camera_elevation,
|
|
308
211
|
azimuth: DEFAULTS.convex_hull.ternary.camera_azimuth,
|
|
@@ -322,23 +225,11 @@
|
|
|
322
225
|
let gizmo_active = $state(false)
|
|
323
226
|
|
|
324
227
|
// Convert elevation/azimuth (degrees) to Three.js camera position + up vector.
|
|
325
|
-
function gizmo_camera(
|
|
326
|
-
elev_deg: number,
|
|
327
|
-
azim_deg: number,
|
|
328
|
-
): { position: Vec3; up: Vec3 } {
|
|
228
|
+
function gizmo_camera(elev_deg: number, azim_deg: number): { position: Vec3; up: Vec3 } {
|
|
329
229
|
const [elev, azim] = [to_radians(elev_deg), to_radians(azim_deg)]
|
|
330
|
-
const [se, ce, sa, ca] = [
|
|
331
|
-
Math.sin(elev),
|
|
332
|
-
Math.cos(elev),
|
|
333
|
-
Math.sin(azim),
|
|
334
|
-
Math.cos(azim),
|
|
335
|
-
]
|
|
230
|
+
const [se, ce, sa, ca] = [Math.sin(elev), Math.cos(elev), Math.sin(azim), Math.cos(azim)]
|
|
336
231
|
return {
|
|
337
|
-
position: [
|
|
338
|
-
-sa * se * GIZMO_CAM_DIST,
|
|
339
|
-
-ca * se * GIZMO_CAM_DIST,
|
|
340
|
-
ce * GIZMO_CAM_DIST,
|
|
341
|
-
],
|
|
232
|
+
position: [-sa * se * GIZMO_CAM_DIST, -ca * se * GIZMO_CAM_DIST, ce * GIZMO_CAM_DIST],
|
|
342
233
|
up: [sa * ce, ca * ce, se],
|
|
343
234
|
}
|
|
344
235
|
}
|
|
@@ -354,7 +245,7 @@
|
|
|
354
245
|
camera.center_x = 0
|
|
355
246
|
// 0.6 matches the draw_data_points() scale factor that maps data coords to canvas pixels
|
|
356
247
|
const scale = Math.min(canvas_dims.width, canvas_dims.height) * 0.6 * camera.zoom
|
|
357
|
-
camera.center_y = Math.sqrt(3) / 12 * scale * Math.cos(to_radians(elev_deg))
|
|
248
|
+
camera.center_y = (Math.sqrt(3) / 12) * scale * Math.cos(to_radians(elev_deg))
|
|
358
249
|
}
|
|
359
250
|
|
|
360
251
|
// Sync: ConvexHull3D → Three.js gizmo camera (on main canvas drag)
|
|
@@ -374,14 +265,15 @@
|
|
|
374
265
|
const cam = gizmo_cam_ref
|
|
375
266
|
if (!cam) return
|
|
376
267
|
const { x: cx, y: cy, z: cz } = cam.position
|
|
377
|
-
const dist = Math.
|
|
268
|
+
const dist = Math.hypot(cx, cy, cz)
|
|
378
269
|
if (dist < 1e-6) return
|
|
379
270
|
const elev_rad = Math.acos(Math.max(-1, Math.min(1, cz / dist)))
|
|
380
271
|
const sin_elev = Math.sin(elev_rad)
|
|
381
|
-
const azim_deg =
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
272
|
+
const azim_deg =
|
|
273
|
+
Math.abs(sin_elev) > 1e-6
|
|
274
|
+
? (Math.atan2(-cx / (dist * sin_elev), -cy / (dist * sin_elev)) * 180) / Math.PI
|
|
275
|
+
: 0
|
|
276
|
+
const elev_deg = (elev_rad * 180) / Math.PI
|
|
385
277
|
camera.elevation = elev_deg
|
|
386
278
|
camera.azimuth = azim_deg
|
|
387
279
|
center_camera(elev_deg)
|
|
@@ -389,14 +281,15 @@
|
|
|
389
281
|
|
|
390
282
|
// Gizmo axis colors (constant — AXIS_COLORS/NEG_AXIS_COLORS never change)
|
|
391
283
|
const gizmo_axis_options = Object.fromEntries(
|
|
392
|
-
[...AXIS_COLORS, ...NEG_AXIS_COLORS].map((
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
284
|
+
[...AXIS_COLORS, ...NEG_AXIS_COLORS].map(([axis, color, hover_color]) => [
|
|
285
|
+
axis,
|
|
286
|
+
{
|
|
287
|
+
color,
|
|
288
|
+
labelColor: `#111`,
|
|
289
|
+
opacity: 0.85,
|
|
290
|
+
hover: { color: hover_color, labelColor: `#222`, opacity: 1 },
|
|
291
|
+
},
|
|
292
|
+
]),
|
|
400
293
|
)
|
|
401
294
|
|
|
402
295
|
// Extract placement from gizmo options (not a Threlte Gizmo prop)
|
|
@@ -418,43 +311,64 @@
|
|
|
418
311
|
}
|
|
419
312
|
})
|
|
420
313
|
|
|
421
|
-
//
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
314
|
+
// Shared canvas-interaction scaffold (mouse/keyboard handlers, hover/drag/popup
|
|
315
|
+
// state, canvas sizing, render scheduler). Rotation math + keydown actions stay local.
|
|
316
|
+
const interactions = create_canvas_interactions({
|
|
317
|
+
wheel_clamp: [0.5, 10],
|
|
318
|
+
fullscreen_bg_var: `--hull-3d-bg-fullscreen`,
|
|
319
|
+
canvas: () => canvas,
|
|
320
|
+
wrapper: () => wrapper,
|
|
321
|
+
ctx: () => ctx,
|
|
322
|
+
set_ctx: (context) => (ctx = context),
|
|
323
|
+
set_canvas_dims: (dims) => (canvas_dims = dims),
|
|
324
|
+
visible_entries: () => visible_entries,
|
|
325
|
+
plot_entries: () => plot_entries,
|
|
326
|
+
selected_entry: () => selected_entry,
|
|
327
|
+
set_selected_entry: (entry) => (selected_entry = entry),
|
|
328
|
+
fullscreen: () => fullscreen,
|
|
329
|
+
enable_click_selection: () => enable_click_selection,
|
|
330
|
+
enable_structure_preview: () => enable_structure_preview,
|
|
331
|
+
on_point_click: () => on_point_click,
|
|
332
|
+
on_point_hover: () => on_point_hover,
|
|
333
|
+
on_file_drop: () => on_file_drop,
|
|
334
|
+
entry_category: () => entry_category,
|
|
335
|
+
zoom: () => camera.zoom,
|
|
336
|
+
set_zoom: (zoom) => (camera.zoom = zoom),
|
|
337
|
+
project_point: project_3d_point,
|
|
338
|
+
extract_structure: extract_structure_from_entry,
|
|
339
|
+
render_frame,
|
|
340
|
+
on_drag: (dx, dy, panning) => {
|
|
341
|
+
if (panning) {
|
|
342
|
+
camera.center_x += dx
|
|
343
|
+
camera.center_y += dy
|
|
344
|
+
} else {
|
|
345
|
+
// Horizontal drag -> azimuth rotation around z-axis
|
|
346
|
+
camera.azimuth += dx * 0.3 // Positive dx (drag right) rotates clockwise
|
|
347
|
+
// Vertical drag -> elevation angle (full range)
|
|
348
|
+
camera.elevation -= dy * 0.3 // Positive dy (drag down) tilts view down
|
|
455
349
|
}
|
|
456
|
-
}
|
|
350
|
+
},
|
|
351
|
+
// Reset pan center when entering/exiting fullscreen
|
|
352
|
+
on_fullscreen_change: () => {
|
|
353
|
+
camera.center_x = 0
|
|
354
|
+
camera.center_y = -50
|
|
355
|
+
},
|
|
356
|
+
actions: () => ({
|
|
357
|
+
r: reset_camera,
|
|
358
|
+
t: () => {
|
|
359
|
+
camera.elevation = 0
|
|
360
|
+
camera.azimuth = 0
|
|
361
|
+
center_camera(0)
|
|
362
|
+
},
|
|
363
|
+
b: () => (color_mode = color_mode === `stability` ? `energy` : `stability`),
|
|
364
|
+
s: () => (show_stable = !show_stable),
|
|
365
|
+
u: () => (show_unstable = !show_unstable),
|
|
366
|
+
h: () => (show_hull_faces = !show_hull_faces),
|
|
367
|
+
l: () => (show_stable_labels = !show_stable_labels),
|
|
368
|
+
}),
|
|
457
369
|
})
|
|
370
|
+
const { render_once } = interactions
|
|
371
|
+
const sorted_points_cache = $derived(interactions.sorted_points_cache)
|
|
458
372
|
|
|
459
373
|
// Hull face color (customizable via controls)
|
|
460
374
|
let hull_face_color = $state(`#4caf50`)
|
|
@@ -467,9 +381,7 @@
|
|
|
467
381
|
let pulse_opacity = $derived(0.3 + 0.4 * pulse.unit)
|
|
468
382
|
|
|
469
383
|
// Merge highlight style with defaults
|
|
470
|
-
const merged_highlight_style = $derived(
|
|
471
|
-
helpers.merge_highlight_style(highlight_style),
|
|
472
|
-
)
|
|
384
|
+
const merged_highlight_style = $derived(helpers.merge_highlight_style(highlight_style))
|
|
473
385
|
|
|
474
386
|
// Helper to check if entry is highlighted
|
|
475
387
|
const is_highlighted = (entry: ConvexHullEntry): boolean =>
|
|
@@ -478,17 +390,14 @@
|
|
|
478
390
|
// Re-render when important state changes
|
|
479
391
|
$effect(() => {
|
|
480
392
|
// oxfmt-ignore
|
|
481
|
-
void [show_hull_faces, color_mode, color_scale, show_stable_labels, show_unstable_labels, max_hull_dist_show_labels, camera.elevation, camera.azimuth, camera.zoom, camera.center_x, camera.center_y, plot_entries, hull_face_color, hull_face_opacity, hull_face_color_mode, element_colors, highlighted_entries, text_color] // track reactively
|
|
393
|
+
void [show_hull_faces, color_mode, color_scale, show_stable_labels, show_unstable_labels, max_hull_dist_show_labels, camera.elevation, camera.azimuth, camera.zoom, camera.center_x, camera.center_y, plot_entries, visible_entries, hull_face_color, hull_face_opacity, hull_face_color_mode, element_colors, highlighted_entries, text_color] // track reactively
|
|
482
394
|
|
|
483
395
|
render_once()
|
|
484
396
|
})
|
|
485
397
|
|
|
486
|
-
//
|
|
487
|
-
function extract_structure_from_entry(
|
|
488
|
-
|
|
489
|
-
): AnyStructure | null {
|
|
490
|
-
const orig_entry = entries.find((ent) => ent.entry_id === entry.entry_id)
|
|
491
|
-
return orig_entry?.structure as AnyStructure || null
|
|
398
|
+
// function (not const) so the create_canvas_interactions options above can reference it
|
|
399
|
+
function extract_structure_from_entry(entry: ConvexHullEntry): AnyStructure | null {
|
|
400
|
+
return helpers.extract_structure_from_entry(entries, entry)
|
|
492
401
|
}
|
|
493
402
|
|
|
494
403
|
const reset_camera = () => Object.assign(camera, camera_default)
|
|
@@ -496,16 +405,17 @@
|
|
|
496
405
|
reset_camera()
|
|
497
406
|
fullscreen = DEFAULTS.convex_hull.ternary.fullscreen
|
|
498
407
|
info_pane_open = DEFAULTS.convex_hull.ternary.info_pane_open
|
|
499
|
-
|
|
408
|
+
controls_open = DEFAULTS.convex_hull.ternary.legend_pane_open
|
|
500
409
|
color_mode = DEFAULTS.convex_hull.ternary.color_mode
|
|
501
410
|
color_scale = DEFAULTS.convex_hull.ternary.color_scale as D3InterpolateName
|
|
502
411
|
show_stable = DEFAULTS.convex_hull.ternary.show_stable
|
|
503
412
|
show_unstable = DEFAULTS.convex_hull.ternary.show_unstable
|
|
413
|
+
hidden_categories = []
|
|
504
414
|
show_stable_labels = DEFAULTS.convex_hull.ternary.show_stable_labels
|
|
505
415
|
show_unstable_labels = DEFAULTS.convex_hull.ternary.show_unstable_labels
|
|
506
416
|
max_hull_dist_show_labels = DEFAULTS.convex_hull.ternary.max_hull_dist_show_labels
|
|
507
417
|
// Use auto-computed threshold based on entry count instead of static default
|
|
508
|
-
max_hull_dist_show_phases = auto_default_threshold
|
|
418
|
+
max_hull_dist_show_phases = hull_data.auto_default_threshold
|
|
509
419
|
show_hull_faces = DEFAULTS.convex_hull.ternary.show_hull_faces
|
|
510
420
|
hull_face_color = DEFAULTS.convex_hull.ternary.hull_face_color
|
|
511
421
|
hull_face_opacity = DEFAULTS.convex_hull.ternary.hull_face_opacity
|
|
@@ -513,75 +423,6 @@
|
|
|
513
423
|
.hull_face_color_mode as HullFaceColorMode
|
|
514
424
|
}
|
|
515
425
|
|
|
516
|
-
const handle_keydown = (event: KeyboardEvent) => {
|
|
517
|
-
const target = event.target
|
|
518
|
-
if (target instanceof HTMLElement && target.tagName.match(/INPUT|TEXTAREA/)) return
|
|
519
|
-
|
|
520
|
-
// Stop propagation if event came from canvas to prevent wrapper's handler
|
|
521
|
-
// from running again (both have onkeydown, causing duplicate handling)
|
|
522
|
-
if (target === canvas) {
|
|
523
|
-
event.stopPropagation()
|
|
524
|
-
}
|
|
525
|
-
|
|
526
|
-
if (event.key === `Escape` && modal_open) {
|
|
527
|
-
close_structure_popup()
|
|
528
|
-
return
|
|
529
|
-
}
|
|
530
|
-
|
|
531
|
-
// Handle Enter for keyboard accessibility - select hovered entry
|
|
532
|
-
if (event.key === `Enter`) {
|
|
533
|
-
const entry = hover_data?.entry
|
|
534
|
-
if (entry) {
|
|
535
|
-
on_point_click?.(entry)
|
|
536
|
-
if (enable_click_selection) {
|
|
537
|
-
selected_entry = entry
|
|
538
|
-
if (enable_structure_preview) {
|
|
539
|
-
const structure = extract_structure_from_entry(entry)
|
|
540
|
-
if (structure) {
|
|
541
|
-
selected_structure = structure
|
|
542
|
-
modal_place_right = helpers.calculate_modal_side(wrapper)
|
|
543
|
-
modal_open = true
|
|
544
|
-
}
|
|
545
|
-
}
|
|
546
|
-
}
|
|
547
|
-
} else if (modal_open) {
|
|
548
|
-
close_structure_popup()
|
|
549
|
-
}
|
|
550
|
-
return
|
|
551
|
-
}
|
|
552
|
-
|
|
553
|
-
const actions: Record<string, () => void> = {
|
|
554
|
-
r: reset_camera,
|
|
555
|
-
t: () => {
|
|
556
|
-
camera.elevation = 0
|
|
557
|
-
camera.azimuth = 0
|
|
558
|
-
center_camera(0)
|
|
559
|
-
},
|
|
560
|
-
b: () => color_mode = color_mode === `stability` ? `energy` : `stability`,
|
|
561
|
-
s: () => show_stable = !show_stable,
|
|
562
|
-
u: () => show_unstable = !show_unstable,
|
|
563
|
-
h: () => show_hull_faces = !show_hull_faces,
|
|
564
|
-
l: () => show_stable_labels = !show_stable_labels,
|
|
565
|
-
}
|
|
566
|
-
actions[event.key.toLowerCase()]?.()
|
|
567
|
-
}
|
|
568
|
-
|
|
569
|
-
async function handle_file_drop(event: DragEvent): Promise<void> {
|
|
570
|
-
drag_over = false
|
|
571
|
-
const data = await helpers.parse_hull_entries_from_drop(event)
|
|
572
|
-
if (data) on_file_drop?.(data)
|
|
573
|
-
}
|
|
574
|
-
|
|
575
|
-
async function copy_entry_data(
|
|
576
|
-
entry: ConvexHullEntry,
|
|
577
|
-
position: { x: number; y: number },
|
|
578
|
-
) {
|
|
579
|
-
await helpers.copy_entry_to_clipboard(entry, position, (visible, pos) => {
|
|
580
|
-
copy_feedback.visible = visible
|
|
581
|
-
copy_feedback.position = pos
|
|
582
|
-
})
|
|
583
|
-
}
|
|
584
|
-
|
|
585
426
|
const get_point_color = (entry: ConvexHullEntry): string =>
|
|
586
427
|
helpers.get_point_color_for_entry(
|
|
587
428
|
entry,
|
|
@@ -592,7 +433,7 @@
|
|
|
592
433
|
|
|
593
434
|
// Cache energy color scale per frame/setting
|
|
594
435
|
const energy_color_scale = $derived.by(() =>
|
|
595
|
-
helpers.get_energy_color_scale(color_mode, color_scale, plot_entries)
|
|
436
|
+
helpers.get_energy_color_scale(color_mode, color_scale, plot_entries),
|
|
596
437
|
)
|
|
597
438
|
|
|
598
439
|
// Convex hull statistics - compute internally and expose via bindable prop
|
|
@@ -608,10 +449,7 @@
|
|
|
608
449
|
): { x: number; y: number; depth: number } {
|
|
609
450
|
if (!canvas) return { x: 0, y: 0, depth: 0 }
|
|
610
451
|
|
|
611
|
-
const [elev, azim] = [
|
|
612
|
-
(camera.elevation * Math.PI) / 180,
|
|
613
|
-
(camera.azimuth * Math.PI) / 180,
|
|
614
|
-
]
|
|
452
|
+
const [elev, azim] = [(camera.elevation * Math.PI) / 180, (camera.azimuth * Math.PI) / 180]
|
|
615
453
|
const [cos_az, sin_az, cos_el, sin_el] = [
|
|
616
454
|
Math.cos(azim),
|
|
617
455
|
Math.sin(azim),
|
|
@@ -666,10 +504,7 @@
|
|
|
666
504
|
ctx.stroke()
|
|
667
505
|
|
|
668
506
|
// Draw vertical edges from corners (from most negative to 0 formation energy)
|
|
669
|
-
const vertical_edges = get_triangle_vertical_edges(
|
|
670
|
-
e_form_min,
|
|
671
|
-
e_form_max,
|
|
672
|
-
)
|
|
507
|
+
const vertical_edges = get_triangle_vertical_edges(e_form_min, e_form_max)
|
|
673
508
|
ctx.beginPath()
|
|
674
509
|
for (const [v1, v2] of vertical_edges) {
|
|
675
510
|
const proj1 = project_3d_point(v1.x, v1.y, v1.z)
|
|
@@ -710,15 +545,11 @@
|
|
|
710
545
|
ctx.textAlign = `center`
|
|
711
546
|
ctx.textBaseline = `middle`
|
|
712
547
|
|
|
713
|
-
for (
|
|
714
|
-
let idx = 0;
|
|
715
|
-
idx < TRIANGLE_VERTICES.length && idx < elements.length;
|
|
716
|
-
idx++
|
|
717
|
-
) {
|
|
548
|
+
for (let idx = 0; idx < TRIANGLE_VERTICES.length && idx < elements.length; idx++) {
|
|
718
549
|
const [x, y] = TRIANGLE_VERTICES[idx]
|
|
719
550
|
const dx = x - centroid.x
|
|
720
551
|
const dy = y - centroid.y
|
|
721
|
-
const length = Math.
|
|
552
|
+
const length = Math.hypot(dx, dy)
|
|
722
553
|
const distance = 0.05
|
|
723
554
|
|
|
724
555
|
const label_pos = {
|
|
@@ -744,14 +575,10 @@
|
|
|
744
575
|
|
|
745
576
|
// Find the vertex that projects to the leftmost x-position (changes with rotation)
|
|
746
577
|
const projected_vertices = TRIANGLE_VERTICES.map(([vx, vy]) =>
|
|
747
|
-
project_3d_point(vx, vy, e_mid)
|
|
578
|
+
project_3d_point(vx, vy, e_mid),
|
|
748
579
|
)
|
|
749
580
|
const leftmost_idx = projected_vertices.reduce(
|
|
750
|
-
(
|
|
751
|
-
min_idx,
|
|
752
|
-
proj,
|
|
753
|
-
idx,
|
|
754
|
-
) => (proj.x < projected_vertices[min_idx].x ? idx : min_idx),
|
|
581
|
+
(min_idx, proj, idx) => (proj.x < projected_vertices[min_idx].x ? idx : min_idx),
|
|
755
582
|
0,
|
|
756
583
|
)
|
|
757
584
|
const [axis_x, axis_y] = TRIANGLE_VERTICES[leftmost_idx]
|
|
@@ -815,10 +642,8 @@
|
|
|
815
642
|
let energy_face_scale: ((val: number) => string) | null = null
|
|
816
643
|
let min_face_e_form = 0
|
|
817
644
|
if (hull_face_color_mode === `formation_energy`) {
|
|
818
|
-
const all_e_form = hull_faces.flatMap((tri) =>
|
|
819
|
-
|
|
820
|
-
)
|
|
821
|
-
min_face_e_form = Math.min(...all_e_form)
|
|
645
|
+
const all_e_form = hull_faces.flatMap((tri) => tri.vertices.map((vertex) => vertex.z))
|
|
646
|
+
min_face_e_form = helpers.array_min(all_e_form)
|
|
822
647
|
energy_face_scale = helpers.get_energy_color_scale(
|
|
823
648
|
`energy`,
|
|
824
649
|
color_scale,
|
|
@@ -829,10 +654,7 @@
|
|
|
829
654
|
}
|
|
830
655
|
|
|
831
656
|
// Helper to get face color based on mode
|
|
832
|
-
const get_face_color = (
|
|
833
|
-
tri: typeof hull_faces[0],
|
|
834
|
-
tri_idx: number,
|
|
835
|
-
): string => {
|
|
657
|
+
const get_face_color = (tri: (typeof hull_faces)[0], tri_idx: number): string => {
|
|
836
658
|
if (hull_face_color_mode === `uniform`) {
|
|
837
659
|
return hull_face_color
|
|
838
660
|
}
|
|
@@ -841,12 +663,14 @@
|
|
|
841
663
|
return energy_face_scale?.(avg_e_form - min_face_e_form) ?? hull_face_color
|
|
842
664
|
}
|
|
843
665
|
if (hull_face_color_mode === `dominant_element`) {
|
|
844
|
-
// Find element vertex closest to face centroid in 2D ternary space
|
|
666
|
+
// Find element vertex closest to face centroid in 2D ternary space (single-pass argmin)
|
|
845
667
|
const { x: cx, y: cy } = tri.centroid
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
668
|
+
let [closest_idx, min_dist] = [0, Infinity]
|
|
669
|
+
for (const [idx, [tx, ty]] of TRIANGLE_VERTICES.entries()) {
|
|
670
|
+
const dist = Math.hypot(cx - tx, cy - ty)
|
|
671
|
+
if (dist < min_dist) [closest_idx, min_dist] = [idx, dist]
|
|
672
|
+
}
|
|
673
|
+
const el = elements[closest_idx]
|
|
850
674
|
return element_colors[el] ?? `#888888`
|
|
851
675
|
}
|
|
852
676
|
if (hull_face_color_mode === `facet_index`) {
|
|
@@ -857,11 +681,7 @@
|
|
|
857
681
|
|
|
858
682
|
// Sort faces by depth for proper rendering
|
|
859
683
|
const faces_with_depth = hull_faces.map((tri, tri_idx) => {
|
|
860
|
-
const centroid_proj = project_3d_point(
|
|
861
|
-
tri.centroid.x,
|
|
862
|
-
tri.centroid.y,
|
|
863
|
-
tri.centroid.z,
|
|
864
|
-
)
|
|
684
|
+
const centroid_proj = project_3d_point(tri.centroid.x, tri.centroid.y, tri.centroid.z)
|
|
865
685
|
return { tri, tri_idx, depth: centroid_proj.depth }
|
|
866
686
|
})
|
|
867
687
|
|
|
@@ -886,16 +706,21 @@
|
|
|
886
706
|
const a3 = norm_alpha?.(p3.z) ?? 0
|
|
887
707
|
|
|
888
708
|
// Solve a*x + b*y + c = alpha at the three projected vertices
|
|
889
|
-
const x1 = proj1.x,
|
|
890
|
-
|
|
891
|
-
const
|
|
709
|
+
const x1 = proj1.x,
|
|
710
|
+
y1 = proj1.y
|
|
711
|
+
const x2 = proj2.x,
|
|
712
|
+
y2 = proj2.y
|
|
713
|
+
const x3 = proj3.x,
|
|
714
|
+
y3 = proj3.y
|
|
892
715
|
const det = x1 * (y2 - y3) + x2 * (y3 - y1) + x3 * (y1 - y2)
|
|
893
|
-
let coef_a = 0,
|
|
716
|
+
let coef_a = 0,
|
|
717
|
+
coef_b = 0,
|
|
718
|
+
coef_c = (a1 + a2 + a3) / 3
|
|
894
719
|
if (Math.abs(det) > 1e-9) {
|
|
895
720
|
coef_a = (a1 * (y2 - y3) + a2 * (y3 - y1) + a3 * (y1 - y2)) / det
|
|
896
721
|
coef_b = (a1 * (x3 - x2) + a2 * (x1 - x3) + a3 * (x2 - x1)) / det
|
|
897
|
-
coef_c =
|
|
898
|
-
a3 * (x1 * y2 - x2 * y1)) /
|
|
722
|
+
coef_c =
|
|
723
|
+
(a1 * (x2 * y3 - x3 * y2) + a2 * (x3 * y1 - x1 * y3) + a3 * (x1 * y2 - x2 * y1)) /
|
|
899
724
|
det
|
|
900
725
|
}
|
|
901
726
|
|
|
@@ -962,7 +787,7 @@
|
|
|
962
787
|
}
|
|
963
788
|
|
|
964
789
|
// Formation energy color bar helpers
|
|
965
|
-
const e_form_range = $derived.by(():
|
|
790
|
+
const e_form_range = $derived.by((): Vec2 => {
|
|
966
791
|
const min_fe = plot_entries.length > 0 ? energy_range.min : -1
|
|
967
792
|
return [min_fe, 0]
|
|
968
793
|
})
|
|
@@ -972,7 +797,7 @@
|
|
|
972
797
|
const denom = Math.max(1e-6, max_fe - min_fe)
|
|
973
798
|
return (value: number) => {
|
|
974
799
|
// alpha 0 at 0 eV, goes to hull_face_opacity at most negative energy
|
|
975
|
-
const energy_fraction =
|
|
800
|
+
const energy_fraction = clamp01((value - min_fe) / denom)
|
|
976
801
|
const alpha = (1 - energy_fraction) * hull_face_opacity
|
|
977
802
|
return add_alpha(hull_face_color, alpha)
|
|
978
803
|
}
|
|
@@ -980,59 +805,16 @@
|
|
|
980
805
|
|
|
981
806
|
function draw_data_points(): void {
|
|
982
807
|
if (!ctx || sorted_points_cache.length === 0) return
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
ctx.fillStyle = `rgba(0, 0, 0, 0.2)`
|
|
994
|
-
const shadow_path = helpers.create_marker_path(size * 0.8, marker)
|
|
995
|
-
ctx.save()
|
|
996
|
-
ctx.translate(projected.x + shadow_offset, projected.y + shadow_offset)
|
|
997
|
-
ctx.fill(shadow_path)
|
|
998
|
-
ctx.restore()
|
|
999
|
-
|
|
1000
|
-
// Highlights
|
|
1001
|
-
if (selected_entry && entry.entry_id === selected_entry.entry_id) {
|
|
1002
|
-
helpers.draw_selection_highlight(
|
|
1003
|
-
ctx,
|
|
1004
|
-
projected,
|
|
1005
|
-
size,
|
|
1006
|
-
canvas_dims.scale,
|
|
1007
|
-
pulse.time,
|
|
1008
|
-
pulse_opacity,
|
|
1009
|
-
)
|
|
1010
|
-
}
|
|
1011
|
-
if (is_entry_highlighted) {
|
|
1012
|
-
helpers.draw_highlight_effect(
|
|
1013
|
-
ctx,
|
|
1014
|
-
projected,
|
|
1015
|
-
size,
|
|
1016
|
-
canvas_dims.scale,
|
|
1017
|
-
pulse.time,
|
|
1018
|
-
merged_highlight_style,
|
|
1019
|
-
)
|
|
1020
|
-
}
|
|
1021
|
-
|
|
1022
|
-
// Main point with marker symbol
|
|
1023
|
-
ctx.fillStyle =
|
|
1024
|
-
is_entry_highlighted && merged_highlight_style.effect === `color`
|
|
1025
|
-
? merged_highlight_style.color
|
|
1026
|
-
: color
|
|
1027
|
-
ctx.strokeStyle = is_stable ? `#ffffff` : `#000000`
|
|
1028
|
-
ctx.lineWidth = 0.5 * canvas_dims.scale
|
|
1029
|
-
const marker_path = helpers.create_marker_path(size, marker)
|
|
1030
|
-
ctx.save()
|
|
1031
|
-
ctx.translate(projected.x, projected.y)
|
|
1032
|
-
ctx.fill(marker_path)
|
|
1033
|
-
ctx.stroke(marker_path)
|
|
1034
|
-
ctx.restore()
|
|
1035
|
-
}
|
|
808
|
+
helpers.draw_hull_points(ctx, sorted_points_cache, {
|
|
809
|
+
scale: canvas_dims.scale,
|
|
810
|
+
shadow_factor: 0.1,
|
|
811
|
+
selected_entry,
|
|
812
|
+
is_highlighted,
|
|
813
|
+
get_point_color,
|
|
814
|
+
highlight_style: merged_highlight_style,
|
|
815
|
+
pulse_time: pulse.time,
|
|
816
|
+
pulse_opacity,
|
|
817
|
+
})
|
|
1036
818
|
}
|
|
1037
819
|
|
|
1038
820
|
const hull_label_font_size = 12
|
|
@@ -1129,18 +911,21 @@
|
|
|
1129
911
|
ctx.textBaseline = `top`
|
|
1130
912
|
const label_height = hull_label_font_size + 2
|
|
1131
913
|
|
|
1132
|
-
const label_entries = helpers
|
|
1133
|
-
|
|
1134
|
-
|
|
1135
|
-
|
|
1136
|
-
|
|
1137
|
-
(
|
|
1138
|
-
(
|
|
1139
|
-
|
|
1140
|
-
|
|
914
|
+
const label_entries = helpers
|
|
915
|
+
.get_composition_label_entries(
|
|
916
|
+
visible_entries.filter((entry) => {
|
|
917
|
+
if (entry.is_element) return false
|
|
918
|
+
const is_stable_point = helpers.entry_is_stable(entry)
|
|
919
|
+
return (
|
|
920
|
+
(is_stable_point && show_stable_labels) ||
|
|
921
|
+
(!is_stable_point &&
|
|
922
|
+
show_unstable_labels &&
|
|
923
|
+
(entry.e_above_hull ?? 0) <= max_hull_dist_show_labels)
|
|
924
|
+
)
|
|
925
|
+
}),
|
|
926
|
+
)
|
|
1141
927
|
.sort((entry_1, entry_2) => {
|
|
1142
|
-
const energy_diff = label_priority_energy(entry_1) -
|
|
1143
|
-
label_priority_energy(entry_2)
|
|
928
|
+
const energy_diff = label_priority_energy(entry_1) - label_priority_energy(entry_2)
|
|
1144
929
|
if (energy_diff !== 0) return energy_diff
|
|
1145
930
|
return (entry_1.e_above_hull ?? 0) - (entry_2.e_above_hull ?? 0)
|
|
1146
931
|
})
|
|
@@ -1160,17 +945,13 @@
|
|
|
1160
945
|
const is_stable_point = helpers.entry_is_stable(entry)
|
|
1161
946
|
const point_size = (entry.size || (is_stable_point ? 6 : 4)) * canvas_dims.scale
|
|
1162
947
|
const text_width = measure_formula_segments(ctx, formula_segments)
|
|
1163
|
-
const placements = get_label_placements(
|
|
1164
|
-
|
|
1165
|
-
|
|
1166
|
-
|
|
1167
|
-
|
|
1168
|
-
|
|
1169
|
-
|
|
1170
|
-
rect_within_rect(candidate.rect, canvas_rect) &&
|
|
1171
|
-
!occupied_rects.some((occupied_rect) =>
|
|
1172
|
-
rects_overlap(candidate.rect, occupied_rect)
|
|
1173
|
-
)
|
|
948
|
+
const placements = get_label_placements(projected, point_size, text_width, label_height)
|
|
949
|
+
const placement = placements.find(
|
|
950
|
+
(candidate) =>
|
|
951
|
+
rect_within_rect(candidate.rect, canvas_rect) &&
|
|
952
|
+
!occupied_rects.some((occupied_rect) =>
|
|
953
|
+
rects_overlap(candidate.rect, occupied_rect),
|
|
954
|
+
),
|
|
1174
955
|
)
|
|
1175
956
|
if (!placement) continue
|
|
1176
957
|
|
|
@@ -1216,180 +997,11 @@
|
|
|
1216
997
|
draw_element_labels()
|
|
1217
998
|
}
|
|
1218
999
|
|
|
1219
|
-
function handle_mouse_down(event: MouseEvent) {
|
|
1220
|
-
is_dragging = true
|
|
1221
|
-
drag_started = false
|
|
1222
|
-
hover_data = null
|
|
1223
|
-
on_point_hover?.(null)
|
|
1224
|
-
last_mouse = { x: event.clientX, y: event.clientY }
|
|
1225
|
-
}
|
|
1226
|
-
|
|
1227
|
-
const handle_mouse_move = (event: MouseEvent) => {
|
|
1228
|
-
if (!is_dragging) return
|
|
1229
|
-
const [dx, dy] = [event.clientX - last_mouse.x, event.clientY - last_mouse.y]
|
|
1230
|
-
|
|
1231
|
-
// Mark as drag if any movement occurred
|
|
1232
|
-
if (dx !== 0 || dy !== 0) drag_started = true
|
|
1233
|
-
|
|
1234
|
-
// With Cmd/Ctrl held: pan the view instead of rotating
|
|
1235
|
-
if (event.metaKey || event.ctrlKey) {
|
|
1236
|
-
camera.center_x += dx
|
|
1237
|
-
camera.center_y += dy
|
|
1238
|
-
} else {
|
|
1239
|
-
// Horizontal drag -> azimuth rotation around z-axis
|
|
1240
|
-
camera.azimuth += dx * 0.3 // Positive dx (drag right) rotates clockwise
|
|
1241
|
-
|
|
1242
|
-
// Vertical drag -> elevation angle (full range)
|
|
1243
|
-
camera.elevation -= dy * 0.3 // Positive dy (drag down) tilts view down
|
|
1244
|
-
}
|
|
1245
|
-
|
|
1246
|
-
last_mouse = { x: event.clientX, y: event.clientY }
|
|
1247
|
-
}
|
|
1248
|
-
|
|
1249
|
-
const handle_wheel = (event: WheelEvent) => {
|
|
1250
|
-
event.preventDefault()
|
|
1251
|
-
camera.zoom = Math.max(
|
|
1252
|
-
0.5,
|
|
1253
|
-
Math.min(10, camera.zoom * (event.deltaY > 0 ? 0.98 : 1.02)),
|
|
1254
|
-
)
|
|
1255
|
-
}
|
|
1256
|
-
|
|
1257
|
-
const handle_hover = (event: MouseEvent) => {
|
|
1258
|
-
if (is_dragging) return
|
|
1259
|
-
const entry = find_entry_at_mouse(event)
|
|
1260
|
-
hover_data = entry
|
|
1261
|
-
? { entry, position: { x: event.clientX, y: event.clientY } }
|
|
1262
|
-
: null
|
|
1263
|
-
on_point_hover?.(hover_data)
|
|
1264
|
-
}
|
|
1265
|
-
|
|
1266
|
-
const find_entry_at_mouse = (event: MouseEvent): ConvexHullEntry | null =>
|
|
1267
|
-
helpers.find_hull_entry_at_mouse(
|
|
1268
|
-
canvas,
|
|
1269
|
-
event,
|
|
1270
|
-
visible_entries,
|
|
1271
|
-
(x: number, y: number, z: number) => {
|
|
1272
|
-
const pt = project_3d_point(x, y, z)
|
|
1273
|
-
return { x: pt.x, y: pt.y }
|
|
1274
|
-
},
|
|
1275
|
-
)
|
|
1276
|
-
|
|
1277
|
-
const handle_click = (event: MouseEvent) => {
|
|
1278
|
-
event.stopPropagation()
|
|
1279
|
-
// Check if this was a drag operation (any mouse movement during drag)
|
|
1280
|
-
const was_drag = drag_started
|
|
1281
|
-
drag_started = false // Reset for next interaction
|
|
1282
|
-
if (was_drag) return // Don't trigger click if this was a drag
|
|
1283
|
-
|
|
1284
|
-
const entry = find_entry_at_mouse(event)
|
|
1285
|
-
if (!entry) {
|
|
1286
|
-
if (modal_open) close_structure_popup()
|
|
1287
|
-
return
|
|
1288
|
-
}
|
|
1289
|
-
|
|
1290
|
-
on_point_click?.(entry)
|
|
1291
|
-
|
|
1292
|
-
if (enable_click_selection) {
|
|
1293
|
-
selected_entry = entry
|
|
1294
|
-
if (enable_structure_preview) {
|
|
1295
|
-
const structure = extract_structure_from_entry(entry)
|
|
1296
|
-
if (structure) {
|
|
1297
|
-
selected_structure = structure
|
|
1298
|
-
modal_place_right = helpers.calculate_modal_side(wrapper)
|
|
1299
|
-
modal_open = true
|
|
1300
|
-
}
|
|
1301
|
-
}
|
|
1302
|
-
}
|
|
1303
|
-
}
|
|
1304
|
-
|
|
1305
|
-
function close_structure_popup() {
|
|
1306
|
-
modal_open = false
|
|
1307
|
-
selected_structure = null
|
|
1308
|
-
selected_entry = null
|
|
1309
|
-
}
|
|
1310
|
-
|
|
1311
|
-
const handle_double_click = (event: MouseEvent) => {
|
|
1312
|
-
const entry = find_entry_at_mouse(event)
|
|
1313
|
-
if (entry) {
|
|
1314
|
-
copy_entry_data(entry, {
|
|
1315
|
-
x: event.clientX,
|
|
1316
|
-
y: event.clientY,
|
|
1317
|
-
})
|
|
1318
|
-
}
|
|
1319
|
-
}
|
|
1320
|
-
|
|
1321
|
-
function render_once() {
|
|
1322
|
-
if (!frame_id) {
|
|
1323
|
-
frame_id = requestAnimationFrame(() => {
|
|
1324
|
-
render_frame()
|
|
1325
|
-
frame_id = 0
|
|
1326
|
-
})
|
|
1327
|
-
}
|
|
1328
|
-
}
|
|
1329
|
-
|
|
1330
|
-
function update_canvas_size() {
|
|
1331
|
-
if (!canvas) return
|
|
1332
|
-
const dpr = globalThis.devicePixelRatio || 1
|
|
1333
|
-
const container = canvas.parentElement
|
|
1334
|
-
const rect = container?.getBoundingClientRect()
|
|
1335
|
-
const [w, h] = rect ? [rect.width, rect.height] : [400, 400]
|
|
1336
|
-
|
|
1337
|
-
// Only update canvas dimensions if they actually changed
|
|
1338
|
-
// (assigning canvas.width/height clears the canvas even if values are the same)
|
|
1339
|
-
const new_width = Math.max(0, Math.round(w * dpr))
|
|
1340
|
-
const new_height = Math.max(0, Math.round(h * dpr))
|
|
1341
|
-
if (!ctx || canvas.width !== new_width || canvas.height !== new_height) {
|
|
1342
|
-
canvas.width = new_width
|
|
1343
|
-
canvas.height = new_height
|
|
1344
|
-
ctx = canvas.getContext(`2d`)
|
|
1345
|
-
if (ctx) {
|
|
1346
|
-
ctx.setTransform(dpr, 0, 0, dpr, 0, 0)
|
|
1347
|
-
ctx.imageSmoothingEnabled = true
|
|
1348
|
-
ctx.imageSmoothingQuality = `high`
|
|
1349
|
-
}
|
|
1350
|
-
}
|
|
1351
|
-
canvas_dims = { width: w, height: h, scale: Math.min(w, h) / 600 }
|
|
1352
|
-
render_once()
|
|
1353
|
-
}
|
|
1354
|
-
|
|
1355
1000
|
// Reactive dark mode detection for canvas text color
|
|
1356
1001
|
let dark_mode = $state(is_dark_mode())
|
|
1357
|
-
$effect(() => watch_dark_mode((dark) => dark_mode = dark))
|
|
1002
|
+
$effect(() => watch_dark_mode((dark) => (dark_mode = dark)))
|
|
1358
1003
|
const text_color = $derived(helpers.get_canvas_text_color(dark_mode))
|
|
1359
1004
|
|
|
1360
|
-
$effect(() => {
|
|
1361
|
-
if (!canvas) return
|
|
1362
|
-
|
|
1363
|
-
// Initial setup
|
|
1364
|
-
update_canvas_size()
|
|
1365
|
-
|
|
1366
|
-
// Watch for resize events - only update canvas, don't reset camera
|
|
1367
|
-
const resize_observer = new ResizeObserver(update_canvas_size)
|
|
1368
|
-
|
|
1369
|
-
const container = canvas.parentElement
|
|
1370
|
-
if (container) {
|
|
1371
|
-
resize_observer.observe(container)
|
|
1372
|
-
}
|
|
1373
|
-
|
|
1374
|
-
return () => { // Cleanup on unmount
|
|
1375
|
-
if (frame_id) cancelAnimationFrame(frame_id)
|
|
1376
|
-
resize_observer.disconnect()
|
|
1377
|
-
}
|
|
1378
|
-
})
|
|
1379
|
-
|
|
1380
|
-
// Fullscreen handling with camera reset
|
|
1381
|
-
let was_fullscreen = $state(fullscreen)
|
|
1382
|
-
$effect(() => {
|
|
1383
|
-
setup_fullscreen_effect(fullscreen, wrapper, (entering_fullscreen) => {
|
|
1384
|
-
if (entering_fullscreen !== was_fullscreen) {
|
|
1385
|
-
camera.center_x = 0
|
|
1386
|
-
camera.center_y = -50
|
|
1387
|
-
was_fullscreen = entering_fullscreen
|
|
1388
|
-
}
|
|
1389
|
-
})
|
|
1390
|
-
set_fullscreen_bg(wrapper, fullscreen, `--hull-3d-bg-fullscreen`)
|
|
1391
|
-
})
|
|
1392
|
-
|
|
1393
1005
|
// Performance: Cache canvas dimensions and formation energy range
|
|
1394
1006
|
let canvas_dims = $state({ width: 600, height: 600, scale: 1 })
|
|
1395
1007
|
const energy_range = $derived.by(() => {
|
|
@@ -1404,64 +1016,38 @@
|
|
|
1404
1016
|
return { min, max, center: (min + max) / 2, z_scale }
|
|
1405
1017
|
})
|
|
1406
1018
|
|
|
1407
|
-
|
|
1408
|
-
const sorted_points_cache = $derived.by(() => {
|
|
1409
|
-
if (!canvas || visible_entries.length === 0) return []
|
|
1410
|
-
return visible_entries
|
|
1411
|
-
.map((entry) => ({
|
|
1412
|
-
entry,
|
|
1413
|
-
projected: project_3d_point(entry.x, entry.y, entry.z),
|
|
1414
|
-
}))
|
|
1415
|
-
.sort((left, right) => left.projected.depth - right.projected.depth)
|
|
1416
|
-
})
|
|
1417
|
-
|
|
1418
|
-
let style = $derived(
|
|
1419
|
-
`--hull-stable-color:${merged_config.colors?.stable || `#0072B2`};
|
|
1420
|
-
--hull-unstable-color:${merged_config.colors?.unstable || `#E69F00`};
|
|
1421
|
-
--hull-edge-color:${merged_config.colors?.edge || `var(--text-color, #212121)`};
|
|
1422
|
-
--hull-text-color:${
|
|
1423
|
-
merged_config.colors?.annotation || `var(--text-color, #212121)`
|
|
1424
|
-
}`,
|
|
1425
|
-
)
|
|
1019
|
+
let style = $derived(helpers.hull_style_css(merged_config.colors))
|
|
1426
1020
|
</script>
|
|
1427
1021
|
|
|
1428
1022
|
<svelte:document
|
|
1429
1023
|
onfullscreenchange={() => {
|
|
1430
|
-
fullscreen
|
|
1024
|
+
// tie fullscreen state to this component's own wrapper, not any fullscreen element
|
|
1025
|
+
fullscreen = document.fullscreenElement === wrapper
|
|
1431
1026
|
}}
|
|
1432
|
-
onmousemove={handle_mouse_move}
|
|
1433
|
-
onmouseup={
|
|
1027
|
+
onmousemove={interactions.handle_mouse_move}
|
|
1028
|
+
onmouseup={interactions.handle_mouse_up}
|
|
1434
1029
|
/>
|
|
1435
1030
|
|
|
1436
1031
|
<div
|
|
1437
1032
|
{...rest}
|
|
1438
|
-
class=
|
|
1439
|
-
class:dragover={drag_over}
|
|
1033
|
+
class={[`convex-hull-3d`, rest.class]}
|
|
1034
|
+
class:dragover={interactions.drag_over}
|
|
1440
1035
|
style={`${style}; ${rest.style ?? ``}`}
|
|
1441
1036
|
data-has-selection={selected_entry !== null}
|
|
1442
|
-
data-has-hover={hover_data !== null}
|
|
1443
|
-
data-is-dragging={is_dragging}
|
|
1037
|
+
data-has-hover={interactions.hover_data !== null}
|
|
1038
|
+
data-is-dragging={interactions.is_dragging}
|
|
1444
1039
|
bind:this={wrapper}
|
|
1445
1040
|
role="application"
|
|
1446
1041
|
tabindex="-1"
|
|
1447
|
-
|
|
1448
|
-
ondrop={handle_file_drop}
|
|
1449
|
-
ondragover={(event) => {
|
|
1450
|
-
event.preventDefault()
|
|
1451
|
-
drag_over = true
|
|
1452
|
-
}}
|
|
1453
|
-
ondragleave={(event) => {
|
|
1454
|
-
event.preventDefault()
|
|
1455
|
-
drag_over = false
|
|
1456
|
-
}}
|
|
1042
|
+
{...interactions.wrapper_handlers}
|
|
1457
1043
|
aria-label="Ternary convex hull visualization"
|
|
1458
1044
|
>
|
|
1459
1045
|
{@render children?.({
|
|
1460
|
-
|
|
1461
|
-
|
|
1462
|
-
|
|
1463
|
-
|
|
1464
|
-
|
|
1046
|
+
stable_entries,
|
|
1047
|
+
unstable_entries,
|
|
1048
|
+
highlighted_entries,
|
|
1049
|
+
selected_entry,
|
|
1050
|
+
})}
|
|
1465
1051
|
<h3 style="position: absolute; left: 1em; top: 1ex; margin: 0; font-weight: 500">
|
|
1466
1052
|
{@html sanitize_html(merged_controls.title || phase_stats?.chemical_system || ``)}
|
|
1467
1053
|
</h3>
|
|
@@ -1469,12 +1055,7 @@
|
|
|
1469
1055
|
bind:this={canvas}
|
|
1470
1056
|
tabindex="0"
|
|
1471
1057
|
aria-label={merged_controls.title || phase_stats?.chemical_system || `3D Convex Hull`}
|
|
1472
|
-
|
|
1473
|
-
onmousemove={handle_hover}
|
|
1474
|
-
onclick={handle_click}
|
|
1475
|
-
onkeydown={handle_keydown}
|
|
1476
|
-
ondblclick={handle_double_click}
|
|
1477
|
-
onwheel={handle_wheel}
|
|
1058
|
+
{...interactions.canvas_handlers}
|
|
1478
1059
|
></canvas>
|
|
1479
1060
|
|
|
1480
1061
|
{#if entries.length === 0}
|
|
@@ -1486,14 +1067,9 @@
|
|
|
1486
1067
|
|
|
1487
1068
|
<!-- Formation Energy Color Bar (bottom-left corner) -->
|
|
1488
1069
|
{#if color_mode === `energy` && plot_entries.length > 0}
|
|
1489
|
-
{@const hull_distances = plot_entries
|
|
1490
|
-
.map((entry) => entry.e_above_hull)
|
|
1491
|
-
.filter((value): value is number => typeof value === `number`)}
|
|
1492
|
-
{@const min_energy = hull_distances.length > 0 ? Math.min(...hull_distances) : 0}
|
|
1493
|
-
{@const max_energy = hull_distances.length > 0 ? Math.max(...hull_distances, 0.1) : 0.1}
|
|
1494
1070
|
<ColorBar
|
|
1495
1071
|
title="Energy above hull (eV/atom)"
|
|
1496
|
-
range={
|
|
1072
|
+
range={helpers.hull_distance_range(plot_entries)}
|
|
1497
1073
|
{color_scale}
|
|
1498
1074
|
wrapper_style="position: absolute; bottom: 16px; left: 1em; width: 200px;"
|
|
1499
1075
|
bar_style="height: 12px;"
|
|
@@ -1503,9 +1079,7 @@
|
|
|
1503
1079
|
|
|
1504
1080
|
<!-- Formation Energy Faces Color Bar (bottom-right corner) -->
|
|
1505
1081
|
<!-- Only show for uniform/formation_energy modes where face color relates to E_form -->
|
|
1506
|
-
{#if plot_entries.length > 0 && show_hull_faces &&
|
|
1507
|
-
(hull_face_color_mode === `uniform` ||
|
|
1508
|
-
hull_face_color_mode === `formation_energy`)}
|
|
1082
|
+
{#if plot_entries.length > 0 && show_hull_faces && (hull_face_color_mode === `uniform` || hull_face_color_mode === `formation_energy`)}
|
|
1509
1083
|
<ColorBar
|
|
1510
1084
|
title="Formation energy (eV/atom)"
|
|
1511
1085
|
color_scale_fn={e_form_color_scale_fn}
|
|
@@ -1517,89 +1091,53 @@
|
|
|
1517
1091
|
/>
|
|
1518
1092
|
{/if}
|
|
1519
1093
|
|
|
1520
|
-
<!--
|
|
1521
|
-
|
|
1522
|
-
|
|
1523
|
-
|
|
1524
|
-
|
|
1525
|
-
|
|
1526
|
-
|
|
1527
|
-
|
|
1528
|
-
|
|
1529
|
-
|
|
1530
|
-
|
|
1531
|
-
|
|
1532
|
-
|
|
1533
|
-
|
|
1534
|
-
|
|
1535
|
-
|
|
1536
|
-
|
|
1537
|
-
|
|
1538
|
-
|
|
1539
|
-
|
|
1540
|
-
|
|
1541
|
-
|
|
1542
|
-
|
|
1543
|
-
|
|
1544
|
-
|
|
1545
|
-
|
|
1546
|
-
|
|
1547
|
-
|
|
1548
|
-
|
|
1549
|
-
|
|
1550
|
-
|
|
1551
|
-
|
|
1552
|
-
|
|
1553
|
-
|
|
1554
|
-
|
|
1555
|
-
|
|
1556
|
-
|
|
1557
|
-
|
|
1558
|
-
|
|
1559
|
-
|
|
1560
|
-
<!-- Legend controls pane -->
|
|
1561
|
-
{#if controls_config.visible(`controls`)}
|
|
1562
|
-
<ConvexHullControls
|
|
1563
|
-
bind:controls_open={legend_pane_open}
|
|
1564
|
-
bind:color_mode
|
|
1565
|
-
bind:color_scale
|
|
1566
|
-
bind:show_stable
|
|
1567
|
-
bind:show_unstable
|
|
1568
|
-
bind:show_stable_labels
|
|
1569
|
-
bind:show_unstable_labels
|
|
1570
|
-
bind:max_hull_dist_show_phases
|
|
1571
|
-
bind:max_hull_dist_show_labels
|
|
1572
|
-
{max_hull_dist_in_data}
|
|
1573
|
-
{stable_entries}
|
|
1574
|
-
{unstable_entries}
|
|
1575
|
-
{camera}
|
|
1576
|
-
{merged_controls}
|
|
1577
|
-
toggle_props={{ class: `legend-controls-btn` }}
|
|
1578
|
-
{show_hull_faces}
|
|
1579
|
-
on_hull_faces_change={(value: boolean) => show_hull_faces = value}
|
|
1580
|
-
{hull_face_color}
|
|
1581
|
-
on_hull_face_color_change={(value: string) => hull_face_color = value}
|
|
1582
|
-
{hull_face_opacity}
|
|
1583
|
-
on_hull_face_opacity_change={(value: number) => hull_face_opacity = value}
|
|
1584
|
-
{hull_face_color_mode}
|
|
1585
|
-
on_hull_face_color_mode_change={(value: HullFaceColorMode) =>
|
|
1586
|
-
hull_face_color_mode = value}
|
|
1587
|
-
bind:energy_source_mode
|
|
1588
|
-
{has_precomputed_e_form}
|
|
1589
|
-
{can_compute_e_form}
|
|
1590
|
-
{has_precomputed_hull}
|
|
1591
|
-
{can_compute_hull}
|
|
1592
|
-
/>
|
|
1593
|
-
{/if}
|
|
1594
|
-
</section>
|
|
1595
|
-
{/if}
|
|
1094
|
+
<!-- Toolbar + tooltip/copy-feedback/drag/structure-popup chrome -->
|
|
1095
|
+
<ConvexHullChrome
|
|
1096
|
+
{interactions}
|
|
1097
|
+
{hull_data}
|
|
1098
|
+
{controls_config}
|
|
1099
|
+
{reset_all}
|
|
1100
|
+
reset_title="Reset view and settings"
|
|
1101
|
+
{enable_info_pane}
|
|
1102
|
+
{phase_stats}
|
|
1103
|
+
{label_threshold}
|
|
1104
|
+
{fullscreen}
|
|
1105
|
+
{fullscreen_toggle}
|
|
1106
|
+
{wrapper}
|
|
1107
|
+
{camera}
|
|
1108
|
+
{merged_controls}
|
|
1109
|
+
{stable_entries}
|
|
1110
|
+
{unstable_entries}
|
|
1111
|
+
{get_point_color}
|
|
1112
|
+
{merged_highlight_style}
|
|
1113
|
+
{is_highlighted}
|
|
1114
|
+
{tooltip}
|
|
1115
|
+
{selected_entry}
|
|
1116
|
+
bind:show_hull_faces
|
|
1117
|
+
bind:hull_face_color
|
|
1118
|
+
bind:hull_face_opacity
|
|
1119
|
+
bind:hull_face_color_mode
|
|
1120
|
+
bind:info_pane_open
|
|
1121
|
+
bind:controls_open
|
|
1122
|
+
bind:color_mode
|
|
1123
|
+
bind:color_scale
|
|
1124
|
+
bind:show_stable
|
|
1125
|
+
bind:show_unstable
|
|
1126
|
+
{entry_category}
|
|
1127
|
+
bind:hidden_categories
|
|
1128
|
+
bind:show_stable_labels
|
|
1129
|
+
bind:show_unstable_labels
|
|
1130
|
+
bind:max_hull_dist_show_phases
|
|
1131
|
+
bind:max_hull_dist_show_labels
|
|
1132
|
+
bind:energy_source_mode
|
|
1133
|
+
/>
|
|
1596
1134
|
|
|
1597
1135
|
<!-- Orientation gizmo (configurable placement, default top-right) -->
|
|
1598
1136
|
{#if gizmo && typeof WebGLRenderingContext !== `undefined`}
|
|
1599
1137
|
<div class="gizmo-wrapper {controls_config.class}" data-placement={gizmo_placement}>
|
|
1600
1138
|
<Canvas
|
|
1601
1139
|
createRenderer={(cvs: HTMLCanvasElement) =>
|
|
1602
|
-
|
|
1140
|
+
new WebGLRenderer({ canvas: cvs, alpha: true, antialias: true })}
|
|
1603
1141
|
>
|
|
1604
1142
|
<T.PerspectiveCamera
|
|
1605
1143
|
makeDefault
|
|
@@ -1629,11 +1167,13 @@
|
|
|
1629
1167
|
</div>
|
|
1630
1168
|
{/if}
|
|
1631
1169
|
|
|
1632
|
-
{#if (has_temp_data && temperature !== undefined) ||
|
|
1633
|
-
(gas_analysis.has_gas_dependent_elements && merged_gas_config)}
|
|
1170
|
+
{#if (has_temp_data && temperature !== undefined) || (gas_analysis.has_gas_dependent_elements && merged_gas_config)}
|
|
1634
1171
|
<div class="right-controls">
|
|
1635
1172
|
{#if has_temp_data && temperature !== undefined}
|
|
1636
|
-
<TemperatureSlider
|
|
1173
|
+
<TemperatureSlider
|
|
1174
|
+
available_temperatures={hull_data.available_temperatures}
|
|
1175
|
+
bind:temperature
|
|
1176
|
+
/>
|
|
1637
1177
|
{/if}
|
|
1638
1178
|
{#if gas_analysis.has_gas_dependent_elements && merged_gas_config}
|
|
1639
1179
|
<GasPressureControls
|
|
@@ -1644,46 +1184,6 @@
|
|
|
1644
1184
|
{/if}
|
|
1645
1185
|
</div>
|
|
1646
1186
|
{/if}
|
|
1647
|
-
|
|
1648
|
-
<!-- Hover tooltip -->
|
|
1649
|
-
{#if hover_data}
|
|
1650
|
-
{@const { entry, position } = hover_data}
|
|
1651
|
-
{@const entry_highlight = is_highlighted(entry) ? merged_highlight_style : undefined}
|
|
1652
|
-
{@const tooltip_style =
|
|
1653
|
-
`z-index: ${CONVEX_HULL_STYLE.z_index.tooltip}; backdrop-filter: blur(4px);
|
|
1654
|
-
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3);`}
|
|
1655
|
-
<PlotTooltip
|
|
1656
|
-
x={position.x}
|
|
1657
|
-
y={position.y}
|
|
1658
|
-
offset={{ x: 10, y: -10 }}
|
|
1659
|
-
bg_color={get_point_color(entry)}
|
|
1660
|
-
fixed
|
|
1661
|
-
style={tooltip_style}
|
|
1662
|
-
>
|
|
1663
|
-
<ConvexHullTooltip
|
|
1664
|
-
{entry}
|
|
1665
|
-
{polymorph_stats_map}
|
|
1666
|
-
highlight_style={entry_highlight}
|
|
1667
|
-
{tooltip}
|
|
1668
|
-
/>
|
|
1669
|
-
</PlotTooltip>
|
|
1670
|
-
{/if}
|
|
1671
|
-
|
|
1672
|
-
<ClickFeedback bind:visible={copy_feedback.visible} position={copy_feedback.position} />
|
|
1673
|
-
<DragOverlay visible={drag_over} />
|
|
1674
|
-
|
|
1675
|
-
{#if modal_open && selected_structure}
|
|
1676
|
-
<StructurePopup
|
|
1677
|
-
structure={selected_structure}
|
|
1678
|
-
place_right={modal_place_right}
|
|
1679
|
-
stats={{
|
|
1680
|
-
id: selected_entry?.entry_id,
|
|
1681
|
-
e_above_hull: selected_entry?.e_above_hull,
|
|
1682
|
-
e_form: selected_entry?.e_form_per_atom,
|
|
1683
|
-
}}
|
|
1684
|
-
onclose={close_structure_popup}
|
|
1685
|
-
/>
|
|
1686
|
-
{/if}
|
|
1687
1187
|
</div>
|
|
1688
1188
|
|
|
1689
1189
|
<style>
|
|
@@ -1763,39 +1263,4 @@
|
|
|
1763
1263
|
opacity: 1;
|
|
1764
1264
|
pointer-events: auto;
|
|
1765
1265
|
}
|
|
1766
|
-
.control-buttons {
|
|
1767
|
-
position: absolute;
|
|
1768
|
-
top: 1ex;
|
|
1769
|
-
right: 1ex;
|
|
1770
|
-
display: flex;
|
|
1771
|
-
gap: 8px;
|
|
1772
|
-
transition: opacity 0.2s ease-in-out;
|
|
1773
|
-
}
|
|
1774
|
-
.control-buttons.hover-visible {
|
|
1775
|
-
opacity: 0;
|
|
1776
|
-
pointer-events: none;
|
|
1777
|
-
}
|
|
1778
|
-
.convex-hull-3d:hover .control-buttons.hover-visible,
|
|
1779
|
-
.convex-hull-3d:focus-within .control-buttons.hover-visible {
|
|
1780
|
-
opacity: 1;
|
|
1781
|
-
pointer-events: auto;
|
|
1782
|
-
}
|
|
1783
|
-
.control-buttons.always-visible {
|
|
1784
|
-
opacity: 1;
|
|
1785
|
-
pointer-events: auto;
|
|
1786
|
-
}
|
|
1787
|
-
.control-buttons :global(button) {
|
|
1788
|
-
background: transparent;
|
|
1789
|
-
border: none;
|
|
1790
|
-
padding: 4px;
|
|
1791
|
-
cursor: pointer;
|
|
1792
|
-
border-radius: 3px;
|
|
1793
|
-
color: var(--text-color, currentColor);
|
|
1794
|
-
transition: background-color 0.2s;
|
|
1795
|
-
display: flex;
|
|
1796
|
-
font-size: clamp(0.85em, 2cqmin, 1.3em);
|
|
1797
|
-
}
|
|
1798
|
-
.control-buttons :global(button):hover {
|
|
1799
|
-
background-color: color-mix(in srgb, currentColor 8%, transparent);
|
|
1800
|
-
}
|
|
1801
1266
|
</style>
|