matterviz 0.3.0 → 0.3.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/FilePicker.svelte +37 -20
- package/dist/Icon.svelte +2 -2
- package/dist/MillerIndexInput.svelte +60 -0
- package/dist/MillerIndexInput.svelte.d.ts +7 -0
- package/dist/app.css +38 -2
- package/dist/brillouin/BrillouinZone.svelte +20 -62
- package/dist/brillouin/BrillouinZone.svelte.d.ts +1 -1
- package/dist/brillouin/BrillouinZoneExportPane.svelte +12 -20
- package/dist/brillouin/BrillouinZoneScene.svelte +2 -2
- package/dist/brillouin/BrillouinZoneScene.svelte.d.ts +1 -1
- package/dist/chempot-diagram/ChemPotDiagram.svelte +192 -0
- package/dist/chempot-diagram/ChemPotDiagram.svelte.d.ts +13 -0
- package/dist/chempot-diagram/ChemPotDiagram2D.svelte +677 -0
- package/dist/chempot-diagram/ChemPotDiagram2D.svelte.d.ts +16 -0
- package/dist/chempot-diagram/ChemPotDiagram3D.svelte +2688 -0
- package/dist/chempot-diagram/ChemPotDiagram3D.svelte.d.ts +16 -0
- package/dist/chempot-diagram/ChemPotScene3D.svelte +8 -0
- package/dist/chempot-diagram/ChemPotScene3D.svelte.d.ts +7 -0
- package/dist/chempot-diagram/color.d.ts +10 -0
- package/dist/chempot-diagram/color.js +33 -0
- package/dist/chempot-diagram/compute.d.ts +38 -0
- package/dist/chempot-diagram/compute.js +650 -0
- package/dist/chempot-diagram/index.d.ts +5 -0
- package/dist/chempot-diagram/index.js +5 -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 +37 -0
- package/dist/chempot-diagram/types.d.ts +83 -0
- package/dist/chempot-diagram/types.js +27 -0
- package/dist/colors/index.d.ts +3 -1
- package/dist/colors/index.js +4 -0
- package/dist/composition/BarChart.svelte +13 -22
- package/dist/composition/BubbleChart.svelte +5 -3
- package/dist/composition/FormulaFilter.svelte +770 -90
- package/dist/composition/FormulaFilter.svelte.d.ts +37 -1
- package/dist/composition/PieChart.svelte +43 -18
- package/dist/composition/PieChart.svelte.d.ts +1 -1
- package/dist/constants.d.ts +1 -0
- package/dist/constants.js +2 -0
- package/dist/convex-hull/ConvexHull.svelte +14 -1
- package/dist/convex-hull/ConvexHull.svelte.d.ts +1 -1
- package/dist/convex-hull/ConvexHull2D.svelte +14 -45
- package/dist/convex-hull/ConvexHull2D.svelte.d.ts +1 -1
- package/dist/convex-hull/ConvexHull3D.svelte +396 -134
- package/dist/convex-hull/ConvexHull3D.svelte.d.ts +1 -1
- package/dist/convex-hull/ConvexHull4D.svelte +93 -42
- package/dist/convex-hull/ConvexHull4D.svelte.d.ts +1 -1
- package/dist/convex-hull/ConvexHullControls.svelte +94 -31
- package/dist/convex-hull/ConvexHullControls.svelte.d.ts +4 -2
- package/dist/convex-hull/ConvexHullStats.svelte +697 -128
- package/dist/convex-hull/ConvexHullStats.svelte.d.ts +6 -1
- package/dist/convex-hull/ConvexHullTooltip.svelte +1 -0
- package/dist/convex-hull/GasPressureControls.svelte +72 -38
- package/dist/convex-hull/GasPressureControls.svelte.d.ts +2 -1
- package/dist/convex-hull/TemperatureSlider.svelte +46 -19
- package/dist/convex-hull/TemperatureSlider.svelte.d.ts +2 -1
- package/dist/convex-hull/demo-temperature.d.ts +6 -0
- package/dist/convex-hull/demo-temperature.js +36 -0
- package/dist/convex-hull/gas-thermodynamics.js +16 -5
- package/dist/convex-hull/helpers.d.ts +7 -1
- package/dist/convex-hull/helpers.js +45 -15
- package/dist/convex-hull/index.d.ts +15 -1
- package/dist/convex-hull/index.js +1 -0
- package/dist/convex-hull/thermodynamics.d.ts +8 -21
- package/dist/convex-hull/thermodynamics.js +106 -17
- package/dist/convex-hull/types.d.ts +7 -0
- package/dist/convex-hull/types.js +11 -0
- package/dist/coordination/CoordinationBarPlot.svelte +29 -46
- package/dist/element/BohrAtom.svelte +1 -1
- package/dist/element/data.js +2 -14
- package/dist/element/data.json.gz +0 -0
- package/dist/element/index.d.ts +1 -1
- package/dist/element/index.js +1 -0
- package/dist/element/types.d.ts +1 -0
- package/dist/fermi-surface/FermiSurface.svelte +21 -65
- package/dist/fermi-surface/FermiSurface.svelte.d.ts +1 -1
- package/dist/fermi-surface/FermiSurfaceControls.svelte.d.ts +1 -1
- package/dist/fermi-surface/FermiSurfaceScene.svelte +1 -1
- package/dist/fermi-surface/FermiSurfaceScene.svelte.d.ts +1 -1
- package/dist/fermi-surface/compute.js +1 -21
- package/dist/fermi-surface/marching-cubes.d.ts +2 -13
- package/dist/fermi-surface/marching-cubes.js +2 -519
- package/dist/fermi-surface/parse.js +17 -23
- package/dist/heatmap-matrix/HeatmapMatrix.svelte +1273 -0
- package/dist/heatmap-matrix/HeatmapMatrix.svelte.d.ts +110 -0
- package/dist/heatmap-matrix/HeatmapMatrixControls.svelte +171 -0
- package/dist/heatmap-matrix/HeatmapMatrixControls.svelte.d.ts +31 -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 +119 -0
- package/dist/icons.js +119 -0
- package/dist/index.d.ts +6 -1
- package/dist/index.js +6 -1
- package/dist/io/export.js +15 -3
- 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/types.d.ts +1 -0
- package/dist/io/url-drop.d.ts +2 -0
- package/dist/io/url-drop.js +118 -0
- package/dist/isosurface/Isosurface.svelte +231 -0
- package/dist/isosurface/Isosurface.svelte.d.ts +8 -0
- package/dist/isosurface/IsosurfaceControls.svelte +273 -0
- package/dist/isosurface/IsosurfaceControls.svelte.d.ts +9 -0
- package/dist/isosurface/index.d.ts +5 -0
- package/dist/isosurface/index.js +6 -0
- package/dist/isosurface/parse.d.ts +6 -0
- package/dist/isosurface/parse.js +548 -0
- package/dist/isosurface/slice.d.ts +11 -0
- package/dist/isosurface/slice.js +145 -0
- package/dist/isosurface/types.d.ts +55 -0
- package/dist/isosurface/types.js +178 -0
- package/dist/labels.d.ts +2 -1
- package/dist/labels.js +1 -0
- package/dist/layout/InfoTag.svelte +62 -62
- package/dist/layout/SubpageGrid.svelte +74 -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 +226 -53
- package/dist/layout/json-tree/JsonTree.svelte +425 -51
- package/dist/layout/json-tree/JsonTree.svelte.d.ts +1 -1
- package/dist/layout/json-tree/JsonValue.svelte +218 -97
- package/dist/layout/json-tree/types.d.ts +27 -2
- package/dist/layout/json-tree/utils.d.ts +14 -1
- package/dist/layout/json-tree/utils.js +254 -0
- package/dist/marching-cubes.d.ts +14 -0
- package/dist/marching-cubes.js +519 -0
- package/dist/math.d.ts +8 -0
- package/dist/math.js +374 -7
- package/dist/overlays/ContextMenu.svelte +3 -2
- package/dist/overlays/DraggablePane.svelte +163 -58
- package/dist/overlays/DraggablePane.svelte.d.ts +2 -0
- package/dist/phase-diagram/IsobaricBinaryPhaseDiagram.svelte +232 -77
- package/dist/phase-diagram/IsobaricBinaryPhaseDiagram.svelte.d.ts +6 -2
- package/dist/phase-diagram/PhaseDiagramControls.svelte +32 -11
- package/dist/phase-diagram/PhaseDiagramControls.svelte.d.ts +3 -2
- package/dist/phase-diagram/PhaseDiagramEditorPane.svelte +103 -0
- package/dist/phase-diagram/PhaseDiagramEditorPane.svelte.d.ts +15 -0
- package/dist/phase-diagram/PhaseDiagramExportPane.svelte +102 -95
- package/dist/phase-diagram/PhaseDiagramExportPane.svelte.d.ts +7 -0
- package/dist/phase-diagram/PhaseDiagramTooltip.svelte +100 -26
- package/dist/phase-diagram/PhaseDiagramTooltip.svelte.d.ts +6 -3
- package/dist/phase-diagram/index.d.ts +2 -0
- package/dist/phase-diagram/index.js +2 -0
- package/dist/phase-diagram/svg-to-diagram.d.ts +2 -0
- package/dist/phase-diagram/svg-to-diagram.js +865 -0
- package/dist/phase-diagram/types.d.ts +10 -0
- package/dist/phase-diagram/utils.d.ts +7 -4
- package/dist/phase-diagram/utils.js +149 -59
- package/dist/plot/AxisLabel.svelte +26 -0
- package/dist/plot/AxisLabel.svelte.d.ts +16 -0
- package/dist/plot/BarPlot.svelte +473 -228
- package/dist/plot/BarPlot.svelte.d.ts +3 -3
- package/dist/plot/BarPlotControls.svelte +3 -2
- package/dist/plot/BarPlotControls.svelte.d.ts +1 -1
- package/dist/plot/ColorBar.svelte +54 -54
- package/dist/plot/ColorBar.svelte.d.ts +1 -1
- package/dist/plot/ElementScatter.svelte +4 -3
- package/dist/plot/FillArea.svelte +4 -1
- package/dist/plot/Histogram.svelte +320 -230
- package/dist/plot/Histogram.svelte.d.ts +2 -2
- package/dist/plot/HistogramControls.svelte +29 -10
- package/dist/plot/HistogramControls.svelte.d.ts +6 -2
- package/dist/plot/InteractiveAxisLabel.svelte.d.ts +2 -2
- package/dist/plot/PlotControls.svelte +109 -27
- package/dist/plot/PlotControls.svelte.d.ts +1 -1
- package/dist/plot/PlotLegend.svelte +1 -1
- package/dist/plot/PortalSelect.svelte +2 -1
- package/dist/plot/ReferenceLine.svelte +2 -1
- package/dist/plot/ReferenceLine.svelte.d.ts +1 -0
- package/dist/plot/ReferencePlane.svelte +1 -3
- package/dist/plot/ScatterPlot.svelte +343 -209
- package/dist/plot/ScatterPlot.svelte.d.ts +3 -3
- package/dist/plot/ScatterPlot3D.svelte.d.ts +2 -2
- package/dist/plot/ScatterPlot3DControls.svelte +203 -250
- package/dist/plot/ScatterPlot3DScene.svelte +4 -7
- package/dist/plot/ScatterPlot3DScene.svelte.d.ts +2 -2
- package/dist/plot/ScatterPlotControls.svelte +95 -55
- package/dist/plot/ScatterPlotControls.svelte.d.ts +1 -1
- package/dist/plot/ZeroLines.svelte +44 -0
- package/dist/plot/ZeroLines.svelte.d.ts +32 -0
- package/dist/plot/ZoomRect.svelte +21 -0
- package/dist/plot/ZoomRect.svelte.d.ts +8 -0
- package/dist/plot/axis-utils.d.ts +1 -1
- package/dist/plot/data-cleaning.js +1 -5
- 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 +10 -19
- package/dist/plot/layout.d.ts +7 -1
- package/dist/plot/layout.js +12 -4
- package/dist/plot/reference-line.d.ts +4 -21
- package/dist/plot/reference-line.js +7 -81
- package/dist/plot/types.d.ts +42 -17
- package/dist/plot/types.js +10 -0
- package/dist/plot/utils/label-placement.js +14 -11
- package/dist/plot/utils.d.ts +1 -0
- package/dist/plot/utils.js +14 -0
- package/dist/rdf/RdfPlot.svelte +55 -66
- package/dist/rdf/RdfPlot.svelte.d.ts +1 -1
- package/dist/rdf/index.d.ts +1 -1
- package/dist/rdf/index.js +1 -1
- package/dist/settings.d.ts +5 -0
- package/dist/settings.js +37 -3
- package/dist/spectral/Bands.svelte +515 -143
- package/dist/spectral/Bands.svelte.d.ts +22 -2
- package/dist/spectral/helpers.d.ts +23 -1
- package/dist/spectral/helpers.js +65 -9
- package/dist/spectral/types.d.ts +2 -0
- package/dist/structure/AtomLegend.svelte +31 -10
- package/dist/structure/AtomLegend.svelte.d.ts +1 -1
- package/dist/structure/CellSelect.svelte +92 -22
- package/dist/structure/Lattice.svelte +2 -0
- package/dist/structure/Structure.svelte +716 -173
- package/dist/structure/Structure.svelte.d.ts +7 -2
- package/dist/structure/StructureControls.svelte +26 -14
- package/dist/structure/StructureControls.svelte.d.ts +5 -1
- package/dist/structure/StructureInfoPane.svelte +7 -1
- package/dist/structure/StructureScene.svelte +386 -95
- package/dist/structure/StructureScene.svelte.d.ts +15 -4
- package/dist/structure/atom-properties.d.ts +6 -2
- package/dist/structure/atom-properties.js +38 -25
- package/dist/structure/export.js +10 -7
- 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 +1 -2
- package/dist/structure/index.d.ts +7 -0
- package/dist/structure/index.js +22 -0
- package/dist/structure/parse.js +19 -16
- package/dist/structure/partial-occupancy.d.ts +25 -0
- package/dist/structure/partial-occupancy.js +102 -0
- package/dist/structure/validation.js +6 -3
- package/dist/symmetry/SymmetryStats.svelte +18 -4
- package/dist/symmetry/WyckoffTable.svelte +18 -10
- package/dist/symmetry/index.d.ts +7 -4
- package/dist/symmetry/index.js +83 -18
- package/dist/table/HeatmapTable.svelte +468 -69
- package/dist/table/HeatmapTable.svelte.d.ts +13 -1
- package/dist/table/ToggleMenu.svelte +291 -44
- package/dist/table/ToggleMenu.svelte.d.ts +4 -1
- package/dist/table/index.d.ts +3 -0
- package/dist/tooltip/index.d.ts +1 -1
- package/dist/tooltip/index.js +1 -0
- package/dist/trajectory/Trajectory.svelte +147 -145
- package/dist/trajectory/TrajectoryExportPane.svelte +13 -9
- package/dist/trajectory/TrajectoryExportPane.svelte.d.ts +1 -1
- package/dist/trajectory/constants.d.ts +6 -0
- package/dist/trajectory/constants.js +7 -0
- package/dist/trajectory/extract.js +3 -5
- 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 +339 -0
- package/dist/trajectory/helpers.d.ts +15 -0
- package/dist/trajectory/helpers.js +187 -0
- package/dist/trajectory/index.d.ts +1 -0
- package/dist/trajectory/index.js +11 -4
- package/dist/trajectory/parse/ase.d.ts +2 -0
- package/dist/trajectory/parse/ase.js +76 -0
- package/dist/trajectory/parse/hdf5.d.ts +2 -0
- package/dist/trajectory/parse/hdf5.js +121 -0
- package/dist/trajectory/parse/index.d.ts +12 -0
- package/dist/trajectory/parse/index.js +304 -0
- package/dist/trajectory/parse/lammps.d.ts +5 -0
- package/dist/trajectory/parse/lammps.js +169 -0
- package/dist/trajectory/parse/vasp.d.ts +2 -0
- package/dist/trajectory/parse/vasp.js +65 -0
- package/dist/trajectory/parse/xyz.d.ts +2 -0
- package/dist/trajectory/parse/xyz.js +109 -0
- package/dist/trajectory/types.d.ts +11 -0
- package/dist/trajectory/types.js +1 -0
- package/dist/utils.d.ts +2 -0
- package/dist/utils.js +4 -0
- package/dist/xrd/XrdPlot.svelte +6 -4
- package/dist/xrd/calc-xrd.js +0 -1
- package/package.json +33 -23
- 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
|
@@ -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,6 @@ 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;
|
|
@@ -49,7 +49,7 @@ export const PHASE_DIAGRAM_DEFAULTS = Object.freeze({
|
|
|
49
49
|
special_point: `#d32f2f`,
|
|
50
50
|
}),
|
|
51
51
|
// Margins
|
|
52
|
-
margin: Object.freeze({ t: 25, r:
|
|
52
|
+
margin: Object.freeze({ t: 25, r: 25, b: 50, l: 60 }),
|
|
53
53
|
// Export
|
|
54
54
|
png_dpi: 150,
|
|
55
55
|
});
|
|
@@ -94,7 +94,7 @@ export const PHASE_COLOR_RGB = Object.freeze(Object.fromEntries(Object.entries(P
|
|
|
94
94
|
const PHASE_ALPHA = { two_phase: 0.5, default: 0.5, tie_line: 1 };
|
|
95
95
|
export const PHASE_COLORS = Object.freeze(Object.fromEntries(Object.entries(PHASE_COLOR_HEX).map(([key, hex]) => [
|
|
96
96
|
key,
|
|
97
|
-
add_alpha(hex, PHASE_ALPHA[key]
|
|
97
|
+
add_alpha(hex, key in PHASE_ALPHA ? PHASE_ALPHA[key] : 0.6),
|
|
98
98
|
])));
|
|
99
99
|
// Phase pattern matching rules: [substrings to match, color key, optional prefix check]
|
|
100
100
|
// Order matters: theta before eta (since "theta" contains "eta" as substring)
|
|
@@ -127,7 +127,7 @@ export function get_phase_color_key(name) {
|
|
|
127
127
|
}
|
|
128
128
|
// Get phase color - returns rgba() by default, or RGB string if format='rgb'
|
|
129
129
|
export function get_phase_color(name, format = `rgba`) {
|
|
130
|
-
const lower = name.toLowerCase();
|
|
130
|
+
const lower = name.toLowerCase().trim();
|
|
131
131
|
const key = lower.includes(`+`) ? `two_phase` : get_phase_color_key(name);
|
|
132
132
|
return format === `rgb` ? PHASE_COLOR_RGB[key] : PHASE_COLORS[key];
|
|
133
133
|
}
|
|
@@ -150,8 +150,9 @@ export function find_phase_at_point(composition, temperature, data) {
|
|
|
150
150
|
// Search regions in reverse order so later-defined regions take precedence
|
|
151
151
|
for (let idx = data.regions.length - 1; idx >= 0; idx--) {
|
|
152
152
|
const region = data.regions[idx];
|
|
153
|
-
if (point_in_polygon(composition, temperature, region.vertices))
|
|
153
|
+
if (point_in_polygon(composition, temperature, region.vertices)) {
|
|
154
154
|
return region;
|
|
155
|
+
}
|
|
155
156
|
}
|
|
156
157
|
return null;
|
|
157
158
|
}
|
|
@@ -199,7 +200,7 @@ export function compute_label_properties(label, bounds, font_size) {
|
|
|
199
200
|
}
|
|
200
201
|
// Scale down as last resort (min 70%)
|
|
201
202
|
const scale = Math.max(0.7, Math.min(avail_w / label_width, avail_h / line_height, 1));
|
|
202
|
-
const rotation = is_tall
|
|
203
|
+
const rotation = is_tall ? -90 : 0;
|
|
203
204
|
return { rotation, lines: [label], scale };
|
|
204
205
|
}
|
|
205
206
|
// Wrap text into multiple lines at delimiter boundaries
|
|
@@ -210,7 +211,7 @@ function wrap_text(text, max_chars) {
|
|
|
210
211
|
const lines = [];
|
|
211
212
|
let current_line = ``;
|
|
212
213
|
for (const word of words) {
|
|
213
|
-
const candidate = current_line ? `${current_line}
|
|
214
|
+
const candidate = current_line ? `${current_line} ${word}` : word;
|
|
214
215
|
if (candidate.length <= max_chars) {
|
|
215
216
|
current_line = candidate;
|
|
216
217
|
}
|
|
@@ -222,7 +223,7 @@ function wrap_text(text, max_chars) {
|
|
|
222
223
|
}
|
|
223
224
|
if (current_line)
|
|
224
225
|
lines.push(current_line);
|
|
225
|
-
return lines
|
|
226
|
+
return lines;
|
|
226
227
|
}
|
|
227
228
|
// Transform data coordinates to SVG coordinates using scale functions
|
|
228
229
|
export function transform_vertices(vertices, x_scale, y_scale) {
|
|
@@ -231,78 +232,156 @@ export function transform_vertices(vertices, x_scale, y_scale) {
|
|
|
231
232
|
// Format composition value for display
|
|
232
233
|
export function format_composition(value, unit = `at%`, include_unit = true) {
|
|
233
234
|
if (unit === `fraction`)
|
|
234
|
-
return format_num(value, `.
|
|
235
|
-
const formatted = format_num(value * 100, `.3
|
|
235
|
+
return format_num(value, `.3~f`);
|
|
236
|
+
const formatted = format_num(value * 100, `.3~`);
|
|
236
237
|
return include_unit ? `${formatted} ${unit}` : formatted;
|
|
237
238
|
}
|
|
238
239
|
// Format temperature value for display
|
|
239
240
|
export function format_temperature(value, unit = `K`) {
|
|
240
241
|
return `${format_num(value, `.0f`)} ${unit}`;
|
|
241
242
|
}
|
|
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)
|
|
243
|
+
// Parse a two-phase region name into its two phase names
|
|
244
|
+
// Returns null if the region is not exactly a two-phase region
|
|
245
|
+
function parse_two_phases(name) {
|
|
246
|
+
if (!name.includes(`+`))
|
|
251
247
|
return null;
|
|
252
|
-
|
|
248
|
+
const parts = name.trim().split(/\s*\+\s*/).filter(Boolean);
|
|
249
|
+
return parts.length === 2 ? [parts[0], parts[1]] : null;
|
|
250
|
+
}
|
|
251
|
+
// Find polygon edge intersections along a scan line (horizontal or vertical)
|
|
252
|
+
// For horizontal: fixed_val = temperature, returns x-intersections
|
|
253
|
+
// For vertical: fixed_val = composition, returns y-intersections
|
|
254
|
+
function find_polygon_intersections(vertices, fixed_val, axis) {
|
|
255
|
+
const other = axis === 0 ? 1 : 0;
|
|
253
256
|
const intersections = [];
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
const
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
intersections.push(
|
|
257
|
+
for (let idx = 0; idx < vertices.length; idx++) {
|
|
258
|
+
const v1 = vertices[idx];
|
|
259
|
+
const v2 = vertices[(idx + 1) % vertices.length];
|
|
260
|
+
if ((v1[axis] <= fixed_val && v2[axis] > fixed_val) ||
|
|
261
|
+
(v2[axis] <= fixed_val && v1[axis] > fixed_val)) {
|
|
262
|
+
intersections.push(v1[other] +
|
|
263
|
+
((fixed_val - v1[axis]) / (v2[axis] - v1[axis])) * (v2[other] - v1[other]));
|
|
260
264
|
}
|
|
261
265
|
}
|
|
266
|
+
return intersections.sort((a, b) => a - b);
|
|
267
|
+
}
|
|
268
|
+
function pick_bracketing_intersection_pair(intersections, position) {
|
|
262
269
|
if (intersections.length < 2)
|
|
263
270
|
return null;
|
|
264
|
-
|
|
265
|
-
const
|
|
266
|
-
const
|
|
267
|
-
|
|
271
|
+
const unique_intersections = [];
|
|
272
|
+
const dedup_tol = 1e-9;
|
|
273
|
+
for (const value of intersections) {
|
|
274
|
+
const prev_value = unique_intersections.at(-1);
|
|
275
|
+
if (prev_value === undefined || Math.abs(value - prev_value) > dedup_tol) {
|
|
276
|
+
unique_intersections.push(value);
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
if (unique_intersections.length < 2)
|
|
280
|
+
return null;
|
|
281
|
+
const bound_tol = 1e-10;
|
|
282
|
+
for (let pair_idx = 0; pair_idx + 1 < unique_intersections.length; pair_idx += 2) {
|
|
283
|
+
const low_bound = unique_intersections[pair_idx];
|
|
284
|
+
const high_bound = unique_intersections[pair_idx + 1];
|
|
285
|
+
if (position >= low_bound - bound_tol && position <= high_bound + bound_tol) {
|
|
286
|
+
return [low_bound, high_bound];
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
// Fallback for numerical edge cases where even-odd pairing fails:
|
|
290
|
+
// pick nearest enclosing neighbors around the hovered point.
|
|
291
|
+
let left_idx = -1;
|
|
292
|
+
for (let idx = 0; idx < unique_intersections.length; idx++) {
|
|
293
|
+
if (unique_intersections[idx] <= position + bound_tol)
|
|
294
|
+
left_idx = idx;
|
|
295
|
+
}
|
|
296
|
+
if (left_idx < 0 || left_idx + 1 >= unique_intersections.length)
|
|
268
297
|
return null;
|
|
269
|
-
const
|
|
270
|
-
|
|
298
|
+
const left_bound = unique_intersections[left_idx];
|
|
299
|
+
const right_bound = unique_intersections[left_idx + 1];
|
|
300
|
+
return right_bound - left_bound > bound_tol ? [left_bound, right_bound] : null;
|
|
301
|
+
}
|
|
302
|
+
// Shared core for lever rule calculations (horizontal and vertical)
|
|
303
|
+
// Parses phases, finds intersections along the scan axis, validates bounds,
|
|
304
|
+
// and computes the fractional position within the two-phase region.
|
|
305
|
+
function lever_rule_core(region, position, scan_val, axis) {
|
|
306
|
+
const phases = parse_two_phases(region.name);
|
|
307
|
+
if (!phases)
|
|
308
|
+
return null;
|
|
309
|
+
const intersections = find_polygon_intersections(region.vertices, scan_val, axis);
|
|
310
|
+
const bounds = pick_bracketing_intersection_pair(intersections, position);
|
|
311
|
+
if (!bounds)
|
|
312
|
+
return null;
|
|
313
|
+
const [lo, hi] = bounds;
|
|
314
|
+
const span = hi - lo;
|
|
315
|
+
if (span < 1e-10)
|
|
316
|
+
return null;
|
|
317
|
+
return { phases, lo, hi, fraction_hi: (position - lo) / span };
|
|
318
|
+
}
|
|
319
|
+
// Calculate lever rule for a point in a two-phase region
|
|
320
|
+
// Returns null if the region is not exactly a two-phase region or calculation fails
|
|
321
|
+
// Note: Lever rule is thermodynamically defined only for two-phase equilibria
|
|
322
|
+
export function calculate_lever_rule(region, composition, temperature) {
|
|
323
|
+
// Horizontal scan: fixed temperature, find composition intersections
|
|
324
|
+
const core = lever_rule_core(region, composition, temperature, 1);
|
|
325
|
+
if (!core)
|
|
271
326
|
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
327
|
return {
|
|
279
|
-
left_phase,
|
|
280
|
-
right_phase,
|
|
281
|
-
left_composition,
|
|
282
|
-
right_composition,
|
|
283
|
-
fraction_left,
|
|
284
|
-
fraction_right,
|
|
328
|
+
left_phase: core.phases[0],
|
|
329
|
+
right_phase: core.phases[1],
|
|
330
|
+
left_composition: core.lo,
|
|
331
|
+
right_composition: core.hi,
|
|
332
|
+
fraction_left: 1 - core.fraction_hi,
|
|
333
|
+
fraction_right: core.fraction_hi,
|
|
334
|
+
};
|
|
335
|
+
}
|
|
336
|
+
// Calculate vertical lever rule for a point in a two-phase region
|
|
337
|
+
// Uses constant composition (vertical line) to find temperature boundaries
|
|
338
|
+
export function calculate_vertical_lever_rule(region, composition, temperature) {
|
|
339
|
+
// Vertical scan: fixed composition, find temperature intersections
|
|
340
|
+
const core = lever_rule_core(region, temperature, composition, 0);
|
|
341
|
+
if (!core)
|
|
342
|
+
return null;
|
|
343
|
+
return {
|
|
344
|
+
bottom_phase: core.phases[0],
|
|
345
|
+
top_phase: core.phases[1],
|
|
346
|
+
bottom_temperature: core.lo,
|
|
347
|
+
top_temperature: core.hi,
|
|
348
|
+
fraction_bottom: 1 - core.fraction_hi,
|
|
349
|
+
fraction_top: core.fraction_hi,
|
|
285
350
|
};
|
|
286
351
|
}
|
|
287
352
|
// Format hover info as copyable text for clipboard
|
|
288
|
-
|
|
353
|
+
// Only includes lever rule data for the active mode to match tooltip display
|
|
354
|
+
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`) {
|
|
355
|
+
// Convert temperature from data unit to display unit
|
|
356
|
+
const to_display = (temp) => convert_temp(temp, data_temp_unit, temp_unit);
|
|
289
357
|
const lines = [
|
|
290
358
|
`Phase: ${info.region.name}`,
|
|
291
|
-
`Temperature: ${format_temperature(info.temperature, temp_unit)}`,
|
|
359
|
+
`Temperature: ${format_temperature(to_display(info.temperature), temp_unit)}`,
|
|
292
360
|
`Composition: ${format_composition(info.composition, comp_unit)} ${component_b} (${format_composition(1 - info.composition, comp_unit)} ${component_a})`,
|
|
293
361
|
];
|
|
294
|
-
if (info.lever_rule) {
|
|
362
|
+
if (lever_rule_mode === `horizontal` && info.lever_rule) {
|
|
295
363
|
const lr = info.lever_rule;
|
|
296
364
|
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
365
|
}
|
|
366
|
+
if (lever_rule_mode === `vertical` && info.vertical_lever_rule) {
|
|
367
|
+
const vlr = info.vertical_lever_rule;
|
|
368
|
+
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)})`);
|
|
369
|
+
}
|
|
298
370
|
return lines.join(`\n`);
|
|
299
371
|
}
|
|
300
372
|
// Calculate temperature stability range for a phase at given composition
|
|
301
373
|
export function get_phase_stability_range(region) {
|
|
302
374
|
if (!region.vertices?.length)
|
|
303
375
|
return null;
|
|
304
|
-
|
|
305
|
-
|
|
376
|
+
let t_min = Infinity;
|
|
377
|
+
let t_max = -Infinity;
|
|
378
|
+
for (const [, temp] of region.vertices) {
|
|
379
|
+
if (temp < t_min)
|
|
380
|
+
t_min = temp;
|
|
381
|
+
if (temp > t_max)
|
|
382
|
+
t_max = temp;
|
|
383
|
+
}
|
|
384
|
+
return { t_min, t_max };
|
|
306
385
|
}
|
|
307
386
|
// Extract reference/citation from TDB comments
|
|
308
387
|
export function extract_tdb_reference(comments) {
|
|
@@ -325,8 +404,8 @@ export function summarize_models(phases) {
|
|
|
325
404
|
counts.set(phase.sublattice_count, (counts.get(phase.sublattice_count) ?? 0) + 1);
|
|
326
405
|
}
|
|
327
406
|
return [...counts.entries()]
|
|
328
|
-
.sort(([
|
|
329
|
-
.map(([
|
|
407
|
+
.sort(([sl_a], [sl_b]) => sl_a - sl_b)
|
|
408
|
+
.map(([sublattices, count]) => `${count}×${sublattices}-SL`)
|
|
330
409
|
.join(`, `);
|
|
331
410
|
}
|
|
332
411
|
// Check if a component name is a compound (vs single element)
|
|
@@ -342,13 +421,7 @@ export function is_compound(name) {
|
|
|
342
421
|
// Single element pattern: one uppercase followed by optional lowercase (Fe, Ca, He, C)
|
|
343
422
|
if (/^[A-Z][a-z]?$/.test(name))
|
|
344
423
|
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;
|
|
424
|
+
return (name.match(/[A-Z]/g)?.length ?? 0) >= 2;
|
|
352
425
|
}
|
|
353
426
|
// Tokenize a chemical formula for rendering with subscripts/superscripts
|
|
354
427
|
// Examples:
|
|
@@ -447,15 +520,32 @@ export function format_formula_svg(formula, use_subscripts = true) {
|
|
|
447
520
|
offset += dy;
|
|
448
521
|
}
|
|
449
522
|
}
|
|
523
|
+
// Reset baseline after trailing subscript/superscript using a zero-width space
|
|
524
|
+
// (empty tspans may not apply dy in all SVG renderers)
|
|
450
525
|
if (offset)
|
|
451
|
-
result += `<tspan dy="${-offset}em"
|
|
526
|
+
result += `<tspan dy="${-offset}em">\u200B</tspan>`;
|
|
452
527
|
return result;
|
|
453
528
|
}
|
|
529
|
+
// Split a multi-phase label on " + " and format each part with the given formatter
|
|
530
|
+
function format_label_parts(label, use_subscripts, formatter) {
|
|
531
|
+
if (!use_subscripts)
|
|
532
|
+
return label;
|
|
533
|
+
return label.split(/(\s*\+\s*)/).map((part) => {
|
|
534
|
+
if (part.trim() === `+`)
|
|
535
|
+
return part;
|
|
536
|
+
return formatter(part.trim(), use_subscripts);
|
|
537
|
+
}).join(``);
|
|
538
|
+
}
|
|
539
|
+
// Format a phase region label (e.g. "La2NiO4 + NiO") as SVG with subscripts
|
|
540
|
+
export const format_label_svg = (label, use_subscripts = true) => format_label_parts(label, use_subscripts, format_formula_svg);
|
|
541
|
+
// Format a phase region label as HTML with subscripts (splits on " + ")
|
|
542
|
+
export const format_label_html = (label, use_subscripts = true) => format_label_parts(label, use_subscripts, format_formula_html);
|
|
454
543
|
// Format chemical formula as HTML with <sub> and <sup> tags
|
|
455
544
|
export function format_formula_html(formula, use_subscripts = true) {
|
|
456
545
|
if (!use_subscripts || !is_compound(formula))
|
|
457
546
|
return formula;
|
|
458
547
|
return tokenize_formula(formula)
|
|
459
|
-
.map((token) => token.text ??
|
|
548
|
+
.map((token) => token.text ??
|
|
549
|
+
(token.sub ? `<sub>${token.sub}</sub>` : `<sup>${token.sup}</sup>`))
|
|
460
550
|
.join(``);
|
|
461
551
|
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
<script lang="ts">import { AXIS_LABEL_CONTAINER } from './axis-utils';
|
|
2
|
+
import InteractiveAxisLabel from './InteractiveAxisLabel.svelte';
|
|
3
|
+
let { x, y, rotate = false, label = ``, options, selected_key, color, loading = false, axis_type, on_select, } = $props();
|
|
4
|
+
</script>
|
|
5
|
+
|
|
6
|
+
<foreignObject
|
|
7
|
+
x={x - AXIS_LABEL_CONTAINER.x_offset}
|
|
8
|
+
y={y - AXIS_LABEL_CONTAINER.y_offset}
|
|
9
|
+
width={AXIS_LABEL_CONTAINER.width}
|
|
10
|
+
height={AXIS_LABEL_CONTAINER.height}
|
|
11
|
+
style="overflow: visible; pointer-events: none"
|
|
12
|
+
transform={rotate ? `rotate(-90, ${x}, ${y})` : undefined}
|
|
13
|
+
>
|
|
14
|
+
<div xmlns="http://www.w3.org/1999/xhtml" style="pointer-events: auto">
|
|
15
|
+
<InteractiveAxisLabel
|
|
16
|
+
{label}
|
|
17
|
+
{options}
|
|
18
|
+
{selected_key}
|
|
19
|
+
{loading}
|
|
20
|
+
{axis_type}
|
|
21
|
+
{color}
|
|
22
|
+
{on_select}
|
|
23
|
+
class="axis-label {axis_type}-label"
|
|
24
|
+
/>
|
|
25
|
+
</div>
|
|
26
|
+
</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;
|