matterviz 0.3.2 → 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 +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/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
|
@@ -125,10 +125,10 @@ function extract_mpds_scales(doc) {
|
|
|
125
125
|
// This is intentional — only endpoints are used for scale mapping.
|
|
126
126
|
const comp_vals = [
|
|
127
127
|
...new Set(numbers.filter((v) => v >= 0 && v <= 100 && v % 10 === 0)),
|
|
128
|
-
].
|
|
128
|
+
].toSorted((a, b) => a - b);
|
|
129
129
|
const temp_vals = [
|
|
130
130
|
...new Set(numbers.filter((v) => v >= 100 && v % 100 === 0 && v <= 3000)),
|
|
131
|
-
].
|
|
131
|
+
].toSorted((a, b) => a - b);
|
|
132
132
|
if (comp_vals.length < 2 || temp_vals.length < 2) {
|
|
133
133
|
throw new Error(`MPDS SVG: could not infer axis ranges (found ${comp_vals.length} composition, ${temp_vals.length} temperature values)`);
|
|
134
134
|
}
|
|
@@ -137,13 +137,13 @@ function extract_mpds_scales(doc) {
|
|
|
137
137
|
const x_major_ticks = [];
|
|
138
138
|
const y_major_ticks = [];
|
|
139
139
|
for (const path of Array.from(doc.querySelectorAll(`path`))) {
|
|
140
|
-
const
|
|
140
|
+
const path_data = path.getAttribute(`d`) ?? ``;
|
|
141
141
|
const stroke_width = parse_stroke_width(path);
|
|
142
142
|
// Tick mark paths have stroke-width ~0.5
|
|
143
143
|
if (stroke_width < 0.3 || stroke_width > 1.0)
|
|
144
144
|
continue;
|
|
145
145
|
// Parse path into absolute line segments (handles both absolute & relative commands)
|
|
146
|
-
const segments = parse_path_segments(
|
|
146
|
+
const segments = parse_path_segments(path_data);
|
|
147
147
|
if (segments.length < 3)
|
|
148
148
|
continue;
|
|
149
149
|
for (const [sx1, sy1, sx2, sy2] of segments) {
|
|
@@ -163,10 +163,12 @@ function extract_mpds_scales(doc) {
|
|
|
163
163
|
}
|
|
164
164
|
}
|
|
165
165
|
// Deduplicate and sort
|
|
166
|
-
const x_ticks_sorted = [
|
|
167
|
-
.
|
|
168
|
-
|
|
169
|
-
|
|
166
|
+
const x_ticks_sorted = [
|
|
167
|
+
...new Set(x_major_ticks.map((v) => Math.round(v * 10) / 10)),
|
|
168
|
+
].toSorted((a, b) => a - b);
|
|
169
|
+
const y_ticks_sorted = [
|
|
170
|
+
...new Set(y_major_ticks.map((v) => Math.round(v * 10) / 10)),
|
|
171
|
+
].toSorted((a, b) => a - b);
|
|
170
172
|
if (x_ticks_sorted.length < 2 || y_ticks_sorted.length < 2) {
|
|
171
173
|
throw new Error(`MPDS SVG: could not find tick marks (found ${x_ticks_sorted.length} x-ticks, ${y_ticks_sorted.length} y-ticks)`);
|
|
172
174
|
}
|
|
@@ -265,29 +267,34 @@ function extract_mpds_boundaries(doc, boundaries, x_scale, y_scale, epsilon) {
|
|
|
265
267
|
return;
|
|
266
268
|
const { left, right, top, bottom } = plot_rect;
|
|
267
269
|
for (const path of Array.from(doc.querySelectorAll(`path`))) {
|
|
268
|
-
const
|
|
270
|
+
const path_data = path.getAttribute(`d`) ?? ``;
|
|
269
271
|
const style = path.getAttribute(`style`) ?? ``;
|
|
270
272
|
// Skip tick mark paths (stroke-width > 0.3)
|
|
271
273
|
const stroke_width = parse_stroke_width(path);
|
|
272
274
|
if (stroke_width > 0.3 || stroke_width === 0)
|
|
273
275
|
continue;
|
|
274
276
|
// Skip filled regions (phase region fills)
|
|
275
|
-
if (style.includes(`fill-rule`) || style.includes(`fill: #`) || style.includes(`fill:#`))
|
|
276
|
-
|
|
277
|
-
|
|
277
|
+
if ((style.includes(`fill-rule`) || style.includes(`fill: #`) || style.includes(`fill:#`)) &&
|
|
278
|
+
!style.includes(`fill: none`) &&
|
|
279
|
+
!style.includes(`fill:none`)) {
|
|
280
|
+
continue;
|
|
278
281
|
}
|
|
279
282
|
// Skip red annotation lines
|
|
280
283
|
if (style.includes(`#e30016`) || style.includes(`#E30016`))
|
|
281
284
|
continue;
|
|
282
285
|
// Parse as simple M...L line
|
|
283
|
-
const coords = parse_ml_path(
|
|
286
|
+
const coords = parse_ml_path(path_data);
|
|
284
287
|
if (!coords)
|
|
285
288
|
continue;
|
|
286
289
|
// Must be inside the plot area
|
|
287
|
-
const inside = coords.x1 >= left - 1 &&
|
|
288
|
-
coords.
|
|
289
|
-
coords.
|
|
290
|
-
coords.
|
|
290
|
+
const inside = coords.x1 >= left - 1 &&
|
|
291
|
+
coords.x1 <= right + 1 &&
|
|
292
|
+
coords.x2 >= left - 1 &&
|
|
293
|
+
coords.x2 <= right + 1 &&
|
|
294
|
+
coords.y1 >= top - 1 &&
|
|
295
|
+
coords.y1 <= bottom + 1 &&
|
|
296
|
+
coords.y2 >= top - 1 &&
|
|
297
|
+
coords.y2 <= bottom + 1;
|
|
291
298
|
if (!inside)
|
|
292
299
|
continue;
|
|
293
300
|
// Skip very short segments (< 10px)
|
|
@@ -297,8 +304,7 @@ function extract_mpds_boundaries(doc, boundaries, x_scale, y_scale, epsilon) {
|
|
|
297
304
|
continue;
|
|
298
305
|
// Skip the plot border itself (connects all 4 edges)
|
|
299
306
|
const touches_left = Math.abs(coords.x1 - left) < 2 || Math.abs(coords.x2 - left) < 2;
|
|
300
|
-
const touches_right = Math.abs(coords.x1 - right) < 2 ||
|
|
301
|
-
Math.abs(coords.x2 - right) < 2;
|
|
307
|
+
const touches_right = Math.abs(coords.x1 - right) < 2 || Math.abs(coords.x2 - right) < 2;
|
|
302
308
|
if (touches_left && touches_right)
|
|
303
309
|
continue; // spans full width = likely axis
|
|
304
310
|
add_boundary(boundaries, coords, x_scale, y_scale, epsilon);
|
|
@@ -308,14 +314,14 @@ function extract_mpds_boundaries(doc, boundaries, x_scale, y_scale, epsilon) {
|
|
|
308
314
|
// Handles both M...L...L...L...Z and M...V...H...V...Z formats
|
|
309
315
|
function find_mpds_plot_rect(doc) {
|
|
310
316
|
for (const path of Array.from(doc.querySelectorAll(`path`))) {
|
|
311
|
-
const
|
|
317
|
+
const path_data = path.getAttribute(`d`) ?? ``;
|
|
312
318
|
const style = path.getAttribute(`style`) ?? ``;
|
|
313
319
|
if (!style.includes(`fill: none`) && !style.includes(`fill:none`))
|
|
314
320
|
continue;
|
|
315
|
-
if (!
|
|
321
|
+
if (!path_data.includes(`Z`) && !path_data.includes(`z`))
|
|
316
322
|
continue;
|
|
317
323
|
// Parse path into absolute segments and extract corner points
|
|
318
|
-
const segments = parse_path_segments(
|
|
324
|
+
const segments = parse_path_segments(path_data);
|
|
319
325
|
if (segments.length < 3)
|
|
320
326
|
continue; // rectangle needs at least 3 segments (4th is Z)
|
|
321
327
|
// Collect all x and y coordinates from segment endpoints
|
|
@@ -403,8 +409,7 @@ function extract_matplotlib_labels(doc, labels) {
|
|
|
403
409
|
// Clean LaTeX: "La$_2$NiO$_4$ + NiO" -> "La2NiO4 + NiO"
|
|
404
410
|
const text = clean_latex(comment.trim());
|
|
405
411
|
// Get position from transform="translate(x, y)"
|
|
406
|
-
const pos = parse_translate(group.querySelector(`g[transform]`)) ??
|
|
407
|
-
parse_translate(group);
|
|
412
|
+
const pos = parse_translate(group.querySelector(`g[transform]`)) ?? parse_translate(group);
|
|
408
413
|
if (!pos)
|
|
409
414
|
continue;
|
|
410
415
|
labels.push({ text, px_x: pos[0], px_y: pos[1] });
|
|
@@ -414,7 +419,7 @@ function extract_matplotlib_labels(doc, labels) {
|
|
|
414
419
|
function extract_simple_labels(doc, labels) {
|
|
415
420
|
for (const text_el of Array.from(doc.querySelectorAll(`.label-main`))) {
|
|
416
421
|
// Get plain text content (strips tspan tags)
|
|
417
|
-
const text = (text_el.textContent ?? ``).
|
|
422
|
+
const text = (text_el.textContent ?? ``).replaceAll(/\s+/g, ` `).trim();
|
|
418
423
|
if (!text.includes(`+`))
|
|
419
424
|
continue; // skip non-phase labels
|
|
420
425
|
// Get position from transform or x/y attributes
|
|
@@ -430,7 +435,7 @@ function extract_simple_labels(doc, labels) {
|
|
|
430
435
|
// Infer binary components from region labels
|
|
431
436
|
function infer_components(labels) {
|
|
432
437
|
// Sort labels by x position, split each into phases
|
|
433
|
-
const sorted =
|
|
438
|
+
const sorted = labels.toSorted((a, b) => a.px_x - b.px_x);
|
|
434
439
|
if (sorted.length < 2)
|
|
435
440
|
return [`A`, `B`];
|
|
436
441
|
const split = (label) => label.text.split(/\s*\+\s*/);
|
|
@@ -440,14 +445,14 @@ function infer_components(labels) {
|
|
|
440
445
|
// For "La2NiO4 + La2O3", La2O3 is the pure A endpoint
|
|
441
446
|
let comp_a = `A`;
|
|
442
447
|
if (leftmost.length === 2) {
|
|
443
|
-
const right_phases = sorted.slice(-3).flatMap(split);
|
|
444
|
-
comp_a = leftmost.find((p) => !right_phases.
|
|
448
|
+
const right_phases = new Set(sorted.slice(-3).flatMap(split));
|
|
449
|
+
comp_a = leftmost.find((p) => !right_phases.has(p)) ?? leftmost[1] ?? `A`;
|
|
445
450
|
}
|
|
446
451
|
// Component B: the unique phase in the rightmost region that doesn't appear on the left
|
|
447
452
|
let comp_b = `B`;
|
|
448
453
|
if (rightmost.length === 2) {
|
|
449
|
-
const left_phases = sorted.slice(0, 3).flatMap(split);
|
|
450
|
-
comp_b = rightmost.find((p) => !left_phases.
|
|
454
|
+
const left_phases = new Set(sorted.slice(0, 3).flatMap(split));
|
|
455
|
+
comp_b = rightmost.find((p) => !left_phases.has(p)) ?? rightmost[1] ?? `B`;
|
|
451
456
|
}
|
|
452
457
|
return [comp_a, comp_b];
|
|
453
458
|
}
|
|
@@ -540,12 +545,13 @@ function infer_regions(boundaries, labels, x_scale, y_scale) {
|
|
|
540
545
|
for (let region_id = 0; region_id < next_region_id; region_id++) {
|
|
541
546
|
const name = region_labels.get(region_id) ?? `Region ${region_id + 1}`;
|
|
542
547
|
// Slug can be empty for non-ASCII labels like "α + β" — fall back to region_N
|
|
543
|
-
const slug = name
|
|
548
|
+
const slug = name
|
|
549
|
+
.toLowerCase()
|
|
550
|
+
.replaceAll(/[^a-z0-9]+/g, `_`)
|
|
551
|
+
.replaceAll(/^_|_$/g, ``) || `region_${region_id + 1}`;
|
|
544
552
|
// Find bounding box of all cells in this region
|
|
545
|
-
let min_x = Infinity;
|
|
546
|
-
let
|
|
547
|
-
let min_y = Infinity;
|
|
548
|
-
let max_y = -Infinity;
|
|
553
|
+
let [min_x, max_x] = [Infinity, -Infinity];
|
|
554
|
+
let [min_y, max_y] = [Infinity, -Infinity];
|
|
549
555
|
for (let col = 0; col < n_cols; col++) {
|
|
550
556
|
for (let row = 0; row < n_rows; row++) {
|
|
551
557
|
if (cell_ids[col][row] !== region_id)
|
|
@@ -627,9 +633,7 @@ export function parse_phase_diagram_svg(svg_string) {
|
|
|
627
633
|
const { x_scale, y_scale } = extract_axis_scales(doc, format);
|
|
628
634
|
const boundaries = extract_boundaries(doc, format, x_scale, y_scale);
|
|
629
635
|
const labels = extract_labels(doc, format);
|
|
630
|
-
const components = format === `mpds`
|
|
631
|
-
? infer_mpds_components(doc)
|
|
632
|
-
: infer_components(labels);
|
|
636
|
+
const components = format === `mpds` ? infer_mpds_components(doc) : infer_components(labels);
|
|
633
637
|
if (boundaries.length === 0) {
|
|
634
638
|
throw new Error(`No phase boundaries found in SVG`);
|
|
635
639
|
}
|
|
@@ -666,7 +670,7 @@ function infer_mpds_components(doc) {
|
|
|
666
670
|
// === Utility Functions ===
|
|
667
671
|
// Parse stroke-width from style attribute or direct attribute (returns 0 if not found)
|
|
668
672
|
function parse_stroke_width(el) {
|
|
669
|
-
const style_match =
|
|
673
|
+
const style_match = /stroke-width:\s*([\d.]+)/.exec(el.getAttribute(`style`) ?? ``);
|
|
670
674
|
if (style_match)
|
|
671
675
|
return parseFloat(style_match[1]);
|
|
672
676
|
const attr = el.getAttribute(`stroke-width`);
|
|
@@ -718,24 +722,24 @@ function find_comment_text(group) {
|
|
|
718
722
|
// Clean LaTeX subscript notation: "La$_2$NiO$_4$" -> "La2NiO4"
|
|
719
723
|
function clean_latex(text) {
|
|
720
724
|
return text
|
|
721
|
-
.
|
|
722
|
-
.
|
|
723
|
-
.
|
|
724
|
-
.
|
|
725
|
+
.replaceAll(/\$_\{([^}]*)\}\$/g, `$1`) // $_{10}$ -> 10
|
|
726
|
+
.replaceAll(/\$_(\d)\$/g, `$1`) // $_2$ -> 2
|
|
727
|
+
.replaceAll(`$`, ``) // remove any remaining $
|
|
728
|
+
.replaceAll(/\s+/g, ` `)
|
|
725
729
|
.trim();
|
|
726
730
|
}
|
|
727
731
|
// Parse SVG path data into absolute line segments [x1,y1,x2,y2]
|
|
728
732
|
// Handles all SVG path commands (M/L/H/V/C/S/Q/T/A/Z, both absolute and relative)
|
|
729
733
|
// Curves (C/S/Q/T/A) are approximated as straight lines from start to endpoint
|
|
730
734
|
// After M/m, implicit coordinates are treated as L/l per SVG spec
|
|
731
|
-
function parse_path_segments(
|
|
735
|
+
function parse_path_segments(path_str) {
|
|
732
736
|
const segments = [];
|
|
733
737
|
let [cursor_x, cursor_y] = [0, 0];
|
|
734
738
|
let [start_x, start_y] = [0, 0];
|
|
735
739
|
let last_cmd = ``;
|
|
736
740
|
// Numbers to skip before the endpoint x,y for each curve command
|
|
737
741
|
const curve_skip = { C: 4, S: 2, Q: 2, T: 0, A: 5 };
|
|
738
|
-
const tokens =
|
|
742
|
+
const tokens = path_str.match(/[MmLlHhVvCcSsQqTtAaZz]|[-+]?[\d]*\.?[\d]+(?:[eE][-+]?\d+)?/g);
|
|
739
743
|
if (!tokens)
|
|
740
744
|
return segments;
|
|
741
745
|
let idx = 0;
|
|
@@ -813,8 +817,8 @@ function parse_path_segments(d) {
|
|
|
813
817
|
}
|
|
814
818
|
// Parse a simple 2-point line path (M...L only). Returns null for multi-segment paths
|
|
815
819
|
// to enforce the single-line contract expected by boundary extraction.
|
|
816
|
-
function parse_ml_path(
|
|
817
|
-
const segments = parse_path_segments(
|
|
820
|
+
function parse_ml_path(path_str) {
|
|
821
|
+
const segments = parse_path_segments(path_str);
|
|
818
822
|
if (segments.length !== 1)
|
|
819
823
|
return null;
|
|
820
824
|
const [x1, y1, x2, y2] = segments[0];
|
|
@@ -823,7 +827,7 @@ function parse_ml_path(d) {
|
|
|
823
827
|
// Parse translate(x, y) or translate(x) from a transform attribute
|
|
824
828
|
// Single-arg translate uses implicit y=0 per SVG spec
|
|
825
829
|
function parse_translate(el) {
|
|
826
|
-
const match =
|
|
830
|
+
const match = /translate\(\s*([\d.eE+-]+)(?:\s*[,\s]\s*([\d.eE+-]+))?\s*\)/.exec(el?.getAttribute(`transform`) ?? ``);
|
|
827
831
|
if (!match)
|
|
828
832
|
return null;
|
|
829
833
|
return [parseFloat(match[1]), match[2] ? parseFloat(match[2]) : 0];
|
|
@@ -837,7 +841,7 @@ function get_group_translate(el, axis) {
|
|
|
837
841
|
function collect_unique_sorted(values) {
|
|
838
842
|
if (values.length === 0)
|
|
839
843
|
return [];
|
|
840
|
-
const sorted =
|
|
844
|
+
const sorted = values.toSorted((a, b) => a - b);
|
|
841
845
|
const unique = [sorted[0]];
|
|
842
846
|
for (let idx = 1; idx < sorted.length; idx++) {
|
|
843
847
|
if (Math.abs(sorted[idx] - unique[unique.length - 1]) > 1e-4) {
|
|
@@ -115,3 +115,4 @@ export declare function format_formula_svg(formula: string, use_subscripts?: boo
|
|
|
115
115
|
export declare const format_label_svg: (label: string, use_subscripts?: boolean) => string;
|
|
116
116
|
export declare const format_label_html: (label: string, use_subscripts?: boolean) => string;
|
|
117
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({
|
|
@@ -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
|
};
|
|
@@ -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)
|
|
@@ -157,11 +151,13 @@ export function find_phase_at_point(composition, temperature, data) {
|
|
|
157
151
|
return null;
|
|
158
152
|
}
|
|
159
153
|
// SVG path generator using d3-shape
|
|
160
|
-
const path_line = line()
|
|
154
|
+
const path_line = line()
|
|
155
|
+
.x((d) => d[0])
|
|
156
|
+
.y((d) => d[1]);
|
|
161
157
|
// Generate closed SVG path for polygon regions (min 3 points)
|
|
162
158
|
export const generate_region_path = (vertices) => vertices.length < 3 ? `` : `${path_line(vertices)} Z`;
|
|
163
159
|
// Generate open SVG path for boundary curves (min 2 points)
|
|
164
|
-
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) ?? ``);
|
|
165
161
|
// Compute label properties (rotation, wrapping, scale) to fit within region bounds
|
|
166
162
|
export function compute_label_properties(label, bounds, font_size) {
|
|
167
163
|
if (bounds.width <= 0 || bounds.height <= 0 || !label || font_size <= 0) {
|
|
@@ -245,7 +241,10 @@ export function format_temperature(value, unit = `K`) {
|
|
|
245
241
|
function parse_two_phases(name) {
|
|
246
242
|
if (!name.includes(`+`))
|
|
247
243
|
return null;
|
|
248
|
-
const parts = name
|
|
244
|
+
const parts = name
|
|
245
|
+
.trim()
|
|
246
|
+
.split(/\s*\+\s*/)
|
|
247
|
+
.filter(Boolean);
|
|
249
248
|
return parts.length === 2 ? [parts[0], parts[1]] : null;
|
|
250
249
|
}
|
|
251
250
|
// Find polygon edge intersections along a scan line (horizontal or vertical)
|
|
@@ -259,11 +258,10 @@ function find_polygon_intersections(vertices, fixed_val, axis) {
|
|
|
259
258
|
const v2 = vertices[(idx + 1) % vertices.length];
|
|
260
259
|
if ((v1[axis] <= fixed_val && v2[axis] > fixed_val) ||
|
|
261
260
|
(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]));
|
|
261
|
+
intersections.push(v1[other] + ((fixed_val - v1[axis]) / (v2[axis] - v1[axis])) * (v2[other] - v1[other]));
|
|
264
262
|
}
|
|
265
263
|
}
|
|
266
|
-
return intersections.
|
|
264
|
+
return intersections.toSorted((a, b) => a - b);
|
|
267
265
|
}
|
|
268
266
|
function pick_bracketing_intersection_pair(intersections, position) {
|
|
269
267
|
if (intersections.length < 2)
|
|
@@ -404,7 +402,7 @@ export function summarize_models(phases) {
|
|
|
404
402
|
counts.set(phase.sublattice_count, (counts.get(phase.sublattice_count) ?? 0) + 1);
|
|
405
403
|
}
|
|
406
404
|
return [...counts.entries()]
|
|
407
|
-
.
|
|
405
|
+
.toSorted(([sl_a], [sl_b]) => sl_a - sl_b)
|
|
408
406
|
.map(([sublattices, count]) => `${count}×${sublattices}-SL`)
|
|
409
407
|
.join(`, `);
|
|
410
408
|
}
|
|
@@ -486,7 +484,7 @@ export function tokenize_formula(formula) {
|
|
|
486
484
|
// Any other character (lowercase, hyphen, etc.) - collect as text
|
|
487
485
|
let text = char;
|
|
488
486
|
idx++;
|
|
489
|
-
while (idx < formula.length && !/[A-Z\d
|
|
487
|
+
while (idx < formula.length && !/[A-Z\d-]/.test(formula[idx])) {
|
|
490
488
|
text += formula[idx];
|
|
491
489
|
idx++;
|
|
492
490
|
}
|
|
@@ -530,11 +528,14 @@ export function format_formula_svg(formula, use_subscripts = true) {
|
|
|
530
528
|
function format_label_parts(label, use_subscripts, formatter) {
|
|
531
529
|
if (!use_subscripts)
|
|
532
530
|
return label;
|
|
533
|
-
return label
|
|
531
|
+
return label
|
|
532
|
+
.split(/(\s*\+\s*)/)
|
|
533
|
+
.map((part) => {
|
|
534
534
|
if (part.trim() === `+`)
|
|
535
535
|
return part;
|
|
536
536
|
return formatter(part.trim(), use_subscripts);
|
|
537
|
-
})
|
|
537
|
+
})
|
|
538
|
+
.join(``);
|
|
538
539
|
}
|
|
539
540
|
// Format a phase region label (e.g. "La2NiO4 + NiO") as SVG with subscripts
|
|
540
541
|
export const format_label_svg = (label, use_subscripts = true) => format_label_parts(label, use_subscripts, format_formula_svg);
|
|
@@ -545,7 +546,61 @@ export function format_formula_html(formula, use_subscripts = true) {
|
|
|
545
546
|
if (!use_subscripts || !is_compound(formula))
|
|
546
547
|
return formula;
|
|
547
548
|
return tokenize_formula(formula)
|
|
548
|
-
.map((token) => token.text ??
|
|
549
|
-
(token.sub ? `<sub>${token.sub}</sub>` : `<sup>${token.sup}</sup>`))
|
|
549
|
+
.map((token) => token.text ?? (token.sub ? `<sub>${token.sub}</sub>` : `<sup>${token.sup}</sup>`))
|
|
550
550
|
.join(``);
|
|
551
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
|
+
}
|
|
@@ -1,6 +1,31 @@
|
|
|
1
|
-
<script lang="ts">
|
|
2
|
-
import
|
|
3
|
-
|
|
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()
|
|
4
29
|
</script>
|
|
5
30
|
|
|
6
31
|
<foreignObject
|