matterviz 0.3.1 → 0.3.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/EmptyState.svelte +10 -2
- package/dist/FilePicker.svelte +154 -96
- package/dist/Icon.svelte +20 -14
- package/dist/MillerIndexInput.svelte +27 -21
- package/dist/api/optimade.js +6 -6
- package/dist/app.css +216 -178
- package/dist/brillouin/BrillouinZone.svelte +299 -198
- package/dist/brillouin/BrillouinZone.svelte.d.ts +1 -1
- package/dist/brillouin/BrillouinZoneControls.svelte +32 -5
- package/dist/brillouin/BrillouinZoneExportPane.svelte +74 -55
- package/dist/brillouin/BrillouinZoneExportPane.svelte.d.ts +1 -1
- package/dist/brillouin/BrillouinZoneInfoPane.svelte +99 -68
- package/dist/brillouin/BrillouinZoneScene.svelte +277 -165
- 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 +327 -0
- package/dist/chempot-diagram/ChemPotDiagram.svelte.d.ts +13 -0
- package/dist/chempot-diagram/ChemPotDiagram2D.svelte +847 -0
- package/dist/chempot-diagram/ChemPotDiagram2D.svelte.d.ts +16 -0
- package/dist/chempot-diagram/ChemPotDiagram3D.svelte +3194 -0
- package/dist/chempot-diagram/ChemPotDiagram3D.svelte.d.ts +16 -0
- package/dist/chempot-diagram/ChemPotScene3D.svelte +11 -0
- package/dist/chempot-diagram/ChemPotScene3D.svelte.d.ts +7 -0
- 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.d.ts +10 -0
- package/dist/chempot-diagram/color.js +32 -0
- package/dist/chempot-diagram/compute.d.ts +48 -0
- package/dist/chempot-diagram/compute.js +812 -0
- package/dist/chempot-diagram/index.d.ts +6 -0
- package/dist/chempot-diagram/index.js +6 -0
- package/dist/chempot-diagram/pointer.d.ts +16 -0
- package/dist/chempot-diagram/pointer.js +40 -0
- package/dist/chempot-diagram/temperature.d.ts +15 -0
- package/dist/chempot-diagram/temperature.js +36 -0
- package/dist/chempot-diagram/types.d.ts +86 -0
- package/dist/chempot-diagram/types.js +28 -0
- package/dist/colors/index.d.ts +3 -1
- package/dist/colors/index.js +9 -3
- package/dist/composition/BarChart.svelte +141 -77
- package/dist/composition/BubbleChart.svelte +107 -52
- package/dist/composition/Composition.svelte +100 -79
- package/dist/composition/Formula.svelte +108 -62
- package/dist/composition/FormulaFilter.svelte +973 -353
- package/dist/composition/FormulaFilter.svelte.d.ts +35 -1
- package/dist/composition/PieChart.svelte +199 -99
- package/dist/composition/PieChart.svelte.d.ts +1 -1
- 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 -38
- package/dist/convex-hull/ConvexHull2D.svelte +551 -393
- package/dist/convex-hull/ConvexHull3D.svelte +1303 -825
- package/dist/convex-hull/ConvexHull4D.svelte +1012 -686
- package/dist/convex-hull/ConvexHullControls.svelte +115 -28
- package/dist/convex-hull/ConvexHullInfoPane.svelte +29 -3
- package/dist/convex-hull/ConvexHullStats.svelte +821 -249
- package/dist/convex-hull/ConvexHullStats.svelte.d.ts +6 -1
- package/dist/convex-hull/ConvexHullTooltip.svelte +41 -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.d.ts +6 -0
- package/dist/convex-hull/demo-temperature.js +40 -0
- package/dist/convex-hull/gas-thermodynamics.js +17 -12
- package/dist/convex-hull/helpers.d.ts +10 -1
- package/dist/convex-hull/helpers.js +79 -38
- package/dist/convex-hull/index.d.ts +1 -0
- package/dist/convex-hull/index.js +1 -0
- package/dist/convex-hull/thermodynamics.d.ts +8 -21
- package/dist/convex-hull/thermodynamics.js +163 -69
- package/dist/convex-hull/types.d.ts +12 -12
- package/dist/convex-hull/types.js +0 -12
- package/dist/coordination/CoordinationBarPlot.svelte +232 -176
- package/dist/element/BohrAtom.svelte +56 -13
- 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 +2 -14
- package/dist/element/data.json.gz +0 -0
- package/dist/element/types.d.ts +1 -0
- 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 +336 -239
- package/dist/fermi-surface/FermiSurface.svelte.d.ts +1 -1
- package/dist/fermi-surface/FermiSurfaceControls.svelte +113 -46
- package/dist/fermi-surface/FermiSurfaceScene.svelte +536 -343
- 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 +37 -33
- package/dist/fermi-surface/symmetry.js +2 -7
- package/dist/fermi-surface/types.d.ts +3 -5
- package/dist/heatmap-matrix/HeatmapMatrix.svelte +1527 -0
- package/dist/heatmap-matrix/HeatmapMatrix.svelte.d.ts +110 -0
- package/dist/heatmap-matrix/HeatmapMatrixControls.svelte +225 -0
- package/dist/heatmap-matrix/HeatmapMatrixControls.svelte.d.ts +30 -0
- package/dist/heatmap-matrix/index.d.ts +53 -0
- package/dist/heatmap-matrix/index.js +100 -0
- package/dist/heatmap-matrix/shared.d.ts +2 -0
- package/dist/heatmap-matrix/shared.js +4 -0
- package/dist/icons.d.ts +111 -0
- package/dist/icons.js +158 -0
- package/dist/index.d.ts +5 -2
- package/dist/index.js +5 -2
- package/dist/io/decompress.js +1 -1
- package/dist/io/export.d.ts +3 -0
- package/dist/io/export.js +138 -140
- package/dist/io/file-drop.d.ts +7 -0
- package/dist/io/file-drop.js +43 -0
- package/dist/io/index.d.ts +2 -2
- package/dist/io/index.js +2 -112
- package/dist/io/is-binary.js +2 -3
- package/dist/io/types.d.ts +1 -0
- package/dist/io/url-drop.d.ts +2 -0
- package/dist/io/url-drop.js +117 -0
- package/dist/isosurface/Isosurface.svelte +220 -110
- package/dist/isosurface/IsosurfaceControls.svelte +65 -28
- package/dist/isosurface/parse.js +104 -56
- package/dist/isosurface/slice.d.ts +2 -1
- package/dist/isosurface/slice.js +8 -13
- package/dist/isosurface/types.d.ts +14 -1
- package/dist/isosurface/types.js +152 -5
- package/dist/labels.d.ts +2 -1
- package/dist/labels.js +12 -8
- package/dist/layout/FullscreenToggle.svelte +11 -2
- package/dist/layout/InfoCard.svelte +38 -6
- package/dist/layout/InfoTag.svelte +125 -94
- package/dist/layout/PropertyFilter.svelte +82 -37
- package/dist/layout/SettingsSection.svelte +85 -55
- package/dist/layout/SubpageGrid.svelte +82 -0
- package/dist/layout/SubpageGrid.svelte.d.ts +14 -0
- package/dist/layout/index.d.ts +1 -0
- package/dist/layout/index.js +1 -0
- package/dist/layout/json-tree/JsonNode.svelte +266 -223
- package/dist/layout/json-tree/JsonTree.svelte +516 -429
- package/dist/layout/json-tree/JsonTree.svelte.d.ts +1 -1
- package/dist/layout/json-tree/JsonValue.svelte +281 -173
- package/dist/layout/json-tree/types.d.ts +10 -2
- package/dist/layout/json-tree/utils.d.ts +2 -0
- package/dist/layout/json-tree/utils.js +37 -2
- package/dist/marching-cubes.js +25 -2
- package/dist/math.d.ts +20 -17
- package/dist/math.js +474 -57
- package/dist/overlays/ContextMenu.svelte +66 -40
- package/dist/overlays/DraggablePane.svelte +331 -154
- package/dist/overlays/DraggablePane.svelte.d.ts +2 -0
- 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 +559 -267
- package/dist/phase-diagram/IsobaricBinaryPhaseDiagram.svelte.d.ts +6 -2
- package/dist/phase-diagram/PhaseDiagramControls.svelte +131 -51
- package/dist/phase-diagram/PhaseDiagramControls.svelte.d.ts +3 -2
- package/dist/phase-diagram/PhaseDiagramEditorPane.svelte +126 -0
- package/dist/phase-diagram/PhaseDiagramEditorPane.svelte.d.ts +15 -0
- package/dist/phase-diagram/PhaseDiagramExportPane.svelte +160 -110
- package/dist/phase-diagram/PhaseDiagramExportPane.svelte.d.ts +8 -1
- package/dist/phase-diagram/PhaseDiagramTooltip.svelte +217 -86
- package/dist/phase-diagram/PhaseDiagramTooltip.svelte.d.ts +6 -3
- 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/index.d.ts +2 -0
- package/dist/phase-diagram/index.js +2 -0
- package/dist/phase-diagram/parse.js +10 -9
- package/dist/phase-diagram/svg-to-diagram.d.ts +2 -0
- package/dist/phase-diagram/svg-to-diagram.js +869 -0
- package/dist/phase-diagram/types.d.ts +10 -0
- package/dist/phase-diagram/utils.d.ts +8 -4
- package/dist/phase-diagram/utils.js +219 -74
- package/dist/plot/AxisLabel.svelte +51 -0
- package/dist/plot/AxisLabel.svelte.d.ts +16 -0
- package/dist/plot/BarPlot.svelte +1461 -768
- package/dist/plot/BarPlot.svelte.d.ts +3 -3
- package/dist/plot/BarPlotControls.svelte +33 -6
- package/dist/plot/BarPlotControls.svelte.d.ts +1 -1
- package/dist/plot/ColorBar.svelte +533 -383
- package/dist/plot/ColorBar.svelte.d.ts +1 -1
- package/dist/plot/ColorScaleSelect.svelte +28 -7
- package/dist/plot/ElementScatter.svelte +38 -16
- package/dist/plot/FillArea.svelte +152 -92
- package/dist/plot/Histogram.svelte +1162 -709
- package/dist/plot/Histogram.svelte.d.ts +1 -1
- package/dist/plot/HistogramControls.svelte +81 -18
- package/dist/plot/HistogramControls.svelte.d.ts +6 -2
- 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 +221 -96
- 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 -146
- package/dist/plot/ReferenceLine.svelte +77 -22
- package/dist/plot/ReferenceLine.svelte.d.ts +1 -0
- package/dist/plot/ReferenceLine3D.svelte +132 -107
- package/dist/plot/ReferencePlane.svelte +146 -123
- package/dist/plot/ScatterPlot.svelte +1880 -1156
- package/dist/plot/ScatterPlot.svelte.d.ts +3 -3
- package/dist/plot/ScatterPlot3D.svelte +256 -131
- package/dist/plot/ScatterPlot3D.svelte.d.ts +2 -2
- package/dist/plot/ScatterPlot3DControls.svelte +300 -297
- package/dist/plot/ScatterPlot3DControls.svelte.d.ts +2 -1
- package/dist/plot/ScatterPlot3DScene.svelte +608 -406
- package/dist/plot/ScatterPlot3DScene.svelte.d.ts +2 -2
- package/dist/plot/ScatterPlotControls.svelte +150 -70
- 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 +96 -0
- package/dist/plot/ZeroLines.svelte.d.ts +32 -0
- package/dist/plot/ZoomRect.svelte +23 -0
- package/dist/plot/ZoomRect.svelte.d.ts +8 -0
- package/dist/plot/axis-utils.d.ts +1 -1
- 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/index.d.ts +6 -2
- package/dist/plot/index.js +6 -2
- package/dist/plot/interactions.d.ts +8 -10
- package/dist/plot/interactions.js +2 -3
- package/dist/plot/layout.d.ts +11 -2
- package/dist/plot/layout.js +44 -17
- package/dist/plot/reference-line.d.ts +5 -22
- package/dist/plot/reference-line.js +12 -84
- package/dist/plot/scales.js +24 -36
- package/dist/plot/types.d.ts +53 -40
- package/dist/plot/types.js +12 -7
- package/dist/plot/utils/label-placement.d.ts +32 -15
- package/dist/plot/utils/label-placement.js +227 -63
- package/dist/plot/utils/series-visibility.js +2 -3
- package/dist/plot/utils.d.ts +1 -0
- package/dist/plot/utils.js +14 -0
- package/dist/rdf/RdfPlot.svelte +173 -132
- 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 +21 -6
- package/dist/settings.js +63 -19
- package/dist/spectral/Bands.svelte +963 -412
- package/dist/spectral/Bands.svelte.d.ts +22 -2
- 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.d.ts +23 -1
- package/dist/spectral/helpers.js +119 -51
- package/dist/spectral/types.d.ts +2 -0
- 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 +231 -129
- package/dist/structure/AtomLegend.svelte.d.ts +1 -1
- package/dist/structure/Bond.svelte +73 -47
- package/dist/structure/CanvasTooltip.svelte +10 -2
- package/dist/structure/CellSelect.svelte +148 -51
- package/dist/structure/Cylinder.svelte +33 -17
- package/dist/structure/Lattice.svelte +88 -33
- package/dist/structure/Structure.svelte +1077 -821
- package/dist/structure/Structure.svelte.d.ts +1 -1
- package/dist/structure/StructureControls.svelte +373 -139
- package/dist/structure/StructureControls.svelte.d.ts +1 -1
- package/dist/structure/StructureExportPane.svelte +124 -89
- package/dist/structure/StructureExportPane.svelte.d.ts +1 -1
- package/dist/structure/StructureInfoPane.svelte +304 -231
- package/dist/structure/StructureScene.svelte +919 -445
- package/dist/structure/StructureScene.svelte.d.ts +16 -7
- package/dist/structure/atom-properties.d.ts +6 -2
- package/dist/structure/atom-properties.js +42 -29
- package/dist/structure/bonding.js +6 -7
- package/dist/structure/export.js +22 -34
- package/dist/structure/ferrox-wasm-types.d.ts +3 -2
- package/dist/structure/ferrox-wasm-types.js +0 -3
- package/dist/structure/ferrox-wasm.d.ts +3 -2
- package/dist/structure/ferrox-wasm.js +2 -3
- package/dist/structure/index.d.ts +16 -0
- package/dist/structure/index.js +88 -6
- package/dist/structure/measure.d.ts +2 -2
- package/dist/structure/measure.js +4 -44
- package/dist/structure/parse.js +130 -155
- package/dist/structure/partial-occupancy.d.ts +25 -0
- package/dist/structure/partial-occupancy.js +99 -0
- 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 +5 -3
- package/dist/symmetry/SymmetryStats.svelte +94 -37
- package/dist/symmetry/WyckoffTable.svelte +42 -14
- package/dist/symmetry/cell-transform.js +5 -3
- package/dist/symmetry/index.d.ts +7 -4
- package/dist/symmetry/index.js +87 -21
- package/dist/symmetry/spacegroups.js +148 -148
- package/dist/table/HeatmapTable.svelte +1112 -516
- package/dist/table/HeatmapTable.svelte.d.ts +12 -1
- package/dist/table/ToggleMenu.svelte +125 -90
- package/dist/table/index.d.ts +2 -0
- 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 +889 -687
- package/dist/trajectory/TrajectoryError.svelte +14 -3
- package/dist/trajectory/TrajectoryExportPane.svelte +148 -90
- package/dist/trajectory/TrajectoryExportPane.svelte.d.ts +1 -1
- package/dist/trajectory/TrajectoryInfoPane.svelte +272 -143
- package/dist/trajectory/constants.d.ts +6 -0
- package/dist/trajectory/constants.js +7 -0
- package/dist/trajectory/extract.js +13 -31
- package/dist/trajectory/format-detect.d.ts +9 -0
- package/dist/trajectory/format-detect.js +76 -0
- package/dist/trajectory/frame-reader.d.ts +17 -0
- package/dist/trajectory/frame-reader.js +332 -0
- package/dist/trajectory/helpers.d.ts +14 -0
- package/dist/trajectory/helpers.js +172 -0
- package/dist/trajectory/index.d.ts +1 -0
- package/dist/trajectory/index.js +23 -14
- package/dist/trajectory/parse/ase.d.ts +2 -0
- package/dist/trajectory/parse/ase.js +77 -0
- package/dist/trajectory/parse/hdf5.d.ts +2 -0
- package/dist/trajectory/parse/hdf5.js +129 -0
- package/dist/trajectory/parse/index.d.ts +12 -0
- package/dist/trajectory/parse/index.js +299 -0
- package/dist/trajectory/parse/lammps.d.ts +5 -0
- package/dist/trajectory/parse/lammps.js +179 -0
- package/dist/trajectory/parse/vasp.d.ts +2 -0
- package/dist/trajectory/parse/vasp.js +68 -0
- package/dist/trajectory/parse/xyz.d.ts +2 -0
- package/dist/trajectory/parse/xyz.js +110 -0
- package/dist/trajectory/plotting.js +13 -8
- package/dist/trajectory/types.d.ts +11 -0
- package/dist/trajectory/types.js +1 -0
- package/dist/utils.d.ts +3 -0
- package/dist/utils.js +17 -0
- package/dist/xrd/XrdPlot.svelte +337 -245
- package/dist/xrd/broadening.js +14 -9
- package/dist/xrd/calc-xrd.js +12 -19
- package/dist/xrd/parse.d.ts +1 -1
- package/dist/xrd/parse.js +17 -17
- package/package.json +103 -101
- package/readme.md +4 -4
- package/dist/trajectory/parse.d.ts +0 -42
- package/dist/trajectory/parse.js +0 -1267
- /package/dist/element/{data.json.d.ts → data.json.gz.d.ts} +0 -0
- /package/dist/theme/{themes.js → themes.mjs} +0 -0
|
@@ -74,6 +74,15 @@ export interface LeverRuleResult {
|
|
|
74
74
|
fraction_left: number;
|
|
75
75
|
fraction_right: number;
|
|
76
76
|
}
|
|
77
|
+
export interface VerticalLeverRuleResult {
|
|
78
|
+
bottom_phase: string;
|
|
79
|
+
top_phase: string;
|
|
80
|
+
bottom_temperature: number;
|
|
81
|
+
top_temperature: number;
|
|
82
|
+
fraction_bottom: number;
|
|
83
|
+
fraction_top: number;
|
|
84
|
+
}
|
|
85
|
+
export type LeverRuleMode = `horizontal` | `vertical`;
|
|
77
86
|
export interface PhaseHoverInfo {
|
|
78
87
|
region: PhaseRegion;
|
|
79
88
|
composition: number;
|
|
@@ -83,6 +92,7 @@ export interface PhaseHoverInfo {
|
|
|
83
92
|
y: number;
|
|
84
93
|
};
|
|
85
94
|
lever_rule?: LeverRuleResult;
|
|
95
|
+
vertical_lever_rule?: VerticalLeverRuleResult;
|
|
86
96
|
special_point?: SpecialPoint;
|
|
87
97
|
}
|
|
88
98
|
export type PhaseDiagramTooltipConfig = TooltipConfig<PhaseHoverInfo>;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { type Vec2 } from '../math';
|
|
2
2
|
import type { Sides } from '../plot';
|
|
3
|
-
import type { CompUnit, LeverRuleResult, PhaseDiagramConfig, PhaseDiagramData, PhaseHoverInfo, PhaseRegion, TempUnit } from './types';
|
|
3
|
+
import type { CompUnit, LeverRuleMode, LeverRuleResult, PhaseDiagramConfig, PhaseDiagramData, PhaseHoverInfo, PhaseRegion, TempUnit, VerticalLeverRuleResult } from './types';
|
|
4
4
|
export declare function convert_temp(value: number, from: TempUnit, to: TempUnit): number;
|
|
5
5
|
export declare const PHASE_DIAGRAM_DEFAULTS: Readonly<{
|
|
6
6
|
show_boundaries: true;
|
|
@@ -90,10 +90,11 @@ export declare function compute_label_properties(label: string, bounds: {
|
|
|
90
90
|
scale: number;
|
|
91
91
|
};
|
|
92
92
|
export declare function transform_vertices(vertices: Vec2[], x_scale: (val: number) => number, y_scale: (val: number) => number): Vec2[];
|
|
93
|
-
export declare function format_composition(value: number, unit?: CompUnit
|
|
94
|
-
export declare function format_temperature(value: number, unit?: TempUnit
|
|
93
|
+
export declare function format_composition(value: number, unit?: CompUnit, include_unit?: boolean): string;
|
|
94
|
+
export declare function format_temperature(value: number, unit?: TempUnit): string;
|
|
95
95
|
export declare function calculate_lever_rule(region: PhaseRegion, composition: number, temperature: number): LeverRuleResult | null;
|
|
96
|
-
export declare function
|
|
96
|
+
export declare function calculate_vertical_lever_rule(region: PhaseRegion, composition: number, temperature: number): VerticalLeverRuleResult | null;
|
|
97
|
+
export declare function format_hover_info_text(info: PhaseHoverInfo, temp_unit?: TempUnit, comp_unit?: CompUnit, component_a?: string, component_b?: string, data_temp_unit?: TempUnit, lever_rule_mode?: LeverRuleMode): string;
|
|
97
98
|
export declare function get_phase_stability_range(region: PhaseRegion): {
|
|
98
99
|
t_min: number;
|
|
99
100
|
t_max: number;
|
|
@@ -111,4 +112,7 @@ export interface FormulaToken {
|
|
|
111
112
|
export declare function is_compound(name: string): boolean;
|
|
112
113
|
export declare function tokenize_formula(formula: string): FormulaToken[];
|
|
113
114
|
export declare function format_formula_svg(formula: string, use_subscripts?: boolean): string;
|
|
115
|
+
export declare const format_label_svg: (label: string, use_subscripts?: boolean) => string;
|
|
116
|
+
export declare const format_label_html: (label: string, use_subscripts?: boolean) => string;
|
|
114
117
|
export declare function format_formula_html(formula: string, use_subscripts?: boolean): string;
|
|
118
|
+
export declare function compute_x_domain(x_range: [number | null, number | null] | undefined, data: PhaseDiagramData | null): Vec2;
|
|
@@ -7,17 +7,9 @@ export function convert_temp(value, from, to) {
|
|
|
7
7
|
if (from === to)
|
|
8
8
|
return value;
|
|
9
9
|
// Convert to Kelvin first
|
|
10
|
-
const kelvin = from === `°C`
|
|
11
|
-
? value + 273.15
|
|
12
|
-
: from === `°F`
|
|
13
|
-
? (value - 32) * (5 / 9) + 273.15
|
|
14
|
-
: value;
|
|
10
|
+
const kelvin = from === `°C` ? value + 273.15 : from === `°F` ? (value - 32) * (5 / 9) + 273.15 : value;
|
|
15
11
|
// Convert from Kelvin to target
|
|
16
|
-
return to === `K`
|
|
17
|
-
? kelvin
|
|
18
|
-
: to === `°C`
|
|
19
|
-
? kelvin - 273.15
|
|
20
|
-
: (kelvin - 273.15) * (9 / 5) + 32;
|
|
12
|
+
return to === `K` ? kelvin : to === `°C` ? kelvin - 273.15 : (kelvin - 273.15) * (9 / 5) + 32;
|
|
21
13
|
}
|
|
22
14
|
// Centralized defaults for phase diagram configuration (single source of truth)
|
|
23
15
|
export const PHASE_DIAGRAM_DEFAULTS = Object.freeze({
|
|
@@ -49,7 +41,7 @@ export const PHASE_DIAGRAM_DEFAULTS = Object.freeze({
|
|
|
49
41
|
special_point: `#d32f2f`,
|
|
50
42
|
}),
|
|
51
43
|
// Margins
|
|
52
|
-
margin: Object.freeze({ t: 25, r:
|
|
44
|
+
margin: Object.freeze({ t: 25, r: 25, b: 50, l: 60 }),
|
|
53
45
|
// Export
|
|
54
46
|
png_dpi: 150,
|
|
55
47
|
});
|
|
@@ -58,8 +50,7 @@ export function merge_phase_diagram_config(config) {
|
|
|
58
50
|
return {
|
|
59
51
|
margin: { ...PHASE_DIAGRAM_DEFAULTS.margin, ...config.margin },
|
|
60
52
|
font_size: config.font_size ?? PHASE_DIAGRAM_DEFAULTS.font_size,
|
|
61
|
-
special_point_radius: config.special_point_radius ??
|
|
62
|
-
PHASE_DIAGRAM_DEFAULTS.special_point_radius,
|
|
53
|
+
special_point_radius: config.special_point_radius ?? PHASE_DIAGRAM_DEFAULTS.special_point_radius,
|
|
63
54
|
tie_line: { ...PHASE_DIAGRAM_DEFAULTS.tie_line, ...config.tie_line },
|
|
64
55
|
colors: { ...PHASE_DIAGRAM_DEFAULTS.colors, ...config.colors },
|
|
65
56
|
};
|
|
@@ -94,7 +85,7 @@ export const PHASE_COLOR_RGB = Object.freeze(Object.fromEntries(Object.entries(P
|
|
|
94
85
|
const PHASE_ALPHA = { two_phase: 0.5, default: 0.5, tie_line: 1 };
|
|
95
86
|
export const PHASE_COLORS = Object.freeze(Object.fromEntries(Object.entries(PHASE_COLOR_HEX).map(([key, hex]) => [
|
|
96
87
|
key,
|
|
97
|
-
add_alpha(hex, PHASE_ALPHA[key]
|
|
88
|
+
add_alpha(hex, key in PHASE_ALPHA ? PHASE_ALPHA[key] : 0.6),
|
|
98
89
|
])));
|
|
99
90
|
// Phase pattern matching rules: [substrings to match, color key, optional prefix check]
|
|
100
91
|
// Order matters: theta before eta (since "theta" contains "eta" as substring)
|
|
@@ -127,7 +118,7 @@ export function get_phase_color_key(name) {
|
|
|
127
118
|
}
|
|
128
119
|
// Get phase color - returns rgba() by default, or RGB string if format='rgb'
|
|
129
120
|
export function get_phase_color(name, format = `rgba`) {
|
|
130
|
-
const lower = name.toLowerCase();
|
|
121
|
+
const lower = name.toLowerCase().trim();
|
|
131
122
|
const key = lower.includes(`+`) ? `two_phase` : get_phase_color_key(name);
|
|
132
123
|
return format === `rgb` ? PHASE_COLOR_RGB[key] : PHASE_COLORS[key];
|
|
133
124
|
}
|
|
@@ -136,7 +127,10 @@ export function get_phase_color(name, format = `rgba`) {
|
|
|
136
127
|
export function get_multi_phase_gradient(name) {
|
|
137
128
|
if (!name.includes(`+`))
|
|
138
129
|
return null;
|
|
139
|
-
const phases = name
|
|
130
|
+
const phases = name
|
|
131
|
+
.split(`+`)
|
|
132
|
+
.map((s) => s.trim())
|
|
133
|
+
.filter(Boolean);
|
|
140
134
|
if (phases.length < 2)
|
|
141
135
|
return null;
|
|
142
136
|
// Create evenly spaced gradient stops (phases.length >= 2 guaranteed by early return)
|
|
@@ -150,17 +144,20 @@ export function find_phase_at_point(composition, temperature, data) {
|
|
|
150
144
|
// Search regions in reverse order so later-defined regions take precedence
|
|
151
145
|
for (let idx = data.regions.length - 1; idx >= 0; idx--) {
|
|
152
146
|
const region = data.regions[idx];
|
|
153
|
-
if (point_in_polygon(composition, temperature, region.vertices))
|
|
147
|
+
if (point_in_polygon(composition, temperature, region.vertices)) {
|
|
154
148
|
return region;
|
|
149
|
+
}
|
|
155
150
|
}
|
|
156
151
|
return null;
|
|
157
152
|
}
|
|
158
153
|
// SVG path generator using d3-shape
|
|
159
|
-
const path_line = line()
|
|
154
|
+
const path_line = line()
|
|
155
|
+
.x((d) => d[0])
|
|
156
|
+
.y((d) => d[1]);
|
|
160
157
|
// Generate closed SVG path for polygon regions (min 3 points)
|
|
161
158
|
export const generate_region_path = (vertices) => vertices.length < 3 ? `` : `${path_line(vertices)} Z`;
|
|
162
159
|
// Generate open SVG path for boundary curves (min 2 points)
|
|
163
|
-
export const generate_boundary_path = (points) => points.length < 2 ? `` : path_line(points) ??
|
|
160
|
+
export const generate_boundary_path = (points) => points.length < 2 ? `` : (path_line(points) ?? ``);
|
|
164
161
|
// Compute label properties (rotation, wrapping, scale) to fit within region bounds
|
|
165
162
|
export function compute_label_properties(label, bounds, font_size) {
|
|
166
163
|
if (bounds.width <= 0 || bounds.height <= 0 || !label || font_size <= 0) {
|
|
@@ -199,7 +196,7 @@ export function compute_label_properties(label, bounds, font_size) {
|
|
|
199
196
|
}
|
|
200
197
|
// Scale down as last resort (min 70%)
|
|
201
198
|
const scale = Math.max(0.7, Math.min(avail_w / label_width, avail_h / line_height, 1));
|
|
202
|
-
const rotation = is_tall
|
|
199
|
+
const rotation = is_tall ? -90 : 0;
|
|
203
200
|
return { rotation, lines: [label], scale };
|
|
204
201
|
}
|
|
205
202
|
// Wrap text into multiple lines at delimiter boundaries
|
|
@@ -210,7 +207,7 @@ function wrap_text(text, max_chars) {
|
|
|
210
207
|
const lines = [];
|
|
211
208
|
let current_line = ``;
|
|
212
209
|
for (const word of words) {
|
|
213
|
-
const candidate = current_line ? `${current_line}
|
|
210
|
+
const candidate = current_line ? `${current_line} ${word}` : word;
|
|
214
211
|
if (candidate.length <= max_chars) {
|
|
215
212
|
current_line = candidate;
|
|
216
213
|
}
|
|
@@ -222,7 +219,7 @@ function wrap_text(text, max_chars) {
|
|
|
222
219
|
}
|
|
223
220
|
if (current_line)
|
|
224
221
|
lines.push(current_line);
|
|
225
|
-
return lines
|
|
222
|
+
return lines;
|
|
226
223
|
}
|
|
227
224
|
// Transform data coordinates to SVG coordinates using scale functions
|
|
228
225
|
export function transform_vertices(vertices, x_scale, y_scale) {
|
|
@@ -231,78 +228,158 @@ export function transform_vertices(vertices, x_scale, y_scale) {
|
|
|
231
228
|
// Format composition value for display
|
|
232
229
|
export function format_composition(value, unit = `at%`, include_unit = true) {
|
|
233
230
|
if (unit === `fraction`)
|
|
234
|
-
return format_num(value, `.
|
|
235
|
-
const formatted = format_num(value * 100, `.3
|
|
231
|
+
return format_num(value, `.3~f`);
|
|
232
|
+
const formatted = format_num(value * 100, `.3~`);
|
|
236
233
|
return include_unit ? `${formatted} ${unit}` : formatted;
|
|
237
234
|
}
|
|
238
235
|
// Format temperature value for display
|
|
239
236
|
export function format_temperature(value, unit = `K`) {
|
|
240
237
|
return `${format_num(value, `.0f`)} ${unit}`;
|
|
241
238
|
}
|
|
242
|
-
//
|
|
243
|
-
// Returns null if the region is not exactly a two-phase region
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
// Only works for exactly two-phase regions (lever rule undefined for 3+ phases)
|
|
247
|
-
if (!region.name.includes(`+`))
|
|
248
|
-
return null;
|
|
249
|
-
const phase_count = region.name.split(`+`).filter((s) => s.trim()).length;
|
|
250
|
-
if (phase_count !== 2)
|
|
239
|
+
// Parse a two-phase region name into its two phase names
|
|
240
|
+
// Returns null if the region is not exactly a two-phase region
|
|
241
|
+
function parse_two_phases(name) {
|
|
242
|
+
if (!name.includes(`+`))
|
|
251
243
|
return null;
|
|
252
|
-
|
|
244
|
+
const parts = name
|
|
245
|
+
.trim()
|
|
246
|
+
.split(/\s*\+\s*/)
|
|
247
|
+
.filter(Boolean);
|
|
248
|
+
return parts.length === 2 ? [parts[0], parts[1]] : null;
|
|
249
|
+
}
|
|
250
|
+
// Find polygon edge intersections along a scan line (horizontal or vertical)
|
|
251
|
+
// For horizontal: fixed_val = temperature, returns x-intersections
|
|
252
|
+
// For vertical: fixed_val = composition, returns y-intersections
|
|
253
|
+
function find_polygon_intersections(vertices, fixed_val, axis) {
|
|
254
|
+
const other = axis === 0 ? 1 : 0;
|
|
253
255
|
const intersections = [];
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
const
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
intersections.push(
|
|
256
|
+
for (let idx = 0; idx < vertices.length; idx++) {
|
|
257
|
+
const v1 = vertices[idx];
|
|
258
|
+
const v2 = vertices[(idx + 1) % vertices.length];
|
|
259
|
+
if ((v1[axis] <= fixed_val && v2[axis] > fixed_val) ||
|
|
260
|
+
(v2[axis] <= fixed_val && v1[axis] > fixed_val)) {
|
|
261
|
+
intersections.push(v1[other] + ((fixed_val - v1[axis]) / (v2[axis] - v1[axis])) * (v2[other] - v1[other]));
|
|
260
262
|
}
|
|
261
263
|
}
|
|
264
|
+
return intersections.toSorted((a, b) => a - b);
|
|
265
|
+
}
|
|
266
|
+
function pick_bracketing_intersection_pair(intersections, position) {
|
|
262
267
|
if (intersections.length < 2)
|
|
263
268
|
return null;
|
|
264
|
-
|
|
265
|
-
const
|
|
266
|
-
const
|
|
267
|
-
|
|
269
|
+
const unique_intersections = [];
|
|
270
|
+
const dedup_tol = 1e-9;
|
|
271
|
+
for (const value of intersections) {
|
|
272
|
+
const prev_value = unique_intersections.at(-1);
|
|
273
|
+
if (prev_value === undefined || Math.abs(value - prev_value) > dedup_tol) {
|
|
274
|
+
unique_intersections.push(value);
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
if (unique_intersections.length < 2)
|
|
278
|
+
return null;
|
|
279
|
+
const bound_tol = 1e-10;
|
|
280
|
+
for (let pair_idx = 0; pair_idx + 1 < unique_intersections.length; pair_idx += 2) {
|
|
281
|
+
const low_bound = unique_intersections[pair_idx];
|
|
282
|
+
const high_bound = unique_intersections[pair_idx + 1];
|
|
283
|
+
if (position >= low_bound - bound_tol && position <= high_bound + bound_tol) {
|
|
284
|
+
return [low_bound, high_bound];
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
// Fallback for numerical edge cases where even-odd pairing fails:
|
|
288
|
+
// pick nearest enclosing neighbors around the hovered point.
|
|
289
|
+
let left_idx = -1;
|
|
290
|
+
for (let idx = 0; idx < unique_intersections.length; idx++) {
|
|
291
|
+
if (unique_intersections[idx] <= position + bound_tol)
|
|
292
|
+
left_idx = idx;
|
|
293
|
+
}
|
|
294
|
+
if (left_idx < 0 || left_idx + 1 >= unique_intersections.length)
|
|
295
|
+
return null;
|
|
296
|
+
const left_bound = unique_intersections[left_idx];
|
|
297
|
+
const right_bound = unique_intersections[left_idx + 1];
|
|
298
|
+
return right_bound - left_bound > bound_tol ? [left_bound, right_bound] : null;
|
|
299
|
+
}
|
|
300
|
+
// Shared core for lever rule calculations (horizontal and vertical)
|
|
301
|
+
// Parses phases, finds intersections along the scan axis, validates bounds,
|
|
302
|
+
// and computes the fractional position within the two-phase region.
|
|
303
|
+
function lever_rule_core(region, position, scan_val, axis) {
|
|
304
|
+
const phases = parse_two_phases(region.name);
|
|
305
|
+
if (!phases)
|
|
306
|
+
return null;
|
|
307
|
+
const intersections = find_polygon_intersections(region.vertices, scan_val, axis);
|
|
308
|
+
const bounds = pick_bracketing_intersection_pair(intersections, position);
|
|
309
|
+
if (!bounds)
|
|
310
|
+
return null;
|
|
311
|
+
const [lo, hi] = bounds;
|
|
312
|
+
const span = hi - lo;
|
|
313
|
+
if (span < 1e-10)
|
|
314
|
+
return null;
|
|
315
|
+
return { phases, lo, hi, fraction_hi: (position - lo) / span };
|
|
316
|
+
}
|
|
317
|
+
// Calculate lever rule for a point in a two-phase region
|
|
318
|
+
// Returns null if the region is not exactly a two-phase region or calculation fails
|
|
319
|
+
// Note: Lever rule is thermodynamically defined only for two-phase equilibria
|
|
320
|
+
export function calculate_lever_rule(region, composition, temperature) {
|
|
321
|
+
// Horizontal scan: fixed temperature, find composition intersections
|
|
322
|
+
const core = lever_rule_core(region, composition, temperature, 1);
|
|
323
|
+
if (!core)
|
|
268
324
|
return null;
|
|
269
|
-
|
|
270
|
-
|
|
325
|
+
return {
|
|
326
|
+
left_phase: core.phases[0],
|
|
327
|
+
right_phase: core.phases[1],
|
|
328
|
+
left_composition: core.lo,
|
|
329
|
+
right_composition: core.hi,
|
|
330
|
+
fraction_left: 1 - core.fraction_hi,
|
|
331
|
+
fraction_right: core.fraction_hi,
|
|
332
|
+
};
|
|
333
|
+
}
|
|
334
|
+
// Calculate vertical lever rule for a point in a two-phase region
|
|
335
|
+
// Uses constant composition (vertical line) to find temperature boundaries
|
|
336
|
+
export function calculate_vertical_lever_rule(region, composition, temperature) {
|
|
337
|
+
// Vertical scan: fixed composition, find temperature intersections
|
|
338
|
+
const core = lever_rule_core(region, temperature, composition, 0);
|
|
339
|
+
if (!core)
|
|
271
340
|
return null;
|
|
272
|
-
const fraction_right = (composition - left_composition) / total_width;
|
|
273
|
-
const fraction_left = 1 - fraction_right;
|
|
274
|
-
// Parse phase names from "α + β" format
|
|
275
|
-
const parts = region.name.split(/\s*\+\s*/);
|
|
276
|
-
const left_phase = parts[0]?.trim() || `Phase 1`;
|
|
277
|
-
const right_phase = parts[1]?.trim() || `Phase 2`;
|
|
278
341
|
return {
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
342
|
+
bottom_phase: core.phases[0],
|
|
343
|
+
top_phase: core.phases[1],
|
|
344
|
+
bottom_temperature: core.lo,
|
|
345
|
+
top_temperature: core.hi,
|
|
346
|
+
fraction_bottom: 1 - core.fraction_hi,
|
|
347
|
+
fraction_top: core.fraction_hi,
|
|
285
348
|
};
|
|
286
349
|
}
|
|
287
350
|
// Format hover info as copyable text for clipboard
|
|
288
|
-
|
|
351
|
+
// Only includes lever rule data for the active mode to match tooltip display
|
|
352
|
+
export function format_hover_info_text(info, temp_unit = `K`, comp_unit = `at%`, component_a = `A`, component_b = `B`, data_temp_unit = temp_unit, lever_rule_mode = `horizontal`) {
|
|
353
|
+
// Convert temperature from data unit to display unit
|
|
354
|
+
const to_display = (temp) => convert_temp(temp, data_temp_unit, temp_unit);
|
|
289
355
|
const lines = [
|
|
290
356
|
`Phase: ${info.region.name}`,
|
|
291
|
-
`Temperature: ${format_temperature(info.temperature, temp_unit)}`,
|
|
357
|
+
`Temperature: ${format_temperature(to_display(info.temperature), temp_unit)}`,
|
|
292
358
|
`Composition: ${format_composition(info.composition, comp_unit)} ${component_b} (${format_composition(1 - info.composition, comp_unit)} ${component_a})`,
|
|
293
359
|
];
|
|
294
|
-
if (info.lever_rule) {
|
|
360
|
+
if (lever_rule_mode === `horizontal` && info.lever_rule) {
|
|
295
361
|
const lr = info.lever_rule;
|
|
296
362
|
lines.push(``, `Lever Rule:`, ` ${lr.left_phase}: ${format_num(lr.fraction_left * 100, `.1f`)}% (at ${format_composition(lr.left_composition, comp_unit)})`, ` ${lr.right_phase}: ${format_num(lr.fraction_right * 100, `.1f`)}% (at ${format_composition(lr.right_composition, comp_unit)})`);
|
|
297
363
|
}
|
|
364
|
+
if (lever_rule_mode === `vertical` && info.vertical_lever_rule) {
|
|
365
|
+
const vlr = info.vertical_lever_rule;
|
|
366
|
+
lines.push(``, `Vertical Lever Rule:`, ` ${vlr.bottom_phase}: ${format_num(vlr.fraction_bottom * 100, `.1f`)}% (at ${format_temperature(to_display(vlr.bottom_temperature), temp_unit)})`, ` ${vlr.top_phase}: ${format_num(vlr.fraction_top * 100, `.1f`)}% (at ${format_temperature(to_display(vlr.top_temperature), temp_unit)})`);
|
|
367
|
+
}
|
|
298
368
|
return lines.join(`\n`);
|
|
299
369
|
}
|
|
300
370
|
// Calculate temperature stability range for a phase at given composition
|
|
301
371
|
export function get_phase_stability_range(region) {
|
|
302
372
|
if (!region.vertices?.length)
|
|
303
373
|
return null;
|
|
304
|
-
|
|
305
|
-
|
|
374
|
+
let t_min = Infinity;
|
|
375
|
+
let t_max = -Infinity;
|
|
376
|
+
for (const [, temp] of region.vertices) {
|
|
377
|
+
if (temp < t_min)
|
|
378
|
+
t_min = temp;
|
|
379
|
+
if (temp > t_max)
|
|
380
|
+
t_max = temp;
|
|
381
|
+
}
|
|
382
|
+
return { t_min, t_max };
|
|
306
383
|
}
|
|
307
384
|
// Extract reference/citation from TDB comments
|
|
308
385
|
export function extract_tdb_reference(comments) {
|
|
@@ -325,8 +402,8 @@ export function summarize_models(phases) {
|
|
|
325
402
|
counts.set(phase.sublattice_count, (counts.get(phase.sublattice_count) ?? 0) + 1);
|
|
326
403
|
}
|
|
327
404
|
return [...counts.entries()]
|
|
328
|
-
.
|
|
329
|
-
.map(([
|
|
405
|
+
.toSorted(([sl_a], [sl_b]) => sl_a - sl_b)
|
|
406
|
+
.map(([sublattices, count]) => `${count}×${sublattices}-SL`)
|
|
330
407
|
.join(`, `);
|
|
331
408
|
}
|
|
332
409
|
// Check if a component name is a compound (vs single element)
|
|
@@ -342,13 +419,7 @@ export function is_compound(name) {
|
|
|
342
419
|
// Single element pattern: one uppercase followed by optional lowercase (Fe, Ca, He, C)
|
|
343
420
|
if (/^[A-Z][a-z]?$/.test(name))
|
|
344
421
|
return false;
|
|
345
|
-
|
|
346
|
-
let uppercase_count = 0;
|
|
347
|
-
for (const char of name) {
|
|
348
|
-
if (char >= `A` && char <= `Z`)
|
|
349
|
-
uppercase_count++;
|
|
350
|
-
}
|
|
351
|
-
return uppercase_count >= 2;
|
|
422
|
+
return (name.match(/[A-Z]/g)?.length ?? 0) >= 2;
|
|
352
423
|
}
|
|
353
424
|
// Tokenize a chemical formula for rendering with subscripts/superscripts
|
|
354
425
|
// Examples:
|
|
@@ -413,7 +484,7 @@ export function tokenize_formula(formula) {
|
|
|
413
484
|
// Any other character (lowercase, hyphen, etc.) - collect as text
|
|
414
485
|
let text = char;
|
|
415
486
|
idx++;
|
|
416
|
-
while (idx < formula.length && !/[A-Z\d
|
|
487
|
+
while (idx < formula.length && !/[A-Z\d-]/.test(formula[idx])) {
|
|
417
488
|
text += formula[idx];
|
|
418
489
|
idx++;
|
|
419
490
|
}
|
|
@@ -447,10 +518,29 @@ export function format_formula_svg(formula, use_subscripts = true) {
|
|
|
447
518
|
offset += dy;
|
|
448
519
|
}
|
|
449
520
|
}
|
|
521
|
+
// Reset baseline after trailing subscript/superscript using a zero-width space
|
|
522
|
+
// (empty tspans may not apply dy in all SVG renderers)
|
|
450
523
|
if (offset)
|
|
451
|
-
result += `<tspan dy="${-offset}em"
|
|
524
|
+
result += `<tspan dy="${-offset}em">\u200B</tspan>`;
|
|
452
525
|
return result;
|
|
453
526
|
}
|
|
527
|
+
// Split a multi-phase label on " + " and format each part with the given formatter
|
|
528
|
+
function format_label_parts(label, use_subscripts, formatter) {
|
|
529
|
+
if (!use_subscripts)
|
|
530
|
+
return label;
|
|
531
|
+
return label
|
|
532
|
+
.split(/(\s*\+\s*)/)
|
|
533
|
+
.map((part) => {
|
|
534
|
+
if (part.trim() === `+`)
|
|
535
|
+
return part;
|
|
536
|
+
return formatter(part.trim(), use_subscripts);
|
|
537
|
+
})
|
|
538
|
+
.join(``);
|
|
539
|
+
}
|
|
540
|
+
// Format a phase region label (e.g. "La2NiO4 + NiO") as SVG with subscripts
|
|
541
|
+
export const format_label_svg = (label, use_subscripts = true) => format_label_parts(label, use_subscripts, format_formula_svg);
|
|
542
|
+
// Format a phase region label as HTML with subscripts (splits on " + ")
|
|
543
|
+
export const format_label_html = (label, use_subscripts = true) => format_label_parts(label, use_subscripts, format_formula_html);
|
|
454
544
|
// Format chemical formula as HTML with <sub> and <sup> tags
|
|
455
545
|
export function format_formula_html(formula, use_subscripts = true) {
|
|
456
546
|
if (!use_subscripts || !is_compound(formula))
|
|
@@ -459,3 +549,58 @@ export function format_formula_html(formula, use_subscripts = true) {
|
|
|
459
549
|
.map((token) => token.text ?? (token.sub ? `<sub>${token.sub}</sub>` : `<sup>${token.sup}</sup>`))
|
|
460
550
|
.join(``);
|
|
461
551
|
}
|
|
552
|
+
// Compute the x-axis domain for a binary phase diagram.
|
|
553
|
+
// Uses explicit range if fully specified, otherwise derives from data extent
|
|
554
|
+
// and auto-extends to 0/1 when edge regions contain pure components.
|
|
555
|
+
export function compute_x_domain(x_range, data) {
|
|
556
|
+
const lo = x_range?.[0];
|
|
557
|
+
const hi = x_range?.[1];
|
|
558
|
+
if (lo != null && hi != null)
|
|
559
|
+
return [lo, hi];
|
|
560
|
+
if (data) {
|
|
561
|
+
let data_min = Infinity;
|
|
562
|
+
let data_max = -Infinity;
|
|
563
|
+
const update = (val) => {
|
|
564
|
+
if (val < data_min)
|
|
565
|
+
data_min = val;
|
|
566
|
+
if (val > data_max)
|
|
567
|
+
data_max = val;
|
|
568
|
+
};
|
|
569
|
+
for (const region of data.regions) {
|
|
570
|
+
for (const vertex of region.vertices)
|
|
571
|
+
update(vertex[0]);
|
|
572
|
+
}
|
|
573
|
+
for (const boundary of data.boundaries) {
|
|
574
|
+
for (const point of boundary.points)
|
|
575
|
+
update(point[0]);
|
|
576
|
+
}
|
|
577
|
+
for (const special_point of data.special_points ?? []) {
|
|
578
|
+
update(special_point.position[0]);
|
|
579
|
+
}
|
|
580
|
+
if (data_min <= data_max) {
|
|
581
|
+
let x_min = lo ?? data_min;
|
|
582
|
+
let x_max = hi ?? data_max;
|
|
583
|
+
// Auto-extend to 0/1 when edge regions contain a pure component AND the
|
|
584
|
+
// data already nearly reaches the boundary
|
|
585
|
+
const comp_at_edge = (comp, x_val) => {
|
|
586
|
+
const re = new RegExp(`\\b${comp.replaceAll(/[.*+?^${}()|[\]\\]/g, `\\$&`)}\\b`);
|
|
587
|
+
return data.regions.some((region) => re.test(region.name) &&
|
|
588
|
+
region.vertices.some((vertex) => Math.abs(vertex[0] - x_val) < 1e-6));
|
|
589
|
+
};
|
|
590
|
+
if (lo == null &&
|
|
591
|
+
x_min < 0.05 &&
|
|
592
|
+
data.components[0] &&
|
|
593
|
+
comp_at_edge(data.components[0], x_min)) {
|
|
594
|
+
x_min = 0;
|
|
595
|
+
}
|
|
596
|
+
if (hi == null &&
|
|
597
|
+
x_max > 0.95 &&
|
|
598
|
+
data.components[1] &&
|
|
599
|
+
comp_at_edge(data.components[1], x_max)) {
|
|
600
|
+
x_max = 1;
|
|
601
|
+
}
|
|
602
|
+
return [x_min, x_max];
|
|
603
|
+
}
|
|
604
|
+
}
|
|
605
|
+
return [lo ?? 0, hi ?? 1];
|
|
606
|
+
}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import { AXIS_LABEL_CONTAINER } from './axis-utils'
|
|
3
|
+
import type { AxisOption } from './types'
|
|
4
|
+
import InteractiveAxisLabel from './InteractiveAxisLabel.svelte'
|
|
5
|
+
|
|
6
|
+
let {
|
|
7
|
+
x,
|
|
8
|
+
y,
|
|
9
|
+
rotate = false,
|
|
10
|
+
label = ``,
|
|
11
|
+
options,
|
|
12
|
+
selected_key,
|
|
13
|
+
color,
|
|
14
|
+
loading = false,
|
|
15
|
+
axis_type,
|
|
16
|
+
on_select,
|
|
17
|
+
}: {
|
|
18
|
+
x: number
|
|
19
|
+
y: number
|
|
20
|
+
rotate?: boolean
|
|
21
|
+
label?: string
|
|
22
|
+
options?: AxisOption[]
|
|
23
|
+
selected_key?: string
|
|
24
|
+
color?: string | null
|
|
25
|
+
loading?: boolean
|
|
26
|
+
axis_type: `x` | `x2` | `y` | `y2`
|
|
27
|
+
on_select?: (key: string) => void
|
|
28
|
+
} = $props()
|
|
29
|
+
</script>
|
|
30
|
+
|
|
31
|
+
<foreignObject
|
|
32
|
+
x={x - AXIS_LABEL_CONTAINER.x_offset}
|
|
33
|
+
y={y - AXIS_LABEL_CONTAINER.y_offset}
|
|
34
|
+
width={AXIS_LABEL_CONTAINER.width}
|
|
35
|
+
height={AXIS_LABEL_CONTAINER.height}
|
|
36
|
+
style="overflow: visible; pointer-events: none"
|
|
37
|
+
transform={rotate ? `rotate(-90, ${x}, ${y})` : undefined}
|
|
38
|
+
>
|
|
39
|
+
<div xmlns="http://www.w3.org/1999/xhtml" style="pointer-events: auto">
|
|
40
|
+
<InteractiveAxisLabel
|
|
41
|
+
{label}
|
|
42
|
+
{options}
|
|
43
|
+
{selected_key}
|
|
44
|
+
{loading}
|
|
45
|
+
{axis_type}
|
|
46
|
+
{color}
|
|
47
|
+
{on_select}
|
|
48
|
+
class="axis-label {axis_type}-label"
|
|
49
|
+
/>
|
|
50
|
+
</div>
|
|
51
|
+
</foreignObject>
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { AxisOption } from './types';
|
|
2
|
+
type $$ComponentProps = {
|
|
3
|
+
x: number;
|
|
4
|
+
y: number;
|
|
5
|
+
rotate?: boolean;
|
|
6
|
+
label?: string;
|
|
7
|
+
options?: AxisOption[];
|
|
8
|
+
selected_key?: string;
|
|
9
|
+
color?: string | null;
|
|
10
|
+
loading?: boolean;
|
|
11
|
+
axis_type: `x` | `x2` | `y` | `y2`;
|
|
12
|
+
on_select?: (key: string) => void;
|
|
13
|
+
};
|
|
14
|
+
declare const AxisLabel: import("svelte").Component<$$ComponentProps, {}, "">;
|
|
15
|
+
type AxisLabel = ReturnType<typeof AxisLabel>;
|
|
16
|
+
export default AxisLabel;
|