matterviz 0.4.0 → 0.4.1
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/brillouin/BrillouinZone.svelte +68 -145
- package/dist/brillouin/BrillouinZone.svelte.d.ts +5 -14
- package/dist/brillouin/BrillouinZoneExportPane.svelte +43 -96
- package/dist/brillouin/BrillouinZoneExportPane.svelte.d.ts +1 -1
- package/dist/brillouin/BrillouinZoneInfoPane.svelte +9 -32
- package/dist/brillouin/BrillouinZoneInfoPane.svelte.d.ts +2 -3
- package/dist/brillouin/BrillouinZoneScene.svelte +49 -203
- package/dist/brillouin/BrillouinZoneScene.svelte.d.ts +3 -23
- package/dist/brillouin/ReciprocalVectors.svelte +39 -0
- package/dist/brillouin/ReciprocalVectors.svelte.d.ts +9 -0
- package/dist/brillouin/compute.d.ts +2 -0
- package/dist/brillouin/compute.js +80 -77
- package/dist/brillouin/geometry.d.ts +8 -0
- package/dist/brillouin/geometry.js +57 -0
- package/dist/brillouin/index.d.ts +2 -0
- package/dist/brillouin/index.js +2 -0
- package/dist/brillouin/types.d.ts +2 -2
- package/dist/chempot-diagram/ChemPotDiagram.svelte.d.ts +1 -1
- package/dist/chempot-diagram/ChemPotDiagram2D.svelte +100 -191
- package/dist/chempot-diagram/ChemPotDiagram2D.svelte.d.ts +4 -1
- package/dist/chempot-diagram/ChemPotDiagram3D.svelte +176 -464
- package/dist/chempot-diagram/ChemPotDiagram3D.svelte.d.ts +7 -1
- package/dist/chempot-diagram/color.d.ts +3 -6
- package/dist/chempot-diagram/color.js +5 -5
- package/dist/chempot-diagram/compute.d.ts +3 -3
- package/dist/chempot-diagram/compute.js +3 -1
- package/dist/chempot-diagram/controls-state.svelte.d.ts +10 -0
- package/dist/chempot-diagram/controls-state.svelte.js +42 -0
- package/dist/chempot-diagram/export.d.ts +47 -0
- package/dist/chempot-diagram/export.js +133 -0
- package/dist/chempot-diagram/index.d.ts +1 -0
- package/dist/chempot-diagram/index.js +1 -0
- package/dist/chempot-diagram/pointer.d.ts +0 -10
- package/dist/chempot-diagram/pointer.js +4 -4
- package/dist/chempot-diagram/types.d.ts +3 -3
- package/dist/colors/index.js +2 -2
- package/dist/composition/FormulaFilter.svelte +6 -5
- package/dist/composition/PieChart.svelte +5 -5
- package/dist/composition/chem-sys.js +3 -2
- package/dist/composition/format.js +3 -2
- package/dist/composition/parse.d.ts +0 -1
- package/dist/composition/parse.js +17 -19
- package/dist/controls.d.ts +1 -0
- package/dist/controls.js +0 -1
- package/dist/convex-hull/ConvexHull.svelte +8 -10
- package/dist/convex-hull/ConvexHull.svelte.d.ts +1 -4
- package/dist/convex-hull/ConvexHull2D.svelte +94 -175
- package/dist/convex-hull/ConvexHull2D.svelte.d.ts +1 -1
- package/dist/convex-hull/ConvexHull3D.svelte +176 -680
- package/dist/convex-hull/ConvexHull3D.svelte.d.ts +1 -1
- package/dist/convex-hull/ConvexHull4D.svelte +180 -680
- package/dist/convex-hull/ConvexHull4D.svelte.d.ts +1 -1
- package/dist/convex-hull/ConvexHullChrome.svelte +268 -0
- package/dist/convex-hull/ConvexHullChrome.svelte.d.ts +30 -0
- package/dist/convex-hull/ConvexHullControls.svelte +88 -7
- package/dist/convex-hull/ConvexHullControls.svelte.d.ts +7 -6
- package/dist/convex-hull/ConvexHullInfoPane.svelte +18 -5
- package/dist/convex-hull/ConvexHullInfoPane.svelte.d.ts +6 -5
- package/dist/convex-hull/ConvexHullStats.svelte +29 -168
- package/dist/convex-hull/ConvexHullStats.svelte.d.ts +3 -1
- package/dist/convex-hull/ConvexHullTooltip.svelte +11 -2
- package/dist/convex-hull/ConvexHullTooltip.svelte.d.ts +2 -1
- package/dist/convex-hull/barycentric-coords.d.ts +2 -4
- package/dist/convex-hull/barycentric-coords.js +6 -33
- package/dist/convex-hull/canvas-interactions.svelte.d.ts +79 -0
- package/dist/convex-hull/canvas-interactions.svelte.js +278 -0
- package/dist/convex-hull/helpers.d.ts +39 -7
- package/dist/convex-hull/helpers.js +154 -69
- package/dist/convex-hull/hull-state.svelte.d.ts +44 -0
- package/dist/convex-hull/hull-state.svelte.js +124 -0
- package/dist/convex-hull/index.d.ts +9 -7
- package/dist/convex-hull/index.js +7 -2
- package/dist/convex-hull/thermodynamics.js +91 -920
- package/dist/convex-hull/types.d.ts +12 -4
- package/dist/convex-hull/types.js +12 -0
- package/dist/coordination/CoordinationBarPlot.svelte +4 -11
- package/dist/element/BohrAtom.svelte +2 -1
- package/dist/element/ElementTile.svelte.d.ts +1 -1
- package/dist/element/index.d.ts +4 -0
- package/dist/element/index.js +18 -0
- package/dist/feedback/DragOverlay.svelte +3 -1
- package/dist/feedback/DragOverlay.svelte.d.ts +1 -0
- package/dist/feedback/StatusMessage.svelte +13 -3
- package/dist/fermi-surface/FermiSurface.svelte +67 -146
- package/dist/fermi-surface/FermiSurface.svelte.d.ts +5 -14
- package/dist/fermi-surface/FermiSurfaceControls.svelte.d.ts +1 -1
- package/dist/fermi-surface/FermiSurfaceScene.svelte +72 -224
- package/dist/fermi-surface/FermiSurfaceScene.svelte.d.ts +3 -23
- package/dist/fermi-surface/compute.js +11 -10
- package/dist/fermi-surface/export.js +4 -15
- package/dist/fermi-surface/index.d.ts +0 -1
- package/dist/fermi-surface/index.js +0 -1
- package/dist/fermi-surface/parse.d.ts +1 -1
- package/dist/fermi-surface/parse.js +64 -75
- package/dist/fermi-surface/types.d.ts +2 -2
- package/dist/heatmap-matrix/HeatmapMatrix.svelte +55 -40
- package/dist/heatmap-matrix/HeatmapMatrix.svelte.d.ts +4 -3
- package/dist/heatmap-matrix/HeatmapMatrixControls.svelte +3 -2
- package/dist/heatmap-matrix/HeatmapMatrixControls.svelte.d.ts +5 -5
- package/dist/heatmap-matrix/index.d.ts +3 -2
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/io/ExportPane.svelte +166 -0
- package/dist/io/ExportPane.svelte.d.ts +17 -0
- package/dist/io/decompress.js +1 -2
- package/dist/io/export.d.ts +5 -1
- package/dist/io/export.js +32 -28
- package/dist/io/fetch.d.ts +2 -1
- package/dist/io/file-drop.d.ts +7 -0
- package/dist/io/file-drop.js +13 -0
- package/dist/io/index.d.ts +2 -0
- package/dist/io/index.js +10 -0
- package/dist/io/types.d.ts +13 -0
- package/dist/isosurface/parse.js +46 -44
- package/dist/labels.js +1 -1
- package/dist/layout/FullscreenButton.svelte +33 -0
- package/dist/layout/FullscreenButton.svelte.d.ts +10 -0
- package/dist/layout/FullscreenToggle.svelte +8 -14
- package/dist/layout/ViewerChrome.svelte +116 -0
- package/dist/layout/ViewerChrome.svelte.d.ts +17 -0
- package/dist/layout/fullscreen.d.ts +4 -0
- package/dist/layout/fullscreen.svelte.d.ts +8 -0
- package/dist/layout/fullscreen.svelte.js +37 -0
- package/dist/layout/index.d.ts +3 -0
- package/dist/layout/index.js +3 -0
- package/dist/math.d.ts +7 -3
- package/dist/math.js +18 -21
- package/dist/overlays/index.d.ts +4 -0
- package/dist/periodic-table/PeriodicTable.svelte +9 -8
- package/dist/phase-diagram/IsobaricBinaryPhaseDiagram.svelte.d.ts +1 -1
- package/dist/phase-diagram/PhaseDiagramControls.svelte +3 -2
- package/dist/phase-diagram/PhaseDiagramControls.svelte.d.ts +4 -3
- package/dist/phase-diagram/PhaseDiagramEditorPane.svelte +2 -1
- package/dist/phase-diagram/PhaseDiagramEditorPane.svelte.d.ts +2 -3
- package/dist/phase-diagram/PhaseDiagramExportPane.svelte +47 -132
- package/dist/phase-diagram/PhaseDiagramExportPane.svelte.d.ts +3 -4
- package/dist/phase-diagram/colors.js +1 -1
- package/dist/phase-diagram/parse.d.ts +2 -1
- package/dist/plot/bar/BarPlot.svelte +79 -316
- package/dist/plot/bar/BarPlot.svelte.d.ts +7 -15
- package/dist/plot/bar/BarPlotControls.svelte.d.ts +1 -1
- package/dist/plot/bar/SpacegroupBarPlot.svelte +2 -1
- package/dist/plot/box/BoxPlot.svelte +76 -246
- package/dist/plot/box/BoxPlot.svelte.d.ts +4 -3
- package/dist/plot/box/BoxPlotControls.svelte.d.ts +1 -1
- package/dist/plot/box/Violin.svelte.d.ts +1 -1
- package/dist/plot/box/box-plot.d.ts +3 -2
- package/dist/plot/box/box-plot.js +5 -2
- package/dist/plot/box/kde.d.ts +2 -1
- package/dist/plot/box/kde.js +4 -4
- package/dist/plot/core/auto-place.d.ts +1 -1
- package/dist/plot/core/auto-place.js +4 -1
- package/dist/plot/core/components/ColorBar.svelte +5 -5
- package/dist/plot/core/components/ColorBar.svelte.d.ts +5 -4
- package/dist/plot/core/components/Line.svelte +3 -2
- package/dist/plot/core/components/Line.svelte.d.ts +3 -2
- package/dist/plot/core/components/PlotAxis.svelte +2 -1
- package/dist/plot/core/components/PlotAxis.svelte.d.ts +2 -1
- package/dist/plot/core/components/PlotControls.svelte.d.ts +1 -1
- package/dist/plot/core/components/ReferenceLine3D.svelte +2 -2
- package/dist/plot/core/components/ReferenceLine3D.svelte.d.ts +4 -4
- package/dist/plot/core/components/ReferencePlane.svelte +2 -2
- package/dist/plot/core/components/ReferencePlane.svelte.d.ts +4 -4
- package/dist/plot/core/data-cleaning.js +18 -18
- package/dist/plot/core/fill-utils.d.ts +4 -3
- package/dist/plot/core/fill-utils.js +6 -3
- package/dist/plot/core/interactions.d.ts +5 -1
- package/dist/plot/core/interactions.js +14 -0
- package/dist/plot/core/pan-zoom.svelte.d.ts +35 -0
- package/dist/plot/core/pan-zoom.svelte.js +221 -0
- package/dist/plot/core/placed-tween.svelte.d.ts +21 -0
- package/dist/plot/core/placed-tween.svelte.js +68 -0
- package/dist/plot/core/reference-line.d.ts +10 -10
- package/dist/plot/core/reference-line.js +6 -6
- package/dist/plot/core/scales.d.ts +17 -25
- package/dist/plot/core/scales.js +10 -8
- package/dist/plot/core/svg.d.ts +2 -1
- package/dist/plot/core/types.d.ts +18 -7
- package/dist/plot/core/utils/label-placement.d.ts +1 -1
- package/dist/plot/core/utils/label-placement.js +3 -3
- package/dist/plot/core/utils.d.ts +2 -1
- package/dist/plot/histogram/Histogram.svelte +77 -314
- package/dist/plot/histogram/HistogramControls.svelte.d.ts +1 -1
- package/dist/plot/sankey/Sankey.svelte +2 -5
- package/dist/plot/sankey/Sankey.svelte.d.ts +1 -1
- package/dist/plot/sankey/sankey.js +3 -1
- package/dist/plot/scatter/BinnedScatterPlot.svelte +3 -5
- package/dist/plot/scatter/BinnedScatterPlot.svelte.d.ts +4 -4
- package/dist/plot/scatter/ScatterPlot.svelte +160 -450
- package/dist/plot/scatter/ScatterPlot.svelte.d.ts +7 -15
- package/dist/plot/scatter/ScatterPlotControls.svelte.d.ts +1 -1
- package/dist/plot/scatter/binned-scatter-types.d.ts +4 -11
- package/dist/plot/scatter/index.d.ts +1 -1
- package/dist/plot/scatter-3d/ScatterPlot3D.svelte +15 -26
- package/dist/plot/scatter-3d/ScatterPlot3D.svelte.d.ts +6 -14
- package/dist/plot/scatter-3d/ScatterPlot3DControls.svelte +9 -10
- package/dist/plot/scatter-3d/ScatterPlot3DControls.svelte.d.ts +5 -5
- package/dist/plot/scatter-3d/ScatterPlot3DScene.svelte +122 -121
- package/dist/plot/scatter-3d/ScatterPlot3DScene.svelte.d.ts +5 -14
- package/dist/plot/scatter-3d/Surface3D.svelte +6 -5
- package/dist/plot/scatter-3d/Surface3D.svelte.d.ts +4 -3
- package/dist/plot/sunburst/Sunburst.svelte +16 -20
- package/dist/plot/sunburst/Sunburst.svelte.d.ts +4 -3
- package/dist/plot/sunburst/SunburstControls.svelte.d.ts +1 -1
- package/dist/plot/sunburst/sunburst.js +4 -1
- package/dist/rdf/RdfPlot.svelte.d.ts +1 -1
- package/dist/sanitize.js +13 -2
- package/dist/scene/SceneCamera.svelte +62 -0
- package/dist/scene/SceneCamera.svelte.d.ts +19 -0
- package/dist/scene/bind-renderer.svelte.d.ts +2 -0
- package/dist/scene/bind-renderer.svelte.js +14 -0
- package/dist/scene/index.d.ts +4 -0
- package/dist/scene/index.js +5 -0
- package/dist/scene/props.js +52 -0
- package/dist/scene/types.d.ts +26 -0
- package/dist/scene/types.js +1 -0
- package/dist/settings.d.ts +14 -2
- package/dist/settings.js +59 -1
- package/dist/spectral/Bands.svelte +8 -7
- package/dist/spectral/Bands.svelte.d.ts +3 -2
- package/dist/spectral/BandsAndDos.svelte +22 -24
- package/dist/spectral/BrillouinBandsDos.svelte +3 -3
- package/dist/spectral/Dos.svelte +5 -4
- package/dist/spectral/Dos.svelte.d.ts +2 -1
- package/dist/spectral/helpers.d.ts +6 -6
- package/dist/spectral/helpers.js +43 -37
- package/dist/state.svelte.d.ts +0 -7
- package/dist/state.svelte.js +0 -6
- package/dist/structure/Arrow.svelte +2 -4
- package/dist/structure/AtomLegend.svelte.d.ts +1 -1
- package/dist/structure/CanvasTooltip.svelte +1 -0
- package/dist/structure/CellSelect.svelte +11 -3
- package/dist/structure/CellSelect.svelte.d.ts +2 -1
- package/dist/structure/Lattice.svelte +2 -2
- package/dist/structure/Structure.svelte +291 -355
- package/dist/structure/Structure.svelte.d.ts +5 -15
- package/dist/structure/StructureControls.svelte +217 -2
- package/dist/structure/StructureControls.svelte.d.ts +5 -3
- package/dist/structure/StructureExportPane.svelte +54 -156
- package/dist/structure/StructureExportPane.svelte.d.ts +4 -5
- package/dist/structure/StructureInfoPane.svelte +5 -3
- package/dist/structure/StructureInfoPane.svelte.d.ts +5 -5
- package/dist/structure/StructureScene.svelte +365 -198
- package/dist/structure/StructureScene.svelte.d.ts +22 -20
- package/dist/structure/{label-placement.d.ts → atom-label-placement.d.ts} +3 -3
- package/dist/structure/{label-placement.js → atom-label-placement.js} +12 -2
- package/dist/structure/atom-properties.d.ts +1 -1
- package/dist/structure/atom-properties.js +11 -16
- package/dist/structure/bond-order-perception.js +2 -4
- package/dist/structure/bonding.d.ts +3 -0
- package/dist/structure/bonding.js +91 -48
- package/dist/structure/export.d.ts +24 -4
- package/dist/structure/export.js +64 -122
- package/dist/structure/index.d.ts +2 -0
- package/dist/structure/index.js +2 -0
- package/dist/structure/parse.d.ts +3 -2
- package/dist/structure/parse.js +333 -370
- package/dist/structure/partial-occupancy.d.ts +0 -1
- package/dist/structure/partial-occupancy.js +1 -1
- package/dist/structure/pbc.d.ts +1 -1
- package/dist/structure/pbc.js +186 -13
- package/dist/structure/polyhedra.d.ts +41 -0
- package/dist/structure/polyhedra.js +602 -0
- package/dist/structure/site.d.ts +4 -0
- package/dist/structure/site.js +1 -0
- package/dist/structure/supercell.js +3 -2
- package/dist/structure/validation.js +5 -6
- package/dist/symmetry/SymmetryElementControls.svelte +69 -0
- package/dist/symmetry/SymmetryElementControls.svelte.d.ts +9 -0
- package/dist/symmetry/SymmetryElements.svelte +354 -0
- package/dist/symmetry/SymmetryElements.svelte.d.ts +24 -0
- package/dist/symmetry/SymmetryStats.svelte +111 -6
- package/dist/symmetry/WyckoffTable.svelte +68 -7
- package/dist/symmetry/WyckoffTable.svelte.d.ts +3 -0
- package/dist/symmetry/cell-transform.js +7 -14
- package/dist/symmetry/index.d.ts +14 -4
- package/dist/symmetry/index.js +301 -80
- package/dist/symmetry/spacegroups.d.ts +5 -1
- package/dist/symmetry/spacegroups.js +15 -1
- package/dist/symmetry/symmetry-elements.d.ts +33 -0
- package/dist/symmetry/symmetry-elements.js +521 -0
- package/dist/symmetry/wyckoff-db.d.ts +9 -0
- package/dist/symmetry/wyckoff-db.js +87 -0
- package/dist/table/HeatmapTable.svelte +4 -15
- package/dist/table/HeatmapTable.svelte.d.ts +1 -1
- package/dist/trajectory/Trajectory.svelte +58 -61
- package/dist/trajectory/Trajectory.svelte.d.ts +10 -22
- package/dist/trajectory/TrajectoryExportPane.svelte +15 -24
- package/dist/trajectory/TrajectoryExportPane.svelte.d.ts +4 -5
- package/dist/trajectory/TrajectoryInfoPane.svelte +3 -2
- package/dist/trajectory/TrajectoryInfoPane.svelte.d.ts +3 -2
- package/dist/trajectory/constants.js +6 -2
- package/dist/trajectory/extract.js +17 -37
- package/dist/trajectory/format-detect.d.ts +0 -1
- package/dist/trajectory/format-detect.js +3 -9
- package/dist/trajectory/frame-reader.d.ts +0 -1
- package/dist/trajectory/frame-reader.js +62 -128
- package/dist/trajectory/helpers.d.ts +10 -2
- package/dist/trajectory/helpers.js +56 -36
- package/dist/trajectory/parse/ase.d.ts +9 -1
- package/dist/trajectory/parse/ase.js +47 -32
- package/dist/trajectory/parse/diagnostics.d.ts +3 -0
- package/dist/trajectory/parse/diagnostics.js +14 -0
- package/dist/trajectory/parse/index.d.ts +1 -1
- package/dist/trajectory/parse/index.js +54 -102
- package/dist/trajectory/parse/lammps.d.ts +0 -2
- package/dist/trajectory/parse/lammps.js +8 -6
- package/dist/trajectory/parse/pymatgen.d.ts +2 -0
- package/dist/trajectory/parse/pymatgen.js +74 -0
- package/dist/trajectory/parse/vasp.js +4 -3
- package/dist/trajectory/parse/xyz.d.ts +9 -21
- package/dist/trajectory/parse/xyz.js +28 -33
- package/dist/trajectory/plotting.d.ts +0 -1
- package/dist/trajectory/plotting.js +3 -100
- package/dist/utils.d.ts +1 -0
- package/dist/utils.js +1 -1
- package/dist/xrd/XrdPlot.svelte +14 -29
- package/dist/xrd/broadening.d.ts +2 -1
- package/dist/xrd/calc-xrd.js +6 -11
- package/dist/xrd/index.d.ts +2 -2
- package/package.json +29 -16
- package/dist/element/data.json +0 -11864
- package/dist/fermi-surface/marching-cubes.d.ts +0 -2
- package/dist/fermi-surface/marching-cubes.js +0 -2
- package/dist/plot/core/hover-lock.svelte.d.ts +0 -14
- package/dist/plot/core/hover-lock.svelte.js +0 -45
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
lang="ts"
|
|
3
3
|
generics="Metadata extends Record<string, unknown> = Record<string, unknown>"
|
|
4
4
|
>
|
|
5
|
-
import type {
|
|
5
|
+
import type { D3InterpolateName } from '../../colors'
|
|
6
6
|
import { format_value } from '../../labels'
|
|
7
7
|
import { sanitize_html } from '../../sanitize'
|
|
8
8
|
import { FullscreenToggle, set_fullscreen_bg } from '../../layout'
|
|
@@ -10,6 +10,7 @@
|
|
|
10
10
|
import type {
|
|
11
11
|
AxisLoadError,
|
|
12
12
|
BasePlotProps,
|
|
13
|
+
ColorScaleConfig,
|
|
13
14
|
ControlsConfig,
|
|
14
15
|
DataLoaderFn,
|
|
15
16
|
DataSeries,
|
|
@@ -17,7 +18,6 @@
|
|
|
17
18
|
FillHandlerEvent,
|
|
18
19
|
FillRegion,
|
|
19
20
|
HoverConfig,
|
|
20
|
-
InitialRanges,
|
|
21
21
|
InternalPoint,
|
|
22
22
|
LabelPlacementConfig,
|
|
23
23
|
LegendConfig,
|
|
@@ -26,9 +26,9 @@
|
|
|
26
26
|
Point,
|
|
27
27
|
RefLine,
|
|
28
28
|
RefLineEvent,
|
|
29
|
-
ScaleType,
|
|
30
29
|
ScatterHandlerEvent,
|
|
31
30
|
ScatterHandlerProps,
|
|
31
|
+
SizeScaleConfig,
|
|
32
32
|
StyleOverrides,
|
|
33
33
|
UserContentProps,
|
|
34
34
|
} from '..'
|
|
@@ -56,10 +56,7 @@
|
|
|
56
56
|
import type { AxisChangeState } from '../core/axis-utils'
|
|
57
57
|
import { AXIS_DEFAULTS, create_axis_loader } from '../core/axis-utils'
|
|
58
58
|
import { get_series_color, get_series_symbol } from '../core/data-transform'
|
|
59
|
-
import {
|
|
60
|
-
create_dimension_tracker,
|
|
61
|
-
create_hover_lock,
|
|
62
|
-
} from '../core/hover-lock.svelte'
|
|
59
|
+
import { create_placed_tween } from '../core/placed-tween.svelte'
|
|
63
60
|
import {
|
|
64
61
|
DEFAULT_MARKERS,
|
|
65
62
|
get_scale_type_name,
|
|
@@ -73,7 +70,7 @@
|
|
|
73
70
|
import type { ComponentProps, Snippet } from 'svelte'
|
|
74
71
|
import { onDestroy, untrack } from 'svelte'
|
|
75
72
|
import type { HTMLAttributes } from 'svelte/elements'
|
|
76
|
-
import {
|
|
73
|
+
import type { TweenOptions } from 'svelte/motion'
|
|
77
74
|
import { SvelteSet } from 'svelte/reactivity'
|
|
78
75
|
import type { Pt } from '../core/fill-utils'
|
|
79
76
|
import {
|
|
@@ -84,16 +81,11 @@
|
|
|
84
81
|
import {
|
|
85
82
|
expand_range_if_needed,
|
|
86
83
|
get_relative_coords,
|
|
87
|
-
|
|
84
|
+
invert_rect_range,
|
|
88
85
|
normalize_y2_sync,
|
|
89
|
-
pan_range_by_pixels,
|
|
90
|
-
PINCH_ZOOM_THRESHOLD,
|
|
91
|
-
remove_drag_listeners,
|
|
92
|
-
sorted_range,
|
|
93
86
|
sync_y2_range,
|
|
94
|
-
to_epoch_num,
|
|
95
|
-
zoom_range_by_factor,
|
|
96
87
|
} from '../core/interactions'
|
|
88
|
+
import { create_pan_zoom } from '../core/pan-zoom.svelte'
|
|
97
89
|
import type { Rect, Sides } from '../core/layout'
|
|
98
90
|
import {
|
|
99
91
|
calc_auto_padding,
|
|
@@ -193,16 +185,8 @@
|
|
|
193
185
|
change?: (
|
|
194
186
|
data: (Point<Metadata> & { series: DataSeries<Metadata> }) | null,
|
|
195
187
|
) => void
|
|
196
|
-
color_scale?:
|
|
197
|
-
|
|
198
|
-
scheme?: D3ColorSchemeName | D3InterpolateName
|
|
199
|
-
value_range?: [number, number]
|
|
200
|
-
} | D3InterpolateName
|
|
201
|
-
size_scale?: {
|
|
202
|
-
type?: ScaleType
|
|
203
|
-
radius_range?: [number, number]
|
|
204
|
-
value_range?: [number, number]
|
|
205
|
-
}
|
|
188
|
+
color_scale?: ColorScaleConfig | D3InterpolateName
|
|
189
|
+
size_scale?: SizeScaleConfig
|
|
206
190
|
color_bar?:
|
|
207
191
|
| (ComponentProps<typeof ColorBar> & {
|
|
208
192
|
margin?: number | Sides
|
|
@@ -277,7 +261,6 @@
|
|
|
277
261
|
|
|
278
262
|
let [width, height] = $state([0, 0])
|
|
279
263
|
let svg_element: SVGElement | null = $state(null) // Bind the SVG element
|
|
280
|
-
let svg_bounding_box: DOMRect | null = $state(null) // Store SVG bounds during drag
|
|
281
264
|
|
|
282
265
|
// Track which specific control properties user has modified
|
|
283
266
|
let touched = new SvelteSet<string>()
|
|
@@ -296,19 +279,14 @@
|
|
|
296
279
|
}),
|
|
297
280
|
)
|
|
298
281
|
|
|
299
|
-
// State for rectangle zoom selection
|
|
300
|
-
let drag_start_coords = $state<Point2D | null>(null)
|
|
301
|
-
let drag_current_coords = $state<Point2D | null>(null)
|
|
302
|
-
|
|
303
282
|
// Zoom/pan state - track both initial (data-driven) and current (after pan/zoom) ranges
|
|
304
|
-
let
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
let zoom_y2_range = $state<[number, number]>([0, 1])
|
|
283
|
+
let ranges = $state<{
|
|
284
|
+
initial: { x: Vec2; x2: Vec2; y: Vec2; y2: Vec2 }
|
|
285
|
+
current: { x: Vec2; x2: Vec2; y: Vec2; y2: Vec2 }
|
|
286
|
+
}>({
|
|
287
|
+
initial: { x: [0, 1], x2: [0, 1], y: [0, 1], y2: [0, 1] },
|
|
288
|
+
current: { x: [0, 1], x2: [0, 1], y: [0, 1], y2: [0, 1] },
|
|
289
|
+
})
|
|
312
290
|
const legend_vis = create_legend_visibility(() => series, (next) => (series = next))
|
|
313
291
|
|
|
314
292
|
// Y2 axis sync configuration
|
|
@@ -319,7 +297,7 @@
|
|
|
319
297
|
// Helper to compute synced y2 range or return fallback when sync disabled
|
|
320
298
|
const get_synced_y2 = (y1_range: Vec2, fallback: Vec2): Vec2 =>
|
|
321
299
|
y2_sync_config.mode !== `none`
|
|
322
|
-
? sync_y2_range(y1_range,
|
|
300
|
+
? sync_y2_range(y1_range, ranges.initial.y2, y2_sync_config)
|
|
323
301
|
: fallback
|
|
324
302
|
|
|
325
303
|
// Effect to update y2 range when sync mode changes - use $effect.pre to capture
|
|
@@ -330,25 +308,15 @@
|
|
|
330
308
|
if (mode !== prev_sync_mode) {
|
|
331
309
|
// When sync mode becomes enabled (or changes), apply sync immediately
|
|
332
310
|
if (mode !== `none`) {
|
|
333
|
-
|
|
311
|
+
ranges.current.y2 = sync_y2_range(ranges.current.y, ranges.initial.y2, y2_sync_config)
|
|
334
312
|
} else {
|
|
335
313
|
// When switching to independent mode, reset Y2 to its data range
|
|
336
|
-
|
|
314
|
+
ranges.current.y2 = [...ranges.initial.y2] as Vec2
|
|
337
315
|
}
|
|
338
316
|
prev_sync_mode = mode
|
|
339
317
|
}
|
|
340
318
|
})
|
|
341
319
|
|
|
342
|
-
// Pan state
|
|
343
|
-
let is_focused = $state(false)
|
|
344
|
-
let shift_held = $state(false)
|
|
345
|
-
let pan_drag_state = $state<
|
|
346
|
-
InitialRanges & { start: { x: number; y: number } } | null
|
|
347
|
-
>(null)
|
|
348
|
-
let touch_state = $state<
|
|
349
|
-
InitialRanges & { start_touches: { x: number; y: number }[] } | null
|
|
350
|
-
>(null)
|
|
351
|
-
|
|
352
320
|
// Fill region hover state
|
|
353
321
|
let hovered_fill_key = $state<string | null>(null)
|
|
354
322
|
|
|
@@ -370,17 +338,6 @@
|
|
|
370
338
|
// State for legend/colorbar placement stability
|
|
371
339
|
let legend_element = $state<HTMLDivElement | undefined>()
|
|
372
340
|
let colorbar_element = $state<HTMLDivElement | undefined>()
|
|
373
|
-
const legend_hover = create_hover_lock()
|
|
374
|
-
const colorbar_hover = create_hover_lock()
|
|
375
|
-
const dim_tracker = create_dimension_tracker()
|
|
376
|
-
let has_initial_legend_placement = $state(false)
|
|
377
|
-
let has_initial_colorbar_placement = $state(false)
|
|
378
|
-
|
|
379
|
-
// Clear pending hover lock timeouts on unmount
|
|
380
|
-
$effect(() => () => {
|
|
381
|
-
legend_hover.cleanup()
|
|
382
|
-
colorbar_hover.cleanup()
|
|
383
|
-
})
|
|
384
341
|
|
|
385
342
|
// Module-level constants to avoid repeated allocations
|
|
386
343
|
// Create and categorize points in a single pass (instead of 3 separate iterations)
|
|
@@ -596,67 +553,52 @@
|
|
|
596
553
|
return { explicit, range }
|
|
597
554
|
}
|
|
598
555
|
|
|
599
|
-
const
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
// X axis: explicit → direct, auto → lazy expand
|
|
605
|
-
if (x.explicit) {
|
|
606
|
-
zoom_x_range = x.range
|
|
607
|
-
} else {
|
|
608
|
-
const result = expand_range_if_needed(initial_x_range, x.range)
|
|
609
|
-
if (result.changed) {
|
|
610
|
-
;[initial_x_range, zoom_x_range] = [result.range, result.range]
|
|
611
|
-
}
|
|
556
|
+
const resolved = {
|
|
557
|
+
x: get_range(final_x_axis, auto_x_range),
|
|
558
|
+
x2: get_range(final_x2_axis, auto_x2_range),
|
|
559
|
+
y: get_range(final_y_axis, auto_y_range),
|
|
560
|
+
y2: get_range(final_y2_axis, auto_y2_range),
|
|
612
561
|
}
|
|
613
562
|
|
|
614
|
-
//
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
zoom_y_range = y.range
|
|
627
|
-
} else {
|
|
628
|
-
const result = expand_range_if_needed(initial_y_range, y.range)
|
|
629
|
-
if (result.changed) {
|
|
630
|
-
;[initial_y_range, zoom_y_range] = [result.range, result.range]
|
|
563
|
+
// untrack reads of `ranges`: this effect also writes it, and tracked reads of the
|
|
564
|
+
// deep proxy would re-trigger the effect on every current/initial write
|
|
565
|
+
for (const axis of [`x`, `x2`, `y`] as const) {
|
|
566
|
+
const { explicit, range } = resolved[axis]
|
|
567
|
+
if (explicit) {
|
|
568
|
+
ranges.current[axis] = range
|
|
569
|
+
} else {
|
|
570
|
+
const result = expand_range_if_needed(untrack(() => ranges.initial[axis]), range)
|
|
571
|
+
if (result.changed) {
|
|
572
|
+
ranges.initial[axis] = result.range
|
|
573
|
+
ranges.current[axis] = result.range
|
|
574
|
+
}
|
|
631
575
|
}
|
|
632
576
|
}
|
|
633
577
|
|
|
634
578
|
// Y2 axis: explicit → direct, else expand initial range then optionally sync
|
|
635
|
-
if (y2.explicit) {
|
|
636
|
-
|
|
579
|
+
if (resolved.y2.explicit) {
|
|
580
|
+
ranges.current.y2 = resolved.y2.range
|
|
637
581
|
} else {
|
|
638
|
-
const result = expand_range_if_needed(
|
|
639
|
-
if (result.changed)
|
|
582
|
+
const result = expand_range_if_needed(untrack(() => ranges.initial.y2), resolved.y2.range)
|
|
583
|
+
if (result.changed) ranges.initial.y2 = result.range
|
|
640
584
|
// Apply sync if enabled, otherwise use expanded range (or keep current if unchanged)
|
|
641
585
|
if (y2_sync_config.mode !== `none`) {
|
|
642
|
-
//
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
untrack(() => zoom_y_range),
|
|
647
|
-
initial_y2_range,
|
|
586
|
+
// Pan/zoom handlers sync y2 themselves.
|
|
587
|
+
ranges.current.y2 = sync_y2_range(
|
|
588
|
+
untrack(() => ranges.current.y),
|
|
589
|
+
untrack(() => ranges.initial.y2),
|
|
648
590
|
y2_sync_config,
|
|
649
591
|
)
|
|
650
592
|
} else if (result.changed) {
|
|
651
|
-
|
|
593
|
+
ranges.current.y2 = result.range
|
|
652
594
|
}
|
|
653
595
|
}
|
|
654
596
|
})
|
|
655
597
|
|
|
656
|
-
let [x_min, x_max] = $derived(
|
|
657
|
-
let [x2_min, x2_max] = $derived(
|
|
658
|
-
let [y_min, y_max] = $derived(
|
|
659
|
-
let [y2_min, y2_max] = $derived(
|
|
598
|
+
let [x_min, x_max] = $derived(ranges.current.x)
|
|
599
|
+
let [x2_min, x2_max] = $derived(ranges.current.x2)
|
|
600
|
+
let [y_min, y_max] = $derived(ranges.current.y)
|
|
601
|
+
let [y2_min, y2_max] = $derived(ranges.current.y2)
|
|
660
602
|
|
|
661
603
|
// Create auto color range
|
|
662
604
|
let auto_color_range = $derived(
|
|
@@ -983,60 +925,23 @@
|
|
|
983
925
|
return legend_placement
|
|
984
926
|
})
|
|
985
927
|
|
|
986
|
-
//
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
{
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
const dims_changed = dim_tracker.has_changed(width, height)
|
|
1004
|
-
if (dims_changed) dim_tracker.update(width, height)
|
|
1005
|
-
|
|
1006
|
-
// Update colorbar position (stable after initial placement unless responsive)
|
|
1007
|
-
if (color_bar_placement) {
|
|
1008
|
-
const is_responsive = color_bar?.responsive ?? false
|
|
1009
|
-
const should_update = dims_changed || (!colorbar_hover.is_locked.current &&
|
|
1010
|
-
(is_responsive || !has_initial_colorbar_placement))
|
|
1011
|
-
|
|
1012
|
-
if (should_update) {
|
|
1013
|
-
tweened_colorbar_coords.set(
|
|
1014
|
-
{ x: color_bar_placement.x, y: color_bar_placement.y },
|
|
1015
|
-
has_initial_colorbar_placement ? undefined : { duration: 0 },
|
|
1016
|
-
)
|
|
1017
|
-
if (colorbar_element && !has_initial_colorbar_placement) {
|
|
1018
|
-
has_initial_colorbar_placement = true
|
|
1019
|
-
}
|
|
1020
|
-
}
|
|
1021
|
-
}
|
|
1022
|
-
|
|
1023
|
-
// Update legend position (stable after initial placement unless responsive)
|
|
1024
|
-
if (legend_manual_position && !legend_is_dragging) {
|
|
1025
|
-
// Immediate update (no animation) for manually dragged positions
|
|
1026
|
-
tweened_legend_coords.set(legend_manual_position, { duration: 0 })
|
|
1027
|
-
} else if (active_legend_placement && !legend_is_dragging) {
|
|
1028
|
-
const is_responsive = legend?.responsive ?? false
|
|
1029
|
-
const should_update = dims_changed || (!legend_hover.is_locked.current &&
|
|
1030
|
-
(is_responsive || !has_initial_legend_placement))
|
|
1031
|
-
|
|
1032
|
-
if (should_update) {
|
|
1033
|
-
tweened_legend_coords.set(
|
|
1034
|
-
{ x: active_legend_placement.x, y: active_legend_placement.y },
|
|
1035
|
-
has_initial_legend_placement ? undefined : { duration: 0 },
|
|
1036
|
-
)
|
|
1037
|
-
if (legend_element) has_initial_legend_placement = true
|
|
1038
|
-
}
|
|
1039
|
-
}
|
|
928
|
+
// Tweened colorbar/legend coordinates with shared placement stability gating
|
|
929
|
+
const colorbar_tween = create_placed_tween({
|
|
930
|
+
placement: () => color_bar_placement,
|
|
931
|
+
dims: () => ({ width, height }),
|
|
932
|
+
responsive: () => color_bar?.responsive ?? false,
|
|
933
|
+
element: () => colorbar_element,
|
|
934
|
+
tween: () => color_bar?.tween,
|
|
935
|
+
})
|
|
936
|
+
const legend_tween = create_placed_tween({
|
|
937
|
+
placement: () => active_legend_placement,
|
|
938
|
+
dims: () => ({ width, height }),
|
|
939
|
+
responsive: () => legend?.responsive ?? false,
|
|
940
|
+
element: () => legend_element,
|
|
941
|
+
tween: () => legend?.tween,
|
|
942
|
+
// Leave coords alone mid-drag; once dragged, the manual position wins permanently
|
|
943
|
+
suspended: () => legend_is_dragging,
|
|
944
|
+
manual_position: () => legend_manual_position,
|
|
1040
945
|
})
|
|
1041
946
|
|
|
1042
947
|
// Generate axis ticks - consolidated into single derived for efficiency
|
|
@@ -1102,250 +1007,76 @@
|
|
|
1102
1007
|
y2_max: measure_max_tick_width(y2_tick_values, final_y2_axis.format ?? ``),
|
|
1103
1008
|
})
|
|
1104
1009
|
|
|
1105
|
-
//
|
|
1106
|
-
|
|
1107
|
-
|
|
1108
|
-
|
|
1109
|
-
|
|
1110
|
-
|
|
1111
|
-
|
|
1112
|
-
|
|
1113
|
-
|
|
1114
|
-
|
|
1115
|
-
|
|
1116
|
-
|
|
1117
|
-
|
|
1118
|
-
|
|
1119
|
-
|
|
1120
|
-
|
|
1121
|
-
|
|
1122
|
-
|
|
1123
|
-
|
|
1124
|
-
|
|
1125
|
-
|
|
1126
|
-
|
|
1127
|
-
|
|
1128
|
-
|
|
1129
|
-
|
|
1130
|
-
|
|
1131
|
-
|
|
1132
|
-
|
|
1133
|
-
|
|
1134
|
-
|
|
1135
|
-
|
|
1136
|
-
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
|
|
1140
|
-
//
|
|
1141
|
-
const
|
|
1142
|
-
|
|
1143
|
-
|
|
1144
|
-
|
|
1145
|
-
|
|
1146
|
-
|
|
1147
|
-
|
|
1148
|
-
|
|
1149
|
-
|
|
1150
|
-
|
|
1151
|
-
|
|
1152
|
-
|
|
1153
|
-
|
|
1154
|
-
|
|
1155
|
-
// X2 axis: invert screen coords using x2 scale
|
|
1156
|
-
if (x2_points.length > 0) {
|
|
1157
|
-
const x2_a = to_epoch_num(x2_scale_fn.invert(drag_start_coords.x))
|
|
1158
|
-
const x2_b = to_epoch_num(x2_scale_fn.invert(drag_current_coords.x))
|
|
1159
|
-
x2_axis = { ...x2_axis, range: sorted_range(x2_a, x2_b) }
|
|
1160
|
-
}
|
|
1161
|
-
|
|
1162
|
-
// Y2 axis: when sync is enabled the y_axis effect derives y2; with sync 'none'
|
|
1163
|
-
// y2 must zoom from the rect directly (parity with BarPlot/Histogram/BoxPlot)
|
|
1164
|
-
if (y2_points.length > 0 && y2_sync_config.mode === `none`) {
|
|
1165
|
-
const y2_a = y2_scale_fn.invert(drag_start_coords.y)
|
|
1166
|
-
const y2_b = y2_scale_fn.invert(drag_current_coords.y)
|
|
1167
|
-
y2_axis = { ...y2_axis, range: sorted_range(y2_a, y2_b) }
|
|
1168
|
-
}
|
|
1010
|
+
// Shared pan/zoom/touch/drag-rect interaction controller. set_range routes y2
|
|
1011
|
+
// writes through get_synced_y2 (write-order contract: y is written before y2, so
|
|
1012
|
+
// the sync reads the just-updated y range).
|
|
1013
|
+
const pan_zoom = create_pan_zoom({
|
|
1014
|
+
ranges: () => ranges.current,
|
|
1015
|
+
scale_type: (axis) =>
|
|
1016
|
+
({ x: final_x_axis, x2: final_x2_axis, y: final_y_axis, y2: final_y2_axis })[axis]
|
|
1017
|
+
.scale_type,
|
|
1018
|
+
// Clamp to at least 1 to avoid Infinity deltas when padding equals container size
|
|
1019
|
+
plot_dims: () => ({
|
|
1020
|
+
width: Math.max(1, width - pad.l - pad.r),
|
|
1021
|
+
height: Math.max(1, height - pad.t - pad.b),
|
|
1022
|
+
}),
|
|
1023
|
+
pan: () => pan,
|
|
1024
|
+
set_range: (axis, range) => {
|
|
1025
|
+
if (axis === `y2`) ranges.current.y2 = get_synced_y2(ranges.current.y, range)
|
|
1026
|
+
else ranges.current[axis] = range
|
|
1027
|
+
},
|
|
1028
|
+
svg: () => svg_element,
|
|
1029
|
+
on_rect_zoom: (start, current) => {
|
|
1030
|
+
// Update axis ranges to trigger reactivity; both x and y must invert to valid
|
|
1031
|
+
// (finite, non-degenerate) ranges or the rect zoom is discarded entirely
|
|
1032
|
+
const next_x = invert_rect_range(x_scale_fn, start.x, current.x)
|
|
1033
|
+
const next_y = invert_rect_range(y_scale_fn, start.y, current.y)
|
|
1034
|
+
if (!next_x || !next_y) return
|
|
1035
|
+
x_axis = { ...x_axis, range: next_x }
|
|
1036
|
+
y_axis = { ...y_axis, range: next_y }
|
|
1037
|
+
|
|
1038
|
+
// X2 axis: invert screen coords using x2 scale
|
|
1039
|
+
const next_x2 = x2_points.length > 0
|
|
1040
|
+
? invert_rect_range(x2_scale_fn, start.x, current.x)
|
|
1041
|
+
: null
|
|
1042
|
+
if (next_x2) x2_axis = { ...x2_axis, range: next_x2 }
|
|
1043
|
+
|
|
1044
|
+
// Y2 axis: when sync is enabled the y_axis effect derives y2; with sync 'none'
|
|
1045
|
+
// y2 must zoom from the rect directly (parity with BarPlot/Histogram/BoxPlot)
|
|
1046
|
+
const next_y2 = y2_points.length > 0 && y2_sync_config.mode === `none`
|
|
1047
|
+
? invert_rect_range(y2_scale_fn, start.y, current.y)
|
|
1048
|
+
: null
|
|
1049
|
+
if (next_y2) y2_axis = { ...y2_axis, range: next_y2 }
|
|
1050
|
+
},
|
|
1051
|
+
on_reset: () => {
|
|
1052
|
+
// Reset to current auto ranges (not stale initial ranges which may have expanded)
|
|
1053
|
+
// This ensures lazy expansion restarts fresh from current data bounds
|
|
1054
|
+
ranges.initial = {
|
|
1055
|
+
x: [...auto_x_range] as Vec2,
|
|
1056
|
+
x2: [...auto_x2_range] as Vec2,
|
|
1057
|
+
y: [...auto_y_range] as Vec2,
|
|
1058
|
+
y2: [...auto_y2_range] as Vec2,
|
|
1169
1059
|
}
|
|
1170
|
-
|
|
1171
|
-
|
|
1172
|
-
|
|
1173
|
-
|
|
1174
|
-
|
|
1175
|
-
svg_bounding_box = null
|
|
1176
|
-
window.removeEventListener(`mousemove`, on_window_mouse_move)
|
|
1177
|
-
window.removeEventListener(`mouseup`, on_window_mouse_up)
|
|
1178
|
-
document.body.style.cursor = `default`
|
|
1179
|
-
}
|
|
1180
|
-
|
|
1181
|
-
// Pan/zoom all four axes from an interaction-start snapshot, each in its own
|
|
1182
|
-
// scale's transform space (log axes pan by a constant factor, linear by a shift).
|
|
1183
|
-
// Plot dims clamped to 1px so degenerate containers can't produce Infinity deltas.
|
|
1184
|
-
const pan_all_axes = (init: InitialRanges, dx_px: number, dy_px: number) => {
|
|
1185
|
-
const plot_width = Math.max(1, width - pad.l - pad.r)
|
|
1186
|
-
const plot_height = Math.max(1, height - pad.t - pad.b)
|
|
1187
|
-
zoom_x_range = pan_range_by_pixels(init.initial_x_range, dx_px, plot_width, final_x_axis.scale_type)
|
|
1188
|
-
zoom_x2_range = pan_range_by_pixels(init.initial_x2_range, dx_px, plot_width, final_x2_axis.scale_type)
|
|
1189
|
-
zoom_y_range = pan_range_by_pixels(init.initial_y_range, dy_px, plot_height, final_y_axis.scale_type)
|
|
1190
|
-
zoom_y2_range = get_synced_y2(
|
|
1191
|
-
zoom_y_range,
|
|
1192
|
-
pan_range_by_pixels(init.initial_y2_range, dy_px, plot_height, final_y2_axis.scale_type),
|
|
1193
|
-
)
|
|
1194
|
-
}
|
|
1195
|
-
const zoom_all_axes = (init: InitialRanges, factor: number) => {
|
|
1196
|
-
zoom_x_range = zoom_range_by_factor(init.initial_x_range, factor, final_x_axis.scale_type)
|
|
1197
|
-
zoom_x2_range = zoom_range_by_factor(init.initial_x2_range, factor, final_x2_axis.scale_type)
|
|
1198
|
-
zoom_y_range = zoom_range_by_factor(init.initial_y_range, factor, final_y_axis.scale_type)
|
|
1199
|
-
zoom_y2_range = get_synced_y2(
|
|
1200
|
-
zoom_y_range,
|
|
1201
|
-
zoom_range_by_factor(init.initial_y2_range, factor, final_y2_axis.scale_type),
|
|
1202
|
-
)
|
|
1203
|
-
}
|
|
1204
|
-
|
|
1205
|
-
// Pan drag handler (drag direction inverted on x for natural pan feel)
|
|
1206
|
-
const on_pan_move = (evt: MouseEvent) => {
|
|
1207
|
-
if (!pan_drag_state) return
|
|
1208
|
-
const sensitivity = pan?.drag_sensitivity ?? 1
|
|
1209
|
-
pan_all_axes(
|
|
1210
|
-
pan_drag_state,
|
|
1211
|
-
-(evt.clientX - pan_drag_state.start.x) * sensitivity,
|
|
1212
|
-
(evt.clientY - pan_drag_state.start.y) * sensitivity,
|
|
1213
|
-
)
|
|
1214
|
-
}
|
|
1215
|
-
|
|
1216
|
-
const on_pan_end = () => {
|
|
1217
|
-
pan_drag_state = null
|
|
1218
|
-
document.body.style.cursor = ``
|
|
1219
|
-
window.removeEventListener(`mousemove`, on_pan_move)
|
|
1220
|
-
window.removeEventListener(`mouseup`, on_pan_end)
|
|
1221
|
-
}
|
|
1222
|
-
|
|
1223
|
-
// Tear down any window listeners + cursor override if the component unmounts mid-drag
|
|
1224
|
-
// (mouseup/panend would otherwise never fire, leaking listeners and a stuck cursor).
|
|
1225
|
-
// onDestroy also runs during SSR teardown, where window/document don't exist.
|
|
1226
|
-
onDestroy(() => {
|
|
1227
|
-
remove_drag_listeners([on_window_mouse_move, on_pan_move], [on_window_mouse_up, on_pan_end])
|
|
1228
|
-
drag_start_coords = null
|
|
1229
|
-
drag_current_coords = null
|
|
1230
|
-
svg_bounding_box = null
|
|
1231
|
-
pan_drag_state = null
|
|
1232
|
-
})
|
|
1233
|
-
|
|
1234
|
-
function handle_mouse_down(evt: MouseEvent) {
|
|
1235
|
-
if (!svg_element) return
|
|
1236
|
-
|
|
1237
|
-
// Check if pan is enabled and shift is held for pan mode
|
|
1238
|
-
const pan_enabled = pan?.enabled !== false
|
|
1239
|
-
if (pan_enabled && evt.shiftKey) {
|
|
1240
|
-
evt.preventDefault()
|
|
1241
|
-
pan_drag_state = {
|
|
1242
|
-
start: { x: evt.clientX, y: evt.clientY },
|
|
1243
|
-
initial_x_range: [...zoom_x_range] as [number, number],
|
|
1244
|
-
initial_x2_range: [...zoom_x2_range] as [number, number],
|
|
1245
|
-
initial_y_range: [...zoom_y_range] as [number, number],
|
|
1246
|
-
initial_y2_range: [...zoom_y2_range] as [number, number],
|
|
1060
|
+
ranges.current = {
|
|
1061
|
+
x: [...auto_x_range] as Vec2,
|
|
1062
|
+
x2: [...auto_x2_range] as Vec2,
|
|
1063
|
+
y: [...auto_y_range] as Vec2,
|
|
1064
|
+
y2: get_synced_y2(auto_y_range, [...auto_y2_range] as Vec2),
|
|
1247
1065
|
}
|
|
1248
|
-
|
|
1249
|
-
|
|
1250
|
-
|
|
1251
|
-
|
|
1252
|
-
|
|
1253
|
-
|
|
1254
|
-
//
|
|
1255
|
-
|
|
1256
|
-
|
|
1257
|
-
|
|
1258
|
-
|
|
1259
|
-
|
|
1260
|
-
|
|
1261
|
-
|
|
1262
|
-
drag_start_coords = coords
|
|
1263
|
-
drag_current_coords = coords
|
|
1264
|
-
|
|
1265
|
-
window.addEventListener(`mousemove`, on_window_mouse_move)
|
|
1266
|
-
window.addEventListener(`mouseup`, on_window_mouse_up)
|
|
1267
|
-
document.body.style.cursor = `crosshair`
|
|
1268
|
-
evt.preventDefault()
|
|
1269
|
-
}
|
|
1270
|
-
|
|
1271
|
-
// Wheel handler for pan (requires focus and shift)
|
|
1272
|
-
function handle_wheel(evt: WheelEvent) {
|
|
1273
|
-
const pan_enabled = pan?.enabled !== false
|
|
1274
|
-
// Only capture wheel when focused AND Shift is held
|
|
1275
|
-
// Use shift_held state (tracked via keydown/keyup) for compatibility with synthetic events
|
|
1276
|
-
if (!pan_enabled || !is_focused || !shift_held) return
|
|
1277
|
-
|
|
1278
|
-
evt.preventDefault()
|
|
1279
|
-
|
|
1280
|
-
// Clamp to at least 1 to avoid Infinity deltas when padding equals container size
|
|
1281
|
-
const plot_width = Math.max(1, width - pad.l - pad.r)
|
|
1282
|
-
const plot_height = Math.max(1, height - pad.t - pad.b)
|
|
1283
|
-
const sensitivity = pan?.wheel_sensitivity ?? 1
|
|
1284
|
-
|
|
1285
|
-
// Pan along the dominant wheel direction
|
|
1286
|
-
// (deltaX for horizontal scroll on trackpads, deltaY for vertical)
|
|
1287
|
-
if (Math.abs(evt.deltaX) > Math.abs(evt.deltaY)) {
|
|
1288
|
-
const dx = evt.deltaX * sensitivity
|
|
1289
|
-
zoom_x_range = pan_range_by_pixels(zoom_x_range, dx, plot_width, final_x_axis.scale_type)
|
|
1290
|
-
zoom_x2_range = pan_range_by_pixels(zoom_x2_range, dx, plot_width, final_x2_axis.scale_type)
|
|
1291
|
-
} else {
|
|
1292
|
-
const dy = evt.deltaY * sensitivity
|
|
1293
|
-
zoom_y_range = pan_range_by_pixels(zoom_y_range, dy, plot_height, final_y_axis.scale_type)
|
|
1294
|
-
zoom_y2_range = get_synced_y2(
|
|
1295
|
-
zoom_y_range,
|
|
1296
|
-
pan_range_by_pixels(zoom_y2_range, dy, plot_height, final_y2_axis.scale_type),
|
|
1297
|
-
)
|
|
1298
|
-
}
|
|
1299
|
-
}
|
|
1300
|
-
|
|
1301
|
-
// Touch handlers for pinch-zoom and two-finger pan
|
|
1302
|
-
function handle_touch_start(evt: TouchEvent) {
|
|
1303
|
-
const touch_enabled = pan?.enabled !== false && pan?.touch_enabled !== false
|
|
1304
|
-
if (!touch_enabled || evt.touches.length !== 2) return
|
|
1305
|
-
|
|
1306
|
-
evt.preventDefault()
|
|
1307
|
-
const touches = Array.from(evt.touches)
|
|
1308
|
-
touch_state = {
|
|
1309
|
-
start_touches: touches.map((touch) => ({ x: touch.clientX, y: touch.clientY })),
|
|
1310
|
-
initial_x_range: [...zoom_x_range] as [number, number],
|
|
1311
|
-
initial_x2_range: [...zoom_x2_range] as [number, number],
|
|
1312
|
-
initial_y_range: [...zoom_y_range] as [number, number],
|
|
1313
|
-
initial_y2_range: [...zoom_y2_range] as [number, number],
|
|
1314
|
-
}
|
|
1315
|
-
}
|
|
1316
|
-
|
|
1317
|
-
function handle_touch_move(evt: TouchEvent) {
|
|
1318
|
-
if (!touch_state || evt.touches.length !== 2) return
|
|
1319
|
-
evt.preventDefault()
|
|
1320
|
-
|
|
1321
|
-
const [t1, t2] = Array.from(evt.touches)
|
|
1322
|
-
const [s1, s2] = touch_state.start_touches
|
|
1323
|
-
|
|
1324
|
-
// Calculate center movement for pan
|
|
1325
|
-
const start_center = { x: (s1.x + s2.x) / 2, y: (s1.y + s2.y) / 2 }
|
|
1326
|
-
const curr_center = {
|
|
1327
|
-
x: (t1.clientX + t2.clientX) / 2,
|
|
1328
|
-
y: (t1.clientY + t2.clientY) / 2,
|
|
1329
|
-
}
|
|
1330
|
-
const dx = curr_center.x - start_center.x
|
|
1331
|
-
const dy = curr_center.y - start_center.y
|
|
1332
|
-
|
|
1333
|
-
// Calculate pinch scale (curr/start so spread = zoom out, pinch = zoom in)
|
|
1334
|
-
const start_dist = Math.hypot(s2.x - s1.x, s2.y - s1.y)
|
|
1335
|
-
// ignore near-coincident touches so curr_dist / start_dist can't blow up the scale
|
|
1336
|
-
if (start_dist < MIN_TOUCH_DISTANCE_PIXELS) return
|
|
1337
|
-
const curr_dist = Math.hypot(t2.clientX - t1.clientX, t2.clientY - t1.clientY)
|
|
1338
|
-
const scale = curr_dist / start_dist
|
|
1339
|
-
|
|
1340
|
-
// Pinch zoom about the view center (spread = zoom in, pinch = zoom out)
|
|
1341
|
-
if (Math.abs(scale - 1) > PINCH_ZOOM_THRESHOLD && scale > Number.EPSILON) {
|
|
1342
|
-
zoom_all_axes(touch_state, scale)
|
|
1343
|
-
} else pan_all_axes(touch_state, -dx, dy)
|
|
1344
|
-
}
|
|
1345
|
-
|
|
1346
|
-
function handle_touch_end() {
|
|
1347
|
-
touch_state = null
|
|
1348
|
-
}
|
|
1066
|
+
// Also reset axis props so future data changes recalculate auto ranges
|
|
1067
|
+
x_axis = { ...x_axis, range: [null, null] }
|
|
1068
|
+
x2_axis = { ...x2_axis, range: [null, null] }
|
|
1069
|
+
y_axis = { ...y_axis, range: [null, null] }
|
|
1070
|
+
y2_axis = { ...y2_axis, range: [null, null] }
|
|
1071
|
+
},
|
|
1072
|
+
// Live tooltip while rect-dragging: update for the closest point inside the
|
|
1073
|
+
// plot bounds, clear when the cursor leaves the svg
|
|
1074
|
+
on_drag_move: (coords, inside_svg) => {
|
|
1075
|
+
if (inside_svg) update_tooltip_point(coords.x, coords.y)
|
|
1076
|
+
else tooltip_point = null
|
|
1077
|
+
},
|
|
1078
|
+
})
|
|
1079
|
+
onDestroy(() => pan_zoom.destroy())
|
|
1349
1080
|
|
|
1350
1081
|
// tooltip logic: find closest point and update tooltip state
|
|
1351
1082
|
function update_tooltip_point(x_rel: number, y_rel: number, evt?: MouseEvent) {
|
|
@@ -1477,7 +1208,7 @@
|
|
|
1477
1208
|
legend_manual_position = { x: constrained_x, y: constrained_y }
|
|
1478
1209
|
}
|
|
1479
1210
|
|
|
1480
|
-
function get_screen_coords(point: Point, data_series?: DataSeries):
|
|
1211
|
+
function get_screen_coords(point: Point, data_series?: DataSeries): Vec2 {
|
|
1481
1212
|
// convert data coordinates to potentially non-finite screen coordinates
|
|
1482
1213
|
const use_x2 = data_series?.x_axis === `x2`
|
|
1483
1214
|
const active_x_scale = use_x2 ? x2_scale_fn : x_scale_fn
|
|
@@ -1658,11 +1389,9 @@
|
|
|
1658
1389
|
evt.preventDefault()
|
|
1659
1390
|
fullscreen = false
|
|
1660
1391
|
}
|
|
1661
|
-
|
|
1662
|
-
}}
|
|
1663
|
-
onkeyup={(evt) => {
|
|
1664
|
-
if (evt.key === `Shift`) shift_held = false
|
|
1392
|
+
pan_zoom.on_window_key_down(evt)
|
|
1665
1393
|
}}
|
|
1394
|
+
onkeyup={pan_zoom.on_window_key_up}
|
|
1666
1395
|
/>
|
|
1667
1396
|
|
|
1668
1397
|
<div
|
|
@@ -1689,46 +1418,27 @@
|
|
|
1689
1418
|
([final_x_axis.label, final_y_axis.label].filter(Boolean).join(` vs `) ||
|
|
1690
1419
|
`Scatter plot`)}
|
|
1691
1420
|
tabindex="0"
|
|
1692
|
-
onfocusin={() => (
|
|
1693
|
-
onfocusout={() => (
|
|
1421
|
+
onfocusin={() => pan_zoom.set_focused(true)}
|
|
1422
|
+
onfocusout={() => pan_zoom.set_focused(false)}
|
|
1694
1423
|
onmouseenter={() => (hovered = true)}
|
|
1695
|
-
onmousedown={
|
|
1424
|
+
onmousedown={pan_zoom.on_mouse_down}
|
|
1696
1425
|
onmousemove={(evt: MouseEvent) => {
|
|
1697
1426
|
// Only find closest point if not actively dragging
|
|
1698
|
-
if (!
|
|
1427
|
+
if (!pan_zoom.drag_start && !pan_zoom.is_pan_dragging) on_mouse_move(evt)
|
|
1699
1428
|
}}
|
|
1700
1429
|
onmouseleave={() => {
|
|
1701
1430
|
hovered = false
|
|
1702
1431
|
tooltip_point = null
|
|
1703
1432
|
on_point_hover?.(null)
|
|
1704
1433
|
}}
|
|
1705
|
-
ondblclick={
|
|
1706
|
-
|
|
1707
|
-
|
|
1708
|
-
|
|
1709
|
-
|
|
1710
|
-
|
|
1711
|
-
|
|
1712
|
-
|
|
1713
|
-
zoom_x2_range = [...auto_x2_range] as [number, number]
|
|
1714
|
-
zoom_y_range = [...auto_y_range] as [number, number]
|
|
1715
|
-
zoom_y2_range = get_synced_y2(auto_y_range, [...auto_y2_range] as Vec2)
|
|
1716
|
-
// Also reset axis props so future data changes recalculate auto ranges
|
|
1717
|
-
x_axis = { ...x_axis, range: [null, null] }
|
|
1718
|
-
x2_axis = { ...x2_axis, range: [null, null] }
|
|
1719
|
-
y_axis = { ...y_axis, range: [null, null] }
|
|
1720
|
-
y2_axis = { ...y2_axis, range: [null, null] }
|
|
1721
|
-
}}
|
|
1722
|
-
onwheel={handle_wheel}
|
|
1723
|
-
ontouchstart={handle_touch_start}
|
|
1724
|
-
ontouchmove={handle_touch_move}
|
|
1725
|
-
ontouchend={handle_touch_end}
|
|
1726
|
-
ontouchcancel={handle_touch_end}
|
|
1727
|
-
style:cursor={pan_drag_state
|
|
1728
|
-
? `grabbing`
|
|
1729
|
-
: shift_held && pan?.enabled !== false
|
|
1730
|
-
? `grab`
|
|
1731
|
-
: `crosshair`}
|
|
1434
|
+
ondblclick={pan_zoom.reset_view}
|
|
1435
|
+
onkeydown={pan_zoom.on_key_down}
|
|
1436
|
+
onwheel={pan_zoom.on_wheel}
|
|
1437
|
+
ontouchstart={pan_zoom.on_touch_start}
|
|
1438
|
+
ontouchmove={pan_zoom.on_touch_move}
|
|
1439
|
+
ontouchend={pan_zoom.on_touch_end}
|
|
1440
|
+
ontouchcancel={pan_zoom.on_touch_end}
|
|
1441
|
+
style:cursor={pan_zoom.cursor}
|
|
1732
1442
|
>
|
|
1733
1443
|
{@render user_content?.({
|
|
1734
1444
|
height,
|
|
@@ -1859,7 +1569,7 @@
|
|
|
1859
1569
|
|
|
1860
1570
|
<!-- Tooltip rendered inside overlay (moved outside SVG for stacking above colorbar) -->
|
|
1861
1571
|
|
|
1862
|
-
<ZoomRect start={
|
|
1572
|
+
<ZoomRect start={pan_zoom.drag_start} current={pan_zoom.drag_current} />
|
|
1863
1573
|
|
|
1864
1574
|
<ZeroLines
|
|
1865
1575
|
display={final_display}
|
|
@@ -1867,10 +1577,10 @@
|
|
|
1867
1577
|
{x2_scale_fn}
|
|
1868
1578
|
{y_scale_fn}
|
|
1869
1579
|
{y2_scale_fn}
|
|
1870
|
-
x_range={
|
|
1871
|
-
x2_range={
|
|
1872
|
-
y_range={
|
|
1873
|
-
y2_range={
|
|
1580
|
+
x_range={ranges.current.x}
|
|
1581
|
+
x2_range={ranges.current.x2}
|
|
1582
|
+
y_range={ranges.current.y}
|
|
1583
|
+
y2_range={ranges.current.y2}
|
|
1874
1584
|
x_scale_type={final_x_axis.scale_type}
|
|
1875
1585
|
x2_scale_type={final_x2_axis.scale_type}
|
|
1876
1586
|
y_scale_type={final_y_axis.scale_type}
|
|
@@ -2138,15 +1848,15 @@
|
|
|
2138
1848
|
] as Vec2}
|
|
2139
1849
|
<div
|
|
2140
1850
|
bind:this={colorbar_element}
|
|
2141
|
-
onmouseenter={() =>
|
|
2142
|
-
onmouseleave={() =>
|
|
1851
|
+
onmouseenter={() => colorbar_tween.set_locked(true)}
|
|
1852
|
+
onmouseleave={() => colorbar_tween.set_locked(false)}
|
|
2143
1853
|
class="colorbar-wrapper"
|
|
2144
1854
|
role="img"
|
|
2145
1855
|
aria-label="Color scale legend"
|
|
2146
1856
|
style={`${
|
|
2147
1857
|
// explicit wrapper_style or auto-outside places the colorbar; else auto-placement coords
|
|
2148
1858
|
effective_cbar_wrapper_style ??
|
|
2149
|
-
`position: absolute; left: ${
|
|
1859
|
+
`position: absolute; left: ${colorbar_tween.coords.current.x}px; top: ${colorbar_tween.coords.current.y}px`}; pointer-events: auto;`}
|
|
2150
1860
|
>
|
|
2151
1861
|
<ColorBar
|
|
2152
1862
|
tick_labels={4}
|
|
@@ -2173,14 +1883,14 @@
|
|
|
2173
1883
|
: legend_auto_outside
|
|
2174
1884
|
? legend_outside_x
|
|
2175
1885
|
: legend_placement
|
|
2176
|
-
?
|
|
1886
|
+
? legend_tween.coords.current.x
|
|
2177
1887
|
: default_x}
|
|
2178
1888
|
{@const current_y = legend_is_dragging && legend_manual_position
|
|
2179
1889
|
? legend_manual_position.y
|
|
2180
1890
|
: legend_auto_outside
|
|
2181
1891
|
? legend_outside_y
|
|
2182
1892
|
: legend_placement
|
|
2183
|
-
?
|
|
1893
|
+
? legend_tween.coords.current.y
|
|
2184
1894
|
: default_y}
|
|
2185
1895
|
<PlotLegend
|
|
2186
1896
|
bind:root_element={legend_element}
|
|
@@ -2188,7 +1898,7 @@
|
|
|
2188
1898
|
on_drag_start={handle_legend_drag_start}
|
|
2189
1899
|
on_drag={handle_legend_drag}
|
|
2190
1900
|
on_drag_end={() => (legend_is_dragging = false)}
|
|
2191
|
-
on_hover_change={
|
|
1901
|
+
on_hover_change={legend_tween.set_locked}
|
|
2192
1902
|
on_item_hover={(item) => {
|
|
2193
1903
|
if (item?.item_type === `fill`) {
|
|
2194
1904
|
// highlight the matching fill in the plot (same state plot fill-hover uses), but skip
|