matterviz 0.3.7 → 0.4.0
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/Icon.svelte +7 -4
- package/dist/MillerIndexInput.svelte +1 -1
- package/dist/api/optimade.js +32 -26
- package/dist/app.css +0 -3
- package/dist/brillouin/BrillouinZone.svelte +8 -3
- package/dist/brillouin/BrillouinZone.svelte.d.ts +2 -1
- package/dist/brillouin/BrillouinZoneScene.svelte +52 -6
- package/dist/brillouin/BrillouinZoneScene.svelte.d.ts +1 -0
- package/dist/brillouin/BrillouinZoneTooltip.svelte +16 -25
- package/dist/brillouin/compute.js +10 -14
- package/dist/chempot-diagram/ChemPotDiagram.svelte +14 -13
- package/dist/chempot-diagram/ChemPotDiagram2D.svelte +12 -15
- package/dist/chempot-diagram/ChemPotDiagram3D.svelte +8 -10
- package/dist/chempot-diagram/async-compute.svelte.js +3 -1
- package/dist/chempot-diagram/chempot-worker.js +2 -1
- package/dist/chempot-diagram/compute.d.ts +1 -1
- package/dist/chempot-diagram/compute.js +17 -19
- package/dist/colors/index.js +6 -5
- package/dist/composition/FormulaFilter.svelte +12 -6
- package/dist/composition/PieChart.svelte +6 -5
- package/dist/composition/chem-sys.d.ts +8 -0
- package/dist/composition/chem-sys.js +85 -0
- package/dist/composition/format.js +4 -2
- package/dist/composition/index.d.ts +1 -0
- package/dist/composition/index.js +1 -0
- package/dist/composition/parse.js +25 -13
- package/dist/convex-hull/ConvexHull2D.svelte +12 -10
- package/dist/convex-hull/ConvexHull3D.svelte +5 -5
- package/dist/convex-hull/ConvexHull4D.svelte +5 -9
- package/dist/convex-hull/ConvexHullStats.svelte +12 -12
- package/dist/convex-hull/GasPressureControls.svelte +4 -4
- package/dist/convex-hull/TemperatureSlider.svelte +2 -2
- package/dist/convex-hull/demo-temperature.d.ts +1 -1
- package/dist/convex-hull/demo-temperature.js +20 -22
- package/dist/convex-hull/gas-thermodynamics.d.ts +2 -2
- package/dist/convex-hull/gas-thermodynamics.js +22 -30
- package/dist/convex-hull/helpers.d.ts +3 -0
- package/dist/convex-hull/helpers.js +17 -9
- package/dist/convex-hull/index.d.ts +1 -1
- package/dist/convex-hull/thermodynamics.js +83 -78
- package/dist/convex-hull/types.d.ts +1 -1
- package/dist/coordination/CoordinationBarPlot.svelte +23 -23
- package/dist/coordination/CoordinationBarPlot.svelte.d.ts +1 -1
- package/dist/element/ElementTile.svelte.d.ts +1 -1
- package/dist/fermi-surface/FermiSlice.svelte +13 -5
- package/dist/fermi-surface/FermiSurface.svelte +11 -5
- package/dist/fermi-surface/FermiSurface.svelte.d.ts +1 -1
- package/dist/fermi-surface/FermiSurfaceControls.svelte +1 -1
- package/dist/fermi-surface/FermiSurfaceScene.svelte +3 -0
- package/dist/fermi-surface/FermiSurfaceTooltip.svelte +8 -34
- package/dist/fermi-surface/compute.js +59 -59
- package/dist/fermi-surface/export.js +3 -2
- package/dist/fermi-surface/parse.js +7 -4
- package/dist/fermi-surface/types.d.ts +1 -0
- package/dist/heatmap-matrix/HeatmapMatrix.svelte +23 -21
- package/dist/heatmap-matrix/index.js +1 -1
- package/dist/io/decompress.js +4 -2
- package/dist/io/export.d.ts +4 -4
- package/dist/io/export.js +47 -25
- package/dist/io/fetch.js +5 -1
- package/dist/io/file-drop.d.ts +1 -1
- package/dist/io/file-drop.js +35 -36
- package/dist/io/url-drop.js +64 -33
- package/dist/isosurface/parse.js +6 -7
- package/dist/isosurface/slice.js +5 -4
- package/dist/isosurface/types.js +1 -1
- package/dist/keyboard.d.ts +3 -0
- package/dist/keyboard.js +23 -0
- package/dist/labels.d.ts +1 -1
- package/dist/labels.js +8 -7
- package/dist/layout/PropertyFilter.svelte +3 -2
- package/dist/layout/SettingsSection.svelte +1 -1
- package/dist/layout/json-tree/JsonNode.svelte +1 -1
- package/dist/layout/json-tree/JsonTree.svelte +2 -2
- package/dist/layout/json-tree/utils.js +5 -4
- package/dist/marching-cubes.js +8 -13
- package/dist/math.d.ts +5 -1
- package/dist/math.js +24 -9
- package/dist/overlays/DraggablePane.svelte +4 -4
- package/dist/periodic-table/PeriodicTable.svelte +20 -9
- package/dist/periodic-table/PropertySelect.svelte +1 -0
- package/dist/phase-diagram/IsobaricBinaryPhaseDiagram.svelte +9 -3
- package/dist/phase-diagram/IsobaricBinaryPhaseDiagram.svelte.d.ts +1 -1
- package/dist/phase-diagram/PhaseDiagramControls.svelte.d.ts +1 -1
- package/dist/phase-diagram/PhaseDiagramEditorPane.svelte +2 -1
- package/dist/phase-diagram/PhaseDiagramTooltip.svelte +1 -1
- package/dist/phase-diagram/build-diagram.js +2 -2
- package/dist/phase-diagram/parse.js +6 -5
- package/dist/phase-diagram/types.d.ts +1 -1
- package/dist/phase-diagram/utils.d.ts +3 -3
- package/dist/phase-diagram/utils.js +8 -12
- package/dist/plot/{BarPlot.svelte → bar/BarPlot.svelte} +229 -587
- package/dist/plot/{BarPlot.svelte.d.ts → bar/BarPlot.svelte.d.ts} +5 -5
- package/dist/plot/{BarPlotControls.svelte → bar/BarPlotControls.svelte} +6 -5
- package/dist/plot/{BarPlotControls.svelte.d.ts → bar/BarPlotControls.svelte.d.ts} +3 -3
- package/dist/plot/{SpacegroupBarPlot.svelte → bar/SpacegroupBarPlot.svelte} +6 -6
- package/dist/plot/{SpacegroupBarPlot.svelte.d.ts → bar/SpacegroupBarPlot.svelte.d.ts} +1 -1
- package/dist/plot/bar/data.d.ts +40 -0
- package/dist/plot/bar/data.js +154 -0
- package/dist/plot/bar/geometry.d.ts +39 -0
- package/dist/plot/bar/geometry.js +60 -0
- package/dist/plot/bar/index.d.ts +3 -0
- package/dist/plot/bar/index.js +3 -0
- package/dist/plot/box/BoxPlot.svelte +1462 -0
- package/dist/plot/box/BoxPlot.svelte.d.ts +94 -0
- package/dist/plot/box/BoxPlotControls.svelte +109 -0
- package/dist/plot/box/BoxPlotControls.svelte.d.ts +19 -0
- package/dist/plot/box/Violin.svelte +14 -0
- package/dist/plot/box/Violin.svelte.d.ts +70 -0
- package/dist/plot/box/box-plot.d.ts +55 -0
- package/dist/plot/box/box-plot.js +126 -0
- package/dist/plot/box/index.d.ts +5 -0
- package/dist/plot/box/index.js +5 -0
- package/dist/plot/box/kde.d.ts +16 -0
- package/dist/plot/box/kde.js +160 -0
- package/dist/plot/box/quantile.d.ts +3 -0
- package/dist/plot/box/quantile.js +53 -0
- package/dist/plot/{auto-place.js → core/auto-place.js} +2 -2
- package/dist/plot/core/axis-utils.d.ts +46 -0
- package/dist/plot/core/axis-utils.js +110 -0
- package/dist/plot/{AxisLabel.svelte → core/components/AxisLabel.svelte} +2 -2
- package/dist/plot/{AxisLabel.svelte.d.ts → core/components/AxisLabel.svelte.d.ts} +1 -1
- package/dist/plot/{ColorBar.svelte → core/components/ColorBar.svelte} +36 -33
- package/dist/plot/{ColorBar.svelte.d.ts → core/components/ColorBar.svelte.d.ts} +2 -2
- package/dist/plot/{ColorScaleSelect.svelte → core/components/ColorScaleSelect.svelte} +4 -3
- package/dist/plot/{ColorScaleSelect.svelte.d.ts → core/components/ColorScaleSelect.svelte.d.ts} +2 -2
- package/dist/plot/core/components/ControlPane.svelte +46 -0
- package/dist/plot/core/components/ControlPane.svelte.d.ts +13 -0
- package/dist/plot/{FillArea.svelte → core/components/FillArea.svelte} +17 -6
- package/dist/plot/{FillArea.svelte.d.ts → core/components/FillArea.svelte.d.ts} +1 -1
- package/dist/plot/{InteractiveAxisLabel.svelte → core/components/InteractiveAxisLabel.svelte} +3 -3
- package/dist/plot/{InteractiveAxisLabel.svelte.d.ts → core/components/InteractiveAxisLabel.svelte.d.ts} +2 -2
- package/dist/plot/{Line.svelte → core/components/Line.svelte} +30 -13
- package/dist/plot/{PlotAxis.svelte → core/components/PlotAxis.svelte} +7 -5
- package/dist/plot/{PlotAxis.svelte.d.ts → core/components/PlotAxis.svelte.d.ts} +3 -2
- package/dist/plot/{PlotControls.svelte → core/components/PlotControls.svelte} +17 -29
- package/dist/plot/core/components/PlotControls.svelte.d.ts +4 -0
- package/dist/plot/{PlotLegend.svelte → core/components/PlotLegend.svelte} +21 -10
- package/dist/plot/{PlotLegend.svelte.d.ts → core/components/PlotLegend.svelte.d.ts} +3 -2
- package/dist/plot/{PlotTooltip.svelte → core/components/PlotTooltip.svelte} +17 -1
- package/dist/plot/{PlotTooltip.svelte.d.ts → core/components/PlotTooltip.svelte.d.ts} +8 -0
- package/dist/plot/{PortalSelect.svelte → core/components/PortalSelect.svelte} +11 -7
- package/dist/plot/{ReferenceLine.svelte → core/components/ReferenceLine.svelte} +3 -3
- package/dist/plot/{ReferenceLine.svelte.d.ts → core/components/ReferenceLine.svelte.d.ts} +1 -1
- package/dist/plot/{ReferenceLine3D.svelte → core/components/ReferenceLine3D.svelte} +4 -4
- package/dist/plot/{ReferenceLine3D.svelte.d.ts → core/components/ReferenceLine3D.svelte.d.ts} +2 -2
- package/dist/plot/{ReferencePlane.svelte → core/components/ReferencePlane.svelte} +7 -7
- package/dist/plot/{ReferencePlane.svelte.d.ts → core/components/ReferencePlane.svelte.d.ts} +2 -2
- package/dist/plot/{ZeroLines.svelte → core/components/ZeroLines.svelte} +3 -3
- package/dist/plot/{ZeroLines.svelte.d.ts → core/components/ZeroLines.svelte.d.ts} +3 -3
- package/dist/plot/{ZoomRect.svelte → core/components/ZoomRect.svelte} +1 -1
- package/dist/plot/{ZoomRect.svelte.d.ts → core/components/ZoomRect.svelte.d.ts} +1 -1
- package/dist/plot/core/components/index.d.ts +17 -0
- package/dist/plot/core/components/index.js +17 -0
- package/dist/plot/{data-cleaning.d.ts → core/data-cleaning.d.ts} +71 -1
- package/dist/plot/{data-cleaning.js → core/data-cleaning.js} +3 -5
- package/dist/plot/{data-transform.d.ts → core/data-transform.d.ts} +2 -2
- package/dist/plot/{data-transform.js → core/data-transform.js} +3 -3
- package/dist/plot/core/fill-utils.d.ts +33 -0
- package/dist/plot/core/fill-utils.js +388 -0
- package/dist/plot/{hover-lock.svelte.js → core/hover-lock.svelte.js} +5 -6
- package/dist/plot/core/index.d.ts +10 -0
- package/dist/plot/core/index.js +11 -0
- package/dist/plot/core/interactions.d.ts +35 -0
- package/dist/plot/core/interactions.js +195 -0
- package/dist/plot/{layout.d.ts → core/layout.d.ts} +1 -0
- package/dist/plot/{layout.js → core/layout.js} +16 -8
- package/dist/plot/{reference-line.d.ts → core/reference-line.d.ts} +1 -1
- package/dist/plot/{reference-line.js → core/reference-line.js} +23 -36
- package/dist/plot/{scales.d.ts → core/scales.d.ts} +2 -2
- package/dist/plot/{scales.js → core/scales.js} +84 -85
- package/dist/plot/core/svg.d.ts +2 -0
- package/dist/plot/core/svg.js +41 -0
- package/dist/plot/{types.d.ts → core/types.d.ts} +19 -79
- package/dist/plot/{types.js → core/types.js} +1 -1
- package/dist/plot/{utils → core/utils}/label-placement.d.ts +2 -2
- package/dist/plot/core/utils/series-visibility.d.ts +26 -0
- package/dist/plot/{utils → core/utils}/series-visibility.js +29 -2
- package/dist/plot/core/utils.d.ts +11 -0
- package/dist/plot/core/utils.js +27 -0
- package/dist/plot/{Histogram.svelte → histogram/Histogram.svelte} +154 -294
- package/dist/plot/{Histogram.svelte.d.ts → histogram/Histogram.svelte.d.ts} +2 -2
- package/dist/plot/{HistogramControls.svelte → histogram/HistogramControls.svelte} +6 -6
- package/dist/plot/{HistogramControls.svelte.d.ts → histogram/HistogramControls.svelte.d.ts} +4 -4
- package/dist/plot/histogram/index.d.ts +2 -0
- package/dist/plot/histogram/index.js +2 -0
- package/dist/plot/index.d.ts +8 -41
- package/dist/plot/index.js +10 -39
- package/dist/plot/sankey/Sankey.svelte +700 -0
- package/dist/plot/sankey/Sankey.svelte.d.ts +74 -0
- package/dist/plot/sankey/SankeyControls.svelte +98 -0
- package/dist/plot/sankey/SankeyControls.svelte.d.ts +19 -0
- package/dist/plot/sankey/index.d.ts +4 -0
- package/dist/plot/sankey/index.js +3 -0
- package/dist/plot/sankey/sankey-types.d.ts +42 -0
- package/dist/plot/sankey/sankey-types.js +4 -0
- package/dist/plot/sankey/sankey.d.ts +52 -0
- package/dist/plot/sankey/sankey.js +187 -0
- package/dist/plot/{BinnedScatterPlot.svelte → scatter/BinnedScatterPlot.svelte} +61 -59
- package/dist/plot/{BinnedScatterPlot.svelte.d.ts → scatter/BinnedScatterPlot.svelte.d.ts} +4 -4
- package/dist/plot/{ElementScatter.svelte → scatter/ElementScatter.svelte} +6 -6
- package/dist/plot/{ElementScatter.svelte.d.ts → scatter/ElementScatter.svelte.d.ts} +2 -2
- package/dist/plot/{ScatterPlot.svelte → scatter/ScatterPlot.svelte} +221 -642
- package/dist/plot/{ScatterPlot.svelte.d.ts → scatter/ScatterPlot.svelte.d.ts} +7 -7
- package/dist/plot/{ScatterPlotControls.svelte → scatter/ScatterPlotControls.svelte} +6 -5
- package/dist/plot/{ScatterPlotControls.svelte.d.ts → scatter/ScatterPlotControls.svelte.d.ts} +1 -1
- package/dist/plot/{ScatterPoint.svelte → scatter/ScatterPoint.svelte} +7 -7
- package/dist/plot/{ScatterPoint.svelte.d.ts → scatter/ScatterPoint.svelte.d.ts} +3 -3
- package/dist/plot/{adaptive-density.d.ts → scatter/adaptive-density.d.ts} +14 -4
- package/dist/plot/{adaptive-density.js → scatter/adaptive-density.js} +46 -20
- package/dist/plot/{binned-scatter-types.d.ts → scatter/binned-scatter-types.d.ts} +3 -3
- package/dist/plot/scatter/index.d.ts +7 -0
- package/dist/plot/scatter/index.js +5 -0
- package/dist/plot/scatter/scatter-data.d.ts +19 -0
- package/dist/plot/scatter/scatter-data.js +212 -0
- package/dist/plot/{ScatterPlot3D.svelte → scatter-3d/ScatterPlot3D.svelte} +12 -10
- package/dist/plot/{ScatterPlot3D.svelte.d.ts → scatter-3d/ScatterPlot3D.svelte.d.ts} +7 -7
- package/dist/plot/{ScatterPlot3DControls.svelte → scatter-3d/ScatterPlot3DControls.svelte} +5 -4
- package/dist/plot/{ScatterPlot3DControls.svelte.d.ts → scatter-3d/ScatterPlot3DControls.svelte.d.ts} +2 -2
- package/dist/plot/{ScatterPlot3DScene.svelte → scatter-3d/ScatterPlot3DScene.svelte} +11 -11
- package/dist/plot/{ScatterPlot3DScene.svelte.d.ts → scatter-3d/ScatterPlot3DScene.svelte.d.ts} +3 -3
- package/dist/plot/{Surface3D.svelte → scatter-3d/Surface3D.svelte} +1 -1
- package/dist/plot/{Surface3D.svelte.d.ts → scatter-3d/Surface3D.svelte.d.ts} +1 -1
- package/dist/plot/scatter-3d/index.d.ts +4 -0
- package/dist/plot/scatter-3d/index.js +4 -0
- package/dist/plot/sunburst/Sunburst.svelte +1045 -0
- package/dist/plot/sunburst/Sunburst.svelte.d.ts +96 -0
- package/dist/plot/sunburst/SunburstControls.svelte +200 -0
- package/dist/plot/sunburst/SunburstControls.svelte.d.ts +26 -0
- package/dist/plot/sunburst/index.d.ts +4 -0
- package/dist/plot/sunburst/index.js +4 -0
- package/dist/plot/sunburst/render.d.ts +34 -0
- package/dist/plot/sunburst/render.js +122 -0
- package/dist/plot/sunburst/sunburst.d.ts +62 -0
- package/dist/plot/sunburst/sunburst.js +266 -0
- package/dist/rdf/RdfPlot.svelte +2 -1
- package/dist/rdf/calc-rdf.js +11 -24
- package/dist/sanitize.js +1 -1
- package/dist/settings.d.ts +65 -1
- package/dist/settings.js +262 -0
- package/dist/spectral/Bands.svelte +39 -29
- package/dist/spectral/Bands.svelte.d.ts +3 -4
- package/dist/spectral/BandsAndDos.svelte +1 -1
- package/dist/spectral/BrillouinBandsDos.svelte +39 -27
- package/dist/spectral/Dos.svelte +10 -19
- package/dist/spectral/Dos.svelte.d.ts +2 -2
- package/dist/spectral/helpers.d.ts +3 -1
- package/dist/spectral/helpers.js +95 -29
- package/dist/structure/AtomLegend.svelte +8 -9
- package/dist/structure/CellSelect.svelte +1 -2
- package/dist/structure/Cylinder.svelte +12 -8
- package/dist/structure/Cylinder.svelte.d.ts +4 -1
- package/dist/structure/Structure.svelte +78 -72
- package/dist/structure/Structure.svelte.d.ts +1 -1
- package/dist/structure/StructureInfoPane.svelte +5 -6
- package/dist/structure/StructureScene.svelte +11 -10
- package/dist/structure/atom-properties.js +6 -6
- package/dist/structure/bond-order-perception.js +1 -1
- package/dist/structure/bonding.d.ts +1 -0
- package/dist/structure/bonding.js +43 -15
- package/dist/structure/export.js +27 -23
- package/dist/structure/index.d.ts +2 -4
- package/dist/structure/index.js +1 -3
- package/dist/structure/label-placement.js +4 -4
- package/dist/structure/measure.d.ts +3 -2
- package/dist/structure/measure.js +6 -5
- package/dist/structure/parse.js +121 -103
- package/dist/structure/pbc.js +4 -0
- package/dist/symmetry/SymmetryStats.svelte +2 -2
- package/dist/symmetry/index.d.ts +1 -1
- package/dist/symmetry/index.js +22 -24
- package/dist/symmetry/spacegroups.d.ts +7 -0
- package/dist/symmetry/spacegroups.js +48 -13
- package/dist/table/HeatmapTable.svelte +63 -11
- package/dist/table/HeatmapTable.svelte.d.ts +1 -1
- package/dist/table/index.d.ts +1 -3
- package/dist/table/index.js +1 -1
- package/dist/theme/index.js +8 -8
- package/dist/tooltip/KCoords.svelte +45 -0
- package/dist/tooltip/KCoords.svelte.d.ts +8 -0
- package/dist/tooltip/index.d.ts +1 -0
- package/dist/tooltip/index.js +1 -0
- package/dist/trajectory/Trajectory.svelte +66 -40
- package/dist/trajectory/Trajectory.svelte.d.ts +2 -1
- package/dist/trajectory/TrajectoryExportPane.svelte +2 -1
- package/dist/trajectory/TrajectoryInfoPane.svelte +2 -1
- package/dist/trajectory/format-detect.d.ts +1 -0
- package/dist/trajectory/format-detect.js +25 -11
- package/dist/trajectory/frame-reader.js +17 -50
- package/dist/trajectory/helpers.js +1 -1
- package/dist/trajectory/index.js +1 -1
- package/dist/trajectory/parse/hdf5.js +1 -1
- package/dist/trajectory/parse/index.js +14 -6
- package/dist/trajectory/parse/vasp.js +36 -17
- package/dist/trajectory/parse/xyz.d.ts +24 -0
- package/dist/trajectory/parse/xyz.js +102 -89
- package/dist/trajectory/plotting.d.ts +1 -1
- package/dist/trajectory/plotting.js +15 -15
- package/dist/utils.d.ts +1 -0
- package/dist/utils.js +6 -4
- package/dist/xrd/XrdPlot.svelte +2 -1
- package/dist/xrd/calc-xrd.js +15 -12
- package/dist/xrd/parse.js +2 -2
- package/package.json +22 -18
- package/dist/plot/PlotControls.svelte.d.ts +0 -4
- package/dist/plot/axis-utils.d.ts +0 -19
- package/dist/plot/axis-utils.js +0 -78
- package/dist/plot/defaults.d.ts +0 -19
- package/dist/plot/defaults.js +0 -9
- package/dist/plot/fill-utils.d.ts +0 -46
- package/dist/plot/fill-utils.js +0 -322
- package/dist/plot/interactions.d.ts +0 -12
- package/dist/plot/interactions.js +0 -101
- package/dist/plot/svg.d.ts +0 -1
- package/dist/plot/svg.js +0 -11
- package/dist/plot/utils/series-visibility.d.ts +0 -15
- package/dist/plot/utils.d.ts +0 -1
- package/dist/plot/utils.js +0 -14
- /package/dist/plot/{auto-place.d.ts → core/auto-place.d.ts} +0 -0
- /package/dist/plot/{Line.svelte.d.ts → core/components/Line.svelte.d.ts} +0 -0
- /package/dist/plot/{PortalSelect.svelte.d.ts → core/components/PortalSelect.svelte.d.ts} +0 -0
- /package/dist/plot/{hover-lock.svelte.d.ts → core/hover-lock.svelte.d.ts} +0 -0
- /package/dist/plot/{utils → core/utils}/label-placement.js +0 -0
- /package/dist/plot/{binned-scatter-types.js → scatter/binned-scatter-types.js} +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
|
-
import { format_value } from '
|
|
3
|
-
import { FullscreenToggle, set_fullscreen_bg } from '
|
|
2
|
+
import { format_value } from '../../labels'
|
|
3
|
+
import { FullscreenToggle, set_fullscreen_bg } from '../../layout'
|
|
4
4
|
import type {
|
|
5
5
|
AxisLoadError,
|
|
6
6
|
BarStyle,
|
|
@@ -9,50 +9,55 @@
|
|
|
9
9
|
PanConfig,
|
|
10
10
|
RefLine,
|
|
11
11
|
RefLineEvent,
|
|
12
|
-
} from '
|
|
12
|
+
} from '..'
|
|
13
13
|
import {
|
|
14
14
|
compute_element_placement,
|
|
15
15
|
HistogramControls,
|
|
16
16
|
PlotAxis,
|
|
17
17
|
PlotLegend,
|
|
18
18
|
ReferenceLine,
|
|
19
|
-
} from '
|
|
20
|
-
import type { AxisChangeState } from '
|
|
21
|
-
import {
|
|
22
|
-
import { extract_series_color, prepare_legend_data } from '
|
|
23
|
-
import { AXIS_DEFAULTS } from './defaults'
|
|
19
|
+
} from '..'
|
|
20
|
+
import type { AxisChangeState } from '../core/axis-utils'
|
|
21
|
+
import { AXIS_DEFAULTS, create_axis_loader } from '../core/axis-utils'
|
|
22
|
+
import { extract_series_color, prepare_legend_data } from '../core/data-transform'
|
|
24
23
|
import {
|
|
25
24
|
create_dimension_tracker,
|
|
26
25
|
create_hover_lock,
|
|
27
|
-
} from '
|
|
26
|
+
} from '../core/hover-lock.svelte'
|
|
27
|
+
import { create_legend_visibility } from '../core/utils/series-visibility'
|
|
28
28
|
import {
|
|
29
29
|
get_relative_coords,
|
|
30
|
-
|
|
30
|
+
MIN_TOUCH_DISTANCE_PIXELS,
|
|
31
|
+
pan_range_by_pixels,
|
|
31
32
|
PINCH_ZOOM_THRESHOLD,
|
|
32
|
-
|
|
33
|
-
|
|
33
|
+
remove_drag_listeners,
|
|
34
|
+
resolve_axis_ranges,
|
|
35
|
+
sorted_range,
|
|
36
|
+
vec2_equal,
|
|
37
|
+
zoom_range_by_factor,
|
|
38
|
+
} from '../core/interactions'
|
|
34
39
|
import {
|
|
35
40
|
calc_auto_padding,
|
|
36
|
-
constrain_tooltip_position,
|
|
37
41
|
filter_padding,
|
|
38
42
|
LABEL_GAP_DEFAULT,
|
|
43
|
+
y2_axis_label_x,
|
|
39
44
|
measure_max_tick_width,
|
|
40
|
-
} from '
|
|
45
|
+
} from '../core/layout'
|
|
41
46
|
import {
|
|
42
47
|
build_obstacles_norm,
|
|
43
48
|
clip_bar,
|
|
44
49
|
has_explicit_position,
|
|
45
50
|
measured_footprint,
|
|
46
51
|
place_decorations,
|
|
47
|
-
} from '
|
|
48
|
-
import type { IndexedRefLine } from '
|
|
49
|
-
import { group_ref_lines_by_z, index_ref_lines } from '
|
|
52
|
+
} from '../core/auto-place'
|
|
53
|
+
import type { IndexedRefLine } from '../core/reference-line'
|
|
54
|
+
import { group_ref_lines_by_z, index_ref_lines } from '../core/reference-line'
|
|
50
55
|
import {
|
|
51
56
|
create_scale,
|
|
52
57
|
generate_ticks,
|
|
53
58
|
get_nice_data_range,
|
|
54
59
|
get_tick_label,
|
|
55
|
-
} from '
|
|
60
|
+
} from '../core/scales'
|
|
56
61
|
import type {
|
|
57
62
|
BasePlotProps,
|
|
58
63
|
DataSeries,
|
|
@@ -60,19 +65,20 @@
|
|
|
60
65
|
LegendConfig,
|
|
61
66
|
PlotConfig,
|
|
62
67
|
ScaleType,
|
|
63
|
-
} from '
|
|
64
|
-
import { get_scale_type_name } from '
|
|
65
|
-
import ZeroLines from '
|
|
66
|
-
import ZoomRect from '
|
|
67
|
-
import { DEFAULTS } from '
|
|
68
|
+
} from '../core/types'
|
|
69
|
+
import { get_scale_type_name } from '../core/types'
|
|
70
|
+
import ZeroLines from '../core/components/ZeroLines.svelte'
|
|
71
|
+
import ZoomRect from '../core/components/ZoomRect.svelte'
|
|
72
|
+
import { DEFAULTS } from '../../settings'
|
|
68
73
|
import { bin, max } from 'd3-array'
|
|
69
74
|
import type { Snippet } from 'svelte'
|
|
70
|
-
import { untrack } from 'svelte'
|
|
75
|
+
import { onDestroy, untrack } from 'svelte'
|
|
71
76
|
import type { HTMLAttributes } from 'svelte/elements'
|
|
72
77
|
import { Tween } from 'svelte/motion'
|
|
73
|
-
import type { Vec2 } from '
|
|
74
|
-
import PlotTooltip from '
|
|
75
|
-
import { bar_path } from '
|
|
78
|
+
import type { Vec2 } from '../../math'
|
|
79
|
+
import PlotTooltip from '../core/components/PlotTooltip.svelte'
|
|
80
|
+
import { bar_path } from '../core/svg'
|
|
81
|
+
import { unique_id } from '../core/utils'
|
|
76
82
|
|
|
77
83
|
let {
|
|
78
84
|
series = $bindable([]),
|
|
@@ -81,10 +87,6 @@
|
|
|
81
87
|
y_axis: y_axis_init = {},
|
|
82
88
|
y2_axis: y2_axis_init = {},
|
|
83
89
|
display: display_init = DEFAULTS.histogram.display,
|
|
84
|
-
x_range = [null, null],
|
|
85
|
-
x2_range = [null, null],
|
|
86
|
-
y_range = [null, null],
|
|
87
|
-
y2_range = [null, null],
|
|
88
90
|
range_padding = 0.05,
|
|
89
91
|
padding = { t: 20, b: 60, l: 60, r: 20 },
|
|
90
92
|
bins = $bindable(100),
|
|
@@ -173,10 +175,10 @@
|
|
|
173
175
|
...x2_axis_init,
|
|
174
176
|
})))
|
|
175
177
|
let y_axis = $state(untrack(() => ({ ...axis_state_defaults, ...y_axis_init })))
|
|
176
|
-
// y2
|
|
178
|
+
// y2 title stays vertically centered; its x position is computed by y2_axis_label_x
|
|
177
179
|
let y2_axis = $state(untrack(() => ({
|
|
178
180
|
...axis_state_defaults,
|
|
179
|
-
label_shift: { x: 0, y:
|
|
181
|
+
label_shift: { x: 0, y: 0 },
|
|
180
182
|
...y2_axis_init,
|
|
181
183
|
})))
|
|
182
184
|
let display = $state(
|
|
@@ -194,7 +196,7 @@
|
|
|
194
196
|
let [width, height] = $state([0, 0])
|
|
195
197
|
let wrapper: HTMLDivElement | undefined = $state()
|
|
196
198
|
let svg_element: SVGElement | null = $state(null)
|
|
197
|
-
|
|
199
|
+
const clip_path_id = unique_id(`histogram-clip`) // stable, collision-resistant (see unique_id)
|
|
198
200
|
let hover_info = $state<HistogramHandlerProps | null>(null)
|
|
199
201
|
|
|
200
202
|
// Reference line hover state
|
|
@@ -206,7 +208,6 @@
|
|
|
206
208
|
// Compute ref_lines with index and group by z-index (using shared utilities)
|
|
207
209
|
let indexed_ref_lines = $derived(index_ref_lines(ref_lines))
|
|
208
210
|
let ref_lines_by_z = $derived(group_ref_lines_by_z(indexed_ref_lines))
|
|
209
|
-
let tooltip_el = $state<HTMLDivElement | undefined>()
|
|
210
211
|
let drag_state = $state<{
|
|
211
212
|
start: { x: number; y: number } | null
|
|
212
213
|
current: { x: number; y: number } | null
|
|
@@ -270,11 +271,12 @@
|
|
|
270
271
|
)
|
|
271
272
|
|
|
272
273
|
let auto_ranges = $derived.by(() => {
|
|
273
|
-
|
|
274
|
+
// Only x1 series contribute to the x1 auto-range (x2 series get their own domain below)
|
|
275
|
+
const x1_values = selected_series.flatMap((srs) => srs.x_axis === `x2` ? [] : srs.y)
|
|
274
276
|
const auto_x = get_nice_data_range(
|
|
275
|
-
|
|
277
|
+
x1_values.map((val) => ({ x: val, y: 0 })),
|
|
276
278
|
({ x }) => x,
|
|
277
|
-
|
|
279
|
+
final_x_axis.range ?? [null, null],
|
|
278
280
|
final_x_axis.scale_type ?? `linear`,
|
|
279
281
|
range_padding,
|
|
280
282
|
false,
|
|
@@ -285,7 +287,7 @@
|
|
|
285
287
|
? get_nice_data_range(
|
|
286
288
|
x2_values.map((val) => ({ x: val, y: 0 })),
|
|
287
289
|
({ x }) => x,
|
|
288
|
-
|
|
290
|
+
final_x2_axis.range ?? [null, null],
|
|
289
291
|
final_x2_axis.scale_type ?? `linear`,
|
|
290
292
|
range_padding,
|
|
291
293
|
false,
|
|
@@ -295,20 +297,22 @@
|
|
|
295
297
|
// Calculate y-range for a specific set of series
|
|
296
298
|
const calc_y_range = (
|
|
297
299
|
series_list: typeof selected_series,
|
|
298
|
-
y_limit:
|
|
300
|
+
y_limit: [number | null, number | null],
|
|
299
301
|
scale_type: ScaleType,
|
|
300
302
|
): Vec2 => {
|
|
301
303
|
const type_name = get_scale_type_name(scale_type)
|
|
302
|
-
if (
|
|
304
|
+
if (series_list.length === 0) {
|
|
303
305
|
const fallback = type_name === `log` ? 1 : 0
|
|
304
306
|
return [fallback, 1]
|
|
305
307
|
}
|
|
306
|
-
|
|
308
|
+
// Bin each series over the domain of the x-axis it renders on (d3 bin() drops
|
|
309
|
+
// out-of-domain values, so binning x2 series over the x1 domain skews max_count)
|
|
307
310
|
const max_count = Math.max(
|
|
308
311
|
0,
|
|
309
|
-
...series_list.map((srs: DataSeries) =>
|
|
310
|
-
|
|
311
|
-
|
|
312
|
+
...series_list.map((srs: DataSeries) => {
|
|
313
|
+
const hist = bin().domain(srs.x_axis === `x2` ? auto_x2 : auto_x).thresholds(bins)
|
|
314
|
+
return max(hist(srs.y), (data) => data.length) || 0
|
|
315
|
+
}),
|
|
312
316
|
)
|
|
313
317
|
|
|
314
318
|
// If there's effectively no data, avoid log-range issues (counts can't be <= 0 on log)
|
|
@@ -333,12 +337,12 @@
|
|
|
333
337
|
|
|
334
338
|
const y1_range = calc_y_range(
|
|
335
339
|
y1_series,
|
|
336
|
-
|
|
340
|
+
final_y_axis.range ?? [null, null],
|
|
337
341
|
final_y_axis.scale_type ?? `linear`,
|
|
338
342
|
)
|
|
339
343
|
const y2_auto_range = calc_y_range(
|
|
340
344
|
y2_series,
|
|
341
|
-
|
|
345
|
+
final_y2_axis.range ?? [null, null],
|
|
342
346
|
final_y2_axis.scale_type ?? `linear`,
|
|
343
347
|
)
|
|
344
348
|
|
|
@@ -362,47 +366,21 @@
|
|
|
362
366
|
})
|
|
363
367
|
|
|
364
368
|
$effect(() => {
|
|
365
|
-
//
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
final_y_axis.range[0] ?? auto_ranges.y[0],
|
|
381
|
-
final_y_axis.range[1] ?? auto_ranges.y[1],
|
|
382
|
-
]
|
|
383
|
-
: auto_ranges.y
|
|
384
|
-
const new_y2: [number, number] = final_y2_axis.range
|
|
385
|
-
? [
|
|
386
|
-
final_y2_axis.range[0] ?? auto_ranges.y2[0],
|
|
387
|
-
final_y2_axis.range[1] ?? auto_ranges.y2[1],
|
|
388
|
-
]
|
|
389
|
-
: auto_ranges.y2
|
|
390
|
-
|
|
391
|
-
// Only update if the initial (data-driven) ranges changed, not when user pans
|
|
392
|
-
// Comparing against initial preserves user's pan/zoom state
|
|
393
|
-
const x_changed = new_x[0] !== ranges.initial.x[0] ||
|
|
394
|
-
new_x[1] !== ranges.initial.x[1]
|
|
395
|
-
const x2_changed = new_x2[0] !== ranges.initial.x2[0] ||
|
|
396
|
-
new_x2[1] !== ranges.initial.x2[1]
|
|
397
|
-
const y_changed = new_y[0] !== ranges.initial.y[0] ||
|
|
398
|
-
new_y[1] !== ranges.initial.y[1]
|
|
399
|
-
const y2_changed = new_y2[0] !== ranges.initial.y2[0] ||
|
|
400
|
-
new_y2[1] !== ranges.initial.y2[1]
|
|
401
|
-
|
|
402
|
-
if (x_changed) [ranges.initial.x, ranges.current.x] = [new_x, new_x]
|
|
403
|
-
if (x2_changed) [ranges.initial.x2, ranges.current.x2] = [new_x2, new_x2]
|
|
404
|
-
if (y_changed) [ranges.initial.y, ranges.current.y] = [new_y, new_y]
|
|
405
|
-
if (y2_changed) [ranges.initial.y2, ranges.current.y2] = [new_y2, new_y2]
|
|
369
|
+
// Supports one-sided range pinning (null bounds fall back to auto); returns null
|
|
370
|
+
// for transient non-finite bounds (skip: writing NaN breaks scales and loops here)
|
|
371
|
+
const next = resolve_axis_ranges(
|
|
372
|
+
{ x: final_x_axis, x2: final_x2_axis, y: final_y_axis, y2: final_y2_axis },
|
|
373
|
+
auto_ranges,
|
|
374
|
+
)
|
|
375
|
+
if (!next) return
|
|
376
|
+
// Update only changed axes (preserving each unchanged axis's panned current view).
|
|
377
|
+
// untrack the reads of `ranges` so the writes below can't re-trigger this effect
|
|
378
|
+
// (reading + writing the same state otherwise causes effect_update_depth_exceeded).
|
|
379
|
+
const init = untrack(() => ranges.initial)
|
|
380
|
+
if (!vec2_equal(init.x, next.x)) [ranges.initial.x, ranges.current.x] = [next.x, next.x]
|
|
381
|
+
if (!vec2_equal(init.x2, next.x2)) [ranges.initial.x2, ranges.current.x2] = [next.x2, next.x2]
|
|
382
|
+
if (!vec2_equal(init.y, next.y)) [ranges.initial.y, ranges.current.y] = [next.y, next.y]
|
|
383
|
+
if (!vec2_equal(init.y2, next.y2)) [ranges.initial.y2, ranges.current.y2] = [next.y2, next.y2]
|
|
406
384
|
})
|
|
407
385
|
|
|
408
386
|
// Layout: dynamic padding based on tick label widths
|
|
@@ -416,7 +394,7 @@
|
|
|
416
394
|
const current_ticks_y = untrack(() => ticks.y)
|
|
417
395
|
const current_ticks_y2 = untrack(() => ticks.y2)
|
|
418
396
|
|
|
419
|
-
const new_pad = width && height && current_ticks_y.length
|
|
397
|
+
const new_pad = width && height && current_ticks_y.length > 0
|
|
420
398
|
? calc_auto_padding({
|
|
421
399
|
padding,
|
|
422
400
|
default_padding,
|
|
@@ -428,7 +406,7 @@
|
|
|
428
406
|
|
|
429
407
|
// Add y2 axis label space (calc_auto_padding only accounts for tick labels)
|
|
430
408
|
if (
|
|
431
|
-
width && height && y2_series.length && current_ticks_y2.length &&
|
|
409
|
+
width && height && y2_series.length > 0 && current_ticks_y2.length > 0 &&
|
|
432
410
|
final_y2_axis.label
|
|
433
411
|
) {
|
|
434
412
|
const inside = final_y2_axis.tick?.label?.inside ?? false
|
|
@@ -444,7 +422,7 @@
|
|
|
444
422
|
|
|
445
423
|
// Add x2 axis label space (mirroring y2 logic for top padding)
|
|
446
424
|
if (
|
|
447
|
-
width && height && x2_series.length && current_ticks_x2.length &&
|
|
425
|
+
width && height && x2_series.length > 0 && current_ticks_x2.length > 0 &&
|
|
448
426
|
final_x2_axis.label
|
|
449
427
|
) {
|
|
450
428
|
const inside = final_x2_axis.tick?.label?.inside ?? false
|
|
@@ -472,7 +450,7 @@
|
|
|
472
450
|
// vertical segment (top -> baseline) so the legend can't hide inside a tall bar. Built from
|
|
473
451
|
// histogram_bins (pad-independent) + ranges so the crowding decision can't see its own reservation.
|
|
474
452
|
const obstacles_norm = $derived.by(() => {
|
|
475
|
-
if (!width || !height ||
|
|
453
|
+
if (!width || !height || histogram_bins.length === 0) return []
|
|
476
454
|
const base_w = width - base_pad.l - base_pad.r
|
|
477
455
|
const base_h = height - base_pad.t - base_pad.b
|
|
478
456
|
if (base_w <= 0 || base_h <= 0) return []
|
|
@@ -540,7 +518,7 @@
|
|
|
540
518
|
|
|
541
519
|
// Pad-independent binning (no pixel scales) so the auto-place obstacle field can reuse it
|
|
542
520
|
let histogram_bins = $derived.by(() => {
|
|
543
|
-
if (
|
|
521
|
+
if (selected_series.length === 0 || !width || !height) return []
|
|
544
522
|
const hist_generator = bin()
|
|
545
523
|
.domain([ranges.current.x[0], ranges.current.x[1]])
|
|
546
524
|
.thresholds(bins)
|
|
@@ -625,7 +603,7 @@
|
|
|
625
603
|
|
|
626
604
|
// Collect histogram bar positions for legend placement
|
|
627
605
|
let hist_points_for_placement = $derived.by(() => {
|
|
628
|
-
if (!width || !height ||
|
|
606
|
+
if (!width || !height || histogram_data.length === 0) return []
|
|
629
607
|
|
|
630
608
|
const points: { x: number; y: number }[] = []
|
|
631
609
|
|
|
@@ -716,23 +694,15 @@
|
|
|
716
694
|
const dy = Math.abs(drag_state.start.y - drag_state.current.y)
|
|
717
695
|
if (dx > 5 && dy > 5) {
|
|
718
696
|
// Update axis ranges to trigger reactivity and prevent effect from overriding
|
|
719
|
-
x_axis = {
|
|
720
|
-
...x_axis,
|
|
721
|
-
range: [Math.min(start_x, end_x), Math.max(start_x, end_x)],
|
|
722
|
-
}
|
|
697
|
+
x_axis = { ...x_axis, range: sorted_range(start_x, end_x) }
|
|
723
698
|
if (x2_series.length > 0) {
|
|
724
|
-
x2_axis = {
|
|
725
|
-
...x2_axis,
|
|
726
|
-
range: [Math.min(start_x2, end_x2), Math.max(start_x2, end_x2)],
|
|
727
|
-
}
|
|
728
|
-
}
|
|
729
|
-
y_axis = {
|
|
730
|
-
...y_axis,
|
|
731
|
-
range: [Math.min(start_y, end_y), Math.max(start_y, end_y)],
|
|
699
|
+
x2_axis = { ...x2_axis, range: sorted_range(start_x2, end_x2) }
|
|
732
700
|
}
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
701
|
+
y_axis = { ...y_axis, range: sorted_range(start_y, end_y) }
|
|
702
|
+
// gate on y2 series presence (like x2): the y2 scale is a [0, 1] sentinel
|
|
703
|
+
// otherwise, so inverting would store a phantom range in the bindable prop
|
|
704
|
+
if (y2_series.length > 0) {
|
|
705
|
+
y2_axis = { ...y2_axis, range: sorted_range(start_y2, end_y2) }
|
|
736
706
|
}
|
|
737
707
|
}
|
|
738
708
|
}
|
|
@@ -754,42 +724,33 @@
|
|
|
754
724
|
document.body.style.cursor = `default`
|
|
755
725
|
}
|
|
756
726
|
|
|
757
|
-
// Pan
|
|
727
|
+
// Pan/zoom all four axes from an interaction-start snapshot, each in its own
|
|
728
|
+
// scale's transform space (log axes pan by a constant factor, linear by a shift).
|
|
729
|
+
// Plot dims clamped to 1px so degenerate containers can't produce Infinity deltas.
|
|
730
|
+
const pan_all_axes = (init: InitialRanges, dx_px: number, dy_px: number) => {
|
|
731
|
+
const plot_width = Math.max(1, width - pad.l - pad.r)
|
|
732
|
+
const plot_height = Math.max(1, height - pad.t - pad.b)
|
|
733
|
+
ranges.current.x = pan_range_by_pixels(init.initial_x_range, dx_px, plot_width, final_x_axis.scale_type)
|
|
734
|
+
ranges.current.x2 = pan_range_by_pixels(init.initial_x2_range, dx_px, plot_width, final_x2_axis.scale_type)
|
|
735
|
+
ranges.current.y = pan_range_by_pixels(init.initial_y_range, dy_px, plot_height, final_y_axis.scale_type)
|
|
736
|
+
ranges.current.y2 = pan_range_by_pixels(init.initial_y2_range, dy_px, plot_height, final_y2_axis.scale_type)
|
|
737
|
+
}
|
|
738
|
+
const zoom_all_axes = (init: InitialRanges, factor: number) => {
|
|
739
|
+
ranges.current.x = zoom_range_by_factor(init.initial_x_range, factor, final_x_axis.scale_type)
|
|
740
|
+
ranges.current.x2 = zoom_range_by_factor(init.initial_x2_range, factor, final_x2_axis.scale_type)
|
|
741
|
+
ranges.current.y = zoom_range_by_factor(init.initial_y_range, factor, final_y_axis.scale_type)
|
|
742
|
+
ranges.current.y2 = zoom_range_by_factor(init.initial_y2_range, factor, final_y2_axis.scale_type)
|
|
743
|
+
}
|
|
744
|
+
|
|
745
|
+
// Pan drag handler (drag direction inverted on x for natural pan feel)
|
|
758
746
|
const on_pan_move = (evt: MouseEvent) => {
|
|
759
747
|
if (!pan_drag_state) return
|
|
760
|
-
const dx = evt.clientX - pan_drag_state.start.x
|
|
761
|
-
const dy = evt.clientY - pan_drag_state.start.y
|
|
762
|
-
|
|
763
|
-
// Convert pixel delta to data delta (note: drag direction is inverted for natural pan feel)
|
|
764
|
-
const plot_width = width - pad.l - pad.r
|
|
765
|
-
const plot_height = height - pad.t - pad.b
|
|
766
748
|
const sensitivity = pan?.drag_sensitivity ?? 1
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
-
|
|
770
|
-
pan_drag_state.
|
|
771
|
-
plot_width,
|
|
772
|
-
)
|
|
773
|
-
const x2_delta = pixels_to_data_delta(
|
|
774
|
-
-dx * sensitivity,
|
|
775
|
-
pan_drag_state.initial_x2_range,
|
|
776
|
-
plot_width,
|
|
749
|
+
pan_all_axes(
|
|
750
|
+
pan_drag_state,
|
|
751
|
+
-(evt.clientX - pan_drag_state.start.x) * sensitivity,
|
|
752
|
+
(evt.clientY - pan_drag_state.start.y) * sensitivity,
|
|
777
753
|
)
|
|
778
|
-
const y_delta = pixels_to_data_delta(
|
|
779
|
-
dy * sensitivity,
|
|
780
|
-
pan_drag_state.initial_y_range,
|
|
781
|
-
plot_height,
|
|
782
|
-
)
|
|
783
|
-
const y2_delta = pixels_to_data_delta(
|
|
784
|
-
dy * sensitivity,
|
|
785
|
-
pan_drag_state.initial_y2_range,
|
|
786
|
-
plot_height,
|
|
787
|
-
)
|
|
788
|
-
|
|
789
|
-
ranges.current.x = pan_range(pan_drag_state.initial_x_range, x_delta)
|
|
790
|
-
ranges.current.x2 = pan_range(pan_drag_state.initial_x2_range, x2_delta)
|
|
791
|
-
ranges.current.y = pan_range(pan_drag_state.initial_y_range, y_delta)
|
|
792
|
-
ranges.current.y2 = pan_range(pan_drag_state.initial_y2_range, y2_delta)
|
|
793
754
|
}
|
|
794
755
|
|
|
795
756
|
const on_pan_end = () => {
|
|
@@ -799,6 +760,15 @@
|
|
|
799
760
|
window.removeEventListener(`mouseup`, on_pan_end)
|
|
800
761
|
}
|
|
801
762
|
|
|
763
|
+
// Tear down any window listeners + cursor override if the component unmounts mid-drag
|
|
764
|
+
// (mouseup/panend would otherwise never fire, leaking listeners and a stuck cursor).
|
|
765
|
+
// onDestroy also runs during SSR teardown, where window/document don't exist.
|
|
766
|
+
onDestroy(() => {
|
|
767
|
+
remove_drag_listeners([on_window_mouse_move, on_pan_move], [on_window_mouse_up, on_pan_end])
|
|
768
|
+
drag_state = { start: null, current: null, bounds: null }
|
|
769
|
+
pan_drag_state = null
|
|
770
|
+
})
|
|
771
|
+
|
|
802
772
|
function handle_mouse_down(evt: MouseEvent) {
|
|
803
773
|
const coords = get_relative_coords(evt)
|
|
804
774
|
if (!coords || !svg_element) return
|
|
@@ -844,34 +814,15 @@
|
|
|
844
814
|
const plot_height = Math.max(1, height - pad.t - pad.b)
|
|
845
815
|
const sensitivity = pan?.wheel_sensitivity ?? 1
|
|
846
816
|
|
|
847
|
-
//
|
|
848
|
-
const x_delta = pixels_to_data_delta(
|
|
849
|
-
evt.deltaX * sensitivity,
|
|
850
|
-
ranges.current.x,
|
|
851
|
-
plot_width,
|
|
852
|
-
)
|
|
853
|
-
const x2_delta = pixels_to_data_delta(
|
|
854
|
-
evt.deltaX * sensitivity,
|
|
855
|
-
ranges.current.x2,
|
|
856
|
-
plot_width,
|
|
857
|
-
)
|
|
858
|
-
const y_delta = pixels_to_data_delta(
|
|
859
|
-
evt.deltaY * sensitivity,
|
|
860
|
-
ranges.current.y,
|
|
861
|
-
plot_height,
|
|
862
|
-
)
|
|
863
|
-
const y2_delta = pixels_to_data_delta(
|
|
864
|
-
evt.deltaY * sensitivity,
|
|
865
|
-
ranges.current.y2,
|
|
866
|
-
plot_height,
|
|
867
|
-
)
|
|
868
|
-
|
|
817
|
+
// Pan along the dominant wheel direction
|
|
869
818
|
if (Math.abs(evt.deltaX) > Math.abs(evt.deltaY)) {
|
|
870
|
-
|
|
871
|
-
ranges.current.
|
|
819
|
+
const dx = evt.deltaX * sensitivity
|
|
820
|
+
ranges.current.x = pan_range_by_pixels(ranges.current.x, dx, plot_width, final_x_axis.scale_type)
|
|
821
|
+
ranges.current.x2 = pan_range_by_pixels(ranges.current.x2, dx, plot_width, final_x2_axis.scale_type)
|
|
872
822
|
} else {
|
|
873
|
-
|
|
874
|
-
ranges.current.
|
|
823
|
+
const dy = evt.deltaY * sensitivity
|
|
824
|
+
ranges.current.y = pan_range_by_pixels(ranges.current.y, dy, plot_height, final_y_axis.scale_type)
|
|
825
|
+
ranges.current.y2 = pan_range_by_pixels(ranges.current.y2, dy, plot_height, final_y2_axis.scale_type)
|
|
875
826
|
}
|
|
876
827
|
}
|
|
877
828
|
|
|
@@ -909,78 +860,15 @@
|
|
|
909
860
|
|
|
910
861
|
// Calculate pinch scale (curr/start so spread = zoom out, pinch = zoom in)
|
|
911
862
|
const start_dist = Math.hypot(s2.x - s1.x, s2.y - s1.y)
|
|
912
|
-
//
|
|
913
|
-
if (start_dist <
|
|
863
|
+
// ignore near-coincident touches so curr_dist / start_dist can't blow up the scale
|
|
864
|
+
if (start_dist < MIN_TOUCH_DISTANCE_PIXELS) return
|
|
914
865
|
const curr_dist = Math.hypot(t2.clientX - t1.clientX, t2.clientY - t1.clientY)
|
|
915
866
|
const scale = curr_dist / start_dist
|
|
916
867
|
|
|
917
|
-
//
|
|
918
|
-
const plot_width = Math.max(1, width - pad.l - pad.r)
|
|
919
|
-
const plot_height = Math.max(1, height - pad.t - pad.b)
|
|
920
|
-
|
|
921
|
-
// If scale changed significantly, treat as pinch-zoom
|
|
922
|
-
// Also guard against scale being too small to avoid division by zero
|
|
868
|
+
// Pinch zoom about the view center (spread = zoom in, pinch = zoom out)
|
|
923
869
|
if (Math.abs(scale - 1) > PINCH_ZOOM_THRESHOLD && scale > Number.EPSILON) {
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
const x_span = touch_state.initial_x_range[1] - touch_state.initial_x_range[0]
|
|
927
|
-
const x2_span = touch_state.initial_x2_range[1] -
|
|
928
|
-
touch_state.initial_x2_range[0]
|
|
929
|
-
const y_span = touch_state.initial_y_range[1] - touch_state.initial_y_range[0]
|
|
930
|
-
const y2_span = touch_state.initial_y2_range[1] -
|
|
931
|
-
touch_state.initial_y2_range[0]
|
|
932
|
-
const x_center =
|
|
933
|
-
(touch_state.initial_x_range[0] + touch_state.initial_x_range[1]) / 2
|
|
934
|
-
const x2_center =
|
|
935
|
-
(touch_state.initial_x2_range[0] + touch_state.initial_x2_range[1]) / 2
|
|
936
|
-
const y_center =
|
|
937
|
-
(touch_state.initial_y_range[0] + touch_state.initial_y_range[1]) / 2
|
|
938
|
-
const y2_center =
|
|
939
|
-
(touch_state.initial_y2_range[0] + touch_state.initial_y2_range[1]) / 2
|
|
940
|
-
|
|
941
|
-
ranges.current.x = [
|
|
942
|
-
x_center - x_span / scale / 2,
|
|
943
|
-
x_center + x_span / scale / 2,
|
|
944
|
-
]
|
|
945
|
-
ranges.current.x2 = [
|
|
946
|
-
x2_center - x2_span / scale / 2,
|
|
947
|
-
x2_center + x2_span / scale / 2,
|
|
948
|
-
]
|
|
949
|
-
ranges.current.y = [
|
|
950
|
-
y_center - y_span / scale / 2,
|
|
951
|
-
y_center + y_span / scale / 2,
|
|
952
|
-
]
|
|
953
|
-
ranges.current.y2 = [
|
|
954
|
-
y2_center - y2_span / scale / 2,
|
|
955
|
-
y2_center + y2_span / scale / 2,
|
|
956
|
-
]
|
|
957
|
-
} else {
|
|
958
|
-
// Pan
|
|
959
|
-
const x_delta = pixels_to_data_delta(
|
|
960
|
-
-dx,
|
|
961
|
-
touch_state.initial_x_range,
|
|
962
|
-
plot_width,
|
|
963
|
-
)
|
|
964
|
-
const x2_delta = pixels_to_data_delta(
|
|
965
|
-
-dx,
|
|
966
|
-
touch_state.initial_x2_range,
|
|
967
|
-
plot_width,
|
|
968
|
-
)
|
|
969
|
-
const y_delta = pixels_to_data_delta(
|
|
970
|
-
dy,
|
|
971
|
-
touch_state.initial_y_range,
|
|
972
|
-
plot_height,
|
|
973
|
-
)
|
|
974
|
-
const y2_delta = pixels_to_data_delta(
|
|
975
|
-
dy,
|
|
976
|
-
touch_state.initial_y2_range,
|
|
977
|
-
plot_height,
|
|
978
|
-
)
|
|
979
|
-
ranges.current.x = pan_range(touch_state.initial_x_range, x_delta)
|
|
980
|
-
ranges.current.x2 = pan_range(touch_state.initial_x2_range, x2_delta)
|
|
981
|
-
ranges.current.y = pan_range(touch_state.initial_y_range, y_delta)
|
|
982
|
-
ranges.current.y2 = pan_range(touch_state.initial_y2_range, y2_delta)
|
|
983
|
-
}
|
|
870
|
+
zoom_all_axes(touch_state, scale)
|
|
871
|
+
} else pan_all_axes(touch_state, -dx, dy)
|
|
984
872
|
}
|
|
985
873
|
|
|
986
874
|
function handle_touch_end() {
|
|
@@ -1030,16 +918,7 @@
|
|
|
1030
918
|
on_bar_hover?.({ value, count, property, event: evt })
|
|
1031
919
|
}
|
|
1032
920
|
|
|
1033
|
-
|
|
1034
|
-
if (series_idx >= 0 && series_idx < series.length) {
|
|
1035
|
-
// Toggle series visibility
|
|
1036
|
-
series = series.map((srs: DataSeries, idx: number) => {
|
|
1037
|
-
if (idx === series_idx) return { ...srs, visible: !(srs.visible ?? true) }
|
|
1038
|
-
return srs
|
|
1039
|
-
})
|
|
1040
|
-
;(legend?.on_toggle || on_series_toggle)(series_idx)
|
|
1041
|
-
}
|
|
1042
|
-
}
|
|
921
|
+
const legend_vis = create_legend_visibility(() => series, (next) => (series = next))
|
|
1043
922
|
|
|
1044
923
|
// Set theme-aware background when entering fullscreen
|
|
1045
924
|
$effect(() => {
|
|
@@ -1067,32 +946,12 @@
|
|
|
1067
946
|
set_loading: (axis) => (axis_loading = axis),
|
|
1068
947
|
}
|
|
1069
948
|
|
|
1070
|
-
//
|
|
1071
|
-
|
|
1072
|
-
const handle_axis_change = $derived(create_axis_change_handler(
|
|
949
|
+
// Shared handler + one-shot auto-load bound to this component's state
|
|
950
|
+
const { handle_axis_change, try_auto_load } = create_axis_loader(
|
|
1073
951
|
axis_state,
|
|
1074
|
-
data_loader,
|
|
1075
|
-
|
|
1076
|
-
|
|
1077
|
-
))
|
|
1078
|
-
|
|
1079
|
-
let auto_load_attempted = false // prevent infinite retries on failure
|
|
1080
|
-
|
|
1081
|
-
// Auto-load data if series is empty but options exist (runs once)
|
|
1082
|
-
$effect(() => {
|
|
1083
|
-
if (series.length === 0 && data_loader && !auto_load_attempted) {
|
|
1084
|
-
// Check x-axis first, then y-axis
|
|
1085
|
-
if (x_axis.options?.length) {
|
|
1086
|
-
auto_load_attempted = true
|
|
1087
|
-
const first_key = x_axis.selected_key ?? x_axis.options[0].key
|
|
1088
|
-
handle_axis_change(`x`, first_key).catch(() => {})
|
|
1089
|
-
} else if (y_axis.options?.length) {
|
|
1090
|
-
auto_load_attempted = true
|
|
1091
|
-
const first_key = y_axis.selected_key ?? y_axis.options[0].key
|
|
1092
|
-
handle_axis_change(`y`, first_key).catch(() => {})
|
|
1093
|
-
}
|
|
1094
|
-
}
|
|
1095
|
-
})
|
|
952
|
+
() => ({ data_loader, on_axis_change, on_error }),
|
|
953
|
+
)
|
|
954
|
+
$effect(try_auto_load)
|
|
1096
955
|
</script>
|
|
1097
956
|
|
|
1098
957
|
{#snippet ref_lines_layer(lines: IndexedRefLine[])}
|
|
@@ -1175,6 +1034,7 @@
|
|
|
1175
1034
|
ontouchstart={handle_touch_start}
|
|
1176
1035
|
ontouchmove={handle_touch_move}
|
|
1177
1036
|
ontouchend={handle_touch_end}
|
|
1037
|
+
ontouchcancel={handle_touch_end}
|
|
1178
1038
|
style:cursor={pan_drag_state
|
|
1179
1039
|
? `grabbing`
|
|
1180
1040
|
: shift_held && pan?.enabled !== false
|
|
@@ -1240,6 +1100,7 @@
|
|
|
1240
1100
|
ticks={ticks.x as number[]}
|
|
1241
1101
|
place={scales.x}
|
|
1242
1102
|
axis={final_x_axis}
|
|
1103
|
+
domain={ranges.current.x as Vec2}
|
|
1243
1104
|
{pad}
|
|
1244
1105
|
{width}
|
|
1245
1106
|
{height}
|
|
@@ -1258,6 +1119,7 @@
|
|
|
1258
1119
|
ticks={ticks.x2 as number[]}
|
|
1259
1120
|
place={scales.x2}
|
|
1260
1121
|
axis={final_x2_axis}
|
|
1122
|
+
domain={ranges.current.x2 as Vec2}
|
|
1261
1123
|
{pad}
|
|
1262
1124
|
{width}
|
|
1263
1125
|
{height}
|
|
@@ -1276,6 +1138,7 @@
|
|
|
1276
1138
|
ticks={ticks.y as number[]}
|
|
1277
1139
|
place={scales.y}
|
|
1278
1140
|
axis={final_y_axis}
|
|
1141
|
+
domain={ranges.current.y as Vec2}
|
|
1279
1142
|
{pad}
|
|
1280
1143
|
{width}
|
|
1281
1144
|
{height}
|
|
@@ -1293,21 +1156,18 @@
|
|
|
1293
1156
|
|
|
1294
1157
|
<!-- Y2-axis (Right) -->
|
|
1295
1158
|
{#if y2_series.length > 0}
|
|
1296
|
-
{@const y2_inside = final_y2_axis.tick?.label?.inside ?? false}
|
|
1297
|
-
{@const y2_tick_shift = y2_inside ? 0 : (final_y2_axis.tick?.label?.shift?.x ?? 0) + 8}
|
|
1298
|
-
{@const y2_tick_width = y2_inside ? 0 : tick_label_widths.y2_max}
|
|
1299
1159
|
<PlotAxis
|
|
1300
1160
|
side="y2"
|
|
1301
1161
|
ticks={ticks.y2 as number[]}
|
|
1302
1162
|
place={scales.y2}
|
|
1303
1163
|
axis={final_y2_axis}
|
|
1164
|
+
domain={ranges.current.y2 as Vec2}
|
|
1304
1165
|
{pad}
|
|
1305
1166
|
{width}
|
|
1306
1167
|
{height}
|
|
1307
1168
|
show_grid={display.y2_grid}
|
|
1308
1169
|
tick_label={(tick) => get_tick_label(tick, final_y2_axis.ticks)}
|
|
1309
|
-
label_x={width
|
|
1310
|
-
(final_y2_axis.label_shift?.x ?? 0)}
|
|
1170
|
+
label_x={y2_axis_label_x(final_y2_axis, width, pad.r, tick_label_widths.y2_max)}
|
|
1311
1171
|
label_y={pad.t + (height - pad.t - pad.b) / 2 + (final_y2_axis.label_shift?.y ?? 0)}
|
|
1312
1172
|
axis_loading={axis_loading === `y2`}
|
|
1313
1173
|
on_axis_change={(key) => handle_axis_change(`y2`, key)}
|
|
@@ -1323,6 +1183,7 @@
|
|
|
1323
1183
|
<g
|
|
1324
1184
|
class="histogram-series"
|
|
1325
1185
|
data-series-idx={series_idx}
|
|
1186
|
+
clip-path="url(#{clip_path_id})"
|
|
1326
1187
|
opacity={hovered_legend_series_idx !== null &&
|
|
1327
1188
|
hovered_legend_series_idx !== series_idx
|
|
1328
1189
|
? 0.25
|
|
@@ -1389,20 +1250,12 @@
|
|
|
1389
1250
|
{@const { value, count, property, active_y_axis, active_x_axis } = hover_info}
|
|
1390
1251
|
{@const tooltip_x = (active_x_axis === `x2` ? scales.x2 : scales.x)(value)}
|
|
1391
1252
|
{@const tooltip_y = (active_y_axis === `y2` ? scales.y2 : scales.y)(count)}
|
|
1392
|
-
{@const tooltip_pos = constrain_tooltip_position(
|
|
1393
|
-
tooltip_x,
|
|
1394
|
-
tooltip_y,
|
|
1395
|
-
tooltip_el?.offsetWidth ?? 120,
|
|
1396
|
-
tooltip_el?.offsetHeight ?? (mode === `overlay` ? 60 : 40),
|
|
1397
|
-
width,
|
|
1398
|
-
height,
|
|
1399
|
-
{ offset_x: 5, offset_y: -10 },
|
|
1400
|
-
)}
|
|
1401
1253
|
<PlotTooltip
|
|
1402
|
-
x={
|
|
1403
|
-
y={
|
|
1404
|
-
offset={{ x:
|
|
1405
|
-
|
|
1254
|
+
x={tooltip_x}
|
|
1255
|
+
y={tooltip_y}
|
|
1256
|
+
offset={{ x: 5, y: -10 }}
|
|
1257
|
+
constrain_to={{ width, height }}
|
|
1258
|
+
fallback_size={{ width: 120, height: mode === `overlay` ? 60 : 40 }}
|
|
1406
1259
|
>
|
|
1407
1260
|
{#if tooltip}
|
|
1408
1261
|
{@render tooltip({ ...hover_info, fullscreen })}
|
|
@@ -1461,11 +1314,16 @@
|
|
|
1461
1314
|
bind:root_element={legend_element}
|
|
1462
1315
|
{...legend}
|
|
1463
1316
|
series_data={legend_data}
|
|
1464
|
-
on_toggle={legend?.on_toggle
|
|
1317
|
+
on_toggle={legend?.on_toggle ?? ((series_idx: number) => {
|
|
1318
|
+
if (series_idx < 0 || series_idx >= series.length) return
|
|
1319
|
+
legend_vis.on_toggle(series_idx)
|
|
1320
|
+
on_series_toggle(series_idx)
|
|
1321
|
+
})}
|
|
1322
|
+
on_double_click={legend?.on_double_click ?? legend_vis.on_double_click}
|
|
1465
1323
|
on_hover_change={legend_hover.set_locked}
|
|
1466
|
-
on_item_hover={(
|
|
1467
|
-
(hovered_legend_series_idx =
|
|
1468
|
-
? series_idx
|
|
1324
|
+
on_item_hover={(item) =>
|
|
1325
|
+
(hovered_legend_series_idx = item != null && item.series_idx >= 0
|
|
1326
|
+
? item.series_idx
|
|
1469
1327
|
: null)}
|
|
1470
1328
|
active_series_idx={hover_info?.series_idx ?? hovered_legend_series_idx}
|
|
1471
1329
|
style={`
|
|
@@ -1509,8 +1367,10 @@
|
|
|
1509
1367
|
background: var(--histogram-fullscreen-bg, var(--histogram-bg, var(--plot-bg)));
|
|
1510
1368
|
max-height: none !important;
|
|
1511
1369
|
overflow: hidden;
|
|
1512
|
-
/*
|
|
1513
|
-
|
|
1370
|
+
/* border-top (not padding-top): bind:clientHeight includes padding but excludes
|
|
1371
|
+
borders - padding made the chart overflow + clip its bottom 2em (x-axis title) */
|
|
1372
|
+
border-top: var(--plot-fullscreen-padding-top, 2em) solid
|
|
1373
|
+
var(--histogram-fullscreen-bg, var(--histogram-bg, var(--plot-bg, transparent)));
|
|
1514
1374
|
box-sizing: border-box;
|
|
1515
1375
|
}
|
|
1516
1376
|
.header-controls {
|