matterviz 0.3.2 → 0.3.4
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 -2
- package/dist/FilePicker.svelte +123 -82
- package/dist/Icon.svelte +18 -12
- package/dist/MillerIndexInput.svelte +27 -21
- package/dist/api/optimade.js +6 -6
- package/dist/app.css +216 -207
- package/dist/brillouin/BrillouinZone.svelte +292 -149
- package/dist/brillouin/BrillouinZone.svelte.d.ts +1 -1
- package/dist/brillouin/BrillouinZoneControls.svelte +32 -5
- package/dist/brillouin/BrillouinZoneExportPane.svelte +69 -42
- package/dist/brillouin/BrillouinZoneExportPane.svelte.d.ts +1 -1
- package/dist/brillouin/BrillouinZoneInfoPane.svelte +99 -68
- package/dist/brillouin/BrillouinZoneScene.svelte +275 -163
- package/dist/brillouin/BrillouinZoneScene.svelte.d.ts +1 -1
- package/dist/brillouin/BrillouinZoneTooltip.svelte +17 -7
- package/dist/brillouin/compute.js +11 -6
- package/dist/chempot-diagram/ChemPotDiagram.svelte +162 -27
- package/dist/chempot-diagram/ChemPotDiagram2D.svelte +451 -281
- package/dist/chempot-diagram/ChemPotDiagram3D.svelte +2148 -1642
- package/dist/chempot-diagram/ChemPotScene3D.svelte +8 -5
- package/dist/chempot-diagram/async-compute.svelte.d.ts +3 -0
- package/dist/chempot-diagram/async-compute.svelte.js +77 -0
- package/dist/chempot-diagram/chempot-worker.d.ts +1 -0
- package/dist/chempot-diagram/chempot-worker.js +11 -0
- package/dist/chempot-diagram/color.js +1 -2
- package/dist/chempot-diagram/compute.d.ts +10 -0
- package/dist/chempot-diagram/compute.js +250 -88
- package/dist/chempot-diagram/index.d.ts +2 -1
- package/dist/chempot-diagram/index.js +2 -1
- package/dist/chempot-diagram/temperature.js +8 -9
- package/dist/chempot-diagram/types.d.ts +3 -0
- package/dist/chempot-diagram/types.js +1 -0
- package/dist/colors/index.d.ts +1 -1
- package/dist/colors/index.js +5 -3
- package/dist/composition/BarChart.svelte +128 -55
- package/dist/composition/BubbleChart.svelte +102 -49
- package/dist/composition/Composition.svelte +100 -79
- package/dist/composition/Formula.svelte +108 -62
- package/dist/composition/FormulaFilter.svelte +665 -537
- package/dist/composition/PieChart.svelte +183 -108
- package/dist/composition/format.d.ts +5 -0
- package/dist/composition/format.js +20 -3
- package/dist/composition/parse.js +14 -9
- package/dist/convex-hull/ConvexHull.svelte +93 -40
- package/dist/convex-hull/ConvexHull.svelte.d.ts +1 -1
- package/dist/convex-hull/ConvexHull2D.svelte +549 -360
- package/dist/convex-hull/ConvexHull2D.svelte.d.ts +1 -1
- package/dist/convex-hull/ConvexHull3D.svelte +1296 -827
- package/dist/convex-hull/ConvexHull3D.svelte.d.ts +1 -1
- package/dist/convex-hull/ConvexHull4D.svelte +1004 -688
- package/dist/convex-hull/ConvexHull4D.svelte.d.ts +1 -1
- package/dist/convex-hull/ConvexHullControls.svelte +115 -28
- package/dist/convex-hull/ConvexHullControls.svelte.d.ts +1 -1
- package/dist/convex-hull/ConvexHullInfoPane.svelte +29 -3
- package/dist/convex-hull/ConvexHullStats.svelte +425 -328
- package/dist/convex-hull/ConvexHullTooltip.svelte +40 -16
- package/dist/convex-hull/GasPressureControls.svelte +104 -61
- package/dist/convex-hull/StructurePopup.svelte +25 -4
- package/dist/convex-hull/TemperatureSlider.svelte +45 -25
- package/dist/convex-hull/barycentric-coords.js +13 -7
- package/dist/convex-hull/demo-temperature.js +8 -4
- package/dist/convex-hull/gas-thermodynamics.js +17 -12
- package/dist/convex-hull/helpers.d.ts +9 -0
- package/dist/convex-hull/helpers.js +77 -34
- package/dist/convex-hull/thermodynamics.js +61 -56
- package/dist/convex-hull/types.d.ts +9 -14
- package/dist/convex-hull/types.js +0 -17
- package/dist/coordination/CoordinationBarPlot.svelte +227 -154
- package/dist/element/BohrAtom.svelte +55 -12
- package/dist/element/ElementHeading.svelte +7 -2
- package/dist/element/ElementPhoto.svelte +15 -9
- package/dist/element/ElementStats.svelte +10 -4
- package/dist/element/ElementTile.svelte +137 -73
- package/dist/element/Nucleus.svelte +39 -11
- package/dist/element/data.js +1 -1
- package/dist/feedback/ClickFeedback.svelte +16 -5
- package/dist/feedback/DragOverlay.svelte +10 -2
- package/dist/feedback/Spinner.svelte +4 -2
- package/dist/feedback/StatusMessage.svelte +8 -2
- package/dist/fermi-surface/FermiSlice.svelte +118 -88
- package/dist/fermi-surface/FermiSurface.svelte +328 -187
- package/dist/fermi-surface/FermiSurface.svelte.d.ts +1 -1
- package/dist/fermi-surface/FermiSurfaceControls.svelte +113 -46
- package/dist/fermi-surface/FermiSurfaceControls.svelte.d.ts +1 -1
- package/dist/fermi-surface/FermiSurfaceScene.svelte +535 -342
- package/dist/fermi-surface/FermiSurfaceScene.svelte.d.ts +1 -1
- package/dist/fermi-surface/FermiSurfaceTooltip.svelte +14 -5
- package/dist/fermi-surface/compute.js +16 -20
- package/dist/fermi-surface/parse.js +24 -14
- package/dist/fermi-surface/symmetry.js +2 -7
- package/dist/fermi-surface/types.d.ts +3 -5
- package/dist/heatmap-matrix/HeatmapMatrix.svelte +1019 -765
- package/dist/heatmap-matrix/HeatmapMatrix.svelte.d.ts +1 -1
- package/dist/heatmap-matrix/HeatmapMatrixControls.svelte +76 -22
- package/dist/heatmap-matrix/HeatmapMatrixControls.svelte.d.ts +2 -3
- package/dist/icons.js +47 -0
- package/dist/index.d.ts +2 -1
- package/dist/index.js +2 -1
- package/dist/io/decompress.js +1 -1
- package/dist/io/export.d.ts +3 -0
- package/dist/io/export.js +129 -143
- package/dist/io/is-binary.js +2 -3
- package/dist/io/url-drop.js +1 -2
- package/dist/isosurface/Isosurface.svelte +202 -148
- package/dist/isosurface/IsosurfaceControls.svelte +46 -28
- package/dist/isosurface/parse.js +34 -29
- package/dist/isosurface/slice.js +5 -10
- package/dist/isosurface/types.d.ts +2 -1
- package/dist/isosurface/types.js +61 -12
- package/dist/labels.js +11 -8
- package/dist/layout/FullscreenToggle.svelte +11 -2
- package/dist/layout/InfoCard.svelte +38 -6
- package/dist/layout/InfoTag.svelte +63 -32
- package/dist/layout/PropertyFilter.svelte +82 -37
- package/dist/layout/SettingsSection.svelte +85 -55
- package/dist/layout/SubpageGrid.svelte +10 -2
- package/dist/layout/json-tree/JsonNode.svelte +183 -138
- package/dist/layout/json-tree/JsonTree.svelte +499 -413
- package/dist/layout/json-tree/JsonValue.svelte +127 -99
- package/dist/layout/json-tree/utils.js +4 -2
- package/dist/marching-cubes.js +25 -2
- package/dist/math.d.ts +13 -17
- package/dist/math.js +133 -67
- package/dist/overlays/ContextMenu.svelte +65 -40
- package/dist/overlays/DraggablePane.svelte +211 -139
- package/dist/periodic-table/PeriodicTable.svelte +278 -145
- package/dist/periodic-table/PeriodicTableControls.svelte +178 -128
- package/dist/periodic-table/PropertySelect.svelte +25 -7
- package/dist/periodic-table/TableInset.svelte +8 -3
- package/dist/phase-diagram/IsobaricBinaryPhaseDiagram.svelte +446 -309
- package/dist/phase-diagram/IsobaricBinaryPhaseDiagram.svelte.d.ts +1 -1
- package/dist/phase-diagram/PhaseDiagramControls.svelte +102 -43
- package/dist/phase-diagram/PhaseDiagramControls.svelte.d.ts +1 -1
- package/dist/phase-diagram/PhaseDiagramEditorPane.svelte +63 -40
- package/dist/phase-diagram/PhaseDiagramExportPane.svelte +71 -28
- package/dist/phase-diagram/PhaseDiagramExportPane.svelte.d.ts +1 -1
- package/dist/phase-diagram/PhaseDiagramTooltip.svelte +158 -101
- package/dist/phase-diagram/TdbInfoPanel.svelte +28 -4
- package/dist/phase-diagram/build-diagram.js +9 -9
- package/dist/phase-diagram/colors.js +1 -3
- package/dist/phase-diagram/parse.js +10 -9
- package/dist/phase-diagram/svg-to-diagram.js +53 -49
- package/dist/phase-diagram/utils.d.ts +1 -0
- package/dist/phase-diagram/utils.js +80 -25
- package/dist/plot/AxisLabel.svelte +28 -3
- package/dist/plot/BarPlot.svelte +1182 -734
- package/dist/plot/BarPlot.svelte.d.ts +2 -2
- package/dist/plot/BarPlotControls.svelte +31 -5
- package/dist/plot/BarPlotControls.svelte.d.ts +1 -1
- package/dist/plot/ColorBar.svelte +479 -329
- package/dist/plot/ColorScaleSelect.svelte +27 -6
- package/dist/plot/ElementScatter.svelte +36 -15
- package/dist/plot/FillArea.svelte +152 -95
- package/dist/plot/Histogram.svelte +934 -571
- package/dist/plot/Histogram.svelte.d.ts +1 -1
- package/dist/plot/HistogramControls.svelte +53 -9
- package/dist/plot/HistogramControls.svelte.d.ts +1 -1
- package/dist/plot/InteractiveAxisLabel.svelte +34 -11
- package/dist/plot/InteractiveAxisLabel.svelte.d.ts +1 -1
- package/dist/plot/Line.svelte +63 -28
- package/dist/plot/PlotControls.svelte +157 -114
- package/dist/plot/PlotControls.svelte.d.ts +1 -1
- package/dist/plot/PlotLegend.svelte +174 -91
- package/dist/plot/PlotTooltip.svelte +45 -6
- package/dist/plot/PortalSelect.svelte +175 -147
- package/dist/plot/ReferenceLine.svelte +76 -22
- package/dist/plot/ReferenceLine3D.svelte +132 -107
- package/dist/plot/ReferencePlane.svelte +146 -121
- package/dist/plot/ScatterPlot.svelte +1681 -1091
- package/dist/plot/ScatterPlot.svelte.d.ts +2 -2
- package/dist/plot/ScatterPlot3D.svelte +256 -131
- package/dist/plot/ScatterPlot3D.svelte.d.ts +2 -2
- package/dist/plot/ScatterPlot3DControls.svelte +113 -63
- package/dist/plot/ScatterPlot3DControls.svelte.d.ts +2 -1
- package/dist/plot/ScatterPlot3DScene.svelte +608 -403
- package/dist/plot/ScatterPlot3DScene.svelte.d.ts +2 -2
- package/dist/plot/ScatterPlotControls.svelte +65 -25
- package/dist/plot/ScatterPlotControls.svelte.d.ts +1 -1
- package/dist/plot/ScatterPoint.svelte +98 -26
- package/dist/plot/ScatterPoint.svelte.d.ts +1 -0
- package/dist/plot/SpacegroupBarPlot.svelte +142 -85
- package/dist/plot/Surface3D.svelte +159 -108
- package/dist/plot/ZeroLines.svelte +55 -3
- package/dist/plot/ZoomRect.svelte +4 -2
- package/dist/plot/axis-utils.js +1 -3
- package/dist/plot/data-cleaning.js +12 -28
- package/dist/plot/data-transform.js +2 -1
- package/dist/plot/fill-utils.js +2 -0
- package/dist/plot/layout.d.ts +4 -1
- package/dist/plot/layout.js +33 -14
- package/dist/plot/reference-line.d.ts +2 -2
- package/dist/plot/reference-line.js +7 -5
- package/dist/plot/scales.js +24 -36
- package/dist/plot/types.d.ts +11 -23
- package/dist/plot/types.js +6 -11
- package/dist/plot/utils/label-placement.d.ts +32 -15
- package/dist/plot/utils/label-placement.js +227 -66
- package/dist/plot/utils/series-visibility.js +2 -3
- package/dist/rdf/RdfPlot.svelte +143 -91
- package/dist/rdf/calc-rdf.js +4 -5
- package/dist/sanitize.d.ts +4 -0
- package/dist/sanitize.js +107 -0
- package/dist/settings.d.ts +18 -6
- package/dist/settings.js +46 -16
- package/dist/spectral/Bands.svelte +632 -453
- package/dist/spectral/BandsAndDos.svelte +90 -49
- package/dist/spectral/BrillouinBandsDos.svelte +151 -93
- package/dist/spectral/Dos.svelte +389 -258
- package/dist/spectral/helpers.js +55 -43
- package/dist/state.svelte.d.ts +1 -1
- package/dist/state.svelte.js +3 -2
- package/dist/structure/Arrow.svelte +59 -20
- package/dist/structure/AtomLegend.svelte +215 -134
- package/dist/structure/Bond.svelte +73 -47
- package/dist/structure/CanvasTooltip.svelte +10 -2
- package/dist/structure/CellSelect.svelte +72 -45
- package/dist/structure/Cylinder.svelte +33 -17
- package/dist/structure/Lattice.svelte +88 -33
- package/dist/structure/Structure.svelte +1063 -797
- package/dist/structure/Structure.svelte.d.ts +1 -1
- package/dist/structure/StructureControls.svelte +349 -118
- package/dist/structure/StructureExportPane.svelte +124 -89
- package/dist/structure/StructureExportPane.svelte.d.ts +1 -1
- package/dist/structure/StructureInfoPane.svelte +304 -237
- package/dist/structure/StructureScene.svelte +879 -443
- package/dist/structure/StructureScene.svelte.d.ts +15 -7
- package/dist/structure/atom-properties.js +8 -8
- package/dist/structure/bonding.js +6 -7
- package/dist/structure/export.js +14 -29
- package/dist/structure/ferrox-wasm.js +1 -1
- package/dist/structure/index.d.ts +13 -3
- package/dist/structure/index.js +83 -23
- package/dist/structure/measure.d.ts +2 -2
- package/dist/structure/measure.js +4 -44
- package/dist/structure/parse.js +113 -141
- package/dist/structure/partial-occupancy.js +7 -10
- package/dist/structure/pbc.d.ts +1 -0
- package/dist/structure/pbc.js +16 -6
- package/dist/structure/supercell.d.ts +2 -2
- package/dist/structure/supercell.js +12 -22
- package/dist/structure/validation.js +1 -2
- package/dist/symmetry/SymmetryStats.svelte +84 -41
- package/dist/symmetry/WyckoffTable.svelte +26 -6
- package/dist/symmetry/cell-transform.js +5 -3
- package/dist/symmetry/index.js +8 -7
- package/dist/symmetry/spacegroups.js +148 -148
- package/dist/table/HeatmapTable.svelte +790 -554
- package/dist/table/HeatmapTable.svelte.d.ts +1 -1
- package/dist/table/ToggleMenu.svelte +125 -92
- package/dist/table/index.js +2 -4
- package/dist/theme/ThemeControl.svelte +21 -12
- package/dist/time.js +4 -1
- package/dist/tooltip/TooltipContent.svelte +33 -8
- package/dist/trajectory/Trajectory.svelte +758 -558
- package/dist/trajectory/TrajectoryError.svelte +14 -3
- package/dist/trajectory/TrajectoryExportPane.svelte +137 -83
- package/dist/trajectory/TrajectoryInfoPane.svelte +272 -143
- package/dist/trajectory/extract.js +10 -26
- package/dist/trajectory/format-detect.js +5 -5
- package/dist/trajectory/frame-reader.d.ts +1 -1
- package/dist/trajectory/frame-reader.js +5 -12
- package/dist/trajectory/helpers.d.ts +0 -1
- package/dist/trajectory/helpers.js +2 -17
- package/dist/trajectory/index.js +14 -12
- package/dist/trajectory/parse/ase.js +5 -4
- package/dist/trajectory/parse/hdf5.js +26 -18
- package/dist/trajectory/parse/index.js +13 -18
- package/dist/trajectory/parse/lammps.js +17 -7
- package/dist/trajectory/parse/vasp.js +5 -2
- package/dist/trajectory/parse/xyz.js +8 -7
- package/dist/trajectory/plotting.js +13 -8
- package/dist/utils.d.ts +1 -0
- package/dist/utils.js +13 -0
- package/dist/xrd/XrdPlot.svelte +337 -247
- package/dist/xrd/broadening.js +14 -9
- package/dist/xrd/calc-xrd.js +12 -18
- package/dist/xrd/parse.d.ts +1 -1
- package/dist/xrd/parse.js +17 -17
- package/package.json +99 -103
- package/readme.md +1 -1
- /package/dist/theme/{themes.js → themes.mjs} +0 -0
|
@@ -1,323 +1,480 @@
|
|
|
1
|
-
<script lang="ts">
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import
|
|
5
|
-
import
|
|
6
|
-
import {
|
|
7
|
-
import
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
10
|
-
import
|
|
11
|
-
import {
|
|
12
|
-
import {
|
|
13
|
-
import {
|
|
14
|
-
import {
|
|
15
|
-
import {
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import { type D3InterpolateName } from '../colors'
|
|
3
|
+
import { get_electro_neg_formula } from '../composition/format'
|
|
4
|
+
import { extract_formula_elements } from '../composition/parse'
|
|
5
|
+
import TemperatureSlider from '../convex-hull/TemperatureSlider.svelte'
|
|
6
|
+
import type { PhaseData } from '../convex-hull/types'
|
|
7
|
+
import Spinner from '../feedback/Spinner.svelte'
|
|
8
|
+
import { export_svg_as_png, export_svg_as_svg } from '../io/export'
|
|
9
|
+
import { download } from '../io/fetch'
|
|
10
|
+
import DraggablePane from '../overlays/DraggablePane.svelte'
|
|
11
|
+
import { ColorBar, ScatterPlot } from '../plot'
|
|
12
|
+
import { constrain_tooltip_position } from '../plot/layout'
|
|
13
|
+
import type { DataSeries, UserContentProps } from '../plot/types'
|
|
14
|
+
import { sanitize_html } from '../sanitize'
|
|
15
|
+
import { onDestroy } from 'svelte'
|
|
16
|
+
import { SvelteMap } from 'svelte/reactivity'
|
|
17
|
+
import { compute_chempot_async } from './async-compute.svelte'
|
|
18
|
+
import { get_chempot_color_bar_config, make_chempot_color_scale } from './color'
|
|
19
|
+
import {
|
|
20
|
+
apply_element_padding,
|
|
21
|
+
best_form_energy_for_formula,
|
|
22
|
+
build_axis_ranges,
|
|
23
|
+
formula_key_from_composition,
|
|
24
|
+
get_energy_per_atom,
|
|
25
|
+
get_min_entries_and_el_refs,
|
|
26
|
+
orthonormal_2d,
|
|
27
|
+
pad_domain_points,
|
|
28
|
+
} from './compute'
|
|
29
|
+
import { with_hover_pointer } from './pointer'
|
|
30
|
+
import { get_temp_filter_payload, get_valid_temperature } from './temperature'
|
|
31
|
+
import type { ChemPotDiagramConfig, ChemPotDiagramData, ChemPotHoverInfo } from './types'
|
|
32
|
+
import { CHEMPOT_DEFAULTS } from './types'
|
|
33
|
+
|
|
34
|
+
let {
|
|
35
|
+
entries = [],
|
|
36
|
+
config = {},
|
|
37
|
+
width = $bindable(800),
|
|
38
|
+
height = $bindable(600),
|
|
39
|
+
// Auto-corrected to a valid available temperature when needed.
|
|
40
|
+
temperature = $bindable<number | undefined>(undefined),
|
|
41
|
+
interpolate_temperature = CHEMPOT_DEFAULTS.interpolate_temperature,
|
|
42
|
+
max_interpolation_gap = CHEMPOT_DEFAULTS.max_interpolation_gap,
|
|
43
|
+
hover_info = $bindable<ChemPotHoverInfo | null>(null),
|
|
44
|
+
render_local_tooltip = true,
|
|
45
|
+
}: {
|
|
46
|
+
entries: PhaseData[]
|
|
47
|
+
config?: ChemPotDiagramConfig
|
|
48
|
+
width?: number
|
|
49
|
+
height?: number
|
|
50
|
+
temperature?: number
|
|
51
|
+
interpolate_temperature?: boolean
|
|
52
|
+
max_interpolation_gap?: number
|
|
53
|
+
hover_info?: ChemPotHoverInfo | null
|
|
54
|
+
render_local_tooltip?: boolean
|
|
55
|
+
} = $props()
|
|
56
|
+
let container_width = $state(0)
|
|
57
|
+
const base_aspect_ratio = $derived(height > 0 && width > 0 ? height / width : 1)
|
|
58
|
+
const render_width = $derived(container_width > 0 ? container_width : width)
|
|
59
|
+
const render_height = $derived(Math.round(render_width * base_aspect_ratio))
|
|
60
|
+
|
|
61
|
+
// === Control overrides ===
|
|
62
|
+
let formal_chempots_override = $state<boolean | null>(null)
|
|
63
|
+
let label_stable_override = $state<boolean | null>(null)
|
|
64
|
+
let element_padding_override = $state<number | null>(null)
|
|
65
|
+
let default_min_limit_override = $state<number | null>(null)
|
|
66
|
+
const formal_chempots = $derived(
|
|
67
|
+
formal_chempots_override ??
|
|
68
|
+
(config.formal_chempots ?? CHEMPOT_DEFAULTS.formal_chempots),
|
|
69
|
+
)
|
|
70
|
+
const label_stable = $derived(
|
|
71
|
+
label_stable_override ?? (config.label_stable ?? CHEMPOT_DEFAULTS.label_stable),
|
|
72
|
+
)
|
|
73
|
+
const element_padding = $derived(
|
|
74
|
+
element_padding_override ??
|
|
75
|
+
(config.element_padding ?? CHEMPOT_DEFAULTS.element_padding),
|
|
76
|
+
)
|
|
77
|
+
const default_min_limit = $derived(
|
|
78
|
+
default_min_limit_override ??
|
|
79
|
+
(config.default_min_limit ?? CHEMPOT_DEFAULTS.default_min_limit),
|
|
80
|
+
)
|
|
81
|
+
let color_mode_override = $state<
|
|
82
|
+
NonNullable<ChemPotDiagramConfig[`color_mode`]> | null
|
|
83
|
+
>(
|
|
84
|
+
null,
|
|
85
|
+
)
|
|
86
|
+
let color_scale_override = $state<D3InterpolateName | null>(null)
|
|
87
|
+
let reverse_color_scale_override = $state<boolean | null>(null)
|
|
88
|
+
const color_mode = $derived(
|
|
89
|
+
color_mode_override ?? (config.color_mode ?? CHEMPOT_DEFAULTS.color_mode),
|
|
90
|
+
)
|
|
91
|
+
const color_scale = $derived(
|
|
92
|
+
color_scale_override ?? (config.color_scale ?? CHEMPOT_DEFAULTS.color_scale),
|
|
93
|
+
)
|
|
94
|
+
const reverse_color_scale = $derived(
|
|
95
|
+
reverse_color_scale_override ??
|
|
96
|
+
(config.reverse_color_scale ?? CHEMPOT_DEFAULTS.reverse_color_scale),
|
|
97
|
+
)
|
|
98
|
+
const arity_colors = [`#3498db`, `#2ecc71`, `#e67e22`, `#9b59b6`] as const
|
|
99
|
+
const show_tooltip = $derived(config.show_tooltip ?? CHEMPOT_DEFAULTS.show_tooltip)
|
|
100
|
+
const effective_config = $derived({
|
|
45
101
|
...config,
|
|
46
102
|
formal_chempots,
|
|
47
103
|
label_stable,
|
|
48
104
|
element_padding,
|
|
49
105
|
default_min_limit,
|
|
50
|
-
})
|
|
51
|
-
const { has_temp_data, available_temperatures, temp_filtered_entries } = $derived(
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
106
|
+
})
|
|
107
|
+
const { has_temp_data, available_temperatures, temp_filtered_entries } = $derived(
|
|
108
|
+
get_temp_filter_payload(entries, temperature, config, {
|
|
109
|
+
interpolate_temperature,
|
|
110
|
+
max_interpolation_gap,
|
|
111
|
+
}),
|
|
112
|
+
)
|
|
113
|
+
|
|
114
|
+
$effect(() => {
|
|
56
115
|
// Keep bound temperature aligned with available data points.
|
|
57
|
-
const next_temperature = get_valid_temperature(
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
116
|
+
const next_temperature = get_valid_temperature(
|
|
117
|
+
temperature,
|
|
118
|
+
has_temp_data,
|
|
119
|
+
available_temperatures,
|
|
120
|
+
)
|
|
121
|
+
if (next_temperature !== temperature) temperature = next_temperature
|
|
122
|
+
})
|
|
123
|
+
|
|
124
|
+
const show_temperature_slider = $derived(
|
|
125
|
+
has_temp_data && available_temperatures.length > 0,
|
|
126
|
+
)
|
|
127
|
+
|
|
128
|
+
function reset_controls(): void {
|
|
129
|
+
formal_chempots_override = null
|
|
130
|
+
label_stable_override = null
|
|
131
|
+
element_padding_override = null
|
|
132
|
+
default_min_limit_override = null
|
|
133
|
+
color_mode_override = null
|
|
134
|
+
color_scale_override = null
|
|
135
|
+
reverse_color_scale_override = null
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
// === Diagram computation (off main thread via Web Worker) ===
|
|
139
|
+
let diagram_data = $state<ChemPotDiagramData | null>(null)
|
|
140
|
+
let diagram_computing = $state(false)
|
|
141
|
+
$effect(() => {
|
|
142
|
+
if (temp_filtered_entries.length < 2) {
|
|
143
|
+
diagram_data = null
|
|
144
|
+
diagram_computing = false
|
|
145
|
+
return
|
|
81
146
|
}
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
return
|
|
87
|
-
|
|
147
|
+
let cancelled = false
|
|
148
|
+
diagram_computing = true
|
|
149
|
+
compute_chempot_async(temp_filtered_entries, effective_config)
|
|
150
|
+
.then((data) => {
|
|
151
|
+
if (cancelled) return
|
|
152
|
+
diagram_data = data
|
|
153
|
+
diagram_computing = false
|
|
154
|
+
})
|
|
155
|
+
.catch((err) => {
|
|
156
|
+
if (cancelled) return
|
|
157
|
+
console.error(`ChemPotDiagram2D:`, err)
|
|
158
|
+
diagram_data = null
|
|
159
|
+
diagram_computing = false
|
|
160
|
+
})
|
|
161
|
+
return () => { cancelled = true }
|
|
162
|
+
})
|
|
163
|
+
|
|
164
|
+
const plot_elements = $derived(
|
|
165
|
+
(diagram_data?.elements ?? config.elements ?? []).slice(0, 2),
|
|
166
|
+
)
|
|
167
|
+
|
|
168
|
+
const draw_domains = $derived.by(() => {
|
|
169
|
+
if (!diagram_data || plot_elements.length < 2) return {}
|
|
170
|
+
const indices = [0, 1]
|
|
88
171
|
if (element_padding <= 0) {
|
|
89
|
-
|
|
172
|
+
return Object.fromEntries(
|
|
173
|
+
Object.entries(diagram_data.domains).filter(([, pts]) => pts.length > 0),
|
|
174
|
+
)
|
|
90
175
|
}
|
|
91
|
-
const new_lims = apply_element_padding(
|
|
92
|
-
|
|
176
|
+
const new_lims = apply_element_padding(
|
|
177
|
+
diagram_data.domains,
|
|
178
|
+
indices,
|
|
179
|
+
element_padding,
|
|
180
|
+
default_min_limit,
|
|
181
|
+
)
|
|
182
|
+
const result: Record<string, number[][]> = {}
|
|
93
183
|
for (const [formula, pts] of Object.entries(diagram_data.domains)) {
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
184
|
+
const padded = pad_domain_points(
|
|
185
|
+
pts,
|
|
186
|
+
indices,
|
|
187
|
+
new_lims,
|
|
188
|
+
default_min_limit,
|
|
189
|
+
element_padding,
|
|
190
|
+
)
|
|
191
|
+
if (padded.length > 0) result[formula] = padded
|
|
97
192
|
}
|
|
98
|
-
return result
|
|
99
|
-
})
|
|
100
|
-
const domain_entries = $derived(Object.entries(draw_domains))
|
|
101
|
-
const domain_formulas = $derived(Object.keys(draw_domains))
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
193
|
+
return result
|
|
194
|
+
})
|
|
195
|
+
const domain_entries = $derived(Object.entries(draw_domains))
|
|
196
|
+
const domain_formulas = $derived(Object.keys(draw_domains))
|
|
197
|
+
|
|
198
|
+
interface FormulaEnergyStats {
|
|
199
|
+
matching_entry_count: number
|
|
200
|
+
min_energy_per_atom: number | null
|
|
201
|
+
}
|
|
202
|
+
type NumericColorMode = Exclude<
|
|
203
|
+
NonNullable<ChemPotDiagramConfig[`color_mode`]>,
|
|
204
|
+
`none` | `arity`
|
|
205
|
+
>
|
|
206
|
+
|
|
207
|
+
const raw_el_refs = $derived(
|
|
208
|
+
get_min_entries_and_el_refs(temp_filtered_entries).el_refs,
|
|
209
|
+
)
|
|
210
|
+
const entry_energy_stats_by_formula = $derived.by(
|
|
211
|
+
(): SvelteMap<string, FormulaEnergyStats> => {
|
|
212
|
+
const stats = new SvelteMap<string, FormulaEnergyStats>()
|
|
213
|
+
for (const entry of temp_filtered_entries) {
|
|
214
|
+
const formula_key = formula_key_from_composition(entry.composition)
|
|
215
|
+
const epa = get_energy_per_atom(entry)
|
|
216
|
+
const prev_stats = stats.get(formula_key)
|
|
109
217
|
if (!prev_stats) {
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
218
|
+
stats.set(formula_key, {
|
|
219
|
+
matching_entry_count: 1,
|
|
220
|
+
min_energy_per_atom: epa,
|
|
221
|
+
})
|
|
222
|
+
continue
|
|
115
223
|
}
|
|
116
224
|
stats.set(formula_key, {
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
})
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
}
|
|
123
|
-
|
|
225
|
+
matching_entry_count: prev_stats.matching_entry_count + 1,
|
|
226
|
+
min_energy_per_atom: Math.min(prev_stats.min_energy_per_atom ?? epa, epa),
|
|
227
|
+
})
|
|
228
|
+
}
|
|
229
|
+
return stats
|
|
230
|
+
},
|
|
231
|
+
)
|
|
232
|
+
const color_mode_labels: Record<NumericColorMode, string> = {
|
|
124
233
|
energy: `Energy per atom (eV)`,
|
|
125
234
|
formation_energy: `Formation energy (eV/atom)`,
|
|
126
235
|
entries: `Entry count`,
|
|
127
|
-
}
|
|
128
|
-
function get_numeric_color_value(
|
|
236
|
+
}
|
|
237
|
+
function get_numeric_color_value(
|
|
238
|
+
formula: string,
|
|
239
|
+
active_color_mode: NumericColorMode,
|
|
240
|
+
): number | null {
|
|
129
241
|
if (active_color_mode === `energy`) {
|
|
130
|
-
|
|
242
|
+
return entry_energy_stats_by_formula.get(formula)?.min_energy_per_atom ?? null
|
|
131
243
|
}
|
|
132
244
|
if (active_color_mode === `formation_energy`) {
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
if (color_mode === `none` || color_mode === `arity`)
|
|
139
|
-
return null;
|
|
140
|
-
const active_color_mode = color_mode;
|
|
141
|
-
const value_by_formula = new SvelteMap();
|
|
142
|
-
const values = [];
|
|
143
|
-
for (const formula of domain_formulas) {
|
|
144
|
-
const value = get_numeric_color_value(formula, active_color_mode);
|
|
145
|
-
if (value == null || !Number.isFinite(value))
|
|
146
|
-
continue;
|
|
147
|
-
values.push(value);
|
|
148
|
-
value_by_formula.set(formula, value);
|
|
245
|
+
return best_form_energy_for_formula(
|
|
246
|
+
temp_filtered_entries,
|
|
247
|
+
formula,
|
|
248
|
+
raw_el_refs,
|
|
249
|
+
) ?? null
|
|
149
250
|
}
|
|
150
|
-
return
|
|
151
|
-
}
|
|
152
|
-
const
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
251
|
+
return entry_energy_stats_by_formula.get(formula)?.matching_entry_count ?? 0
|
|
252
|
+
}
|
|
253
|
+
const domain_color_values = $derived.by(
|
|
254
|
+
(): { value_by_formula: SvelteMap<string, number>; values: number[] } | null => {
|
|
255
|
+
if (color_mode === `none` || color_mode === `arity`) return null
|
|
256
|
+
const active_color_mode = color_mode as NumericColorMode
|
|
257
|
+
const value_by_formula = new SvelteMap<string, number>()
|
|
258
|
+
const values: number[] = []
|
|
259
|
+
for (const formula of domain_formulas) {
|
|
260
|
+
const value = get_numeric_color_value(formula, active_color_mode)
|
|
261
|
+
if (value == null || !Number.isFinite(value)) continue
|
|
262
|
+
values.push(value)
|
|
263
|
+
value_by_formula.set(formula, value)
|
|
264
|
+
}
|
|
265
|
+
return { value_by_formula, values }
|
|
266
|
+
},
|
|
267
|
+
)
|
|
268
|
+
const domain_colors = $derived.by((): SvelteMap<string, string> => {
|
|
269
|
+
const colors = new SvelteMap<string, string>()
|
|
270
|
+
if (color_mode === `none`) return colors
|
|
156
271
|
if (color_mode === `arity`) {
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
272
|
+
for (const formula of domain_formulas) {
|
|
273
|
+
const n_elements = extract_formula_elements(formula).length
|
|
274
|
+
const color_idx = Math.min(n_elements, arity_colors.length) - 1
|
|
275
|
+
colors.set(formula, arity_colors[Math.max(0, color_idx)])
|
|
276
|
+
}
|
|
277
|
+
return colors
|
|
163
278
|
}
|
|
164
|
-
const values_payload = domain_color_values
|
|
165
|
-
const scale = make_chempot_color_scale(
|
|
279
|
+
const values_payload = domain_color_values
|
|
280
|
+
const scale = make_chempot_color_scale(
|
|
281
|
+
values_payload?.values ?? [],
|
|
282
|
+
color_scale,
|
|
283
|
+
reverse_color_scale,
|
|
284
|
+
)
|
|
166
285
|
for (const formula of domain_formulas) {
|
|
167
|
-
|
|
168
|
-
|
|
286
|
+
const color_val = values_payload?.value_by_formula.get(formula)
|
|
287
|
+
colors.set(formula, color_val != null && scale ? scale(color_val) : `#999`)
|
|
169
288
|
}
|
|
170
|
-
return colors
|
|
171
|
-
})
|
|
172
|
-
const color_range = $derived.by(
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
if (values[idx] < min_val)
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
}
|
|
183
|
-
return {
|
|
289
|
+
return colors
|
|
290
|
+
})
|
|
291
|
+
const color_range = $derived.by(
|
|
292
|
+
(): { min: number; max: number; label: string } | null => {
|
|
293
|
+
const values = domain_color_values?.values ?? []
|
|
294
|
+
if (values.length === 0) return null
|
|
295
|
+
let min_val = values[0], max_val = values[0]
|
|
296
|
+
for (let idx = 1; idx < values.length; idx++) {
|
|
297
|
+
if (values[idx] < min_val) min_val = values[idx]
|
|
298
|
+
if (values[idx] > max_val) max_val = values[idx]
|
|
299
|
+
}
|
|
300
|
+
return {
|
|
184
301
|
min: min_val,
|
|
185
302
|
max: Math.max(max_val, min_val + 1e-6),
|
|
186
303
|
label: color_mode === `none` || color_mode === `arity`
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
}
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
if (
|
|
220
|
-
|
|
221
|
-
|
|
304
|
+
? ``
|
|
305
|
+
: color_mode_labels[color_mode],
|
|
306
|
+
}
|
|
307
|
+
},
|
|
308
|
+
)
|
|
309
|
+
|
|
310
|
+
// === Convert domains to ScatterPlot DataSeries ===
|
|
311
|
+
const series = $derived<DataSeries[]>(
|
|
312
|
+
domain_entries.map(([formula, pts]) => ({
|
|
313
|
+
id: formula,
|
|
314
|
+
label: formula,
|
|
315
|
+
x: pts.map((pt) => pt[0]),
|
|
316
|
+
y: pts.map((pt) => pt[1]),
|
|
317
|
+
markers: `line+points` as const,
|
|
318
|
+
line_style: { stroke: domain_colors.get(formula) ?? `black`, stroke_width: 3 },
|
|
319
|
+
point_style: { fill: domain_colors.get(formula) ?? `black`, radius: 3 },
|
|
320
|
+
})),
|
|
321
|
+
)
|
|
322
|
+
|
|
323
|
+
// Axis label text
|
|
324
|
+
function axis_label(element: string): string {
|
|
325
|
+
const prefix = formal_chempots ? `\u0394` : ``
|
|
326
|
+
return `${prefix}\u03BC<sub>${element}</sub> <span style="font-weight:300;opacity:0.7">(eV)</span>`
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
let x_axis = $state({ label: ``, label_shift: { y: -45 } })
|
|
330
|
+
let y_axis = $state({ label: `` })
|
|
331
|
+
|
|
332
|
+
$effect(() => {
|
|
333
|
+
const next_x_label = axis_label(plot_elements[0] ?? ``)
|
|
334
|
+
const next_y_label = axis_label(plot_elements[1] ?? ``)
|
|
335
|
+
if (x_axis.label !== next_x_label) x_axis = { ...x_axis, label: next_x_label }
|
|
336
|
+
if (y_axis.label !== next_y_label) y_axis = { ...y_axis, label: next_y_label }
|
|
337
|
+
})
|
|
338
|
+
|
|
339
|
+
// === Domain label annotations (in data coordinates) ===
|
|
340
|
+
const annotations = $derived.by(() => {
|
|
341
|
+
if (!label_stable) return []
|
|
342
|
+
const result: { formula: string; data_x: number; data_y: number }[] = []
|
|
222
343
|
for (const [formula, pts] of Object.entries(draw_domains)) {
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
});
|
|
344
|
+
if (pts.length === 0) continue
|
|
345
|
+
const center_x = pts.reduce((s, p) => s + p[0], 0) / pts.length
|
|
346
|
+
const center_y = pts.reduce((s, p) => s + p[1], 0) / pts.length
|
|
347
|
+
let offset_x = 0
|
|
348
|
+
let offset_y = 0
|
|
349
|
+
if (pts.length >= 2) {
|
|
350
|
+
const [nx, ny] = orthonormal_2d(pts)
|
|
351
|
+
offset_x = nx * 0.25
|
|
352
|
+
offset_y = ny * 0.25
|
|
353
|
+
}
|
|
354
|
+
result.push({
|
|
355
|
+
formula,
|
|
356
|
+
data_x: center_x + offset_x,
|
|
357
|
+
data_y: center_y + offset_y,
|
|
358
|
+
})
|
|
239
359
|
}
|
|
240
|
-
return result
|
|
241
|
-
})
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
360
|
+
return result
|
|
361
|
+
})
|
|
362
|
+
|
|
363
|
+
// === Hover info for external consumers ===
|
|
364
|
+
let locked_hover_formula = $state<string | null>(null)
|
|
365
|
+
|
|
366
|
+
function set_hover_info(
|
|
367
|
+
formula: string,
|
|
368
|
+
pts: number[][],
|
|
369
|
+
event: MouseEvent,
|
|
370
|
+
): void {
|
|
371
|
+
const bounds = scatter_wrapper?.getBoundingClientRect()
|
|
372
|
+
hover_info = with_hover_pointer<ChemPotHoverInfo>(
|
|
373
|
+
{
|
|
247
374
|
formula,
|
|
248
375
|
view: `2d`,
|
|
249
376
|
n_points: pts.length,
|
|
250
377
|
axis_ranges: build_axis_ranges(pts, plot_elements),
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
function
|
|
378
|
+
},
|
|
379
|
+
event,
|
|
380
|
+
bounds,
|
|
381
|
+
)
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
function clear_hover_lock(): void {
|
|
385
|
+
locked_hover_formula = null
|
|
386
|
+
hover_info = null
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
function handle_hover(
|
|
390
|
+
data: { point: { series_idx: number }; event: MouseEvent } | null,
|
|
391
|
+
): void {
|
|
258
392
|
if (!data) {
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
return;
|
|
393
|
+
if (!locked_hover_formula) hover_info = null
|
|
394
|
+
return
|
|
262
395
|
}
|
|
263
|
-
const entry = domain_entries[data.point.series_idx]
|
|
264
|
-
if (!entry)
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
const [formula, pts] = entry
|
|
396
|
+
const entry = domain_entries[data.point.series_idx]
|
|
397
|
+
if (!entry) return
|
|
398
|
+
const [formula, pts] = entry
|
|
399
|
+
if (locked_hover_formula && locked_hover_formula !== formula) return
|
|
400
|
+
set_hover_info(formula, pts, data.event)
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
function handle_click(
|
|
404
|
+
data: { point: { series_idx: number }; event: MouseEvent },
|
|
405
|
+
): void {
|
|
406
|
+
const entry = domain_entries[data.point.series_idx]
|
|
407
|
+
if (!entry) return
|
|
408
|
+
const [formula, pts] = entry
|
|
276
409
|
if (locked_hover_formula === formula) {
|
|
277
|
-
|
|
278
|
-
|
|
410
|
+
clear_hover_lock()
|
|
411
|
+
return
|
|
279
412
|
}
|
|
280
|
-
locked_hover_formula = formula
|
|
281
|
-
set_hover_info(formula, pts, data.event)
|
|
282
|
-
}
|
|
283
|
-
|
|
284
|
-
let
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
413
|
+
locked_hover_formula = formula
|
|
414
|
+
set_hover_info(formula, pts, data.event)
|
|
415
|
+
}
|
|
416
|
+
|
|
417
|
+
let tooltip_el = $state<HTMLElement>()
|
|
418
|
+
const tooltip_pos = $derived.by(() => {
|
|
419
|
+
const pointer = hover_info?.pointer
|
|
420
|
+
if (!pointer) return { x: 4, y: 4 }
|
|
421
|
+
return constrain_tooltip_position(
|
|
422
|
+
pointer.x, pointer.y,
|
|
423
|
+
tooltip_el?.offsetWidth ?? 150,
|
|
424
|
+
tooltip_el?.offsetHeight ?? 40,
|
|
425
|
+
render_width, render_height,
|
|
426
|
+
{ offset: 0 },
|
|
427
|
+
)
|
|
428
|
+
})
|
|
429
|
+
|
|
430
|
+
// === Export ===
|
|
431
|
+
let scatter_wrapper = $state<HTMLDivElement>()
|
|
432
|
+
let export_pane_open = $state(false)
|
|
433
|
+
let copy_status = $state(false)
|
|
434
|
+
let copy_timeout_id: ReturnType<typeof setTimeout> | null = null
|
|
435
|
+
|
|
436
|
+
function get_svg_element(): SVGSVGElement | null {
|
|
437
|
+
return scatter_wrapper?.querySelector<SVGSVGElement>(`svg`) ?? null
|
|
438
|
+
}
|
|
439
|
+
|
|
440
|
+
function get_json_string(): string {
|
|
441
|
+
return JSON.stringify(
|
|
442
|
+
{
|
|
293
443
|
elements: diagram_data?.elements ?? [],
|
|
294
444
|
domains: draw_domains,
|
|
295
445
|
lims: diagram_data?.lims ?? [],
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
}
|
|
301
|
-
|
|
446
|
+
},
|
|
447
|
+
null,
|
|
448
|
+
2,
|
|
449
|
+
)
|
|
450
|
+
}
|
|
451
|
+
|
|
452
|
+
function export_json_file(): void {
|
|
453
|
+
download(
|
|
454
|
+
get_json_string(),
|
|
455
|
+
`chempot-${plot_elements.join(`-`)}.json`,
|
|
456
|
+
`application/json`,
|
|
457
|
+
)
|
|
458
|
+
}
|
|
459
|
+
|
|
460
|
+
async function copy_json(): Promise<void> {
|
|
302
461
|
try {
|
|
303
|
-
|
|
304
|
-
|
|
462
|
+
await navigator.clipboard.writeText(get_json_string())
|
|
463
|
+
copy_status = true
|
|
464
|
+
} catch (err) {
|
|
465
|
+
copy_status = false
|
|
466
|
+
console.error(`Failed to copy JSON to clipboard:`, err)
|
|
305
467
|
}
|
|
306
|
-
|
|
307
|
-
copy_status = false;
|
|
308
|
-
console.error(`Failed to copy JSON to clipboard:`, err);
|
|
309
|
-
}
|
|
310
|
-
if (copy_timeout_id !== null)
|
|
311
|
-
clearTimeout(copy_timeout_id);
|
|
468
|
+
if (copy_timeout_id !== null) clearTimeout(copy_timeout_id)
|
|
312
469
|
copy_timeout_id = setTimeout(() => {
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
}, 1000)
|
|
316
|
-
}
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
})
|
|
470
|
+
copy_status = false
|
|
471
|
+
copy_timeout_id = null
|
|
472
|
+
}, 1000)
|
|
473
|
+
}
|
|
474
|
+
|
|
475
|
+
onDestroy(() => {
|
|
476
|
+
if (copy_timeout_id !== null) clearTimeout(copy_timeout_id)
|
|
477
|
+
})
|
|
321
478
|
</script>
|
|
322
479
|
|
|
323
480
|
{#snippet domain_labels(props: UserContentProps)}
|
|
@@ -328,7 +485,7 @@ onDestroy(() => {
|
|
|
328
485
|
text-anchor="middle"
|
|
329
486
|
class="domain-label"
|
|
330
487
|
>
|
|
331
|
-
{
|
|
488
|
+
{get_electro_neg_formula(formula, true, ``, `.3~s`)}
|
|
332
489
|
</text>
|
|
333
490
|
{/each}
|
|
334
491
|
{/snippet}
|
|
@@ -496,7 +653,11 @@ onDestroy(() => {
|
|
|
496
653
|
<button type="button" onclick={reset_controls}>Reset defaults</button>
|
|
497
654
|
{/snippet}
|
|
498
655
|
|
|
499
|
-
{#if
|
|
656
|
+
{#if diagram_computing}
|
|
657
|
+
<div class="computing-state">
|
|
658
|
+
<Spinner text="Computing chemical potential domains..." style="--spinner-size: 1.2em" />
|
|
659
|
+
</div>
|
|
660
|
+
{:else if !diagram_data}
|
|
500
661
|
<div class="error-state" role="alert" aria-live="polite">
|
|
501
662
|
<p>Cannot compute chemical potential diagram.</p>
|
|
502
663
|
<p>Need at least 2 elements with elemental reference entries.</p>
|
|
@@ -564,11 +725,14 @@ onDestroy(() => {
|
|
|
564
725
|
{/if}
|
|
565
726
|
{#if render_local_tooltip && show_tooltip && hover_info?.view === `2d`}
|
|
566
727
|
<aside
|
|
728
|
+
bind:this={tooltip_el}
|
|
567
729
|
class="tooltip"
|
|
568
|
-
style:left="{
|
|
569
|
-
style:top="{
|
|
730
|
+
style:left="{tooltip_pos.x}px"
|
|
731
|
+
style:top="{tooltip_pos.y}px"
|
|
570
732
|
>
|
|
571
|
-
<strong>
|
|
733
|
+
<strong>
|
|
734
|
+
{@html sanitize_html(get_electro_neg_formula(hover_info.formula, false, ``, `.3~s`))}
|
|
735
|
+
</strong>
|
|
572
736
|
{#if locked_hover_formula === hover_info.formula}
|
|
573
737
|
<div>Pinned · Press Esc to unlock</div>
|
|
574
738
|
{/if}
|
|
@@ -625,6 +789,12 @@ onDestroy(() => {
|
|
|
625
789
|
gap: 4pt;
|
|
626
790
|
margin-left: 4pt;
|
|
627
791
|
}
|
|
792
|
+
.computing-state {
|
|
793
|
+
display: flex;
|
|
794
|
+
align-items: center;
|
|
795
|
+
justify-content: center;
|
|
796
|
+
min-height: 200px;
|
|
797
|
+
}
|
|
628
798
|
.error-state {
|
|
629
799
|
display: flex;
|
|
630
800
|
flex-direction: column;
|