matterviz 0.4.0 → 0.4.1
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/brillouin/BrillouinZone.svelte +68 -145
- package/dist/brillouin/BrillouinZone.svelte.d.ts +5 -14
- package/dist/brillouin/BrillouinZoneExportPane.svelte +43 -96
- package/dist/brillouin/BrillouinZoneExportPane.svelte.d.ts +1 -1
- package/dist/brillouin/BrillouinZoneInfoPane.svelte +9 -32
- package/dist/brillouin/BrillouinZoneInfoPane.svelte.d.ts +2 -3
- package/dist/brillouin/BrillouinZoneScene.svelte +49 -203
- 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.d.ts +1 -1
- package/dist/chempot-diagram/ChemPotDiagram2D.svelte +100 -191
- package/dist/chempot-diagram/ChemPotDiagram2D.svelte.d.ts +4 -1
- package/dist/chempot-diagram/ChemPotDiagram3D.svelte +176 -464
- package/dist/chempot-diagram/ChemPotDiagram3D.svelte.d.ts +7 -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.js +2 -2
- package/dist/composition/FormulaFilter.svelte +6 -5
- package/dist/composition/PieChart.svelte +5 -5
- package/dist/composition/chem-sys.js +3 -2
- package/dist/composition/format.js +3 -2
- package/dist/composition/parse.d.ts +0 -1
- package/dist/composition/parse.js +17 -19
- package/dist/controls.d.ts +1 -0
- package/dist/controls.js +0 -1
- package/dist/convex-hull/ConvexHull.svelte +8 -10
- package/dist/convex-hull/ConvexHull.svelte.d.ts +1 -4
- package/dist/convex-hull/ConvexHull2D.svelte +94 -175
- package/dist/convex-hull/ConvexHull2D.svelte.d.ts +1 -1
- package/dist/convex-hull/ConvexHull3D.svelte +176 -680
- package/dist/convex-hull/ConvexHull3D.svelte.d.ts +1 -1
- package/dist/convex-hull/ConvexHull4D.svelte +180 -680
- package/dist/convex-hull/ConvexHull4D.svelte.d.ts +1 -1
- package/dist/convex-hull/ConvexHullChrome.svelte +268 -0
- package/dist/convex-hull/ConvexHullChrome.svelte.d.ts +30 -0
- package/dist/convex-hull/ConvexHullControls.svelte +88 -7
- 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 +29 -168
- package/dist/convex-hull/ConvexHullStats.svelte.d.ts +3 -1
- package/dist/convex-hull/ConvexHullTooltip.svelte +11 -2
- package/dist/convex-hull/ConvexHullTooltip.svelte.d.ts +2 -1
- 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 +278 -0
- package/dist/convex-hull/helpers.d.ts +39 -7
- package/dist/convex-hull/helpers.js +154 -69
- 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 +91 -920
- package/dist/convex-hull/types.d.ts +12 -4
- package/dist/convex-hull/types.js +12 -0
- package/dist/coordination/CoordinationBarPlot.svelte +4 -11
- package/dist/element/BohrAtom.svelte +2 -1
- package/dist/element/ElementTile.svelte.d.ts +1 -1
- package/dist/element/index.d.ts +4 -0
- package/dist/element/index.js +18 -0
- package/dist/feedback/DragOverlay.svelte +3 -1
- package/dist/feedback/DragOverlay.svelte.d.ts +1 -0
- package/dist/feedback/StatusMessage.svelte +13 -3
- package/dist/fermi-surface/FermiSurface.svelte +67 -146
- package/dist/fermi-surface/FermiSurface.svelte.d.ts +5 -14
- package/dist/fermi-surface/FermiSurfaceControls.svelte.d.ts +1 -1
- package/dist/fermi-surface/FermiSurfaceScene.svelte +72 -224
- package/dist/fermi-surface/FermiSurfaceScene.svelte.d.ts +3 -23
- package/dist/fermi-surface/compute.js +11 -10
- 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 +64 -75
- package/dist/fermi-surface/types.d.ts +2 -2
- package/dist/heatmap-matrix/HeatmapMatrix.svelte +55 -40
- package/dist/heatmap-matrix/HeatmapMatrix.svelte.d.ts +4 -3
- package/dist/heatmap-matrix/HeatmapMatrixControls.svelte +3 -2
- package/dist/heatmap-matrix/HeatmapMatrixControls.svelte.d.ts +5 -5
- package/dist/heatmap-matrix/index.d.ts +3 -2
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/io/ExportPane.svelte +166 -0
- package/dist/io/ExportPane.svelte.d.ts +17 -0
- package/dist/io/decompress.js +1 -2
- package/dist/io/export.d.ts +5 -1
- package/dist/io/export.js +32 -28
- package/dist/io/fetch.d.ts +2 -1
- package/dist/io/file-drop.d.ts +7 -0
- package/dist/io/file-drop.js +13 -0
- package/dist/io/index.d.ts +2 -0
- package/dist/io/index.js +10 -0
- package/dist/io/types.d.ts +13 -0
- package/dist/isosurface/parse.js +46 -44
- package/dist/labels.js +1 -1
- package/dist/layout/FullscreenButton.svelte +33 -0
- package/dist/layout/FullscreenButton.svelte.d.ts +10 -0
- package/dist/layout/FullscreenToggle.svelte +8 -14
- package/dist/layout/ViewerChrome.svelte +116 -0
- package/dist/layout/ViewerChrome.svelte.d.ts +17 -0
- package/dist/layout/fullscreen.d.ts +4 -0
- package/dist/layout/fullscreen.svelte.d.ts +8 -0
- package/dist/layout/fullscreen.svelte.js +37 -0
- package/dist/layout/index.d.ts +3 -0
- package/dist/layout/index.js +3 -0
- package/dist/math.d.ts +7 -3
- package/dist/math.js +18 -21
- package/dist/overlays/index.d.ts +4 -0
- package/dist/periodic-table/PeriodicTable.svelte +9 -8
- package/dist/phase-diagram/IsobaricBinaryPhaseDiagram.svelte.d.ts +1 -1
- package/dist/phase-diagram/PhaseDiagramControls.svelte +3 -2
- package/dist/phase-diagram/PhaseDiagramControls.svelte.d.ts +4 -3
- package/dist/phase-diagram/PhaseDiagramEditorPane.svelte +2 -1
- package/dist/phase-diagram/PhaseDiagramEditorPane.svelte.d.ts +2 -3
- package/dist/phase-diagram/PhaseDiagramExportPane.svelte +47 -132
- package/dist/phase-diagram/PhaseDiagramExportPane.svelte.d.ts +3 -4
- package/dist/phase-diagram/colors.js +1 -1
- package/dist/phase-diagram/parse.d.ts +2 -1
- package/dist/plot/bar/BarPlot.svelte +79 -316
- package/dist/plot/bar/BarPlot.svelte.d.ts +7 -15
- package/dist/plot/bar/BarPlotControls.svelte.d.ts +1 -1
- package/dist/plot/bar/SpacegroupBarPlot.svelte +2 -1
- package/dist/plot/box/BoxPlot.svelte +76 -246
- package/dist/plot/box/BoxPlot.svelte.d.ts +4 -3
- package/dist/plot/box/BoxPlotControls.svelte.d.ts +1 -1
- package/dist/plot/box/Violin.svelte.d.ts +1 -1
- package/dist/plot/box/box-plot.d.ts +3 -2
- package/dist/plot/box/box-plot.js +5 -2
- 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 +4 -1
- package/dist/plot/core/components/ColorBar.svelte +5 -5
- package/dist/plot/core/components/ColorBar.svelte.d.ts +5 -4
- package/dist/plot/core/components/Line.svelte +3 -2
- package/dist/plot/core/components/Line.svelte.d.ts +3 -2
- package/dist/plot/core/components/PlotAxis.svelte +2 -1
- package/dist/plot/core/components/PlotAxis.svelte.d.ts +2 -1
- package/dist/plot/core/components/PlotControls.svelte.d.ts +1 -1
- package/dist/plot/core/components/ReferenceLine3D.svelte +2 -2
- package/dist/plot/core/components/ReferenceLine3D.svelte.d.ts +4 -4
- package/dist/plot/core/components/ReferencePlane.svelte +2 -2
- package/dist/plot/core/components/ReferencePlane.svelte.d.ts +4 -4
- package/dist/plot/core/data-cleaning.js +18 -18
- package/dist/plot/core/fill-utils.d.ts +4 -3
- package/dist/plot/core/fill-utils.js +6 -3
- package/dist/plot/core/interactions.d.ts +5 -1
- package/dist/plot/core/interactions.js +14 -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 +6 -6
- package/dist/plot/core/scales.d.ts +17 -25
- package/dist/plot/core/scales.js +10 -8
- package/dist/plot/core/svg.d.ts +2 -1
- package/dist/plot/core/types.d.ts +18 -7
- package/dist/plot/core/utils/label-placement.d.ts +1 -1
- package/dist/plot/core/utils/label-placement.js +3 -3
- package/dist/plot/core/utils.d.ts +2 -1
- package/dist/plot/histogram/Histogram.svelte +77 -314
- package/dist/plot/histogram/HistogramControls.svelte.d.ts +1 -1
- package/dist/plot/sankey/Sankey.svelte +2 -5
- package/dist/plot/sankey/Sankey.svelte.d.ts +1 -1
- package/dist/plot/sankey/sankey.js +3 -1
- package/dist/plot/scatter/BinnedScatterPlot.svelte +3 -5
- package/dist/plot/scatter/BinnedScatterPlot.svelte.d.ts +4 -4
- package/dist/plot/scatter/ScatterPlot.svelte +160 -450
- package/dist/plot/scatter/ScatterPlot.svelte.d.ts +7 -15
- package/dist/plot/scatter/ScatterPlotControls.svelte.d.ts +1 -1
- package/dist/plot/scatter/binned-scatter-types.d.ts +4 -11
- package/dist/plot/scatter/index.d.ts +1 -1
- package/dist/plot/scatter-3d/ScatterPlot3D.svelte +15 -26
- package/dist/plot/scatter-3d/ScatterPlot3D.svelte.d.ts +6 -14
- package/dist/plot/scatter-3d/ScatterPlot3DControls.svelte +9 -10
- package/dist/plot/scatter-3d/ScatterPlot3DControls.svelte.d.ts +5 -5
- package/dist/plot/scatter-3d/ScatterPlot3DScene.svelte +122 -121
- package/dist/plot/scatter-3d/ScatterPlot3DScene.svelte.d.ts +5 -14
- package/dist/plot/scatter-3d/Surface3D.svelte +6 -5
- package/dist/plot/scatter-3d/Surface3D.svelte.d.ts +4 -3
- package/dist/plot/sunburst/Sunburst.svelte +16 -20
- package/dist/plot/sunburst/Sunburst.svelte.d.ts +4 -3
- package/dist/plot/sunburst/SunburstControls.svelte.d.ts +1 -1
- package/dist/plot/sunburst/sunburst.js +4 -1
- package/dist/rdf/RdfPlot.svelte.d.ts +1 -1
- package/dist/sanitize.js +13 -2
- 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 +14 -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 +14 -2
- package/dist/settings.js +59 -1
- package/dist/spectral/Bands.svelte +8 -7
- package/dist/spectral/Bands.svelte.d.ts +3 -2
- package/dist/spectral/BandsAndDos.svelte +22 -24
- package/dist/spectral/BrillouinBandsDos.svelte +3 -3
- package/dist/spectral/Dos.svelte +5 -4
- package/dist/spectral/Dos.svelte.d.ts +2 -1
- package/dist/spectral/helpers.d.ts +6 -6
- package/dist/spectral/helpers.js +43 -37
- package/dist/state.svelte.d.ts +0 -7
- package/dist/state.svelte.js +0 -6
- package/dist/structure/Arrow.svelte +2 -4
- package/dist/structure/AtomLegend.svelte.d.ts +1 -1
- package/dist/structure/CanvasTooltip.svelte +1 -0
- package/dist/structure/CellSelect.svelte +11 -3
- package/dist/structure/CellSelect.svelte.d.ts +2 -1
- package/dist/structure/Lattice.svelte +2 -2
- package/dist/structure/Structure.svelte +291 -355
- package/dist/structure/Structure.svelte.d.ts +5 -15
- package/dist/structure/StructureControls.svelte +217 -2
- package/dist/structure/StructureControls.svelte.d.ts +5 -3
- package/dist/structure/StructureExportPane.svelte +54 -156
- package/dist/structure/StructureExportPane.svelte.d.ts +4 -5
- package/dist/structure/StructureInfoPane.svelte +5 -3
- package/dist/structure/StructureInfoPane.svelte.d.ts +5 -5
- package/dist/structure/StructureScene.svelte +365 -198
- package/dist/structure/StructureScene.svelte.d.ts +22 -20
- package/dist/structure/{label-placement.d.ts → atom-label-placement.d.ts} +3 -3
- package/dist/structure/{label-placement.js → atom-label-placement.js} +12 -2
- package/dist/structure/atom-properties.d.ts +1 -1
- package/dist/structure/atom-properties.js +11 -16
- package/dist/structure/bond-order-perception.js +2 -4
- package/dist/structure/bonding.d.ts +3 -0
- package/dist/structure/bonding.js +91 -48
- package/dist/structure/export.d.ts +24 -4
- package/dist/structure/export.js +64 -122
- package/dist/structure/index.d.ts +2 -0
- package/dist/structure/index.js +2 -0
- package/dist/structure/parse.d.ts +3 -2
- package/dist/structure/parse.js +333 -370
- package/dist/structure/partial-occupancy.d.ts +0 -1
- package/dist/structure/partial-occupancy.js +1 -1
- package/dist/structure/pbc.d.ts +1 -1
- package/dist/structure/pbc.js +186 -13
- package/dist/structure/polyhedra.d.ts +41 -0
- package/dist/structure/polyhedra.js +602 -0
- package/dist/structure/site.d.ts +4 -0
- package/dist/structure/site.js +1 -0
- package/dist/structure/supercell.js +3 -2
- 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 +354 -0
- package/dist/symmetry/SymmetryElements.svelte.d.ts +24 -0
- package/dist/symmetry/SymmetryStats.svelte +111 -6
- package/dist/symmetry/WyckoffTable.svelte +68 -7
- package/dist/symmetry/WyckoffTable.svelte.d.ts +3 -0
- package/dist/symmetry/cell-transform.js +7 -14
- package/dist/symmetry/index.d.ts +14 -4
- package/dist/symmetry/index.js +301 -80
- package/dist/symmetry/spacegroups.d.ts +5 -1
- package/dist/symmetry/spacegroups.js +15 -1
- 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 +4 -15
- package/dist/table/HeatmapTable.svelte.d.ts +1 -1
- package/dist/trajectory/Trajectory.svelte +58 -61
- package/dist/trajectory/Trajectory.svelte.d.ts +10 -22
- package/dist/trajectory/TrajectoryExportPane.svelte +15 -24
- package/dist/trajectory/TrajectoryExportPane.svelte.d.ts +4 -5
- package/dist/trajectory/TrajectoryInfoPane.svelte +3 -2
- package/dist/trajectory/TrajectoryInfoPane.svelte.d.ts +3 -2
- package/dist/trajectory/constants.js +6 -2
- package/dist/trajectory/extract.js +17 -37
- package/dist/trajectory/format-detect.d.ts +0 -1
- package/dist/trajectory/format-detect.js +3 -9
- package/dist/trajectory/frame-reader.d.ts +0 -1
- package/dist/trajectory/frame-reader.js +62 -128
- package/dist/trajectory/helpers.d.ts +10 -2
- package/dist/trajectory/helpers.js +56 -36
- 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/index.d.ts +1 -1
- package/dist/trajectory/parse/index.js +54 -102
- package/dist/trajectory/parse/lammps.d.ts +0 -2
- package/dist/trajectory/parse/lammps.js +8 -6
- package/dist/trajectory/parse/pymatgen.d.ts +2 -0
- package/dist/trajectory/parse/pymatgen.js +74 -0
- package/dist/trajectory/parse/vasp.js +4 -3
- package/dist/trajectory/parse/xyz.d.ts +9 -21
- package/dist/trajectory/parse/xyz.js +28 -33
- package/dist/trajectory/plotting.d.ts +0 -1
- package/dist/trajectory/plotting.js +3 -100
- package/dist/utils.d.ts +1 -0
- package/dist/utils.js +1 -1
- package/dist/xrd/XrdPlot.svelte +14 -29
- package/dist/xrd/broadening.d.ts +2 -1
- package/dist/xrd/calc-xrd.js +6 -11
- package/dist/xrd/index.d.ts +2 -2
- package/package.json +29 -16
- 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
|
@@ -9,14 +9,8 @@
|
|
|
9
9
|
} from '../colors'
|
|
10
10
|
import { normalize_show_controls } from '../controls'
|
|
11
11
|
import { sanitize_html } from '../sanitize'
|
|
12
|
-
import {
|
|
13
|
-
import
|
|
14
|
-
import {
|
|
15
|
-
set_fullscreen_bg,
|
|
16
|
-
setup_fullscreen_effect,
|
|
17
|
-
toggle_fullscreen,
|
|
18
|
-
} from '../layout'
|
|
19
|
-
import { ColorBar, PlotTooltip } from '../plot'
|
|
12
|
+
import { Spinner } from '../feedback'
|
|
13
|
+
import { ColorBar } from '../plot'
|
|
20
14
|
import { create_pulse_animation } from '../effects.svelte'
|
|
21
15
|
import { DEFAULTS } from '../settings'
|
|
22
16
|
import type { AnyStructure } from '../structure'
|
|
@@ -25,38 +19,41 @@
|
|
|
25
19
|
compute_4d_coords,
|
|
26
20
|
TETRAHEDRON_VERTICES,
|
|
27
21
|
} from './barycentric-coords'
|
|
28
|
-
import
|
|
29
|
-
import
|
|
30
|
-
import ConvexHullTooltip from './ConvexHullTooltip.svelte'
|
|
22
|
+
import { create_canvas_interactions } from './canvas-interactions.svelte'
|
|
23
|
+
import ConvexHullChrome from './ConvexHullChrome.svelte'
|
|
31
24
|
import GasPressureControls from './GasPressureControls.svelte'
|
|
32
25
|
import * as helpers from './helpers'
|
|
26
|
+
import { create_hull_data_pipeline } from './hull-state.svelte'
|
|
33
27
|
import type { BaseConvexHullProps, Hull3DProps } from './index'
|
|
34
28
|
import { CONVEX_HULL_STYLE, default_controls, default_hull_config } from './index'
|
|
35
|
-
import StructurePopup from './StructurePopup.svelte'
|
|
36
29
|
import TemperatureSlider from './TemperatureSlider.svelte'
|
|
37
30
|
import type { Point4D } from './thermodynamics'
|
|
38
31
|
import * as thermo from './thermodynamics'
|
|
39
32
|
import type {
|
|
40
33
|
ConvexHullEntry,
|
|
41
34
|
HighlightStyle,
|
|
42
|
-
HoverData3D,
|
|
43
35
|
HullFaceColorMode,
|
|
36
|
+
PhaseData,
|
|
44
37
|
} from './types'
|
|
38
|
+
import { MAGNETIC_ORDERING_CATEGORY } from './types'
|
|
45
39
|
import { compute_hull_stability } from './helpers'
|
|
46
40
|
|
|
47
41
|
let {
|
|
48
42
|
entries = [],
|
|
49
43
|
controls = {},
|
|
50
44
|
config = {},
|
|
45
|
+
show_controls,
|
|
51
46
|
on_point_click,
|
|
52
47
|
on_point_hover,
|
|
53
48
|
fullscreen = $bindable(DEFAULTS.convex_hull.quaternary.fullscreen),
|
|
54
|
-
|
|
49
|
+
fullscreen_toggle = true,
|
|
55
50
|
enable_info_pane = true,
|
|
56
51
|
wrapper = $bindable(),
|
|
57
52
|
label_threshold = 50,
|
|
58
53
|
show_stable = $bindable(DEFAULTS.convex_hull.quaternary.show_stable),
|
|
59
54
|
show_unstable = $bindable(DEFAULTS.convex_hull.quaternary.show_unstable),
|
|
55
|
+
entry_category = MAGNETIC_ORDERING_CATEGORY,
|
|
56
|
+
hidden_categories = $bindable([]),
|
|
60
57
|
show_hull_faces = $bindable(DEFAULTS.convex_hull.quaternary.show_hull_faces),
|
|
61
58
|
hull_face_opacity = $bindable(DEFAULTS.convex_hull.quaternary.hull_face_opacity),
|
|
62
59
|
hull_face_color_mode = $bindable(
|
|
@@ -68,7 +65,7 @@
|
|
|
68
65
|
DEFAULTS.convex_hull.quaternary.color_scale as D3InterpolateName,
|
|
69
66
|
),
|
|
70
67
|
info_pane_open = $bindable(DEFAULTS.convex_hull.quaternary.info_pane_open),
|
|
71
|
-
|
|
68
|
+
controls_open = $bindable(DEFAULTS.convex_hull.quaternary.legend_pane_open),
|
|
72
69
|
max_hull_dist_show_phases = $bindable(
|
|
73
70
|
DEFAULTS.convex_hull.quaternary.max_hull_dist_show_phases,
|
|
74
71
|
),
|
|
@@ -104,7 +101,7 @@
|
|
|
104
101
|
} = $props()
|
|
105
102
|
|
|
106
103
|
const merged_controls = $derived({ ...default_controls, ...controls })
|
|
107
|
-
const controls_config = $derived(normalize_show_controls(
|
|
104
|
+
const controls_config = $derived(normalize_show_controls(show_controls))
|
|
108
105
|
const merged_config = $derived({
|
|
109
106
|
...default_hull_config,
|
|
110
107
|
...config,
|
|
@@ -117,87 +114,36 @@
|
|
|
117
114
|
$effect(() => watch_dark_mode((dark) => dark_mode = dark))
|
|
118
115
|
const text_color = $derived(helpers.get_canvas_text_color(dark_mode))
|
|
119
116
|
|
|
120
|
-
//
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
)
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
const {
|
|
146
|
-
entries: gas_corrected_entries,
|
|
147
|
-
analysis: gas_analysis,
|
|
148
|
-
merged_config: merged_gas_config,
|
|
149
|
-
} = $derived(
|
|
150
|
-
helpers.get_gas_corrected_entries(
|
|
151
|
-
temp_filtered_entries,
|
|
152
|
-
gas_config,
|
|
153
|
-
gas_pressures,
|
|
154
|
-
temperature ?? helpers.DEFAULT_GAS_TEMP,
|
|
155
|
-
),
|
|
156
|
-
)
|
|
157
|
-
|
|
158
|
-
let { // Compute energy mode information
|
|
159
|
-
has_precomputed_e_form,
|
|
160
|
-
has_precomputed_hull,
|
|
161
|
-
can_compute_e_form,
|
|
162
|
-
can_compute_hull,
|
|
163
|
-
energy_mode,
|
|
164
|
-
unary_refs,
|
|
165
|
-
} = $derived(
|
|
166
|
-
helpers.compute_energy_mode_info(
|
|
167
|
-
gas_corrected_entries,
|
|
168
|
-
thermo.find_lowest_energy_unary_refs,
|
|
169
|
-
energy_source_mode,
|
|
170
|
-
),
|
|
171
|
-
)
|
|
172
|
-
|
|
173
|
-
const effective_entries = $derived(
|
|
174
|
-
helpers.get_effective_entries(
|
|
175
|
-
gas_corrected_entries,
|
|
176
|
-
energy_mode,
|
|
177
|
-
unary_refs,
|
|
178
|
-
thermo.compute_e_form_per_atom,
|
|
179
|
-
),
|
|
180
|
-
)
|
|
181
|
-
|
|
182
|
-
// Process convex hull data with unified PhaseData interface using effective entries
|
|
183
|
-
const pd_data = $derived(thermo.process_hull_entries(effective_entries))
|
|
184
|
-
|
|
185
|
-
// Pre-compute polymorph stats once for O(1) tooltip lookups
|
|
186
|
-
const polymorph_stats_map = $derived(
|
|
187
|
-
helpers.compute_all_polymorph_stats(effective_entries),
|
|
188
|
-
)
|
|
189
|
-
|
|
190
|
-
const elements = $derived.by(() => {
|
|
191
|
-
if (pd_data.elements.length > 4) {
|
|
192
|
-
console.error(
|
|
193
|
-
`ConvexHull4D: Dataset contains ${pd_data.elements.length} elements, but quaternary diagrams require exactly 4. Found: [${
|
|
194
|
-
pd_data.elements.join(`, `)
|
|
195
|
-
}]`,
|
|
196
|
-
)
|
|
197
|
-
return []
|
|
198
|
-
}
|
|
199
|
-
return pd_data.elements
|
|
117
|
+
// Shared reactive data pipeline (temperature → gas → energy mode → hull data → threshold)
|
|
118
|
+
// Explicit generic breaks the circular type inference through the all_enriched_entries thunk
|
|
119
|
+
const hull_data = create_hull_data_pipeline<ConvexHullEntry>({
|
|
120
|
+
dim: 4,
|
|
121
|
+
entries: () => entries,
|
|
122
|
+
temperature: () => temperature,
|
|
123
|
+
interpolate_temperature: () => interpolate_temperature,
|
|
124
|
+
max_interpolation_gap: () => max_interpolation_gap,
|
|
125
|
+
gas_config: () => gas_config,
|
|
126
|
+
gas_pressures: () => gas_pressures,
|
|
127
|
+
energy_source_mode: () => energy_source_mode,
|
|
128
|
+
all_enriched_entries: () => all_enriched_entries,
|
|
129
|
+
max_hull_dist_show_phases: () => max_hull_dist_show_phases,
|
|
130
|
+
show_stable: () => show_stable,
|
|
131
|
+
show_unstable: () => show_unstable,
|
|
132
|
+
entry_category: () => entry_category,
|
|
133
|
+
hidden_categories: () => hidden_categories,
|
|
134
|
+
// Always include stable entries and elemental reference points
|
|
135
|
+
keep_plot_entry: (entry, max_dist) =>
|
|
136
|
+
helpers.entry_is_stable(entry) ||
|
|
137
|
+
(typeof entry.e_above_hull === `number` && entry.e_above_hull <= max_dist),
|
|
138
|
+
set_temperature: (next_temp) => temperature = next_temp,
|
|
139
|
+
set_max_hull_dist_show_phases: (value) => max_hull_dist_show_phases = value,
|
|
140
|
+
set_stable_entries: (value) => stable_entries = value,
|
|
141
|
+
set_unstable_entries: (value) => unstable_entries = value,
|
|
200
142
|
})
|
|
143
|
+
const merged_gas_config = $derived(hull_data.merged_gas_config)
|
|
144
|
+
const pd_data = $derived(hull_data.pd_data)
|
|
145
|
+
const elements = $derived(hull_data.elements)
|
|
146
|
+
const plot_entries = $derived(hull_data.plot_entries)
|
|
201
147
|
|
|
202
148
|
// Compute 4D hull for visualization (always compute when we have formation energies)
|
|
203
149
|
const hull_4d = $derived.by(() => {
|
|
@@ -234,11 +180,12 @@
|
|
|
234
180
|
})
|
|
235
181
|
|
|
236
182
|
// Enrich coords with e_above_hull (before filtering)
|
|
237
|
-
|
|
183
|
+
// Explicit return type breaks circular type inference with the hull_data pipeline
|
|
184
|
+
const all_enriched_entries = $derived.by((): ConvexHullEntry[] => {
|
|
238
185
|
if (elements.length !== 4) return []
|
|
239
186
|
try {
|
|
240
187
|
const coords = compute_4d_coords(pd_data.entries, elements)
|
|
241
|
-
if (energy_mode !== `on-the-fly` || hull_4d.length === 0) return coords
|
|
188
|
+
if (hull_data.energy_mode !== `on-the-fly` || hull_4d.length === 0) return coords
|
|
242
189
|
|
|
243
190
|
// Build 4D points, tracking original indices for mapping hull distances back
|
|
244
191
|
const valid = coords.flatMap((entry, idx) => {
|
|
@@ -267,51 +214,8 @@
|
|
|
267
214
|
}
|
|
268
215
|
})
|
|
269
216
|
|
|
270
|
-
// Auto threshold: show all for few entries, use default for many, interpolate between
|
|
271
|
-
const max_hull_dist_in_data = $derived(
|
|
272
|
-
helpers.calc_max_hull_dist_in_data(all_enriched_entries),
|
|
273
|
-
)
|
|
274
|
-
const auto_default_threshold = $derived(helpers.compute_auto_hull_dist_threshold(
|
|
275
|
-
all_enriched_entries.length,
|
|
276
|
-
max_hull_dist_in_data,
|
|
277
|
-
DEFAULTS.convex_hull.quaternary.max_hull_dist_show_phases,
|
|
278
|
-
))
|
|
279
|
-
|
|
280
|
-
const next_auto_threshold = helpers.auto_threshold_reset(
|
|
281
|
-
DEFAULTS.convex_hull.quaternary.max_hull_dist_show_phases,
|
|
282
|
-
)
|
|
283
|
-
$effect(() => {
|
|
284
|
-
max_hull_dist_show_phases = next_auto_threshold(
|
|
285
|
-
entries,
|
|
286
|
-
max_hull_dist_show_phases,
|
|
287
|
-
auto_default_threshold,
|
|
288
|
-
) ?? max_hull_dist_show_phases
|
|
289
|
-
})
|
|
290
|
-
|
|
291
|
-
// Filter by threshold; visibility is a view predicate, not entry state.
|
|
292
|
-
const plot_entries = $derived(
|
|
293
|
-
all_enriched_entries.filter((entry) => {
|
|
294
|
-
// Always include stable entries and elemental reference points
|
|
295
|
-
if (helpers.entry_is_stable(entry)) return true
|
|
296
|
-
return typeof entry.e_above_hull === `number` &&
|
|
297
|
-
entry.e_above_hull <= max_hull_dist_show_phases
|
|
298
|
-
}),
|
|
299
|
-
)
|
|
300
|
-
const visible_entries = $derived(helpers.visible_entries(
|
|
301
|
-
plot_entries,
|
|
302
|
-
show_stable,
|
|
303
|
-
show_unstable,
|
|
304
|
-
))
|
|
305
|
-
|
|
306
|
-
// Stable and unstable entries exposed as bindable props
|
|
307
|
-
$effect(() => {
|
|
308
|
-
stable_entries = plot_entries.filter(helpers.entry_is_stable)
|
|
309
|
-
unstable_entries = plot_entries.filter(helpers.entry_is_unstable)
|
|
310
|
-
})
|
|
311
|
-
|
|
312
217
|
let canvas: HTMLCanvasElement | undefined = undefined
|
|
313
218
|
let ctx: CanvasRenderingContext2D | null = null
|
|
314
|
-
let frame_id = 0 // Performance optimization
|
|
315
219
|
|
|
316
220
|
// Camera state - following Materials Project's 3D camera setup
|
|
317
221
|
let camera = $state({
|
|
@@ -322,43 +226,60 @@
|
|
|
322
226
|
center_y: 20, // Slight offset to avoid legend overlap
|
|
323
227
|
})
|
|
324
228
|
|
|
325
|
-
//
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
229
|
+
// Shared canvas-interaction scaffold (mouse/keyboard handlers, hover/drag/popup
|
|
230
|
+
// state, canvas sizing, render scheduler). Rotation math + keydown actions stay local.
|
|
231
|
+
const interactions = create_canvas_interactions({
|
|
232
|
+
wheel_clamp: [1.0, 15],
|
|
233
|
+
fullscreen_bg_var: `--hull-4d-bg-fullscreen`,
|
|
234
|
+
canvas: () => canvas,
|
|
235
|
+
wrapper: () => wrapper,
|
|
236
|
+
ctx: () => ctx,
|
|
237
|
+
set_ctx: (context) => ctx = context,
|
|
238
|
+
set_canvas_dims: (dims) => canvas_dims = dims,
|
|
239
|
+
visible_entries: () => hull_data.visible_entries,
|
|
240
|
+
plot_entries: () => plot_entries,
|
|
241
|
+
selected_entry: () => selected_entry,
|
|
242
|
+
set_selected_entry: (entry) => selected_entry = entry,
|
|
243
|
+
fullscreen: () => fullscreen,
|
|
244
|
+
enable_click_selection: () => enable_click_selection,
|
|
245
|
+
enable_structure_preview: () => enable_structure_preview,
|
|
246
|
+
on_point_click: () => on_point_click,
|
|
247
|
+
on_point_hover: () => on_point_hover,
|
|
248
|
+
on_file_drop: () => on_file_drop,
|
|
249
|
+
entry_category: () => entry_category,
|
|
250
|
+
zoom: () => camera.zoom,
|
|
251
|
+
set_zoom: (zoom) => camera.zoom = zoom,
|
|
252
|
+
project_point: project_3d_point,
|
|
253
|
+
extract_structure: extract_structure_from_entry,
|
|
254
|
+
render_frame,
|
|
255
|
+
on_drag: (dx, dy, panning) => {
|
|
256
|
+
if (panning) {
|
|
257
|
+
camera.center_x += dx
|
|
258
|
+
camera.center_y += dy
|
|
259
|
+
} else {
|
|
260
|
+
camera.rotation_y += dx * 0.005
|
|
261
|
+
camera.rotation_x = Math.max(
|
|
262
|
+
-Math.PI / 3,
|
|
263
|
+
Math.min(Math.PI / 3, camera.rotation_x - dy * 0.005),
|
|
264
|
+
)
|
|
359
265
|
}
|
|
360
|
-
}
|
|
266
|
+
},
|
|
267
|
+
// Reset pan center when entering/exiting fullscreen
|
|
268
|
+
on_fullscreen_change: () => {
|
|
269
|
+
camera.center_x = 0
|
|
270
|
+
camera.center_y = 20
|
|
271
|
+
},
|
|
272
|
+
actions: () => ({
|
|
273
|
+
r: reset_camera,
|
|
274
|
+
b: () => color_mode = color_mode === `stability` ? `energy` : `stability`,
|
|
275
|
+
s: () => show_stable = !show_stable,
|
|
276
|
+
u: () => show_unstable = !show_unstable,
|
|
277
|
+
h: () => show_hull_faces = !show_hull_faces,
|
|
278
|
+
l: () => show_stable_labels = !show_stable_labels,
|
|
279
|
+
}),
|
|
361
280
|
})
|
|
281
|
+
const { render_once } = interactions
|
|
282
|
+
const sorted_points_cache = $derived(interactions.sorted_points_cache)
|
|
362
283
|
|
|
363
284
|
// Hull face color (customizable via controls)
|
|
364
285
|
let hull_face_color = $state(`#4caf50`)
|
|
@@ -382,31 +303,27 @@
|
|
|
382
303
|
// Re-render when important state changes
|
|
383
304
|
$effect(() => {
|
|
384
305
|
// oxfmt-ignore
|
|
385
|
-
void [show_hull_faces, color_mode, color_scale, camera.rotation_x, camera.rotation_y, camera.zoom, camera.center_x, camera.center_y, plot_entries, hull_face_color, hull_face_opacity, hull_face_color_mode, element_colors, text_color, elements] // track reactively
|
|
306
|
+
void [show_hull_faces, color_mode, color_scale, camera.rotation_x, camera.rotation_y, camera.zoom, camera.center_x, camera.center_y, plot_entries, hull_data.visible_entries, hull_face_color, hull_face_opacity, hull_face_color_mode, element_colors, text_color, elements] // track reactively
|
|
386
307
|
|
|
387
308
|
render_once()
|
|
388
309
|
})
|
|
389
310
|
|
|
390
311
|
// Visibility toggles are now bindable props
|
|
391
312
|
|
|
392
|
-
// Smart label defaults
|
|
313
|
+
// Smart label defaults: hide labels for large datasets. Applied once per dataset
|
|
314
|
+
// (keyed on the entries prop) so later entry-count changes from temperature/gas
|
|
315
|
+
// filtering don't clobber the user's label toggles.
|
|
316
|
+
let label_defaults_applied_for: PhaseData[] | null = null
|
|
393
317
|
$effect(() => {
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
} else {
|
|
398
|
-
// For smaller datasets, show stable labels by default
|
|
399
|
-
show_stable_labels = true
|
|
400
|
-
}
|
|
318
|
+
if (label_defaults_applied_for === entries) return
|
|
319
|
+
label_defaults_applied_for = entries
|
|
320
|
+
show_stable_labels = hull_data.effective_entries.length <= label_threshold
|
|
401
321
|
show_unstable_labels = false
|
|
402
322
|
})
|
|
403
323
|
|
|
404
|
-
//
|
|
405
|
-
function extract_structure_from_entry(
|
|
406
|
-
|
|
407
|
-
): AnyStructure | null {
|
|
408
|
-
const orig_entry = entries.find((ent) => ent.entry_id === entry.entry_id)
|
|
409
|
-
return orig_entry?.structure as AnyStructure || null
|
|
324
|
+
// function (not const) so the create_canvas_interactions options above can reference it
|
|
325
|
+
function extract_structure_from_entry(entry: ConvexHullEntry): AnyStructure | null {
|
|
326
|
+
return helpers.extract_structure_from_entry(entries, entry)
|
|
410
327
|
}
|
|
411
328
|
|
|
412
329
|
const reset_camera = () => {
|
|
@@ -420,15 +337,16 @@
|
|
|
420
337
|
reset_camera()
|
|
421
338
|
fullscreen = DEFAULTS.convex_hull.quaternary.fullscreen
|
|
422
339
|
info_pane_open = DEFAULTS.convex_hull.quaternary.info_pane_open
|
|
423
|
-
|
|
340
|
+
controls_open = DEFAULTS.convex_hull.quaternary.legend_pane_open
|
|
424
341
|
color_mode = DEFAULTS.convex_hull.quaternary.color_mode
|
|
425
342
|
color_scale = DEFAULTS.convex_hull.quaternary.color_scale as D3InterpolateName
|
|
426
343
|
show_stable = DEFAULTS.convex_hull.quaternary.show_stable
|
|
427
344
|
show_unstable = DEFAULTS.convex_hull.quaternary.show_unstable
|
|
345
|
+
hidden_categories = []
|
|
428
346
|
show_stable_labels = DEFAULTS.convex_hull.quaternary.show_stable_labels
|
|
429
347
|
show_unstable_labels = DEFAULTS.convex_hull.quaternary.show_unstable_labels
|
|
430
348
|
// Use auto-computed threshold based on entry count instead of static default
|
|
431
|
-
max_hull_dist_show_phases = auto_default_threshold
|
|
349
|
+
max_hull_dist_show_phases = hull_data.auto_default_threshold
|
|
432
350
|
max_hull_dist_show_labels =
|
|
433
351
|
DEFAULTS.convex_hull.quaternary.max_hull_dist_show_labels
|
|
434
352
|
show_hull_faces = DEFAULTS.convex_hull.quaternary.show_hull_faces
|
|
@@ -438,69 +356,6 @@
|
|
|
438
356
|
.hull_face_color_mode as HullFaceColorMode
|
|
439
357
|
}
|
|
440
358
|
|
|
441
|
-
const handle_keydown = (event: KeyboardEvent) => {
|
|
442
|
-
const target = event.target
|
|
443
|
-
// Skip if focus is on an interactive element that handles Enter natively
|
|
444
|
-
const interactive_selector =
|
|
445
|
-
`input,textarea,select,button,a,[contenteditable="true"],[role="button"],[tabindex]:not([tabindex="-1"])`
|
|
446
|
-
if (
|
|
447
|
-
target instanceof HTMLElement &&
|
|
448
|
-
target.matches(interactive_selector) &&
|
|
449
|
-
target !== canvas
|
|
450
|
-
) return
|
|
451
|
-
|
|
452
|
-
// Prevent double handling from canvas + wrapper bubbling
|
|
453
|
-
if (event.target !== event.currentTarget && event.currentTarget !== canvas) return
|
|
454
|
-
|
|
455
|
-
// Handle Enter for keyboard accessibility - select hovered entry
|
|
456
|
-
if (event.key === `Enter`) {
|
|
457
|
-
const entry = hover_data?.entry
|
|
458
|
-
if (entry) {
|
|
459
|
-
on_point_click?.(entry)
|
|
460
|
-
if (enable_click_selection) {
|
|
461
|
-
selected_entry = entry
|
|
462
|
-
if (enable_structure_preview) {
|
|
463
|
-
const structure = extract_structure_from_entry(entry)
|
|
464
|
-
if (structure) {
|
|
465
|
-
selected_structure = structure
|
|
466
|
-
modal_place_right = helpers.calculate_modal_side(wrapper)
|
|
467
|
-
modal_open = true
|
|
468
|
-
}
|
|
469
|
-
}
|
|
470
|
-
}
|
|
471
|
-
} else if (modal_open) {
|
|
472
|
-
close_structure_popup()
|
|
473
|
-
}
|
|
474
|
-
return
|
|
475
|
-
}
|
|
476
|
-
|
|
477
|
-
const actions: Record<string, () => void> = {
|
|
478
|
-
r: reset_camera,
|
|
479
|
-
b: () => color_mode = color_mode === `stability` ? `energy` : `stability`,
|
|
480
|
-
s: () => show_stable = !show_stable,
|
|
481
|
-
u: () => show_unstable = !show_unstable,
|
|
482
|
-
h: () => show_hull_faces = !show_hull_faces,
|
|
483
|
-
l: () => show_stable_labels = !show_stable_labels,
|
|
484
|
-
}
|
|
485
|
-
actions[event.key.toLowerCase()]?.()
|
|
486
|
-
}
|
|
487
|
-
|
|
488
|
-
async function handle_file_drop(event: DragEvent): Promise<void> {
|
|
489
|
-
drag_over = false
|
|
490
|
-
const data = await helpers.parse_hull_entries_from_drop(event)
|
|
491
|
-
if (data) on_file_drop?.(data)
|
|
492
|
-
}
|
|
493
|
-
|
|
494
|
-
async function copy_entry_data(
|
|
495
|
-
entry: ConvexHullEntry,
|
|
496
|
-
position: { x: number; y: number },
|
|
497
|
-
) {
|
|
498
|
-
await helpers.copy_entry_to_clipboard(entry, position, (visible, pos) => {
|
|
499
|
-
copy_feedback.visible = visible
|
|
500
|
-
copy_feedback.position = pos
|
|
501
|
-
})
|
|
502
|
-
}
|
|
503
|
-
|
|
504
359
|
const get_point_color = (entry: ConvexHullEntry): string =>
|
|
505
360
|
helpers.get_point_color_for_entry(
|
|
506
361
|
entry,
|
|
@@ -736,14 +591,14 @@
|
|
|
736
591
|
triangles.sort((a, b) => a.avg_depth - b.avg_depth)
|
|
737
592
|
|
|
738
593
|
// Lazy computation for uniform mode: normalize alpha by formation energy
|
|
739
|
-
let norm_alpha: ((
|
|
594
|
+
let norm_alpha: ((energy: number) => number) | null = null
|
|
740
595
|
if (hull_face_color_mode === `uniform`) {
|
|
741
596
|
norm_alpha = (energy: number) => {
|
|
742
|
-
const
|
|
597
|
+
const frac = Math.max(
|
|
743
598
|
0,
|
|
744
599
|
Math.min(1, (0 - energy) / Math.max(1e-6, 0 - formation_energy_min)),
|
|
745
600
|
)
|
|
746
|
-
return
|
|
601
|
+
return frac * hull_face_opacity
|
|
747
602
|
}
|
|
748
603
|
}
|
|
749
604
|
|
|
@@ -809,59 +664,16 @@
|
|
|
809
664
|
|
|
810
665
|
function draw_data_points(): void {
|
|
811
666
|
if (!ctx || sorted_points_cache.length === 0) return
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
ctx.fillStyle = `rgba(0, 0, 0, 0.2)`
|
|
823
|
-
const shadow_path = helpers.create_marker_path(size * 0.8, marker)
|
|
824
|
-
ctx.save()
|
|
825
|
-
ctx.translate(projected.x + shadow_offset, projected.y + shadow_offset)
|
|
826
|
-
ctx.fill(shadow_path)
|
|
827
|
-
ctx.restore()
|
|
828
|
-
|
|
829
|
-
// Highlights
|
|
830
|
-
if (selected_entry && entry.entry_id === selected_entry.entry_id) {
|
|
831
|
-
helpers.draw_selection_highlight(
|
|
832
|
-
ctx,
|
|
833
|
-
projected,
|
|
834
|
-
size,
|
|
835
|
-
canvas_dims.scale,
|
|
836
|
-
pulse.time,
|
|
837
|
-
pulse_opacity,
|
|
838
|
-
)
|
|
839
|
-
}
|
|
840
|
-
if (is_entry_highlighted) {
|
|
841
|
-
helpers.draw_highlight_effect(
|
|
842
|
-
ctx,
|
|
843
|
-
projected,
|
|
844
|
-
size,
|
|
845
|
-
canvas_dims.scale,
|
|
846
|
-
pulse.time,
|
|
847
|
-
merged_highlight_style,
|
|
848
|
-
)
|
|
849
|
-
}
|
|
850
|
-
|
|
851
|
-
// Main point with marker symbol
|
|
852
|
-
ctx.fillStyle =
|
|
853
|
-
is_entry_highlighted && merged_highlight_style.effect === `color`
|
|
854
|
-
? merged_highlight_style.color
|
|
855
|
-
: color
|
|
856
|
-
ctx.strokeStyle = is_stable ? `#ffffff` : `#000000`
|
|
857
|
-
ctx.lineWidth = 0.5 * canvas_dims.scale
|
|
858
|
-
const marker_path = helpers.create_marker_path(size, marker)
|
|
859
|
-
ctx.save()
|
|
860
|
-
ctx.translate(projected.x, projected.y)
|
|
861
|
-
ctx.fill(marker_path)
|
|
862
|
-
ctx.stroke(marker_path)
|
|
863
|
-
ctx.restore()
|
|
864
|
-
}
|
|
667
|
+
helpers.draw_hull_points(ctx, sorted_points_cache, {
|
|
668
|
+
scale: canvas_dims.scale,
|
|
669
|
+
shadow_factor: 2,
|
|
670
|
+
selected_entry,
|
|
671
|
+
is_highlighted,
|
|
672
|
+
get_point_color,
|
|
673
|
+
highlight_style: merged_highlight_style,
|
|
674
|
+
pulse_time: pulse.time,
|
|
675
|
+
pulse_opacity,
|
|
676
|
+
})
|
|
865
677
|
|
|
866
678
|
if (!merged_config.show_labels) return
|
|
867
679
|
|
|
@@ -925,169 +737,7 @@
|
|
|
925
737
|
draw_data_points() // Draw data points (on top)
|
|
926
738
|
}
|
|
927
739
|
|
|
928
|
-
|
|
929
|
-
is_dragging = true
|
|
930
|
-
drag_started = false
|
|
931
|
-
hover_data = null
|
|
932
|
-
on_point_hover?.(null)
|
|
933
|
-
last_mouse = { x: event.clientX, y: event.clientY }
|
|
934
|
-
}
|
|
935
|
-
|
|
936
|
-
const handle_mouse_move = (event: MouseEvent) => {
|
|
937
|
-
if (!is_dragging) return
|
|
938
|
-
const [dx, dy] = [event.clientX - last_mouse.x, event.clientY - last_mouse.y]
|
|
939
|
-
|
|
940
|
-
// Mark as drag if any movement occurred
|
|
941
|
-
if (dx !== 0 || dy !== 0) drag_started = true
|
|
942
|
-
|
|
943
|
-
// With Cmd/Ctrl held: pan the view instead of rotating
|
|
944
|
-
if (event.metaKey || event.ctrlKey) {
|
|
945
|
-
camera.center_x += dx
|
|
946
|
-
camera.center_y += dy
|
|
947
|
-
} else {
|
|
948
|
-
camera.rotation_y += dx * 0.005
|
|
949
|
-
camera.rotation_x = Math.max(
|
|
950
|
-
-Math.PI / 3,
|
|
951
|
-
Math.min(Math.PI / 3, camera.rotation_x - dy * 0.005),
|
|
952
|
-
)
|
|
953
|
-
}
|
|
954
|
-
last_mouse = { x: event.clientX, y: event.clientY }
|
|
955
|
-
}
|
|
956
|
-
|
|
957
|
-
const handle_wheel = (event: WheelEvent) => {
|
|
958
|
-
event.preventDefault()
|
|
959
|
-
camera.zoom = Math.max(
|
|
960
|
-
1.0,
|
|
961
|
-
Math.min(15, camera.zoom * (event.deltaY > 0 ? 0.98 : 1.02)),
|
|
962
|
-
)
|
|
963
|
-
}
|
|
964
|
-
|
|
965
|
-
const handle_hover = (event: MouseEvent) => {
|
|
966
|
-
if (is_dragging) return
|
|
967
|
-
const entry = find_entry_at_mouse(event)
|
|
968
|
-
hover_data = entry
|
|
969
|
-
? { entry, position: { x: event.clientX, y: event.clientY } }
|
|
970
|
-
: null
|
|
971
|
-
on_point_hover?.(hover_data)
|
|
972
|
-
}
|
|
973
|
-
|
|
974
|
-
const find_entry_at_mouse = (event: MouseEvent): ConvexHullEntry | null =>
|
|
975
|
-
helpers.find_hull_entry_at_mouse(
|
|
976
|
-
canvas,
|
|
977
|
-
event,
|
|
978
|
-
visible_entries,
|
|
979
|
-
(x: number, y: number, z: number) => {
|
|
980
|
-
const projected = project_3d_point(x, y, z)
|
|
981
|
-
return { x: projected.x, y: projected.y }
|
|
982
|
-
},
|
|
983
|
-
)
|
|
984
|
-
|
|
985
|
-
const handle_click = (event: MouseEvent) => {
|
|
986
|
-
event.stopPropagation()
|
|
987
|
-
|
|
988
|
-
// Check if this was a drag operation (any mouse movement during drag)
|
|
989
|
-
const was_drag = drag_started
|
|
990
|
-
drag_started = false // Reset for next interaction
|
|
991
|
-
if (was_drag) return // Don't trigger click if this was a drag
|
|
992
|
-
|
|
993
|
-
const entry = find_entry_at_mouse(event)
|
|
994
|
-
if (entry) {
|
|
995
|
-
on_point_click?.(entry)
|
|
996
|
-
if (enable_click_selection) {
|
|
997
|
-
selected_entry = entry
|
|
998
|
-
if (enable_structure_preview) {
|
|
999
|
-
const structure = extract_structure_from_entry(entry)
|
|
1000
|
-
if (structure) {
|
|
1001
|
-
selected_structure = structure
|
|
1002
|
-
modal_place_right = helpers.calculate_modal_side(wrapper)
|
|
1003
|
-
modal_open = true
|
|
1004
|
-
}
|
|
1005
|
-
}
|
|
1006
|
-
}
|
|
1007
|
-
} else if (modal_open) close_structure_popup()
|
|
1008
|
-
}
|
|
1009
|
-
|
|
1010
|
-
function close_structure_popup() {
|
|
1011
|
-
modal_open = false
|
|
1012
|
-
selected_structure = null
|
|
1013
|
-
selected_entry = null
|
|
1014
|
-
}
|
|
1015
|
-
|
|
1016
|
-
const handle_double_click = (event: MouseEvent) => {
|
|
1017
|
-
const entry = find_entry_at_mouse(event)
|
|
1018
|
-
if (entry) {
|
|
1019
|
-
copy_entry_data(entry, {
|
|
1020
|
-
x: event.clientX,
|
|
1021
|
-
y: event.clientY,
|
|
1022
|
-
})
|
|
1023
|
-
}
|
|
1024
|
-
}
|
|
1025
|
-
|
|
1026
|
-
function render_once() {
|
|
1027
|
-
if (!frame_id) {
|
|
1028
|
-
frame_id = requestAnimationFrame(() => {
|
|
1029
|
-
render_frame()
|
|
1030
|
-
frame_id = 0
|
|
1031
|
-
})
|
|
1032
|
-
}
|
|
1033
|
-
}
|
|
1034
|
-
|
|
1035
|
-
function update_canvas_size() {
|
|
1036
|
-
if (!canvas) return
|
|
1037
|
-
const dpr = globalThis.devicePixelRatio || 1
|
|
1038
|
-
const container = canvas.parentElement
|
|
1039
|
-
const rect = container?.getBoundingClientRect()
|
|
1040
|
-
const [width, height] = rect ? [rect.width, rect.height] : [400, 400]
|
|
1041
|
-
|
|
1042
|
-
const new_width = Math.max(0, Math.round(width * dpr))
|
|
1043
|
-
const new_height = Math.max(0, Math.round(height * dpr))
|
|
1044
|
-
canvas_dims = { width, height, scale: Math.min(width, height) / 600 }
|
|
1045
|
-
|
|
1046
|
-
if (!ctx || canvas.width !== new_width || canvas.height !== new_height) {
|
|
1047
|
-
canvas.width = new_width
|
|
1048
|
-
canvas.height = new_height
|
|
1049
|
-
ctx = canvas.getContext(`2d`)
|
|
1050
|
-
if (ctx) {
|
|
1051
|
-
ctx.setTransform(dpr, 0, 0, dpr, 0, 0)
|
|
1052
|
-
ctx.imageSmoothingEnabled = true
|
|
1053
|
-
ctx.imageSmoothingQuality = `high`
|
|
1054
|
-
}
|
|
1055
|
-
}
|
|
1056
|
-
render_once()
|
|
1057
|
-
}
|
|
1058
|
-
|
|
1059
|
-
$effect(() => {
|
|
1060
|
-
if (!canvas) return
|
|
1061
|
-
|
|
1062
|
-
// Initial setup
|
|
1063
|
-
update_canvas_size()
|
|
1064
|
-
|
|
1065
|
-
// Watch for resize events - only update canvas, don't reset camera
|
|
1066
|
-
const resize_observer = new ResizeObserver(update_canvas_size)
|
|
1067
|
-
|
|
1068
|
-
const container = canvas.parentElement
|
|
1069
|
-
if (container) resize_observer.observe(container)
|
|
1070
|
-
|
|
1071
|
-
return () => { // Cleanup on unmount
|
|
1072
|
-
if (frame_id) cancelAnimationFrame(frame_id)
|
|
1073
|
-
resize_observer.disconnect()
|
|
1074
|
-
}
|
|
1075
|
-
})
|
|
1076
|
-
|
|
1077
|
-
// Fullscreen handling with camera reset
|
|
1078
|
-
let was_fullscreen = $state(fullscreen)
|
|
1079
|
-
$effect(() => {
|
|
1080
|
-
setup_fullscreen_effect(fullscreen, wrapper, (entering_fullscreen) => {
|
|
1081
|
-
if (entering_fullscreen !== was_fullscreen) {
|
|
1082
|
-
camera.center_x = 0
|
|
1083
|
-
camera.center_y = 20
|
|
1084
|
-
was_fullscreen = entering_fullscreen
|
|
1085
|
-
}
|
|
1086
|
-
})
|
|
1087
|
-
set_fullscreen_bg(wrapper, fullscreen, `--hull-4d-bg-fullscreen`)
|
|
1088
|
-
})
|
|
1089
|
-
|
|
1090
|
-
// Performance: Cache canvas dimensions and pre-compute sorted point projections
|
|
740
|
+
// Performance: Cache canvas dimensions and formation energy minimum
|
|
1091
741
|
let canvas_dims = $state({ width: 600, height: 600, scale: 1 })
|
|
1092
742
|
const formation_energy_min = $derived.by(() => {
|
|
1093
743
|
let min_energy = 0
|
|
@@ -1096,57 +746,33 @@
|
|
|
1096
746
|
}
|
|
1097
747
|
return min_energy
|
|
1098
748
|
})
|
|
1099
|
-
const sorted_points_cache = $derived.by(() => {
|
|
1100
|
-
if (!canvas || visible_entries.length === 0) return []
|
|
1101
|
-
return visible_entries
|
|
1102
|
-
.map((entry) => ({
|
|
1103
|
-
entry,
|
|
1104
|
-
projected: project_3d_point(entry.x, entry.y, entry.z),
|
|
1105
|
-
}))
|
|
1106
|
-
.sort((a, b) => a.projected.depth - b.projected.depth)
|
|
1107
|
-
})
|
|
1108
749
|
|
|
1109
|
-
let style = $derived(
|
|
1110
|
-
`--hull-stable-color:${merged_config.colors?.stable || `#0072B2`};
|
|
1111
|
-
--hull-unstable-color:${merged_config.colors?.unstable || `#E69F00`};
|
|
1112
|
-
--hull-edge-color:${merged_config.colors?.edge || `var(--text-color, #212121)`};
|
|
1113
|
-
--hull-text-color:${
|
|
1114
|
-
merged_config.colors?.annotation || `var(--text-color, #212121)`
|
|
1115
|
-
}`,
|
|
1116
|
-
)
|
|
750
|
+
let style = $derived(helpers.hull_style_css(merged_config.colors))
|
|
1117
751
|
</script>
|
|
1118
752
|
|
|
1119
753
|
<svelte:document
|
|
1120
754
|
onfullscreenchange={() => {
|
|
1121
|
-
fullscreen
|
|
755
|
+
// tie fullscreen state to this component's own wrapper, not any fullscreen element
|
|
756
|
+
fullscreen = document.fullscreenElement === wrapper
|
|
1122
757
|
}}
|
|
1123
|
-
onmousemove={handle_mouse_move}
|
|
1124
|
-
onmouseup={
|
|
758
|
+
onmousemove={interactions.handle_mouse_move}
|
|
759
|
+
onmouseup={interactions.handle_mouse_up}
|
|
1125
760
|
/>
|
|
1126
761
|
|
|
1127
762
|
<div
|
|
1128
763
|
{...rest}
|
|
1129
764
|
class="convex-hull-4d {rest.class ?? ``}"
|
|
1130
|
-
class:dragover={drag_over}
|
|
765
|
+
class:dragover={interactions.drag_over}
|
|
1131
766
|
style={`${style}; ${rest.style ?? ``}`}
|
|
1132
767
|
data-has-selection={selected_entry !== null}
|
|
1133
|
-
data-has-hover={hover_data !== null}
|
|
1134
|
-
data-is-dragging={is_dragging}
|
|
768
|
+
data-has-hover={interactions.hover_data !== null}
|
|
769
|
+
data-is-dragging={interactions.is_dragging}
|
|
1135
770
|
data-rotation-x={camera.rotation_x.toFixed(4)}
|
|
1136
771
|
data-rotation-y={camera.rotation_y.toFixed(4)}
|
|
1137
772
|
bind:this={wrapper}
|
|
1138
773
|
role="application"
|
|
1139
774
|
tabindex="-1"
|
|
1140
|
-
|
|
1141
|
-
ondrop={handle_file_drop}
|
|
1142
|
-
ondragover={(event) => {
|
|
1143
|
-
event.preventDefault()
|
|
1144
|
-
drag_over = true
|
|
1145
|
-
}}
|
|
1146
|
-
ondragleave={(event) => {
|
|
1147
|
-
event.preventDefault()
|
|
1148
|
-
drag_over = false
|
|
1149
|
-
}}
|
|
775
|
+
{...interactions.wrapper_handlers}
|
|
1150
776
|
aria-label="Convex hull visualization"
|
|
1151
777
|
>
|
|
1152
778
|
{@render children?.({
|
|
@@ -1163,12 +789,7 @@
|
|
|
1163
789
|
bind:this={canvas}
|
|
1164
790
|
tabindex="0"
|
|
1165
791
|
aria-label={merged_controls.title || phase_stats?.chemical_system || `4D Convex Hull`}
|
|
1166
|
-
|
|
1167
|
-
onmousemove={handle_hover}
|
|
1168
|
-
onclick={handle_click}
|
|
1169
|
-
onkeydown={handle_keydown}
|
|
1170
|
-
ondblclick={handle_double_click}
|
|
1171
|
-
onwheel={handle_wheel}
|
|
792
|
+
{...interactions.canvas_handlers}
|
|
1172
793
|
></canvas>
|
|
1173
794
|
|
|
1174
795
|
{#if entries.length === 0}
|
|
@@ -1180,14 +801,9 @@
|
|
|
1180
801
|
|
|
1181
802
|
<!-- Energy above hull Color Bar -->
|
|
1182
803
|
{#if color_mode === `energy` && plot_entries.length > 0}
|
|
1183
|
-
{@const hull_distances = plot_entries
|
|
1184
|
-
.map((entry) => entry.e_above_hull)
|
|
1185
|
-
.filter((val): val is number => typeof val === `number`)}
|
|
1186
|
-
{@const min_energy = hull_distances.length > 0 ? Math.min(...hull_distances) : 0}
|
|
1187
|
-
{@const max_energy = hull_distances.length > 0 ? Math.max(...hull_distances, 0.1) : 0.1}
|
|
1188
804
|
<ColorBar
|
|
1189
805
|
title="Energy above hull (eV/atom)"
|
|
1190
|
-
range={
|
|
806
|
+
range={helpers.hull_distance_range(plot_entries)}
|
|
1191
807
|
{color_scale}
|
|
1192
808
|
wrapper_style="position: absolute; bottom: 2em; left: 1em; width: 200px;"
|
|
1193
809
|
bar_style="height: 12px;"
|
|
@@ -1195,88 +811,52 @@
|
|
|
1195
811
|
/>
|
|
1196
812
|
{/if}
|
|
1197
813
|
|
|
1198
|
-
<!--
|
|
1199
|
-
|
|
1200
|
-
|
|
1201
|
-
|
|
1202
|
-
|
|
1203
|
-
|
|
1204
|
-
|
|
1205
|
-
|
|
1206
|
-
|
|
1207
|
-
|
|
1208
|
-
|
|
1209
|
-
|
|
1210
|
-
|
|
1211
|
-
|
|
1212
|
-
|
|
1213
|
-
|
|
1214
|
-
|
|
1215
|
-
|
|
1216
|
-
|
|
1217
|
-
|
|
1218
|
-
|
|
1219
|
-
|
|
1220
|
-
|
|
1221
|
-
|
|
1222
|
-
|
|
1223
|
-
|
|
1224
|
-
|
|
1225
|
-
|
|
1226
|
-
|
|
1227
|
-
|
|
1228
|
-
|
|
1229
|
-
|
|
1230
|
-
|
|
1231
|
-
|
|
1232
|
-
|
|
1233
|
-
|
|
1234
|
-
|
|
1235
|
-
|
|
1236
|
-
|
|
1237
|
-
|
|
1238
|
-
|
|
1239
|
-
|
|
1240
|
-
|
|
1241
|
-
bind:controls_open={legend_pane_open}
|
|
1242
|
-
bind:color_mode
|
|
1243
|
-
bind:color_scale
|
|
1244
|
-
bind:show_stable
|
|
1245
|
-
bind:show_unstable
|
|
1246
|
-
bind:show_stable_labels
|
|
1247
|
-
bind:show_unstable_labels
|
|
1248
|
-
bind:max_hull_dist_show_phases
|
|
1249
|
-
bind:max_hull_dist_show_labels
|
|
1250
|
-
{max_hull_dist_in_data}
|
|
1251
|
-
{stable_entries}
|
|
1252
|
-
{unstable_entries}
|
|
1253
|
-
{camera}
|
|
1254
|
-
{merged_controls}
|
|
1255
|
-
toggle_props={{ class: `legend-controls-btn` }}
|
|
1256
|
-
{show_hull_faces}
|
|
1257
|
-
on_hull_faces_change={(value: boolean) => show_hull_faces = value}
|
|
1258
|
-
{hull_face_color}
|
|
1259
|
-
on_hull_face_color_change={(value: string) => hull_face_color = value}
|
|
1260
|
-
{hull_face_opacity}
|
|
1261
|
-
on_hull_face_opacity_change={(value: number) => hull_face_opacity = value}
|
|
1262
|
-
{hull_face_color_mode}
|
|
1263
|
-
on_hull_face_color_mode_change={(value: HullFaceColorMode) =>
|
|
1264
|
-
hull_face_color_mode = value}
|
|
1265
|
-
bind:energy_source_mode
|
|
1266
|
-
{has_precomputed_e_form}
|
|
1267
|
-
{can_compute_e_form}
|
|
1268
|
-
{has_precomputed_hull}
|
|
1269
|
-
{can_compute_hull}
|
|
1270
|
-
/>
|
|
1271
|
-
{/if}
|
|
1272
|
-
</section>
|
|
814
|
+
<!-- Toolbar + tooltip/copy-feedback/drag/structure-popup chrome -->
|
|
815
|
+
<ConvexHullChrome
|
|
816
|
+
{interactions}
|
|
817
|
+
{hull_data}
|
|
818
|
+
{controls_config}
|
|
819
|
+
{reset_all}
|
|
820
|
+
reset_title="Reset view and settings"
|
|
821
|
+
{enable_info_pane}
|
|
822
|
+
{phase_stats}
|
|
823
|
+
{label_threshold}
|
|
824
|
+
{fullscreen}
|
|
825
|
+
{fullscreen_toggle}
|
|
826
|
+
{wrapper}
|
|
827
|
+
{camera}
|
|
828
|
+
{merged_controls}
|
|
829
|
+
{stable_entries}
|
|
830
|
+
{unstable_entries}
|
|
831
|
+
{get_point_color}
|
|
832
|
+
{merged_highlight_style}
|
|
833
|
+
{is_highlighted}
|
|
834
|
+
{tooltip}
|
|
835
|
+
{selected_entry}
|
|
836
|
+
bind:show_hull_faces
|
|
837
|
+
bind:hull_face_color
|
|
838
|
+
bind:hull_face_opacity
|
|
839
|
+
bind:hull_face_color_mode
|
|
840
|
+
bind:info_pane_open
|
|
841
|
+
bind:controls_open
|
|
842
|
+
bind:color_mode
|
|
843
|
+
bind:color_scale
|
|
844
|
+
bind:show_stable
|
|
845
|
+
bind:show_unstable
|
|
846
|
+
{entry_category}
|
|
847
|
+
bind:hidden_categories
|
|
848
|
+
bind:show_stable_labels
|
|
849
|
+
bind:show_unstable_labels
|
|
850
|
+
bind:max_hull_dist_show_phases
|
|
851
|
+
bind:max_hull_dist_show_labels
|
|
852
|
+
bind:energy_source_mode
|
|
853
|
+
/>
|
|
854
|
+
|
|
855
|
+
{#if hull_data.has_temp_data && temperature !== undefined}
|
|
856
|
+
<TemperatureSlider available_temperatures={hull_data.available_temperatures} bind:temperature />
|
|
1273
857
|
{/if}
|
|
1274
858
|
|
|
1275
|
-
{#if
|
|
1276
|
-
<TemperatureSlider {available_temperatures} bind:temperature />
|
|
1277
|
-
{/if}
|
|
1278
|
-
|
|
1279
|
-
{#if gas_analysis.has_gas_dependent_elements && merged_gas_config}
|
|
859
|
+
{#if hull_data.gas_analysis.has_gas_dependent_elements && merged_gas_config}
|
|
1280
860
|
<GasPressureControls
|
|
1281
861
|
config={merged_gas_config}
|
|
1282
862
|
bind:pressures={gas_pressures}
|
|
@@ -1284,48 +864,6 @@
|
|
|
1284
864
|
/>
|
|
1285
865
|
{/if}
|
|
1286
866
|
|
|
1287
|
-
<!-- Hover tooltip -->
|
|
1288
|
-
{#if hover_data}
|
|
1289
|
-
{@const { entry, position } = hover_data}
|
|
1290
|
-
{@const entry_highlight = is_highlighted(entry) ? merged_highlight_style : undefined}
|
|
1291
|
-
{@const tooltip_style =
|
|
1292
|
-
`z-index: ${CONVEX_HULL_STYLE.z_index.tooltip}; backdrop-filter: blur(4px);
|
|
1293
|
-
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3);`}
|
|
1294
|
-
<PlotTooltip
|
|
1295
|
-
x={position.x}
|
|
1296
|
-
y={position.y}
|
|
1297
|
-
offset={{ x: 10, y: -10 }}
|
|
1298
|
-
bg_color={get_point_color(entry)}
|
|
1299
|
-
fixed
|
|
1300
|
-
style={tooltip_style}
|
|
1301
|
-
>
|
|
1302
|
-
<ConvexHullTooltip
|
|
1303
|
-
{entry}
|
|
1304
|
-
{polymorph_stats_map}
|
|
1305
|
-
highlight_style={entry_highlight}
|
|
1306
|
-
{tooltip}
|
|
1307
|
-
/>
|
|
1308
|
-
</PlotTooltip>
|
|
1309
|
-
{/if}
|
|
1310
|
-
|
|
1311
|
-
<!-- Copy-to-clipboard feedback (double-click on point) -->
|
|
1312
|
-
<ClickFeedback bind:visible={copy_feedback.visible} position={copy_feedback.position} />
|
|
1313
|
-
|
|
1314
|
-
<!-- Drag over overlay -->
|
|
1315
|
-
<DragOverlay visible={drag_over} />
|
|
1316
|
-
|
|
1317
|
-
{#if modal_open && selected_structure}
|
|
1318
|
-
<StructurePopup
|
|
1319
|
-
structure={selected_structure}
|
|
1320
|
-
place_right={modal_place_right}
|
|
1321
|
-
stats={{
|
|
1322
|
-
id: selected_entry?.entry_id,
|
|
1323
|
-
e_above_hull: selected_entry?.e_above_hull,
|
|
1324
|
-
e_form: selected_entry?.e_form_per_atom,
|
|
1325
|
-
}}
|
|
1326
|
-
onclose={close_structure_popup}
|
|
1327
|
-
/>
|
|
1328
|
-
{/if}
|
|
1329
867
|
</div>
|
|
1330
868
|
|
|
1331
869
|
<style>
|
|
@@ -1353,42 +891,4 @@
|
|
|
1353
891
|
canvas:active {
|
|
1354
892
|
cursor: grabbing;
|
|
1355
893
|
}
|
|
1356
|
-
.control-buttons {
|
|
1357
|
-
position: absolute;
|
|
1358
|
-
top: 1ex;
|
|
1359
|
-
right: 1ex;
|
|
1360
|
-
display: flex;
|
|
1361
|
-
gap: 8px;
|
|
1362
|
-
transition: opacity 0.2s ease-in-out;
|
|
1363
|
-
}
|
|
1364
|
-
.control-buttons.hover-visible {
|
|
1365
|
-
opacity: 0;
|
|
1366
|
-
pointer-events: none;
|
|
1367
|
-
}
|
|
1368
|
-
.convex-hull-4d:hover .control-buttons.hover-visible,
|
|
1369
|
-
.convex-hull-4d:focus-within .control-buttons.hover-visible {
|
|
1370
|
-
opacity: 1;
|
|
1371
|
-
pointer-events: auto;
|
|
1372
|
-
}
|
|
1373
|
-
.control-buttons.always-visible {
|
|
1374
|
-
opacity: 1;
|
|
1375
|
-
pointer-events: auto;
|
|
1376
|
-
}
|
|
1377
|
-
.control-buttons :global(.draggable-pane) {
|
|
1378
|
-
z-index: 1001 !important;
|
|
1379
|
-
}
|
|
1380
|
-
.control-buttons :global(button) {
|
|
1381
|
-
background: transparent;
|
|
1382
|
-
border: none;
|
|
1383
|
-
padding: 4px;
|
|
1384
|
-
cursor: pointer;
|
|
1385
|
-
border-radius: 3px;
|
|
1386
|
-
color: var(--text-color, currentColor);
|
|
1387
|
-
transition: background-color 0.2s;
|
|
1388
|
-
display: flex;
|
|
1389
|
-
font-size: clamp(0.85em, 2cqmin, 1.3em);
|
|
1390
|
-
}
|
|
1391
|
-
.control-buttons :global(button):hover {
|
|
1392
|
-
background-color: color-mix(in srgb, currentColor 8%, transparent);
|
|
1393
|
-
}
|
|
1394
894
|
</style>
|