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
|
@@ -1,137 +1,188 @@
|
|
|
1
|
-
<script lang="ts">
|
|
2
|
-
import
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import type { Surface3DConfig } from './types'
|
|
3
|
+
import { T } from '@threlte/core'
|
|
4
|
+
import * as THREE from 'three'
|
|
5
|
+
|
|
6
|
+
let {
|
|
7
|
+
config,
|
|
8
|
+
x_range = [0, 1],
|
|
9
|
+
y_range = [0, 1],
|
|
10
|
+
z_range = [0, 1],
|
|
11
|
+
scene_x = 10,
|
|
12
|
+
scene_y = 10,
|
|
13
|
+
scene_z = 5,
|
|
14
|
+
}: {
|
|
15
|
+
config: Surface3DConfig
|
|
16
|
+
x_range?: [number, number]
|
|
17
|
+
y_range?: [number, number]
|
|
18
|
+
z_range?: [number, number]
|
|
19
|
+
scene_x?: number
|
|
20
|
+
scene_y?: number
|
|
21
|
+
scene_z?: number
|
|
22
|
+
} = $props()
|
|
23
|
+
|
|
24
|
+
// Normalize value to scene coordinates (centered around 0)
|
|
25
|
+
function normalize(
|
|
26
|
+
value: number,
|
|
27
|
+
[min_val, max_val]: [number, number],
|
|
28
|
+
scene_size: number,
|
|
29
|
+
): number {
|
|
30
|
+
return ((value - min_val) / (max_val - min_val || 1) - 0.5) * scene_size
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
// Parse color to THREE.Color with fallback
|
|
34
|
+
function parse_color(color: string): THREE.Color {
|
|
10
35
|
try {
|
|
11
|
-
|
|
36
|
+
return new THREE.Color(color)
|
|
37
|
+
} catch {
|
|
38
|
+
return new THREE.Color(0x4488ff)
|
|
12
39
|
}
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
if (config.
|
|
22
|
-
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
// Calculate vertex color based on config
|
|
43
|
+
function get_vertex_color(
|
|
44
|
+
x_val: number,
|
|
45
|
+
y_val: number,
|
|
46
|
+
z_val: number,
|
|
47
|
+
): THREE.Color {
|
|
48
|
+
if (config.color_fn) return parse_color(config.color_fn(x_val, y_val, z_val))
|
|
49
|
+
if (config.color) return parse_color(config.color)
|
|
23
50
|
// Default: color by z value (blue to red gradient)
|
|
24
|
-
const z_norm = (z_val - z_range[0]) / (z_range[1] - z_range[0] || 1)
|
|
25
|
-
return new THREE.Color().setHSL(0.66 - z_norm * 0.66, 0.8, 0.5)
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
51
|
+
const z_norm = (z_val - z_range[0]) / (z_range[1] - z_range[0] || 1)
|
|
52
|
+
return new THREE.Color().setHSL(0.66 - z_norm * 0.66, 0.8, 0.5)
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
// Add vertex position (with Y/Z swap for Three.js) and color to arrays
|
|
56
|
+
function add_vertex(
|
|
57
|
+
positions: number[],
|
|
58
|
+
colors: number[],
|
|
59
|
+
x_val: number,
|
|
60
|
+
y_val: number,
|
|
61
|
+
z_val: number,
|
|
62
|
+
): void {
|
|
63
|
+
positions.push(
|
|
64
|
+
normalize(x_val, x_range, scene_x),
|
|
65
|
+
normalize(z_val, z_range, scene_z), // user Z → Three.js Y (vertical)
|
|
66
|
+
normalize(y_val, y_range, scene_y), // user Y → Three.js Z (depth)
|
|
67
|
+
)
|
|
68
|
+
const color = get_vertex_color(x_val, y_val, z_val)
|
|
69
|
+
colors.push(color.r, color.g, color.b)
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
// Build geometry from positions/colors arrays with optional grid indices
|
|
73
|
+
function build_geometry(
|
|
74
|
+
positions: number[],
|
|
75
|
+
colors: number[],
|
|
76
|
+
res_a?: number,
|
|
77
|
+
res_b?: number,
|
|
78
|
+
triangles?: number[][],
|
|
79
|
+
): THREE.BufferGeometry {
|
|
80
|
+
const geom = new THREE.BufferGeometry()
|
|
81
|
+
geom.setAttribute(`position`, new THREE.Float32BufferAttribute(positions, 3))
|
|
82
|
+
geom.setAttribute(`color`, new THREE.Float32BufferAttribute(colors, 3))
|
|
39
83
|
// Set indices: either from explicit triangles or generate grid
|
|
40
84
|
if (triangles?.length) {
|
|
41
|
-
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
for (let
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
indices.push(tl, tl + res_a, tl + 1, tl + 1, tl + res_a, tl + res_a + 1);
|
|
49
|
-
}
|
|
85
|
+
geom.setIndex(triangles.flat())
|
|
86
|
+
} else if (res_a && res_b && res_a >= 2 && res_b >= 2) {
|
|
87
|
+
const indices: number[] = []
|
|
88
|
+
for (let ib = 0; ib < res_b - 1; ib++) {
|
|
89
|
+
for (let ia = 0; ia < res_a - 1; ia++) {
|
|
90
|
+
const tl = ib * res_a + ia
|
|
91
|
+
indices.push(tl, tl + res_a, tl + 1, tl + 1, tl + res_a, tl + res_a + 1)
|
|
50
92
|
}
|
|
51
|
-
|
|
93
|
+
}
|
|
94
|
+
geom.setIndex(indices)
|
|
52
95
|
}
|
|
53
|
-
geom.computeVertexNormals()
|
|
54
|
-
return geom
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
|
|
96
|
+
geom.computeVertexNormals()
|
|
97
|
+
return geom
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
// Parse resolution config into [res_a, res_b]
|
|
101
|
+
function get_resolution(): [number, number] {
|
|
58
102
|
return Array.isArray(config.resolution)
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
const
|
|
65
|
-
const
|
|
103
|
+
? config.resolution
|
|
104
|
+
: [config.resolution ?? 20, config.resolution ?? 20]
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
function create_geometry(): THREE.BufferGeometry | null {
|
|
108
|
+
const [res_a, res_b] = get_resolution()
|
|
109
|
+
const positions: number[] = []
|
|
110
|
+
const colors: number[] = []
|
|
111
|
+
|
|
66
112
|
if (config.type === `grid` && config.z_fn) {
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
for (let
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
add_vertex(positions, colors, x_val, y_val, config.z_fn(x_val, y_val));
|
|
78
|
-
}
|
|
113
|
+
if (res_a < 2 || res_b < 2) return new THREE.BufferGeometry()
|
|
114
|
+
const [x0, x1] = config.x_range ?? x_range
|
|
115
|
+
const [y0, y1] = config.y_range ?? y_range
|
|
116
|
+
const x_step = (x1 - x0) / (res_a - 1)
|
|
117
|
+
const y_step = (y1 - y0) / (res_b - 1)
|
|
118
|
+
for (let ib = 0; ib < res_b; ib++) {
|
|
119
|
+
for (let ia = 0; ia < res_a; ia++) {
|
|
120
|
+
const x_val = x0 + ia * x_step
|
|
121
|
+
const y_val = y0 + ib * y_step
|
|
122
|
+
add_vertex(positions, colors, x_val, y_val, config.z_fn(x_val, y_val))
|
|
79
123
|
}
|
|
80
|
-
|
|
124
|
+
}
|
|
125
|
+
return build_geometry(positions, colors, res_a, res_b)
|
|
81
126
|
}
|
|
127
|
+
|
|
82
128
|
if (config.type === `parametric` && config.parametric_fn) {
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
for (let
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
add_vertex(positions, colors, pt.x, pt.y, pt.z);
|
|
93
|
-
}
|
|
129
|
+
if (res_a < 2 || res_b < 2) return new THREE.BufferGeometry()
|
|
130
|
+
const [u0, u1] = config.u_range ?? [0, 1]
|
|
131
|
+
const [v0, v1] = config.v_range ?? [0, 1]
|
|
132
|
+
const u_step = (u1 - u0) / (res_a - 1)
|
|
133
|
+
const v_step = (v1 - v0) / (res_b - 1)
|
|
134
|
+
for (let ib = 0; ib < res_b; ib++) {
|
|
135
|
+
for (let ia = 0; ia < res_a; ia++) {
|
|
136
|
+
const pt = config.parametric_fn(u0 + ia * u_step, v0 + ib * v_step)
|
|
137
|
+
add_vertex(positions, colors, pt.x, pt.y, pt.z)
|
|
94
138
|
}
|
|
95
|
-
|
|
139
|
+
}
|
|
140
|
+
return build_geometry(positions, colors, res_a, res_b)
|
|
96
141
|
}
|
|
142
|
+
|
|
97
143
|
if (config.type === `triangulated` && config.points?.length) {
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
144
|
+
for (const pt of config.points) {
|
|
145
|
+
add_vertex(positions, colors, pt.x, pt.y, pt.z)
|
|
146
|
+
}
|
|
147
|
+
return build_geometry(positions, colors, undefined, undefined, config.triangles)
|
|
102
148
|
}
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
$
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
149
|
+
|
|
150
|
+
return null
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
// Geometry with proper disposal on change/unmount
|
|
154
|
+
let geometry: THREE.BufferGeometry | null = $state(null)
|
|
155
|
+
let wireframe_geometry: THREE.WireframeGeometry | null = $state(null)
|
|
156
|
+
|
|
157
|
+
$effect(() => {
|
|
158
|
+
const new_geom = create_geometry()
|
|
159
|
+
const new_wireframe = new_geom ? new THREE.WireframeGeometry(new_geom) : null
|
|
160
|
+
geometry = new_geom
|
|
161
|
+
wireframe_geometry = new_wireframe
|
|
113
162
|
return () => {
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
}
|
|
117
|
-
})
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
let
|
|
163
|
+
new_geom?.dispose()
|
|
164
|
+
new_wireframe?.dispose()
|
|
165
|
+
}
|
|
166
|
+
})
|
|
167
|
+
|
|
168
|
+
// Material properties
|
|
169
|
+
let is_transparent = $derived((config.opacity ?? 1) < 1)
|
|
170
|
+
let material_props = $derived({
|
|
121
171
|
transparent: is_transparent,
|
|
122
172
|
opacity: config.opacity ?? 1,
|
|
123
173
|
side: (config.double_sided ?? is_transparent)
|
|
124
|
-
|
|
125
|
-
|
|
174
|
+
? THREE.DoubleSide
|
|
175
|
+
: THREE.FrontSide,
|
|
126
176
|
vertexColors: true,
|
|
127
177
|
depthWrite: true,
|
|
128
|
-
})
|
|
129
|
-
|
|
178
|
+
})
|
|
179
|
+
|
|
180
|
+
let wireframe_props = $derived({
|
|
130
181
|
color: config.wireframe_color ?? `#333`,
|
|
131
182
|
linewidth: config.wireframe_width ?? 1,
|
|
132
183
|
transparent: true,
|
|
133
184
|
opacity: 0.5,
|
|
134
|
-
})
|
|
185
|
+
})
|
|
135
186
|
</script>
|
|
136
187
|
|
|
137
188
|
{#if geometry}
|
|
@@ -1,6 +1,58 @@
|
|
|
1
|
-
<script lang="ts">
|
|
2
|
-
|
|
3
|
-
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import type { Vec2 } from '../math'
|
|
3
|
+
import { get_scale_type_name, type ScaleType, type Sides } from './'
|
|
4
|
+
|
|
5
|
+
let {
|
|
6
|
+
display,
|
|
7
|
+
x_scale_fn,
|
|
8
|
+
x2_scale_fn,
|
|
9
|
+
y_scale_fn,
|
|
10
|
+
y2_scale_fn,
|
|
11
|
+
x_range,
|
|
12
|
+
x2_range,
|
|
13
|
+
y_range,
|
|
14
|
+
y2_range,
|
|
15
|
+
x_scale_type,
|
|
16
|
+
x2_scale_type,
|
|
17
|
+
y_scale_type,
|
|
18
|
+
y2_scale_type,
|
|
19
|
+
x_is_time = false,
|
|
20
|
+
x2_is_time = false,
|
|
21
|
+
has_x2 = false,
|
|
22
|
+
has_y2 = false,
|
|
23
|
+
width,
|
|
24
|
+
height,
|
|
25
|
+
pad,
|
|
26
|
+
}: {
|
|
27
|
+
display: {
|
|
28
|
+
x_zero_line?: boolean
|
|
29
|
+
x2_zero_line?: boolean
|
|
30
|
+
y_zero_line?: boolean
|
|
31
|
+
y2_zero_line?: boolean
|
|
32
|
+
}
|
|
33
|
+
x_scale_fn: (val: number) => number
|
|
34
|
+
x2_scale_fn?: (val: number) => number
|
|
35
|
+
y_scale_fn: (val: number) => number
|
|
36
|
+
y2_scale_fn?: (val: number) => number
|
|
37
|
+
x_range: Vec2
|
|
38
|
+
x2_range?: Vec2
|
|
39
|
+
y_range: Vec2
|
|
40
|
+
y2_range?: Vec2
|
|
41
|
+
x_scale_type?: ScaleType
|
|
42
|
+
x2_scale_type?: ScaleType
|
|
43
|
+
y_scale_type?: ScaleType
|
|
44
|
+
y2_scale_type?: ScaleType
|
|
45
|
+
x_is_time?: boolean
|
|
46
|
+
x2_is_time?: boolean
|
|
47
|
+
has_x2?: boolean
|
|
48
|
+
has_y2?: boolean
|
|
49
|
+
width: number
|
|
50
|
+
height: number
|
|
51
|
+
pad: Required<Sides>
|
|
52
|
+
} = $props()
|
|
53
|
+
|
|
54
|
+
const spans_zero = (range: Vec2): boolean =>
|
|
55
|
+
Math.min(range[0], range[1]) <= 0 && Math.max(range[0], range[1]) >= 0
|
|
4
56
|
</script>
|
|
5
57
|
|
|
6
58
|
{#if display.x_zero_line && get_scale_type_name(x_scale_type) !== `log` &&
|
|
@@ -1,5 +1,7 @@
|
|
|
1
|
-
<script lang="ts">
|
|
2
|
-
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import type { XyObj } from './'
|
|
3
|
+
|
|
4
|
+
let { start, current }: { start: XyObj | null; current: XyObj | null } = $props()
|
|
3
5
|
</script>
|
|
4
6
|
|
|
5
7
|
{#if start && current && isFinite(start.x) && isFinite(start.y) &&
|
package/dist/plot/axis-utils.js
CHANGED
|
@@ -10,9 +10,7 @@ export function merge_series_state(old_series, new_series) {
|
|
|
10
10
|
}
|
|
11
11
|
return new_series.map((new_srs, idx) => {
|
|
12
12
|
// Match by id if available (string or number), otherwise fall back to index
|
|
13
|
-
const old_srs = (new_srs.id !== undefined && new_srs.id !== ``
|
|
14
|
-
? by_id.get(new_srs.id)
|
|
15
|
-
: undefined) ??
|
|
13
|
+
const old_srs = (new_srs.id !== undefined && new_srs.id !== `` ? by_id.get(new_srs.id) : undefined) ??
|
|
16
14
|
old_series[idx];
|
|
17
15
|
if (!old_srs) {
|
|
18
16
|
return new_srs;
|
|
@@ -21,9 +21,7 @@ export function compute_local_variance(values, window_size) {
|
|
|
21
21
|
const start = Math.max(0, idx - half_window);
|
|
22
22
|
const end = Math.min(len, idx + half_window + 1);
|
|
23
23
|
// Welford's online variance calculation
|
|
24
|
-
let mean = 0;
|
|
25
|
-
let m2 = 0;
|
|
26
|
-
let count = 0;
|
|
24
|
+
let [mean, m2, count] = [0, 0, 0];
|
|
27
25
|
for (let jdx = start; jdx < end; jdx++) {
|
|
28
26
|
const val = values[jdx];
|
|
29
27
|
if (!Number.isFinite(val))
|
|
@@ -170,13 +168,9 @@ export function detect_instability(x_values, y_values, config = {}) {
|
|
|
170
168
|
}
|
|
171
169
|
}
|
|
172
170
|
if (valid_y.length < window_size * 2) {
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
onset_x: NaN,
|
|
177
|
-
combined_score: 0,
|
|
178
|
-
method_scores: { derivative_variance: 0, amplitude_growth: 0, sign_changes: 0 },
|
|
179
|
-
};
|
|
171
|
+
const method_scores = { derivative_variance: 0, amplitude_growth: 0, sign_changes: 0 };
|
|
172
|
+
const detected = false;
|
|
173
|
+
return { detected, onset_index: -1, onset_x: NaN, combined_score: 0, method_scores };
|
|
180
174
|
}
|
|
181
175
|
// Run all three detection methods
|
|
182
176
|
const deriv_result = detect_derivative_variance(valid_y, window_size, threshold);
|
|
@@ -188,12 +182,12 @@ export function detect_instability(x_values, y_values, config = {}) {
|
|
|
188
182
|
sign_changes: sign_result.score,
|
|
189
183
|
};
|
|
190
184
|
// Compute weighted combined score
|
|
191
|
-
const total_weight = weights.derivative_variance + weights.amplitude_growth +
|
|
192
|
-
weights.sign_changes;
|
|
185
|
+
const total_weight = weights.derivative_variance + weights.amplitude_growth + weights.sign_changes;
|
|
193
186
|
const combined_score = total_weight > 0
|
|
194
187
|
? (weights.derivative_variance * deriv_result.score +
|
|
195
188
|
weights.amplitude_growth * amp_result.score +
|
|
196
|
-
weights.sign_changes * sign_result.score) /
|
|
189
|
+
weights.sign_changes * sign_result.score) /
|
|
190
|
+
total_weight
|
|
197
191
|
: 0;
|
|
198
192
|
// Find earliest onset across all methods that exceeded threshold
|
|
199
193
|
const onset_candidates = [
|
|
@@ -214,16 +208,8 @@ export function detect_instability(x_values, y_values, config = {}) {
|
|
|
214
208
|
}
|
|
215
209
|
}
|
|
216
210
|
const detected = combined_score >= threshold || onset_index >= 0;
|
|
217
|
-
const onset_x = onset_index >= 0 && onset_index < x_values.length
|
|
218
|
-
|
|
219
|
-
: NaN;
|
|
220
|
-
return {
|
|
221
|
-
detected,
|
|
222
|
-
onset_index,
|
|
223
|
-
onset_x,
|
|
224
|
-
combined_score,
|
|
225
|
-
method_scores,
|
|
226
|
-
};
|
|
211
|
+
const onset_x = onset_index >= 0 && onset_index < x_values.length ? x_values[onset_index] : NaN;
|
|
212
|
+
return { detected, onset_index, onset_x, combined_score, method_scores };
|
|
227
213
|
}
|
|
228
214
|
// --- Smoothing Functions ---
|
|
229
215
|
// Moving average - O(n)
|
|
@@ -235,8 +221,7 @@ export function smooth_moving_average(values, window) {
|
|
|
235
221
|
for (let idx = 0; idx < values.length; idx++) {
|
|
236
222
|
const start = Math.max(0, idx - half_window);
|
|
237
223
|
const end = Math.min(values.length, idx + half_window + 1);
|
|
238
|
-
let sum = 0;
|
|
239
|
-
let count = 0;
|
|
224
|
+
let [sum, count] = [0, 0];
|
|
240
225
|
for (let jdx = start; jdx < end; jdx++) {
|
|
241
226
|
if (Number.isFinite(values[jdx])) {
|
|
242
227
|
sum += values[jdx];
|
|
@@ -291,8 +276,7 @@ export function smooth_savitzky_golay(values, window, polynomial_order = DEFAULT
|
|
|
291
276
|
// Cache coefficient sum to avoid O(n × window) redundant reductions in loop
|
|
292
277
|
const coeffs_sum = coeffs.reduce((a, b) => a + b, 0);
|
|
293
278
|
for (let idx = 0; idx < values.length; idx++) {
|
|
294
|
-
let sum = 0;
|
|
295
|
-
let weight_sum = 0;
|
|
279
|
+
let [sum, weight_sum] = [0, 0];
|
|
296
280
|
for (let jdx = 0; jdx < actual_window; jdx++) {
|
|
297
281
|
const data_idx = idx - half + jdx;
|
|
298
282
|
if (data_idx >= 0 && data_idx < values.length && Number.isFinite(values[data_idx])) {
|
|
@@ -300,7 +284,7 @@ export function smooth_savitzky_golay(values, window, polynomial_order = DEFAULT
|
|
|
300
284
|
weight_sum += coeffs[jdx];
|
|
301
285
|
}
|
|
302
286
|
}
|
|
303
|
-
result[idx] = weight_sum !== 0 ? sum / weight_sum * coeffs_sum : values[idx];
|
|
287
|
+
result[idx] = weight_sum !== 0 ? (sum / weight_sum) * coeffs_sum : values[idx];
|
|
304
288
|
}
|
|
305
289
|
return result;
|
|
306
290
|
}
|
|
@@ -17,6 +17,7 @@ export const prepare_legend_data = (series) => series.map((series_data, series_i
|
|
|
17
17
|
label: series_data.label ?? `Series ${series_idx + 1}`,
|
|
18
18
|
visible: series_data.visible ?? true,
|
|
19
19
|
display_style: {
|
|
20
|
+
// Prefer the series’ symbol when present, falling back to settings
|
|
20
21
|
symbol_type: !Array.isArray(series_data.point_style)
|
|
21
22
|
? (series_data.point_style?.symbol_type ?? DEFAULTS.scatter.symbol_type)
|
|
22
23
|
: DEFAULTS.scatter.symbol_type,
|
|
@@ -38,7 +39,7 @@ export const create_data_points = (series, filter_fn) => series
|
|
|
38
39
|
// If prop is a scalar, returns the scalar (applied to all indices).
|
|
39
40
|
// Returns undefined if prop is null/undefined.
|
|
40
41
|
export function process_prop(prop, idx) {
|
|
41
|
-
if (prop
|
|
42
|
+
if (prop == null)
|
|
42
43
|
return undefined;
|
|
43
44
|
return Array.isArray(prop) ? prop[idx] : prop;
|
|
44
45
|
}
|
package/dist/plot/fill-utils.js
CHANGED
|
@@ -113,6 +113,8 @@ export function resolve_boundary(boundary, series, x_values, domains) {
|
|
|
113
113
|
case `function`:
|
|
114
114
|
return x_values.map((curr_x) => boundary.fn(curr_x));
|
|
115
115
|
case `data`:
|
|
116
|
+
if (boundary.values.length === 0)
|
|
117
|
+
return Array(x_values.length).fill(NaN);
|
|
116
118
|
// If lengths match, use directly; otherwise interpolate
|
|
117
119
|
if (boundary.values.length === x_values.length) {
|
|
118
120
|
return [...boundary.values];
|
package/dist/plot/layout.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { AxisConfig, Sides } from './';
|
|
2
2
|
export declare const LABEL_GAP_DEFAULT = 30;
|
|
3
|
-
export declare const filter_padding:
|
|
3
|
+
export declare const filter_padding: (padding: Partial<Sides> | undefined | null, defaults: Required<Sides>) => Required<Sides>;
|
|
4
4
|
export declare function measure_text_width(text: string, font?: string): number;
|
|
5
5
|
export interface AutoPaddingConfig {
|
|
6
6
|
padding: Partial<Sides>;
|
|
@@ -34,6 +34,9 @@ export interface Rect {
|
|
|
34
34
|
width: number;
|
|
35
35
|
height: number;
|
|
36
36
|
}
|
|
37
|
+
export declare const pad_rect: (rect: Rect, padding: number) => Rect;
|
|
38
|
+
export declare const centered_rect: (center_x: number, top_y: number, width: number, height: number) => Rect;
|
|
39
|
+
export declare const rect_within_rect: (rect: Rect, bounds: Rect) => boolean;
|
|
37
40
|
export interface ElementPlacementConfig {
|
|
38
41
|
plot_bounds: Rect;
|
|
39
42
|
element_size: {
|
package/dist/plot/layout.js
CHANGED
|
@@ -23,10 +23,12 @@ export function measure_text_width(text, font = `12px sans-serif`) {
|
|
|
23
23
|
return ctx.measureText(text).width;
|
|
24
24
|
}
|
|
25
25
|
// Measure the widest formatted tick label. Used for auto-padding and label placement.
|
|
26
|
-
export const measure_max_tick_width = (ticks, format = ``) => ticks.length === 0
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
26
|
+
export const measure_max_tick_width = (ticks, format = ``) => ticks.length === 0
|
|
27
|
+
? 0
|
|
28
|
+
: Math.max(...ticks.map((tick) => {
|
|
29
|
+
const label = typeof tick === `string` ? tick : format_value(tick, format);
|
|
30
|
+
return measure_text_width(label, `12px sans-serif`);
|
|
31
|
+
}));
|
|
30
32
|
// Estimated height of a single tick label line (font-size 0.8em ≈ 12px + leading)
|
|
31
33
|
export const TICK_LABEL_HEIGHT = 16;
|
|
32
34
|
// Estimated height of an axis label (font-size ~14px + margin)
|
|
@@ -68,18 +70,22 @@ export function constrain_tooltip_position(cursor_x, cursor_y, tooltip_width, to
|
|
|
68
70
|
const abs_offset_y = Math.abs(offset_y);
|
|
69
71
|
// Determine X position based on preferred side and flip state
|
|
70
72
|
let raw_x;
|
|
71
|
-
if (offset_x >= 0) {
|
|
73
|
+
if (offset_x >= 0) {
|
|
74
|
+
// Prefer right side: flip to left if overflows
|
|
72
75
|
raw_x = flip_x ? cursor_x - abs_offset_x - tooltip_width : cursor_x + abs_offset_x;
|
|
73
76
|
}
|
|
74
|
-
else {
|
|
77
|
+
else {
|
|
78
|
+
// Prefer left side: flip to right if overflows
|
|
75
79
|
raw_x = flip_x ? cursor_x + abs_offset_x : cursor_x - abs_offset_x - tooltip_width;
|
|
76
80
|
}
|
|
77
81
|
// Determine Y position based on preferred side and flip state
|
|
78
82
|
let raw_y;
|
|
79
|
-
if (offset_y >= 0) {
|
|
83
|
+
if (offset_y >= 0) {
|
|
84
|
+
// Prefer bottom: flip to top if overflows
|
|
80
85
|
raw_y = flip_y ? cursor_y - abs_offset_y - tooltip_height : cursor_y + abs_offset_y;
|
|
81
86
|
}
|
|
82
|
-
else {
|
|
87
|
+
else {
|
|
88
|
+
// Prefer top: flip to bottom if overflows
|
|
83
89
|
raw_y = flip_y ? cursor_y + abs_offset_y : cursor_y - abs_offset_y - tooltip_height;
|
|
84
90
|
}
|
|
85
91
|
// Clamp to viewport bounds
|
|
@@ -87,6 +93,22 @@ export function constrain_tooltip_position(cursor_x, cursor_y, tooltip_width, to
|
|
|
87
93
|
const y_pos = Math.max(0, Math.min(raw_y, viewport_height - tooltip_height));
|
|
88
94
|
return { x: x_pos, y: y_pos };
|
|
89
95
|
}
|
|
96
|
+
export const pad_rect = (rect, padding) => ({
|
|
97
|
+
x: rect.x - padding,
|
|
98
|
+
y: rect.y - padding,
|
|
99
|
+
width: rect.width + 2 * padding,
|
|
100
|
+
height: rect.height + 2 * padding,
|
|
101
|
+
});
|
|
102
|
+
export const centered_rect = (center_x, top_y, width, height) => ({
|
|
103
|
+
x: center_x - width / 2,
|
|
104
|
+
y: top_y,
|
|
105
|
+
width,
|
|
106
|
+
height,
|
|
107
|
+
});
|
|
108
|
+
export const rect_within_rect = (rect, bounds) => rect.x >= bounds.x &&
|
|
109
|
+
rect.x + rect.width <= bounds.x + bounds.width &&
|
|
110
|
+
rect.y >= bounds.y &&
|
|
111
|
+
rect.y + rect.height <= bounds.y + bounds.height;
|
|
90
112
|
// Scoring constants
|
|
91
113
|
const EXCLUSION_PENALTY = 1000;
|
|
92
114
|
const DISTANCE_WEIGHT = 0.001;
|
|
@@ -129,7 +151,7 @@ export function compute_element_placement(config) {
|
|
|
129
151
|
const effective_y_max = Math.max(valid_y_min, valid_y_max);
|
|
130
152
|
// Subsample points for performance
|
|
131
153
|
const sampled_points = points.length > MAX_SAMPLE_POINTS
|
|
132
|
-
? Array.from({ length: MAX_SAMPLE_POINTS }, (_, idx) => points[Math.floor(idx * points.length / MAX_SAMPLE_POINTS)])
|
|
154
|
+
? Array.from({ length: MAX_SAMPLE_POINTS }, (_, idx) => points[Math.floor((idx * points.length) / MAX_SAMPLE_POINTS)])
|
|
133
155
|
: points;
|
|
134
156
|
let best_result = {
|
|
135
157
|
x: effective_x_min,
|
|
@@ -197,11 +219,8 @@ export function compute_element_placement(config) {
|
|
|
197
219
|
euclidean_dist([cand_x, elem_bottom], [plot_left, plot_bottom]), // bottom-left
|
|
198
220
|
euclidean_dist([elem_right, elem_bottom], [plot_right, plot_bottom]));
|
|
199
221
|
// Higher bonus for positions closer to corners (0 = at corner, 1 = far from all)
|
|
200
|
-
const corner_bonus = max_corner_dist > 0
|
|
201
|
-
|
|
202
|
-
: 0;
|
|
203
|
-
const score = -overlap_count + min_distance * DISTANCE_WEIGHT + corner_bonus -
|
|
204
|
-
exclusion_penalty;
|
|
222
|
+
const corner_bonus = max_corner_dist > 0 ? (1 - min_corner_dist / max_corner_dist) * CORNER_WEIGHT : 0;
|
|
223
|
+
const score = -overlap_count + min_distance * DISTANCE_WEIGHT + corner_bonus - exclusion_penalty;
|
|
205
224
|
if (score > best_result.score) {
|
|
206
225
|
best_result = { x: cand_x, y: cand_y, score };
|
|
207
226
|
}
|
|
@@ -12,12 +12,12 @@ export interface RefLinesByZIndex {
|
|
|
12
12
|
export declare function group_ref_lines_by_z(lines: IndexedRefLine[]): RefLinesByZIndex;
|
|
13
13
|
export declare function normalize_value(value: RefLineValue): number;
|
|
14
14
|
export declare const normalize_point: (point: [RefLineValue, RefLineValue]) => [number, number];
|
|
15
|
-
export declare function resolve_line_endpoints(ref_line: RefLine, { x_min, x_max, y_min, y_max }: {
|
|
15
|
+
export declare function resolve_line_endpoints(ref_line: RefLine, { x_min, x_max, y_min, y_max, }: {
|
|
16
16
|
x_min: number;
|
|
17
17
|
x_max: number;
|
|
18
18
|
y_min: number;
|
|
19
19
|
y_max: number;
|
|
20
|
-
}, { x_scale, x2_scale, y_scale, y2_scale }: {
|
|
20
|
+
}, { x_scale, x2_scale, y_scale, y2_scale, }: {
|
|
21
21
|
x_scale: (val: number) => number;
|
|
22
22
|
x2_scale?: (val: number) => number;
|
|
23
23
|
y_scale: (val: number) => number;
|