matterviz 0.3.7 → 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/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 +76 -148
- package/dist/brillouin/BrillouinZone.svelte.d.ts +6 -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 +97 -205
- package/dist/brillouin/BrillouinZoneScene.svelte.d.ts +4 -23
- package/dist/brillouin/BrillouinZoneTooltip.svelte +16 -25
- 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 +89 -90
- 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 +14 -13
- package/dist/chempot-diagram/ChemPotDiagram.svelte.d.ts +1 -1
- package/dist/chempot-diagram/ChemPotDiagram2D.svelte +109 -203
- package/dist/chempot-diagram/ChemPotDiagram2D.svelte.d.ts +4 -1
- package/dist/chempot-diagram/ChemPotDiagram3D.svelte +180 -470
- package/dist/chempot-diagram/ChemPotDiagram3D.svelte.d.ts +7 -1
- package/dist/chempot-diagram/async-compute.svelte.js +3 -1
- package/dist/chempot-diagram/chempot-worker.js +2 -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 +4 -4
- package/dist/chempot-diagram/compute.js +20 -20
- 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 +8 -7
- package/dist/composition/FormulaFilter.svelte +18 -11
- package/dist/composition/PieChart.svelte +11 -10
- package/dist/composition/chem-sys.d.ts +8 -0
- package/dist/composition/chem-sys.js +86 -0
- package/dist/composition/format.js +7 -4
- package/dist/composition/index.d.ts +1 -0
- package/dist/composition/index.js +1 -0
- package/dist/composition/parse.d.ts +0 -1
- package/dist/composition/parse.js +41 -31
- 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 +106 -185
- package/dist/convex-hull/ConvexHull2D.svelte.d.ts +1 -1
- package/dist/convex-hull/ConvexHull3D.svelte +179 -683
- package/dist/convex-hull/ConvexHull3D.svelte.d.ts +1 -1
- package/dist/convex-hull/ConvexHull4D.svelte +183 -687
- 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 +36 -175
- 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/GasPressureControls.svelte +4 -4
- package/dist/convex-hull/TemperatureSlider.svelte +2 -2
- 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/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 +42 -7
- package/dist/convex-hull/helpers.js +171 -78
- 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 +10 -8
- package/dist/convex-hull/index.js +7 -2
- package/dist/convex-hull/thermodynamics.js +136 -960
- package/dist/convex-hull/types.d.ts +13 -5
- package/dist/convex-hull/types.js +12 -0
- package/dist/coordination/CoordinationBarPlot.svelte +27 -34
- package/dist/coordination/CoordinationBarPlot.svelte.d.ts +1 -1
- package/dist/element/BohrAtom.svelte +2 -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/FermiSlice.svelte +13 -5
- package/dist/fermi-surface/FermiSurface.svelte +78 -151
- package/dist/fermi-surface/FermiSurface.svelte.d.ts +5 -14
- package/dist/fermi-surface/FermiSurfaceControls.svelte +1 -1
- package/dist/fermi-surface/FermiSurfaceControls.svelte.d.ts +1 -1
- package/dist/fermi-surface/FermiSurfaceScene.svelte +72 -221
- package/dist/fermi-surface/FermiSurfaceScene.svelte.d.ts +3 -23
- package/dist/fermi-surface/FermiSurfaceTooltip.svelte +8 -34
- package/dist/fermi-surface/compute.js +67 -66
- package/dist/fermi-surface/export.js +6 -16
- 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 +71 -79
- package/dist/fermi-surface/types.d.ts +3 -2
- package/dist/heatmap-matrix/HeatmapMatrix.svelte +69 -52
- 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/heatmap-matrix/index.js +1 -1
- 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 +5 -4
- package/dist/io/export.d.ts +9 -5
- package/dist/io/export.js +77 -51
- package/dist/io/fetch.d.ts +2 -1
- package/dist/io/fetch.js +5 -1
- package/dist/io/file-drop.d.ts +8 -1
- package/dist/io/file-drop.js +48 -36
- 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/io/url-drop.js +64 -33
- package/dist/isosurface/parse.js +52 -51
- 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 +9 -8
- 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/PropertyFilter.svelte +3 -2
- package/dist/layout/SettingsSection.svelte +1 -1
- 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/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 +12 -4
- package/dist/math.js +42 -30
- package/dist/overlays/DraggablePane.svelte +4 -4
- package/dist/overlays/index.d.ts +4 -0
- package/dist/periodic-table/PeriodicTable.svelte +27 -15
- 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 +3 -2
- package/dist/phase-diagram/PhaseDiagramControls.svelte.d.ts +4 -3
- package/dist/phase-diagram/PhaseDiagramEditorPane.svelte +4 -2
- 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/PhaseDiagramTooltip.svelte +1 -1
- package/dist/phase-diagram/build-diagram.js +2 -2
- package/dist/phase-diagram/colors.js +1 -1
- package/dist/phase-diagram/parse.d.ts +2 -1
- 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} +246 -841
- package/dist/plot/{BarPlot.svelte.d.ts → bar/BarPlot.svelte.d.ts} +8 -16
- 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} +8 -7
- 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 +1292 -0
- package/dist/plot/box/BoxPlot.svelte.d.ts +95 -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 +56 -0
- package/dist/plot/box/box-plot.js +129 -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 +17 -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.d.ts → core/auto-place.d.ts} +1 -1
- package/dist/plot/{auto-place.js → core/auto-place.js} +6 -3
- 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} +41 -38
- package/dist/plot/{ColorBar.svelte.d.ts → core/components/ColorBar.svelte.d.ts} +7 -6
- 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} +33 -15
- package/dist/plot/{Line.svelte.d.ts → core/components/Line.svelte.d.ts} +3 -2
- package/dist/plot/{PlotAxis.svelte → core/components/PlotAxis.svelte} +9 -6
- package/dist/plot/{PlotAxis.svelte.d.ts → core/components/PlotAxis.svelte.d.ts} +5 -3
- 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} +5 -5
- package/dist/plot/{ReferenceLine3D.svelte.d.ts → core/components/ReferenceLine3D.svelte.d.ts} +5 -5
- package/dist/plot/{ReferencePlane.svelte → core/components/ReferencePlane.svelte} +8 -8
- package/dist/plot/{ReferencePlane.svelte.d.ts → core/components/ReferencePlane.svelte.d.ts} +5 -5
- 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} +21 -23
- 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 +34 -0
- package/dist/plot/core/fill-utils.js +391 -0
- package/dist/plot/core/index.d.ts +10 -0
- package/dist/plot/core/index.js +11 -0
- package/dist/plot/core/interactions.d.ts +39 -0
- package/dist/plot/core/interactions.js +209 -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/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/{reference-line.d.ts → core/reference-line.d.ts} +11 -11
- package/dist/plot/{reference-line.js → core/reference-line.js} +29 -42
- package/dist/plot/core/scales.d.ts +40 -0
- package/dist/plot/{scales.js → core/scales.js} +94 -93
- package/dist/plot/core/svg.d.ts +3 -0
- package/dist/plot/core/svg.js +41 -0
- package/dist/plot/{types.d.ts → core/types.d.ts} +36 -85
- package/dist/plot/{types.js → core/types.js} +1 -1
- package/dist/plot/{utils → core/utils}/label-placement.d.ts +3 -3
- package/dist/plot/{utils → core/utils}/label-placement.js +3 -3
- 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 +12 -0
- package/dist/plot/core/utils.js +27 -0
- package/dist/plot/{Histogram.svelte → histogram/Histogram.svelte} +174 -551
- 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 +697 -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 +189 -0
- package/dist/plot/{BinnedScatterPlot.svelte → scatter/BinnedScatterPlot.svelte} +64 -64
- package/dist/plot/{BinnedScatterPlot.svelte.d.ts → scatter/BinnedScatterPlot.svelte.d.ts} +6 -6
- 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} +297 -1008
- package/dist/plot/{ScatterPlot.svelte.d.ts → scatter/ScatterPlot.svelte.d.ts} +10 -18
- package/dist/plot/{ScatterPlotControls.svelte → scatter/ScatterPlotControls.svelte} +6 -5
- package/dist/plot/{ScatterPlotControls.svelte.d.ts → scatter/ScatterPlotControls.svelte.d.ts} +2 -2
- 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} +5 -12
- 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} +25 -34
- package/dist/plot/{ScatterPlot3D.svelte.d.ts → scatter-3d/ScatterPlot3D.svelte.d.ts} +9 -17
- package/dist/plot/{ScatterPlot3DControls.svelte → scatter-3d/ScatterPlot3DControls.svelte} +14 -14
- package/dist/plot/{ScatterPlot3DControls.svelte.d.ts → scatter-3d/ScatterPlot3DControls.svelte.d.ts} +6 -6
- package/dist/plot/{ScatterPlot3DScene.svelte → scatter-3d/ScatterPlot3DScene.svelte} +129 -128
- package/dist/plot/{ScatterPlot3DScene.svelte.d.ts → scatter-3d/ScatterPlot3DScene.svelte.d.ts} +6 -15
- package/dist/plot/{Surface3D.svelte → scatter-3d/Surface3D.svelte} +7 -6
- package/dist/plot/{Surface3D.svelte.d.ts → scatter-3d/Surface3D.svelte.d.ts} +5 -4
- 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 +1041 -0
- package/dist/plot/sunburst/Sunburst.svelte.d.ts +97 -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 +269 -0
- package/dist/rdf/RdfPlot.svelte +2 -1
- package/dist/rdf/RdfPlot.svelte.d.ts +1 -1
- package/dist/rdf/calc-rdf.js +11 -24
- package/dist/sanitize.js +14 -3
- 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 +79 -3
- package/dist/settings.js +321 -1
- package/dist/spectral/Bands.svelte +47 -36
- package/dist/spectral/Bands.svelte.d.ts +6 -6
- package/dist/spectral/BandsAndDos.svelte +23 -25
- package/dist/spectral/BrillouinBandsDos.svelte +42 -30
- package/dist/spectral/Dos.svelte +15 -23
- package/dist/spectral/Dos.svelte.d.ts +4 -3
- package/dist/spectral/helpers.d.ts +8 -6
- package/dist/spectral/helpers.js +137 -65
- 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 +8 -9
- package/dist/structure/AtomLegend.svelte.d.ts +1 -1
- package/dist/structure/CanvasTooltip.svelte +1 -0
- package/dist/structure/CellSelect.svelte +12 -5
- package/dist/structure/CellSelect.svelte.d.ts +2 -1
- package/dist/structure/Cylinder.svelte +12 -8
- package/dist/structure/Cylinder.svelte.d.ts +4 -1
- package/dist/structure/Lattice.svelte +2 -2
- package/dist/structure/Structure.svelte +365 -423
- 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 +10 -9
- package/dist/structure/StructureInfoPane.svelte.d.ts +5 -5
- package/dist/structure/StructureScene.svelte +376 -208
- 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} +15 -5
- package/dist/structure/atom-properties.d.ts +1 -1
- package/dist/structure/atom-properties.js +17 -22
- package/dist/structure/bond-order-perception.js +3 -5
- package/dist/structure/bonding.d.ts +4 -0
- package/dist/structure/bonding.js +134 -63
- package/dist/structure/export.d.ts +24 -4
- package/dist/structure/export.js +89 -143
- package/dist/structure/index.d.ts +4 -4
- package/dist/structure/index.js +3 -3
- package/dist/structure/measure.d.ts +3 -2
- package/dist/structure/measure.js +6 -5
- package/dist/structure/parse.d.ts +3 -2
- package/dist/structure/parse.js +419 -438
- 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 +190 -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 +113 -8
- 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 +291 -72
- package/dist/symmetry/spacegroups.d.ts +12 -1
- package/dist/symmetry/spacegroups.js +63 -14
- 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 +66 -25
- 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 +123 -100
- package/dist/trajectory/Trajectory.svelte.d.ts +11 -22
- package/dist/trajectory/TrajectoryExportPane.svelte +17 -25
- package/dist/trajectory/TrajectoryExportPane.svelte.d.ts +4 -5
- package/dist/trajectory/TrajectoryInfoPane.svelte +5 -3
- 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 +1 -1
- package/dist/trajectory/format-detect.js +27 -19
- package/dist/trajectory/frame-reader.d.ts +0 -1
- package/dist/trajectory/frame-reader.js +63 -162
- package/dist/trajectory/helpers.d.ts +10 -2
- package/dist/trajectory/helpers.js +56 -36
- package/dist/trajectory/index.js +1 -1
- 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/hdf5.js +1 -1
- package/dist/trajectory/parse/index.d.ts +1 -1
- package/dist/trajectory/parse/index.js +65 -105
- 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 +38 -18
- package/dist/trajectory/parse/xyz.d.ts +13 -1
- package/dist/trajectory/parse/xyz.js +102 -94
- package/dist/trajectory/plotting.d.ts +1 -2
- package/dist/trajectory/plotting.js +16 -113
- package/dist/utils.d.ts +2 -0
- package/dist/utils.js +7 -5
- package/dist/xrd/XrdPlot.svelte +16 -30
- package/dist/xrd/broadening.d.ts +2 -1
- package/dist/xrd/calc-xrd.js +18 -20
- package/dist/xrd/index.d.ts +2 -2
- package/dist/xrd/parse.js +2 -2
- package/package.json +43 -26
- 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/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/hover-lock.svelte.d.ts +0 -14
- package/dist/plot/hover-lock.svelte.js +0 -46
- package/dist/plot/interactions.d.ts +0 -12
- package/dist/plot/interactions.js +0 -101
- package/dist/plot/scales.d.ts +0 -48
- 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/{PortalSelect.svelte.d.ts → core/components/PortalSelect.svelte.d.ts} +0 -0
- /package/dist/plot/{binned-scatter-types.js → scatter/binned-scatter-types.js} +0 -0
|
@@ -2,11 +2,11 @@
|
|
|
2
2
|
lang="ts"
|
|
3
3
|
generics="Metadata extends Record<string, unknown> = Record<string, unknown>"
|
|
4
4
|
>
|
|
5
|
-
import type {
|
|
6
|
-
import { format_value } from '
|
|
7
|
-
import { sanitize_html } from '
|
|
8
|
-
import { FullscreenToggle, set_fullscreen_bg } from '
|
|
9
|
-
import type { Point2D, Vec2 } from '
|
|
5
|
+
import type { D3InterpolateName } from '../../colors'
|
|
6
|
+
import { format_value } from '../../labels'
|
|
7
|
+
import { sanitize_html } from '../../sanitize'
|
|
8
|
+
import { FullscreenToggle, set_fullscreen_bg } from '../../layout'
|
|
9
|
+
import type { Point2D, Vec2 } from '../../math'
|
|
10
10
|
import type {
|
|
11
11
|
AxisLoadError,
|
|
12
12
|
BarHandlerProps,
|
|
@@ -14,8 +14,8 @@
|
|
|
14
14
|
BarSeries,
|
|
15
15
|
BarStyle,
|
|
16
16
|
BasePlotProps,
|
|
17
|
+
ColorScaleConfig,
|
|
17
18
|
DataLoaderFn,
|
|
18
|
-
InitialRanges,
|
|
19
19
|
InternalPoint,
|
|
20
20
|
LegendConfig,
|
|
21
21
|
LegendItem,
|
|
@@ -25,9 +25,9 @@
|
|
|
25
25
|
PlotConfig,
|
|
26
26
|
RefLine,
|
|
27
27
|
RefLineEvent,
|
|
28
|
-
|
|
28
|
+
SizeScaleConfig,
|
|
29
29
|
UserContentProps,
|
|
30
|
-
} from '
|
|
30
|
+
} from '..'
|
|
31
31
|
import {
|
|
32
32
|
BarPlotControls,
|
|
33
33
|
compute_element_placement,
|
|
@@ -35,56 +35,61 @@
|
|
|
35
35
|
PlotLegend,
|
|
36
36
|
ReferenceLine,
|
|
37
37
|
ScatterPoint,
|
|
38
|
-
} from '
|
|
39
|
-
import type { AxisChangeState } from '
|
|
40
|
-
import {
|
|
41
|
-
import {
|
|
38
|
+
} from '..'
|
|
39
|
+
import type { AxisChangeState } from '../core/axis-utils'
|
|
40
|
+
import { create_axis_loader } from '../core/axis-utils'
|
|
41
|
+
import { create_placed_tween } from '../core/placed-tween.svelte'
|
|
42
|
+
import { create_pan_zoom } from '../core/pan-zoom.svelte'
|
|
43
|
+
import { create_legend_visibility } from '../core/utils/series-visibility'
|
|
42
44
|
import {
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
PINCH_ZOOM_THRESHOLD,
|
|
50
|
-
pixels_to_data_delta,
|
|
51
|
-
} from './interactions'
|
|
52
|
-
import type { IndexedRefLine } from './reference-line'
|
|
53
|
-
import { group_ref_lines_by_z, index_ref_lines } from './reference-line'
|
|
45
|
+
axis_ranges_equal,
|
|
46
|
+
invert_rect_range,
|
|
47
|
+
resolve_axis_ranges,
|
|
48
|
+
} from '../core/interactions'
|
|
49
|
+
import type { IndexedRefLine } from '../core/reference-line'
|
|
50
|
+
import { group_ref_lines_by_z, index_ref_lines } from '../core/reference-line'
|
|
54
51
|
import {
|
|
55
52
|
create_color_scale,
|
|
56
53
|
create_scale,
|
|
57
54
|
create_size_scale,
|
|
58
55
|
generate_ticks,
|
|
59
|
-
get_nice_data_range,
|
|
60
56
|
get_tick_label,
|
|
61
|
-
} from '
|
|
62
|
-
import { DEFAULT_MARKERS
|
|
63
|
-
import { DEFAULTS } from '
|
|
57
|
+
} from '../core/scales'
|
|
58
|
+
import { DEFAULT_MARKERS } from '../core/types'
|
|
59
|
+
import { DEFAULTS } from '../../settings'
|
|
64
60
|
import { extent } from 'd3-array'
|
|
65
61
|
import type { Snippet } from 'svelte'
|
|
66
|
-
import { untrack } from 'svelte'
|
|
62
|
+
import { onDestroy, untrack } from 'svelte'
|
|
67
63
|
import type { HTMLAttributes } from 'svelte/elements'
|
|
68
|
-
import {
|
|
69
|
-
import { SvelteMap } from 'svelte/reactivity'
|
|
64
|
+
import type { TweenOptions } from 'svelte/motion'
|
|
70
65
|
import {
|
|
71
66
|
build_obstacles_norm,
|
|
72
67
|
clip_bar,
|
|
73
68
|
has_explicit_position,
|
|
74
69
|
measured_footprint,
|
|
75
70
|
place_decorations,
|
|
76
|
-
|
|
71
|
+
placed_coords,
|
|
72
|
+
} from '../core/auto-place'
|
|
77
73
|
import {
|
|
78
74
|
calc_auto_padding,
|
|
79
|
-
constrain_tooltip_position,
|
|
80
75
|
filter_padding,
|
|
81
76
|
LABEL_GAP_DEFAULT,
|
|
77
|
+
y2_axis_label_x,
|
|
82
78
|
measure_max_tick_width,
|
|
83
|
-
} from '
|
|
84
|
-
import PlotTooltip from '
|
|
85
|
-
import { bar_path } from '
|
|
86
|
-
import
|
|
87
|
-
import
|
|
79
|
+
} from '../core/layout'
|
|
80
|
+
import PlotTooltip from '../core/components/PlotTooltip.svelte'
|
|
81
|
+
import { bar_path } from '../core/svg'
|
|
82
|
+
import { unique_id } from '../core/utils'
|
|
83
|
+
import ZeroLines from '../core/components/ZeroLines.svelte'
|
|
84
|
+
import ZoomRect from '../core/components/ZoomRect.svelte'
|
|
85
|
+
import {
|
|
86
|
+
compute_bar_auto_ranges,
|
|
87
|
+
compute_group_info,
|
|
88
|
+
compute_stacked_offsets,
|
|
89
|
+
normalize_categorical,
|
|
90
|
+
} from './data'
|
|
91
|
+
import { compute_bar_rect, compute_line_points } from './geometry'
|
|
92
|
+
import type { LineSeriesPoint as BarLineSeriesPoint } from './geometry'
|
|
88
93
|
|
|
89
94
|
// Handler props for line marker events (extends BarHandlerProps with point-specific data)
|
|
90
95
|
interface LineMarkerHandlerProps extends BarHandlerProps<Metadata> {
|
|
@@ -92,27 +97,17 @@
|
|
|
92
97
|
}
|
|
93
98
|
|
|
94
99
|
// Extended point type with computed screen coordinates (used internally for rendering)
|
|
95
|
-
type LineSeriesPoint =
|
|
96
|
-
x: number // Screen x coordinate
|
|
97
|
-
y: number // Screen y coordinate
|
|
98
|
-
data_x: number // Original data x value
|
|
99
|
-
data_y: number // Original data y value
|
|
100
|
-
idx: number // Index in series
|
|
101
|
-
}
|
|
100
|
+
type LineSeriesPoint = BarLineSeriesPoint<Metadata>
|
|
102
101
|
|
|
103
102
|
let {
|
|
104
103
|
series = $bindable([]),
|
|
105
104
|
orientation = $bindable(`vertical`),
|
|
106
105
|
mode = $bindable(`overlay`),
|
|
107
106
|
x_axis = $bindable({}),
|
|
108
|
-
x2_axis = $bindable({}),
|
|
107
|
+
x2_axis: x2_axis_prop = $bindable({}),
|
|
109
108
|
y_axis = $bindable({}),
|
|
110
|
-
y2_axis = $bindable({}),
|
|
109
|
+
y2_axis: y2_axis_prop = $bindable({}),
|
|
111
110
|
display = $bindable(DEFAULTS.bar.display),
|
|
112
|
-
x_range = [null, null],
|
|
113
|
-
x2_range = [null, null],
|
|
114
|
-
y_range = [null, null],
|
|
115
|
-
y2_range = [null, null],
|
|
116
111
|
range_padding = 0.05,
|
|
117
112
|
padding = { t: 20, b: 60, l: 60, r: 20 },
|
|
118
113
|
legend = {},
|
|
@@ -174,26 +169,14 @@
|
|
|
174
169
|
data: BarHandlerProps<Metadata> & { event: MouseEvent | KeyboardEvent },
|
|
175
170
|
) => void
|
|
176
171
|
on_bar_hover?: (
|
|
177
|
-
data:
|
|
178
|
-
| (BarHandlerProps<Metadata> & {
|
|
179
|
-
event: MouseEvent | FocusEvent | KeyboardEvent
|
|
180
|
-
})
|
|
181
|
-
| null,
|
|
172
|
+
data: (BarHandlerProps<Metadata> & { event: MouseEvent | FocusEvent | KeyboardEvent }) | null,
|
|
182
173
|
) => void
|
|
183
174
|
// Line marker props (matching ScatterPlot)
|
|
184
175
|
// Note: For line series with markers, BOTH on_bar_* AND on_point_* events fire.
|
|
185
176
|
// Use on_point_* for marker-specific data (includes `point` with InternalPoint details)
|
|
186
177
|
// or on_bar_* for backward compatibility with bar-style event handling.
|
|
187
|
-
color_scale?:
|
|
188
|
-
|
|
189
|
-
scheme?: D3ColorSchemeName | D3InterpolateName
|
|
190
|
-
value_range?: [number, number]
|
|
191
|
-
} | D3InterpolateName
|
|
192
|
-
size_scale?: {
|
|
193
|
-
type?: ScaleType
|
|
194
|
-
radius_range?: [number, number]
|
|
195
|
-
value_range?: [number, number]
|
|
196
|
-
}
|
|
178
|
+
color_scale?: ColorScaleConfig | D3InterpolateName
|
|
179
|
+
size_scale?: SizeScaleConfig
|
|
197
180
|
point_tween?: TweenOptions<Point2D>
|
|
198
181
|
on_point_click?: (
|
|
199
182
|
data: LineMarkerHandlerProps & { event: MouseEvent | KeyboardEvent },
|
|
@@ -222,29 +205,31 @@
|
|
|
222
205
|
// Initialize bar, line, y2_axis with defaults - using $derived for reactivity
|
|
223
206
|
let bar_state = $derived({ ...DEFAULTS.bar.bar, ...bar })
|
|
224
207
|
let line_state = $derived({ ...DEFAULTS.bar.line, ...line })
|
|
225
|
-
|
|
208
|
+
// Merge secondary-axis defaults as deriveds instead of assigning back into the
|
|
209
|
+
// $bindable props (which would push library defaults into the parent's bound state)
|
|
210
|
+
let y2_axis = $derived({
|
|
226
211
|
format: ``,
|
|
227
212
|
scale_type: `linear`,
|
|
228
213
|
ticks: 5,
|
|
229
|
-
label_shift: { y:
|
|
214
|
+
label_shift: { x: 0, y: 0 }, // y2 title stays vertically centered (x pos set by y2_axis_label_x)
|
|
230
215
|
tick: { label: { shift: { x: 0, y: 0 } } }, // base offset handled in rendering
|
|
231
216
|
range: [null, null],
|
|
232
|
-
...
|
|
233
|
-
}
|
|
234
|
-
x2_axis = {
|
|
217
|
+
...y2_axis_prop,
|
|
218
|
+
} as typeof y2_axis_prop)
|
|
219
|
+
let x2_axis = $derived({
|
|
235
220
|
format: ``,
|
|
236
221
|
scale_type: `linear`,
|
|
237
222
|
ticks: 5,
|
|
238
223
|
label_shift: { x: 0, y: 40 },
|
|
239
224
|
tick: { label: { shift: { x: 0, y: 0 } } },
|
|
240
225
|
range: [null, null],
|
|
241
|
-
...
|
|
242
|
-
}
|
|
226
|
+
...x2_axis_prop,
|
|
227
|
+
} as typeof x2_axis_prop)
|
|
243
228
|
|
|
244
229
|
let [width, height] = $state([0, 0])
|
|
245
230
|
let wrapper: HTMLDivElement | undefined = $state()
|
|
246
231
|
let svg_element: SVGElement | null = $state(null)
|
|
247
|
-
|
|
232
|
+
const clip_path_id = unique_id(`chart-clip`) // stable, collision-resistant (see unique_id)
|
|
248
233
|
|
|
249
234
|
// Reference line hover state
|
|
250
235
|
let hovered_ref_line_idx = $state<number | null>(null)
|
|
@@ -256,55 +241,25 @@
|
|
|
256
241
|
let indexed_ref_lines = $derived(index_ref_lines(ref_lines))
|
|
257
242
|
let ref_lines_by_z = $derived(group_ref_lines_by_z(indexed_ref_lines))
|
|
258
243
|
|
|
259
|
-
// === Categorical Normalization ===
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
let is_categorical = $derived(
|
|
264
|
-
series.some((srs) => srs.x.some((val) => typeof val === `string`)),
|
|
265
|
-
)
|
|
266
|
-
|
|
267
|
-
let category_list = $derived.by(() => {
|
|
268
|
-
if (!is_categorical) return [] as string[]
|
|
269
|
-
if (x_axis.categories?.length) return [...x_axis.categories]
|
|
270
|
-
return [...new Set(series.flatMap((srs) => srs.x.map(String)))]
|
|
271
|
-
})
|
|
244
|
+
// === Categorical Normalization (string x values -> integer indices, see ./data) ===
|
|
245
|
+
let cat_norm = $derived(normalize_categorical(series, x_axis.categories))
|
|
246
|
+
let category_list = $derived(cat_norm.category_list)
|
|
247
|
+
let internal_series = $derived(cat_norm.internal_series)
|
|
272
248
|
|
|
273
249
|
let category_indices = $derived(
|
|
274
|
-
category_list.length ? category_list.map((_, idx) => idx) : null,
|
|
250
|
+
category_list.length > 0 ? category_list.map((_, idx) => idx) : null,
|
|
275
251
|
)
|
|
276
252
|
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
)
|
|
288
|
-
}
|
|
289
|
-
// Resolve original index for each category (undefined if series lacks it)
|
|
290
|
-
const orig_indices = category_list.map((cat) => orig_map.get(cat))
|
|
291
|
-
const remap = <T>(arr: readonly T[] | null | undefined, fallback: T): T[] =>
|
|
292
|
-
orig_indices.map((oi) => oi != null ? (arr?.[oi] ?? fallback) : fallback)
|
|
293
|
-
const bw_arr = Array.isArray(srs.bar_width) ? srs.bar_width : null
|
|
294
|
-
const meta_arr = Array.isArray(srs.metadata) ? srs.metadata : null
|
|
295
|
-
return {
|
|
296
|
-
...srs,
|
|
297
|
-
x: category_indices,
|
|
298
|
-
y: remap(srs.y, srs.render_mode === `line` ? NaN : 0),
|
|
299
|
-
labels: remap(srs.labels, null),
|
|
300
|
-
metadata: orig_indices.map((oi) =>
|
|
301
|
-
oi != null ? (meta_arr ? meta_arr[oi] : srs.metadata) : undefined
|
|
302
|
-
) as Metadata[],
|
|
303
|
-
...(bw_arr ? { bar_width: remap(bw_arr, 0.5) } : {}),
|
|
304
|
-
...(srs.color_values ? { color_values: remap(srs.color_values, null) } : {}),
|
|
305
|
-
...(srs.size_values ? { size_values: remap(srs.size_values, null) } : {}),
|
|
306
|
-
} as NumericBarSeries
|
|
307
|
-
})
|
|
253
|
+
// Thin categorical tick labels + grid lines when many categories would overlap.
|
|
254
|
+
// Bars still render for every category (this only reduces drawn ticks/labels/grid).
|
|
255
|
+
let cat_tick_indices = $derived.by<number[]>(() => {
|
|
256
|
+
if (!category_indices) return []
|
|
257
|
+
const axis_px = (orientation === `horizontal` ? height : width) || 0
|
|
258
|
+
const max_ticks = Math.max(1, Math.floor(axis_px / 28)) // ~28px per category label
|
|
259
|
+
const step = Math.ceil(category_indices.length / max_ticks)
|
|
260
|
+
return step <= 1
|
|
261
|
+
? category_indices
|
|
262
|
+
: category_indices.filter((_, idx) => idx % step === 0)
|
|
308
263
|
})
|
|
309
264
|
|
|
310
265
|
// Compute auto ranges from visible series
|
|
@@ -323,124 +278,26 @@
|
|
|
323
278
|
visible_series.filter((srs) => srs.x_axis === `x2`),
|
|
324
279
|
)
|
|
325
280
|
|
|
326
|
-
let auto_ranges = $derived
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
const y_val = srs.y[idx] ?? 0
|
|
347
|
-
const totals = stacked_totals.get(x_val) ?? { pos: 0, neg: 0 }
|
|
348
|
-
if (y_val >= 0) totals.pos += y_val
|
|
349
|
-
else totals.neg += y_val
|
|
350
|
-
stacked_totals.set(x_val, totals)
|
|
351
|
-
})
|
|
352
|
-
)
|
|
353
|
-
|
|
354
|
-
// Replace points with stacked totals + line series (which don't stack)
|
|
355
|
-
points = [
|
|
356
|
-
...Array.from(stacked_totals).flatMap(([x_val, { pos, neg }]) => [
|
|
357
|
-
...(pos > 0 ? [{ x: x_val, y: pos }] : []),
|
|
358
|
-
...(neg < 0 ? [{ x: x_val, y: neg }] : []),
|
|
359
|
-
]),
|
|
360
|
-
...series_list
|
|
361
|
-
.filter((srs) => srs.render_mode === `line`)
|
|
362
|
-
.flatMap((srs) =>
|
|
363
|
-
srs.x.map((x_val, idx) => ({ x: x_val, y: srs.y[idx] }))
|
|
364
|
-
),
|
|
365
|
-
]
|
|
366
|
-
}
|
|
367
|
-
|
|
368
|
-
if (!points.length) return [0, 1]
|
|
369
|
-
|
|
370
|
-
let computed_y_range = get_nice_data_range(
|
|
371
|
-
points,
|
|
372
|
-
(pt) => pt.y,
|
|
373
|
-
y_limit,
|
|
374
|
-
scale_type,
|
|
375
|
-
range_padding,
|
|
376
|
-
false,
|
|
377
|
-
)
|
|
378
|
-
|
|
379
|
-
// For bar plots, ensure the value axis starts at 0 unless there are negative values
|
|
380
|
-
// Only apply zero-clamping for linear and arcsinh scales (not log)
|
|
381
|
-
const type_name = get_scale_type_name(scale_type)
|
|
382
|
-
if (type_name === `linear` || type_name === `arcsinh`) {
|
|
383
|
-
const has_negative = points.some((pt) => pt.y < 0)
|
|
384
|
-
const has_positive = points.some((pt) => pt.y > 0)
|
|
385
|
-
|
|
386
|
-
// Only adjust if no explicit y_range is set
|
|
387
|
-
if (y_limit?.[0] == null && y_limit?.[1] == null) {
|
|
388
|
-
if (has_positive && !has_negative) computed_y_range = [0, computed_y_range[1]]
|
|
389
|
-
else if (has_negative && !has_positive) computed_y_range = [computed_y_range[0], 0]
|
|
390
|
-
}
|
|
391
|
-
}
|
|
392
|
-
|
|
393
|
-
return computed_y_range
|
|
394
|
-
}
|
|
395
|
-
|
|
396
|
-
// Get x values split by axis for range calculation
|
|
397
|
-
// For categorical data, use fixed range centered on integer indices
|
|
398
|
-
let x_auto_range: number[]
|
|
399
|
-
if (category_list.length) {
|
|
400
|
-
x_auto_range = [-0.5, category_list.length - 0.5]
|
|
401
|
-
} else {
|
|
402
|
-
const x1_x_points = visible_series
|
|
403
|
-
.filter((srs) => (srs.x_axis ?? `x1`) === `x1`)
|
|
404
|
-
.flatMap((srs) => srs.x.map((x_val) => ({ x: x_val, y: 0 })))
|
|
405
|
-
x_auto_range = x1_x_points.length
|
|
406
|
-
? get_nice_data_range(
|
|
407
|
-
x1_x_points,
|
|
408
|
-
(pt) => pt.x,
|
|
409
|
-
x_range,
|
|
410
|
-
x_axis.scale_type ?? `linear`,
|
|
411
|
-
range_padding,
|
|
412
|
-
x_axis.format?.startsWith(`%`) || false,
|
|
413
|
-
)
|
|
414
|
-
: [0, 1]
|
|
415
|
-
}
|
|
416
|
-
|
|
417
|
-
const x2_x_points = x2_series.flatMap((srs) =>
|
|
418
|
-
srs.x.map((x_val) => ({ x: x_val, y: 0 }))
|
|
419
|
-
)
|
|
420
|
-
const x2_scale_type = x2_axis.scale_type ?? `linear`
|
|
421
|
-
const x2_auto_range = x2_x_points.length
|
|
422
|
-
? get_nice_data_range(
|
|
423
|
-
x2_x_points,
|
|
424
|
-
(pt) => pt.x,
|
|
425
|
-
x2_range,
|
|
426
|
-
x2_scale_type,
|
|
427
|
-
range_padding,
|
|
428
|
-
x2_axis.format?.startsWith(`%`) || false,
|
|
429
|
-
)
|
|
430
|
-
: [0, 1]
|
|
431
|
-
|
|
432
|
-
const y1_range = calc_y_range(y1_series, y_range, y_axis.scale_type ?? `linear`)
|
|
433
|
-
const y2_auto_range = calc_y_range(
|
|
434
|
-
y2_series,
|
|
435
|
-
y2_range,
|
|
436
|
-
y2_axis.scale_type ?? `linear`,
|
|
437
|
-
)
|
|
438
|
-
|
|
439
|
-
// Map data ranges to axis ranges depending on orientation
|
|
440
|
-
return orientation === `horizontal`
|
|
441
|
-
? ({ x: y1_range, x2: x2_auto_range, y: x_auto_range, y2: y2_auto_range })
|
|
442
|
-
: ({ x: x_auto_range, x2: x2_auto_range, y: y1_range, y2: y2_auto_range })
|
|
443
|
-
})
|
|
281
|
+
let auto_ranges = $derived(compute_bar_auto_ranges({
|
|
282
|
+
visible_series,
|
|
283
|
+
y1_series,
|
|
284
|
+
y2_series,
|
|
285
|
+
x2_series,
|
|
286
|
+
mode,
|
|
287
|
+
orientation,
|
|
288
|
+
range_padding,
|
|
289
|
+
category_count: category_list.length,
|
|
290
|
+
x_range: x_axis.range ?? [null, null],
|
|
291
|
+
x_scale_type: x_axis.scale_type ?? `linear`,
|
|
292
|
+
x_is_time: x_axis.format?.startsWith(`%`) || false,
|
|
293
|
+
x2_range: x2_axis.range ?? [null, null],
|
|
294
|
+
x2_scale_type: x2_axis.scale_type ?? `linear`,
|
|
295
|
+
x2_is_time: x2_axis.format?.startsWith(`%`) || false,
|
|
296
|
+
y_range: y_axis.range ?? [null, null],
|
|
297
|
+
y_scale_type: y_axis.scale_type ?? `linear`,
|
|
298
|
+
y2_range: y2_axis.range ?? [null, null],
|
|
299
|
+
y2_scale_type: y2_axis.scale_type ?? `linear`,
|
|
300
|
+
}))
|
|
444
301
|
|
|
445
302
|
// Initialize and current ranges
|
|
446
303
|
let ranges = $state<{
|
|
@@ -452,38 +309,16 @@
|
|
|
452
309
|
})
|
|
453
310
|
|
|
454
311
|
$effect(() => { // handle x_axis.range / x2_axis.range / y_axis.range / y2_axis.range changes
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
y_axis.range?.[1] ?? auto_ranges.y[1],
|
|
466
|
-
] as Vec2
|
|
467
|
-
const new_y2 = [
|
|
468
|
-
y2_axis.range?.[0] ?? auto_ranges.y2[0],
|
|
469
|
-
y2_axis.range?.[1] ?? auto_ranges.y2[1],
|
|
470
|
-
] as Vec2
|
|
471
|
-
// Only update if the initial (data-driven) ranges changed, not when user pans
|
|
472
|
-
// Comparing against initial preserves user's pan/zoom state
|
|
473
|
-
if (
|
|
474
|
-
ranges.initial.x[0] !== new_x[0] ||
|
|
475
|
-
ranges.initial.x[1] !== new_x[1] ||
|
|
476
|
-
ranges.initial.x2[0] !== new_x2[0] ||
|
|
477
|
-
ranges.initial.x2[1] !== new_x2[1] ||
|
|
478
|
-
ranges.initial.y[0] !== new_y[0] ||
|
|
479
|
-
ranges.initial.y[1] !== new_y[1] ||
|
|
480
|
-
ranges.initial.y2[0] !== new_y2[0] ||
|
|
481
|
-
ranges.initial.y2[1] !== new_y2[1]
|
|
482
|
-
) {
|
|
483
|
-
ranges = {
|
|
484
|
-
initial: { x: new_x, x2: new_x2, y: new_y, y2: new_y2 },
|
|
485
|
-
current: { x: new_x, x2: new_x2, y: new_y, y2: new_y2 },
|
|
486
|
-
}
|
|
312
|
+
// resolve_axis_ranges returns null for transient non-finite bounds (skip: writing
|
|
313
|
+
// NaN breaks scales and, since NaN !== NaN, loops the effect)
|
|
314
|
+
const next = resolve_axis_ranges({ x: x_axis, x2: x2_axis, y: y_axis, y2: y2_axis }, auto_ranges)
|
|
315
|
+
if (!next) return
|
|
316
|
+
// Only update if the initial (data-driven) ranges changed, not when user pans.
|
|
317
|
+
// untrack the read of `ranges` so the assignment below can't re-trigger this effect
|
|
318
|
+
// (reading + writing the same state otherwise causes effect_update_depth_exceeded).
|
|
319
|
+
const init = untrack(() => ranges.initial)
|
|
320
|
+
if (!axis_ranges_equal(init, next)) {
|
|
321
|
+
ranges = { initial: { ...next }, current: { ...next } }
|
|
487
322
|
}
|
|
488
323
|
})
|
|
489
324
|
|
|
@@ -494,7 +329,7 @@
|
|
|
494
329
|
|
|
495
330
|
// Update padding when format or ticks change
|
|
496
331
|
$effect(() => {
|
|
497
|
-
const new_pad = width && height && ticks.y.length
|
|
332
|
+
const new_pad = width && height && ticks.y.length > 0
|
|
498
333
|
? calc_auto_padding({
|
|
499
334
|
padding,
|
|
500
335
|
default_padding,
|
|
@@ -505,7 +340,7 @@
|
|
|
505
340
|
: filter_padding(padding, default_padding)
|
|
506
341
|
// Expand right padding if y2 ticks are shown (only for vertical orientation)
|
|
507
342
|
if (
|
|
508
|
-
width && height && y2_series.length && ticks.y2.length &&
|
|
343
|
+
width && height && y2_series.length > 0 && ticks.y2.length > 0 &&
|
|
509
344
|
orientation === `vertical`
|
|
510
345
|
) {
|
|
511
346
|
// Need space for: tick shift + tick width + gap (30px) + label space (20px if present)
|
|
@@ -521,7 +356,7 @@
|
|
|
521
356
|
}
|
|
522
357
|
// Expand top padding if x2 ticks are shown (only for vertical orientation)
|
|
523
358
|
if (
|
|
524
|
-
width && height && x2_series.length && ticks.x2.length &&
|
|
359
|
+
width && height && x2_series.length > 0 && ticks.x2.length > 0 &&
|
|
525
360
|
orientation === `vertical`
|
|
526
361
|
) {
|
|
527
362
|
const inside = x2_axis.tick?.label?.inside ?? false
|
|
@@ -546,7 +381,7 @@
|
|
|
546
381
|
// from baseline to its tip so the legend can't hide inside a tall bar. Built from internal_series
|
|
547
382
|
// (pad-independent) + ranges so the crowding decision can't see its own reservation.
|
|
548
383
|
const obstacles_norm = $derived.by(() => {
|
|
549
|
-
if (!width || !height ||
|
|
384
|
+
if (!width || !height || visible_series.length === 0) return []
|
|
550
385
|
const base_w = width - base_pad.l - base_pad.r
|
|
551
386
|
const base_h = height - base_pad.t - base_pad.b
|
|
552
387
|
if (base_w <= 0 || base_h <= 0) return []
|
|
@@ -634,7 +469,7 @@
|
|
|
634
469
|
)
|
|
635
470
|
|
|
636
471
|
// Create auto color range (safely handle empty arrays or undefined extent results)
|
|
637
|
-
let auto_color_range:
|
|
472
|
+
let auto_color_range: Vec2 = $derived.by(() => {
|
|
638
473
|
if (all_color_values.length === 0) return [0, 1]
|
|
639
474
|
const [min_val, max_val] = extent(all_color_values)
|
|
640
475
|
return [min_val ?? 0, max_val ?? 1]
|
|
@@ -661,7 +496,7 @@
|
|
|
661
496
|
// In vertical mode categories are on x-axis; in horizontal mode on y-axis
|
|
662
497
|
let cat_axis = $derived(orientation === `horizontal` ? `y` : `x`)
|
|
663
498
|
let effective_cat_ticks = $derived.by(() => {
|
|
664
|
-
if (
|
|
499
|
+
if (category_list.length === 0) return undefined
|
|
665
500
|
// Only respect user ticks when they're a Record (custom label mapping),
|
|
666
501
|
// not a number (tick count) or array (tick positions)
|
|
667
502
|
const user_ticks = cat_axis === `x` ? x_axis.ticks : y_axis.ticks
|
|
@@ -677,7 +512,7 @@
|
|
|
677
512
|
// Ticks
|
|
678
513
|
let ticks = $derived({
|
|
679
514
|
x: width && height
|
|
680
|
-
? (category_indices && cat_axis === `x` ?
|
|
515
|
+
? (category_indices && cat_axis === `x` ? cat_tick_indices : generate_ticks(
|
|
681
516
|
ranges.current.x,
|
|
682
517
|
x_axis.scale_type ?? `linear`,
|
|
683
518
|
x_axis.ticks,
|
|
@@ -686,7 +521,7 @@
|
|
|
686
521
|
))
|
|
687
522
|
: [],
|
|
688
523
|
y: width && height
|
|
689
|
-
? (category_indices && cat_axis === `y` ?
|
|
524
|
+
? (category_indices && cat_axis === `y` ? cat_tick_indices : generate_ticks(
|
|
690
525
|
ranges.current.y,
|
|
691
526
|
y_axis.scale_type ?? `linear`,
|
|
692
527
|
y_axis.ticks,
|
|
@@ -726,298 +561,44 @@
|
|
|
726
561
|
x2_max: measure_max_tick_width(ticks.x2, x2_axis.format ?? ``),
|
|
727
562
|
})
|
|
728
563
|
|
|
729
|
-
//
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
}
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
const y2_1 = scales.y2.invert(drag_state.start.y)
|
|
759
|
-
const y2_2 = scales.y2.invert(drag_state.current.y)
|
|
760
|
-
const x2a_1_raw = scales.x2.invert(drag_state.start.x) as number | Date
|
|
761
|
-
const x2a_2_raw = scales.x2.invert(drag_state.current.x) as number | Date
|
|
762
|
-
const dx = Math.abs(drag_state.start.x - drag_state.current.x)
|
|
763
|
-
const dy = Math.abs(drag_state.start.y - drag_state.current.y)
|
|
764
|
-
|
|
765
|
-
let xr1: number, xr2: number
|
|
766
|
-
if (x1_raw instanceof Date && x2_raw instanceof Date) {
|
|
767
|
-
;[xr1, xr2] = [x1_raw.getTime(), x2_raw.getTime()]
|
|
768
|
-
} else if (typeof x1_raw === `number` && typeof x2_raw === `number`) {
|
|
769
|
-
;[xr1, xr2] = [x1_raw, x2_raw]
|
|
770
|
-
} else [xr1, xr2] = [NaN, NaN] // bail: mixed types
|
|
771
|
-
|
|
772
|
-
let x2r1: number, x2r2: number
|
|
773
|
-
if (x2a_1_raw instanceof Date && x2a_2_raw instanceof Date) {
|
|
774
|
-
;[x2r1, x2r2] = [x2a_1_raw.getTime(), x2a_2_raw.getTime()]
|
|
775
|
-
} else if (typeof x2a_1_raw === `number` && typeof x2a_2_raw === `number`) {
|
|
776
|
-
;[x2r1, x2r2] = [x2a_1_raw, x2a_2_raw]
|
|
777
|
-
} else [x2r1, x2r2] = [NaN, NaN]
|
|
778
|
-
|
|
779
|
-
if (dx > 5 && dy > 5 && Number.isFinite(xr1) && Number.isFinite(xr2)) {
|
|
780
|
-
// Update axis ranges to trigger reactivity and prevent effect from overriding
|
|
781
|
-
x_axis = { ...x_axis, range: [Math.min(xr1, xr2), Math.max(xr1, xr2)] }
|
|
782
|
-
if (x2_series.length > 0 && Number.isFinite(x2r1) && Number.isFinite(x2r2)) {
|
|
783
|
-
x2_axis = {
|
|
784
|
-
...x2_axis,
|
|
785
|
-
range: [Math.min(x2r1, x2r2), Math.max(x2r1, x2r2)],
|
|
786
|
-
}
|
|
787
|
-
}
|
|
788
|
-
y_axis = { ...y_axis, range: [Math.min(y1, y2), Math.max(y1, y2)] }
|
|
789
|
-
y2_axis = { ...y2_axis, range: [Math.min(y2_1, y2_2), Math.max(y2_1, y2_2)] }
|
|
790
|
-
}
|
|
791
|
-
}
|
|
792
|
-
drag_state = { start: null, current: null, bounds: null }
|
|
793
|
-
window.removeEventListener(`mousemove`, on_window_mouse_move)
|
|
794
|
-
window.removeEventListener(`mouseup`, on_window_mouse_up)
|
|
795
|
-
document.body.style.cursor = `default`
|
|
796
|
-
}
|
|
797
|
-
|
|
798
|
-
// Pan drag handlers
|
|
799
|
-
const on_pan_move = (evt: MouseEvent) => {
|
|
800
|
-
if (!pan_drag_state) return
|
|
801
|
-
const dx = evt.clientX - pan_drag_state.start.x
|
|
802
|
-
const dy = evt.clientY - pan_drag_state.start.y
|
|
803
|
-
|
|
804
|
-
// Convert pixel delta to data delta (note: drag direction is inverted for natural pan feel)
|
|
805
|
-
const sensitivity = pan?.drag_sensitivity ?? 1
|
|
806
|
-
|
|
807
|
-
const x_delta = pixels_to_data_delta(
|
|
808
|
-
-dx * sensitivity,
|
|
809
|
-
pan_drag_state.initial_x_range,
|
|
810
|
-
chart_width,
|
|
811
|
-
)
|
|
812
|
-
const x2_delta = pixels_to_data_delta(
|
|
813
|
-
-dx * sensitivity,
|
|
814
|
-
pan_drag_state.initial_x2_range,
|
|
815
|
-
chart_width,
|
|
816
|
-
)
|
|
817
|
-
const y_delta = pixels_to_data_delta(
|
|
818
|
-
dy * sensitivity,
|
|
819
|
-
pan_drag_state.initial_y_range,
|
|
820
|
-
chart_height,
|
|
821
|
-
)
|
|
822
|
-
const y2_delta = pixels_to_data_delta(
|
|
823
|
-
dy * sensitivity,
|
|
824
|
-
pan_drag_state.initial_y2_range,
|
|
825
|
-
chart_height,
|
|
826
|
-
)
|
|
827
|
-
|
|
828
|
-
ranges.current.x = pan_range(pan_drag_state.initial_x_range, x_delta)
|
|
829
|
-
ranges.current.x2 = pan_range(pan_drag_state.initial_x2_range, x2_delta)
|
|
830
|
-
ranges.current.y = pan_range(pan_drag_state.initial_y_range, y_delta)
|
|
831
|
-
ranges.current.y2 = pan_range(pan_drag_state.initial_y2_range, y2_delta)
|
|
832
|
-
}
|
|
833
|
-
|
|
834
|
-
const on_pan_end = () => {
|
|
835
|
-
pan_drag_state = null
|
|
836
|
-
document.body.style.cursor = ``
|
|
837
|
-
window.removeEventListener(`mousemove`, on_pan_move)
|
|
838
|
-
window.removeEventListener(`mouseup`, on_pan_end)
|
|
839
|
-
}
|
|
840
|
-
|
|
841
|
-
function handle_mouse_down(evt: MouseEvent) {
|
|
842
|
-
const coords = get_relative_coords(evt)
|
|
843
|
-
if (!coords || !svg_element) return
|
|
844
|
-
|
|
845
|
-
// Check if pan is enabled and shift is held for pan mode
|
|
846
|
-
const pan_enabled = pan?.enabled !== false
|
|
847
|
-
if (pan_enabled && evt.shiftKey) {
|
|
848
|
-
evt.preventDefault()
|
|
849
|
-
pan_drag_state = {
|
|
850
|
-
start: { x: evt.clientX, y: evt.clientY },
|
|
851
|
-
initial_x_range: [...ranges.current.x] as [number, number],
|
|
852
|
-
initial_x2_range: [...ranges.current.x2] as [number, number],
|
|
853
|
-
initial_y_range: [...ranges.current.y] as [number, number],
|
|
854
|
-
initial_y2_range: [...ranges.current.y2] as [number, number],
|
|
564
|
+
// Shared pan/zoom/touch/drag-rect interaction controller
|
|
565
|
+
const pan_zoom = create_pan_zoom({
|
|
566
|
+
ranges: () => ranges.current,
|
|
567
|
+
scale_type: (axis) => ({ x: x_axis, x2: x2_axis, y: y_axis, y2: y2_axis })[axis].scale_type,
|
|
568
|
+
plot_dims: () => ({ width: chart_width, height: chart_height }),
|
|
569
|
+
pan: () => pan,
|
|
570
|
+
set_range: (axis, range) => (ranges.current[axis] = range),
|
|
571
|
+
svg: () => svg_element,
|
|
572
|
+
on_rect_zoom: (start, current) => {
|
|
573
|
+
// Update axis ranges to trigger reactivity and prevent effect from overriding
|
|
574
|
+
const next_x = invert_rect_range(scales.x, start.x, current.x)
|
|
575
|
+
if (!next_x) return
|
|
576
|
+
x_axis = { ...x_axis, range: next_x }
|
|
577
|
+
// gate x2/y2 on series presence: their scales are [0, 1] sentinels otherwise,
|
|
578
|
+
// so inverting would store a phantom range in the bindable prop
|
|
579
|
+
const next_x2 = x2_series.length > 0 ? invert_rect_range(scales.x2, start.x, current.x) : null
|
|
580
|
+
if (next_x2) x2_axis_prop = { ...x2_axis_prop, range: next_x2 }
|
|
581
|
+
const next_y = invert_rect_range(scales.y, start.y, current.y)
|
|
582
|
+
if (next_y) y_axis = { ...y_axis, range: next_y }
|
|
583
|
+
const next_y2 = y2_series.length > 0 ? invert_rect_range(scales.y2, start.y, current.y) : null
|
|
584
|
+
if (next_y2) y2_axis_prop = { ...y2_axis_prop, range: next_y2 }
|
|
585
|
+
},
|
|
586
|
+
on_reset: () => {
|
|
587
|
+
// Reset zoom to initial ranges (undo any pan/zoom)
|
|
588
|
+
ranges.current = {
|
|
589
|
+
x: [...ranges.initial.x] as Vec2,
|
|
590
|
+
x2: [...ranges.initial.x2] as Vec2,
|
|
591
|
+
y: [...ranges.initial.y] as Vec2,
|
|
592
|
+
y2: [...ranges.initial.y2] as Vec2,
|
|
855
593
|
}
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
current: coords,
|
|
865
|
-
bounds: svg_element.getBoundingClientRect(),
|
|
866
|
-
}
|
|
867
|
-
window.addEventListener(`mousemove`, on_window_mouse_move)
|
|
868
|
-
window.addEventListener(`mouseup`, on_window_mouse_up)
|
|
869
|
-
evt.preventDefault()
|
|
870
|
-
}
|
|
871
|
-
|
|
872
|
-
// Wheel handler for pan (requires focus and shift)
|
|
873
|
-
function handle_wheel(evt: WheelEvent) {
|
|
874
|
-
const pan_enabled = pan?.enabled !== false
|
|
875
|
-
// Only capture wheel when focused AND Shift is held
|
|
876
|
-
// Use shift_held state (tracked via keydown/keyup) for compatibility with synthetic events
|
|
877
|
-
if (!pan_enabled || !is_focused || !shift_held) return
|
|
878
|
-
|
|
879
|
-
evt.preventDefault()
|
|
880
|
-
|
|
881
|
-
const sensitivity = pan?.wheel_sensitivity ?? 1
|
|
882
|
-
|
|
883
|
-
// Determine pan direction based on wheel delta
|
|
884
|
-
const x_delta = pixels_to_data_delta(
|
|
885
|
-
evt.deltaX * sensitivity,
|
|
886
|
-
ranges.current.x,
|
|
887
|
-
chart_width,
|
|
888
|
-
)
|
|
889
|
-
const x2_delta = pixels_to_data_delta(
|
|
890
|
-
evt.deltaX * sensitivity,
|
|
891
|
-
ranges.current.x2,
|
|
892
|
-
chart_width,
|
|
893
|
-
)
|
|
894
|
-
const y_delta = pixels_to_data_delta(
|
|
895
|
-
evt.deltaY * sensitivity,
|
|
896
|
-
ranges.current.y,
|
|
897
|
-
chart_height,
|
|
898
|
-
)
|
|
899
|
-
const y2_delta = pixels_to_data_delta(
|
|
900
|
-
evt.deltaY * sensitivity,
|
|
901
|
-
ranges.current.y2,
|
|
902
|
-
chart_height,
|
|
903
|
-
)
|
|
904
|
-
|
|
905
|
-
if (Math.abs(evt.deltaX) > Math.abs(evt.deltaY)) {
|
|
906
|
-
ranges.current.x = pan_range(ranges.current.x, x_delta)
|
|
907
|
-
ranges.current.x2 = pan_range(ranges.current.x2, x2_delta)
|
|
908
|
-
} else {
|
|
909
|
-
ranges.current.y = pan_range(ranges.current.y, y_delta)
|
|
910
|
-
ranges.current.y2 = pan_range(ranges.current.y2, y2_delta)
|
|
911
|
-
}
|
|
912
|
-
}
|
|
913
|
-
|
|
914
|
-
// Touch handlers for pinch-zoom and two-finger pan
|
|
915
|
-
function handle_touch_start(evt: TouchEvent) {
|
|
916
|
-
const touch_enabled = pan?.enabled !== false && pan?.touch_enabled !== false
|
|
917
|
-
if (!touch_enabled || evt.touches.length !== 2) return
|
|
918
|
-
|
|
919
|
-
evt.preventDefault()
|
|
920
|
-
const touches = Array.from(evt.touches)
|
|
921
|
-
touch_state = {
|
|
922
|
-
start_touches: touches.map((touch) => ({ x: touch.clientX, y: touch.clientY })),
|
|
923
|
-
initial_x_range: [...ranges.current.x] as [number, number],
|
|
924
|
-
initial_x2_range: [...ranges.current.x2] as [number, number],
|
|
925
|
-
initial_y_range: [...ranges.current.y] as [number, number],
|
|
926
|
-
initial_y2_range: [...ranges.current.y2] as [number, number],
|
|
927
|
-
}
|
|
928
|
-
}
|
|
929
|
-
|
|
930
|
-
function handle_touch_move(evt: TouchEvent) {
|
|
931
|
-
if (!touch_state || evt.touches.length !== 2) return
|
|
932
|
-
evt.preventDefault()
|
|
933
|
-
|
|
934
|
-
const [t1, t2] = Array.from(evt.touches)
|
|
935
|
-
const [s1, s2] = touch_state.start_touches
|
|
936
|
-
|
|
937
|
-
// Calculate center movement for pan
|
|
938
|
-
const start_center = { x: (s1.x + s2.x) / 2, y: (s1.y + s2.y) / 2 }
|
|
939
|
-
const curr_center = {
|
|
940
|
-
x: (t1.clientX + t2.clientX) / 2,
|
|
941
|
-
y: (t1.clientY + t2.clientY) / 2,
|
|
942
|
-
}
|
|
943
|
-
const dx = curr_center.x - start_center.x
|
|
944
|
-
const dy = curr_center.y - start_center.y
|
|
945
|
-
|
|
946
|
-
// Calculate pinch scale (curr/start so spread = zoom out, pinch = zoom in)
|
|
947
|
-
const start_dist = Math.hypot(s2.x - s1.x, s2.y - s1.y)
|
|
948
|
-
// Guard against zero-distance pinch to avoid Infinity scale
|
|
949
|
-
if (start_dist < Number.EPSILON) return
|
|
950
|
-
const curr_dist = Math.hypot(t2.clientX - t1.clientX, t2.clientY - t1.clientY)
|
|
951
|
-
const scale = curr_dist / start_dist
|
|
952
|
-
|
|
953
|
-
// If scale changed significantly, treat as pinch-zoom
|
|
954
|
-
// Also guard against scale being too small to avoid division by zero
|
|
955
|
-
if (Math.abs(scale - 1) > PINCH_ZOOM_THRESHOLD && scale > Number.EPSILON) {
|
|
956
|
-
// Pinch zoom centered on gesture center
|
|
957
|
-
// Divide by scale so spread (scale > 1) = smaller span (zoom in)
|
|
958
|
-
const x_span = touch_state.initial_x_range[1] - touch_state.initial_x_range[0]
|
|
959
|
-
const x2_span = touch_state.initial_x2_range[1] -
|
|
960
|
-
touch_state.initial_x2_range[0]
|
|
961
|
-
const y_span = touch_state.initial_y_range[1] - touch_state.initial_y_range[0]
|
|
962
|
-
const y2_span = touch_state.initial_y2_range[1] -
|
|
963
|
-
touch_state.initial_y2_range[0]
|
|
964
|
-
const x_center =
|
|
965
|
-
(touch_state.initial_x_range[0] + touch_state.initial_x_range[1]) / 2
|
|
966
|
-
const x2_center =
|
|
967
|
-
(touch_state.initial_x2_range[0] + touch_state.initial_x2_range[1]) / 2
|
|
968
|
-
const y_center =
|
|
969
|
-
(touch_state.initial_y_range[0] + touch_state.initial_y_range[1]) / 2
|
|
970
|
-
const y2_center =
|
|
971
|
-
(touch_state.initial_y2_range[0] + touch_state.initial_y2_range[1]) / 2
|
|
972
|
-
|
|
973
|
-
ranges.current.x = [
|
|
974
|
-
x_center - x_span / scale / 2,
|
|
975
|
-
x_center + x_span / scale / 2,
|
|
976
|
-
]
|
|
977
|
-
ranges.current.x2 = [
|
|
978
|
-
x2_center - x2_span / scale / 2,
|
|
979
|
-
x2_center + x2_span / scale / 2,
|
|
980
|
-
]
|
|
981
|
-
ranges.current.y = [
|
|
982
|
-
y_center - y_span / scale / 2,
|
|
983
|
-
y_center + y_span / scale / 2,
|
|
984
|
-
]
|
|
985
|
-
ranges.current.y2 = [
|
|
986
|
-
y2_center - y2_span / scale / 2,
|
|
987
|
-
y2_center + y2_span / scale / 2,
|
|
988
|
-
]
|
|
989
|
-
} else {
|
|
990
|
-
// Pan
|
|
991
|
-
const x_delta = pixels_to_data_delta(
|
|
992
|
-
-dx,
|
|
993
|
-
touch_state.initial_x_range,
|
|
994
|
-
chart_width,
|
|
995
|
-
)
|
|
996
|
-
const x2_delta = pixels_to_data_delta(
|
|
997
|
-
-dx,
|
|
998
|
-
touch_state.initial_x2_range,
|
|
999
|
-
chart_width,
|
|
1000
|
-
)
|
|
1001
|
-
const y_delta = pixels_to_data_delta(
|
|
1002
|
-
dy,
|
|
1003
|
-
touch_state.initial_y_range,
|
|
1004
|
-
chart_height,
|
|
1005
|
-
)
|
|
1006
|
-
const y2_delta = pixels_to_data_delta(
|
|
1007
|
-
dy,
|
|
1008
|
-
touch_state.initial_y2_range,
|
|
1009
|
-
chart_height,
|
|
1010
|
-
)
|
|
1011
|
-
ranges.current.x = pan_range(touch_state.initial_x_range, x_delta)
|
|
1012
|
-
ranges.current.x2 = pan_range(touch_state.initial_x2_range, x2_delta)
|
|
1013
|
-
ranges.current.y = pan_range(touch_state.initial_y_range, y_delta)
|
|
1014
|
-
ranges.current.y2 = pan_range(touch_state.initial_y2_range, y2_delta)
|
|
1015
|
-
}
|
|
1016
|
-
}
|
|
1017
|
-
|
|
1018
|
-
function handle_touch_end() {
|
|
1019
|
-
touch_state = null
|
|
1020
|
-
}
|
|
594
|
+
// Also reset axis props so future data changes recalculate auto ranges
|
|
595
|
+
x_axis = { ...x_axis, range: [null, null] }
|
|
596
|
+
x2_axis_prop = { ...x2_axis_prop, range: [null, null] }
|
|
597
|
+
y_axis = { ...y_axis, range: [null, null] }
|
|
598
|
+
y2_axis_prop = { ...y2_axis_prop, range: [null, null] }
|
|
599
|
+
},
|
|
600
|
+
})
|
|
601
|
+
onDestroy(() => pan_zoom.destroy())
|
|
1021
602
|
|
|
1022
603
|
// Legend data and handlers
|
|
1023
604
|
let legend_data = $derived.by<LegendItem[]>(() =>
|
|
@@ -1076,34 +657,11 @@
|
|
|
1076
657
|
})
|
|
1077
658
|
)
|
|
1078
659
|
|
|
1079
|
-
|
|
1080
|
-
if (series_idx >= 0 && series_idx < series.length) {
|
|
1081
|
-
series = series.map((srs, idx) =>
|
|
1082
|
-
idx === series_idx ? { ...srs, visible: !(srs.visible ?? true) } : srs
|
|
1083
|
-
)
|
|
1084
|
-
}
|
|
1085
|
-
}
|
|
1086
|
-
|
|
1087
|
-
function toggle_group_visibility(_group_name: string, series_indices: number[]) {
|
|
1088
|
-
// Filter to valid indices upfront (consistent with shared toggle_group_visibility)
|
|
1089
|
-
const valid_indices = series_indices.filter((idx) =>
|
|
1090
|
-
idx >= 0 && idx < series.length
|
|
1091
|
-
)
|
|
1092
|
-
if (valid_indices.length === 0) return
|
|
1093
|
-
|
|
1094
|
-
const idx_set = new Set(valid_indices)
|
|
1095
|
-
// Check if all series in the group are currently visible
|
|
1096
|
-
const all_visible = valid_indices.every((idx) => series[idx].visible ?? true)
|
|
1097
|
-
// Toggle: if all visible, hide all; otherwise show all
|
|
1098
|
-
const new_visibility = !all_visible
|
|
1099
|
-
series = series.map((srs, idx) =>
|
|
1100
|
-
idx_set.has(idx) ? { ...srs, visible: new_visibility } : srs
|
|
1101
|
-
)
|
|
1102
|
-
}
|
|
660
|
+
const legend_vis = create_legend_visibility(() => series, (next) => (series = next))
|
|
1103
661
|
|
|
1104
662
|
// Collect bar and line positions for legend placement
|
|
1105
663
|
let bar_points_for_placement = $derived.by(() => {
|
|
1106
|
-
if (!width || !height ||
|
|
664
|
+
if (!width || !height || visible_series.length === 0) return []
|
|
1107
665
|
|
|
1108
666
|
return internal_series.flatMap((srs, series_idx) => {
|
|
1109
667
|
if (!(srs?.visible ?? true)) return []
|
|
@@ -1130,12 +688,6 @@
|
|
|
1130
688
|
|
|
1131
689
|
// Legend placement stability state (legend_element declared above for the auto-place block)
|
|
1132
690
|
let hovered_legend_series_idx = $state<number | null>(null)
|
|
1133
|
-
const legend_hover = create_hover_lock()
|
|
1134
|
-
const dim_tracker = create_dimension_tracker()
|
|
1135
|
-
let has_initial_legend_placement = $state(false)
|
|
1136
|
-
|
|
1137
|
-
// Clear pending hover lock timeout on unmount
|
|
1138
|
-
$effect(() => () => legend_hover.cleanup())
|
|
1139
691
|
|
|
1140
692
|
// Calculate best legend placement using continuous grid sampling
|
|
1141
693
|
let legend_placement = $derived.by(() => {
|
|
@@ -1154,42 +706,17 @@
|
|
|
1154
706
|
return result
|
|
1155
707
|
})
|
|
1156
708
|
|
|
1157
|
-
// Tweened legend coordinates
|
|
1158
|
-
|
|
1159
|
-
|
|
1160
|
-
{
|
|
1161
|
-
|
|
1162
|
-
|
|
1163
|
-
|
|
1164
|
-
// Update legend position with stability checks
|
|
1165
|
-
$effect(() => {
|
|
1166
|
-
if (!width || !height || !legend_placement) return
|
|
1167
|
-
|
|
1168
|
-
// Track dimensions for resize detection
|
|
1169
|
-
const dims_changed = dim_tracker.has_changed(width, height)
|
|
1170
|
-
if (dims_changed) dim_tracker.update(width, height)
|
|
1171
|
-
|
|
1172
|
-
const is_responsive = legend?.responsive ?? false
|
|
1173
|
-
// Only update if: resize occurred, OR (not hover-locked AND (responsive OR not yet initially placed))
|
|
1174
|
-
const should_update = dims_changed || (!legend_hover.is_locked.current &&
|
|
1175
|
-
(is_responsive || !has_initial_legend_placement))
|
|
1176
|
-
|
|
1177
|
-
if (should_update) {
|
|
1178
|
-
tweened_legend_coords.set(
|
|
1179
|
-
{ x: legend_placement.x, y: legend_placement.y },
|
|
1180
|
-
// Skip animation on initial placement to avoid jump from (0, 0)
|
|
1181
|
-
has_initial_legend_placement ? undefined : { duration: 0 },
|
|
1182
|
-
)
|
|
1183
|
-
// Only lock position after we have actual measured size
|
|
1184
|
-
if (legend_element) {
|
|
1185
|
-
has_initial_legend_placement = true
|
|
1186
|
-
}
|
|
1187
|
-
}
|
|
709
|
+
// Tweened legend coordinates with shared placement stability gating
|
|
710
|
+
const legend_tween = create_placed_tween({
|
|
711
|
+
placement: () => legend_placement,
|
|
712
|
+
dims: () => ({ width, height }),
|
|
713
|
+
responsive: () => legend?.responsive ?? false,
|
|
714
|
+
element: () => legend_element,
|
|
715
|
+
tween: () => legend?.tween,
|
|
1188
716
|
})
|
|
1189
717
|
|
|
1190
718
|
// Tooltip state
|
|
1191
719
|
let hover_info = $state<BarHandlerProps<Metadata> | null>(null)
|
|
1192
|
-
let tooltip_el = $state<HTMLDivElement | undefined>()
|
|
1193
720
|
|
|
1194
721
|
function get_bar_data(
|
|
1195
722
|
series_idx: number,
|
|
@@ -1267,49 +794,10 @@
|
|
|
1267
794
|
}
|
|
1268
795
|
|
|
1269
796
|
// Stack offsets (only for bar series in stacked mode, grouped by y-axis)
|
|
1270
|
-
let stacked_offsets = $derived
|
|
1271
|
-
if (mode !== `stacked`) return [] as number[][]
|
|
1272
|
-
const max_len = Math.max(
|
|
1273
|
-
0,
|
|
1274
|
-
...internal_series.map((srs) => srs.y.length),
|
|
1275
|
-
)
|
|
1276
|
-
const offsets = internal_series.map(() =>
|
|
1277
|
-
Array.from({ length: max_len }, () => 0)
|
|
1278
|
-
)
|
|
1279
|
-
|
|
1280
|
-
// Separate accumulators for y1 and y2 axes
|
|
1281
|
-
const y1_pos_acc = Array.from({ length: max_len }, () => 0)
|
|
1282
|
-
const y1_neg_acc = Array.from({ length: max_len }, () => 0)
|
|
1283
|
-
const y2_pos_acc = Array.from({ length: max_len }, () => 0)
|
|
1284
|
-
const y2_neg_acc = Array.from({ length: max_len }, () => 0)
|
|
1285
|
-
|
|
1286
|
-
internal_series.forEach((srs, series_idx) => {
|
|
1287
|
-
if (!(srs?.visible ?? true) || srs.render_mode === `line`) return
|
|
1288
|
-
|
|
1289
|
-
const use_y2 = srs.y_axis === `y2`
|
|
1290
|
-
const pos_acc = use_y2 ? y2_pos_acc : y1_pos_acc
|
|
1291
|
-
const neg_acc = use_y2 ? y2_neg_acc : y1_neg_acc
|
|
1292
|
-
|
|
1293
|
-
for (let bar_idx = 0; bar_idx < max_len; bar_idx++) {
|
|
1294
|
-
const y_val = srs.y[bar_idx] ?? 0
|
|
1295
|
-
const acc = y_val >= 0 ? pos_acc : neg_acc
|
|
1296
|
-
offsets[series_idx][bar_idx] = acc[bar_idx]
|
|
1297
|
-
acc[bar_idx] += y_val
|
|
1298
|
-
}
|
|
1299
|
-
})
|
|
1300
|
-
return offsets
|
|
1301
|
-
})
|
|
797
|
+
let stacked_offsets = $derived(compute_stacked_offsets(internal_series, mode))
|
|
1302
798
|
|
|
1303
799
|
// Calculate group positions for grouped mode (side-by-side bars)
|
|
1304
|
-
let group_info = $derived
|
|
1305
|
-
if (mode !== `grouped`) return { bar_series_count: 0, bar_series_indices: [] }
|
|
1306
|
-
const bar_series_indices = internal_series
|
|
1307
|
-
.map((srs, idx) =>
|
|
1308
|
-
(srs?.visible ?? true) && srs.render_mode !== `line` ? idx : -1
|
|
1309
|
-
)
|
|
1310
|
-
.filter((idx) => idx >= 0)
|
|
1311
|
-
return { bar_series_count: bar_series_indices.length, bar_series_indices }
|
|
1312
|
-
})
|
|
800
|
+
let group_info = $derived(compute_group_info(internal_series, mode))
|
|
1313
801
|
|
|
1314
802
|
// Set theme-aware background when entering fullscreen
|
|
1315
803
|
$effect(() => {
|
|
@@ -1327,9 +815,9 @@
|
|
|
1327
815
|
set_axis: (axis, config) => {
|
|
1328
816
|
// Spread into existing state to preserve merged type structure
|
|
1329
817
|
if (axis === `x`) x_axis = { ...x_axis, ...config }
|
|
1330
|
-
else if (axis === `x2`)
|
|
818
|
+
else if (axis === `x2`) x2_axis_prop = { ...x2_axis_prop, ...config }
|
|
1331
819
|
else if (axis === `y`) y_axis = { ...y_axis, ...config }
|
|
1332
|
-
else
|
|
820
|
+
else y2_axis_prop = { ...y2_axis_prop, ...config }
|
|
1333
821
|
},
|
|
1334
822
|
get_series: () => series,
|
|
1335
823
|
set_series: (new_series) => (series = new_series),
|
|
@@ -1337,32 +825,12 @@
|
|
|
1337
825
|
set_loading: (axis) => (axis_loading = axis),
|
|
1338
826
|
}
|
|
1339
827
|
|
|
1340
|
-
//
|
|
1341
|
-
|
|
1342
|
-
const handle_axis_change = $derived(create_axis_change_handler(
|
|
828
|
+
// Shared handler + one-shot auto-load bound to this component's state
|
|
829
|
+
const { handle_axis_change, try_auto_load } = create_axis_loader(
|
|
1343
830
|
axis_state,
|
|
1344
|
-
data_loader,
|
|
1345
|
-
|
|
1346
|
-
|
|
1347
|
-
))
|
|
1348
|
-
|
|
1349
|
-
let auto_load_attempted = false // prevent infinite retries on failure
|
|
1350
|
-
|
|
1351
|
-
// Auto-load data if series is empty but options exist (runs once)
|
|
1352
|
-
$effect(() => {
|
|
1353
|
-
if (series.length === 0 && data_loader && !auto_load_attempted) {
|
|
1354
|
-
// Check x-axis first, then y-axis
|
|
1355
|
-
if (x_axis.options?.length) {
|
|
1356
|
-
auto_load_attempted = true
|
|
1357
|
-
const first_key = x_axis.selected_key ?? x_axis.options[0].key
|
|
1358
|
-
handle_axis_change(`x`, first_key).catch(() => {})
|
|
1359
|
-
} else if (y_axis.options?.length) {
|
|
1360
|
-
auto_load_attempted = true
|
|
1361
|
-
const first_key = y_axis.selected_key ?? y_axis.options[0].key
|
|
1362
|
-
handle_axis_change(`y`, first_key).catch(() => {})
|
|
1363
|
-
}
|
|
1364
|
-
}
|
|
1365
|
-
})
|
|
831
|
+
() => ({ data_loader, on_axis_change, on_error }),
|
|
832
|
+
)
|
|
833
|
+
$effect(try_auto_load)
|
|
1366
834
|
</script>
|
|
1367
835
|
|
|
1368
836
|
{#snippet ref_lines_layer(lines: IndexedRefLine[])}
|
|
@@ -1399,11 +867,9 @@
|
|
|
1399
867
|
evt.preventDefault()
|
|
1400
868
|
fullscreen = false
|
|
1401
869
|
}
|
|
1402
|
-
|
|
1403
|
-
}}
|
|
1404
|
-
onkeyup={(evt) => {
|
|
1405
|
-
if (evt.key === `Shift`) shift_held = false
|
|
870
|
+
pan_zoom.on_window_key_down(evt)
|
|
1406
871
|
}}
|
|
872
|
+
onkeyup={pan_zoom.on_window_key_up}
|
|
1407
873
|
/>
|
|
1408
874
|
|
|
1409
875
|
<div
|
|
@@ -1429,38 +895,25 @@
|
|
|
1429
895
|
aria-label={rest[`aria-label`] ??
|
|
1430
896
|
([x_axis.label, y_axis.label].filter(Boolean).join(` vs `) || `Bar chart`)}
|
|
1431
897
|
tabindex="0"
|
|
1432
|
-
onfocusin={() => (
|
|
1433
|
-
onfocusout={() => (
|
|
1434
|
-
onmousedown={
|
|
1435
|
-
ondblclick={
|
|
1436
|
-
|
|
1437
|
-
ranges.current.x = [...ranges.initial.x] as [number, number]
|
|
1438
|
-
ranges.current.x2 = [...ranges.initial.x2] as [number, number]
|
|
1439
|
-
ranges.current.y = [...ranges.initial.y] as [number, number]
|
|
1440
|
-
ranges.current.y2 = [...ranges.initial.y2] as [number, number]
|
|
1441
|
-
// Also reset axis props so future data changes recalculate auto ranges
|
|
1442
|
-
x_axis = { ...x_axis, range: [null, null] }
|
|
1443
|
-
x2_axis = { ...x2_axis, range: [null, null] }
|
|
1444
|
-
y_axis = { ...y_axis, range: [null, null] }
|
|
1445
|
-
y2_axis = { ...y2_axis, range: [null, null] }
|
|
1446
|
-
}}
|
|
898
|
+
onfocusin={() => pan_zoom.set_focused(true)}
|
|
899
|
+
onfocusout={() => pan_zoom.set_focused(false)}
|
|
900
|
+
onmousedown={pan_zoom.on_mouse_down}
|
|
901
|
+
ondblclick={pan_zoom.reset_view}
|
|
902
|
+
onkeydown={pan_zoom.on_key_down}
|
|
1447
903
|
onmouseleave={() => {
|
|
1448
904
|
hovered = false
|
|
1449
905
|
hover_info = null
|
|
1450
906
|
change(null)
|
|
1451
907
|
on_bar_hover?.(null)
|
|
1452
908
|
}}
|
|
1453
|
-
onwheel={
|
|
1454
|
-
ontouchstart={
|
|
1455
|
-
ontouchmove={
|
|
1456
|
-
ontouchend={
|
|
1457
|
-
|
|
1458
|
-
|
|
1459
|
-
: shift_held && pan?.enabled !== false
|
|
1460
|
-
? `grab`
|
|
1461
|
-
: `crosshair`}
|
|
909
|
+
onwheel={pan_zoom.on_wheel}
|
|
910
|
+
ontouchstart={pan_zoom.on_touch_start}
|
|
911
|
+
ontouchmove={pan_zoom.on_touch_move}
|
|
912
|
+
ontouchend={pan_zoom.on_touch_end}
|
|
913
|
+
ontouchcancel={pan_zoom.on_touch_end}
|
|
914
|
+
style:cursor={pan_zoom.cursor}
|
|
1462
915
|
>
|
|
1463
|
-
<ZoomRect start={
|
|
916
|
+
<ZoomRect start={pan_zoom.drag_start} current={pan_zoom.drag_current} />
|
|
1464
917
|
|
|
1465
918
|
<!-- User content (custom overlays, reference lines, etc.) -->
|
|
1466
919
|
{@render user_content?.({
|
|
@@ -1487,6 +940,7 @@
|
|
|
1487
940
|
ticks={ticks.x as number[]}
|
|
1488
941
|
place={scales.x}
|
|
1489
942
|
axis={x_axis}
|
|
943
|
+
domain={ranges.current.x as Vec2}
|
|
1490
944
|
{pad}
|
|
1491
945
|
{width}
|
|
1492
946
|
{height}
|
|
@@ -1507,6 +961,7 @@
|
|
|
1507
961
|
ticks={ticks.x2 as number[]}
|
|
1508
962
|
place={scales.x2}
|
|
1509
963
|
axis={x2_axis}
|
|
964
|
+
domain={ranges.current.x2 as Vec2}
|
|
1510
965
|
{pad}
|
|
1511
966
|
{width}
|
|
1512
967
|
{height}
|
|
@@ -1525,6 +980,7 @@
|
|
|
1525
980
|
ticks={ticks.y as number[]}
|
|
1526
981
|
place={scales.y}
|
|
1527
982
|
axis={y_axis}
|
|
983
|
+
domain={ranges.current.y as Vec2}
|
|
1528
984
|
{pad}
|
|
1529
985
|
{width}
|
|
1530
986
|
{height}
|
|
@@ -1544,21 +1000,18 @@
|
|
|
1544
1000
|
<!-- Y2-axis (Right) -->
|
|
1545
1001
|
<!-- Note: y2 axis is only supported for vertical orientation. Implementing x2 for horizontal mode requires additional complexity. -->
|
|
1546
1002
|
{#if y2_series.length > 0 && orientation === `vertical`}
|
|
1547
|
-
{@const y2_inside = y2_axis.tick?.label?.inside ?? false}
|
|
1548
|
-
{@const y2_tick_shift = y2_inside ? 0 : (y2_axis.tick?.label?.shift?.x ?? 0) + 8}
|
|
1549
|
-
{@const y2_tick_width = y2_inside ? 0 : tick_label_widths.y2_max}
|
|
1550
1003
|
<PlotAxis
|
|
1551
1004
|
side="y2"
|
|
1552
1005
|
ticks={ticks.y2 as number[]}
|
|
1553
1006
|
place={scales.y2}
|
|
1554
1007
|
axis={y2_axis}
|
|
1008
|
+
domain={ranges.current.y2 as Vec2}
|
|
1555
1009
|
{pad}
|
|
1556
1010
|
{width}
|
|
1557
1011
|
{height}
|
|
1558
1012
|
show_grid={display.y2_grid}
|
|
1559
1013
|
tick_label={(tick) => get_tick_label(tick, y2_axis.ticks)}
|
|
1560
|
-
label_x={width
|
|
1561
|
-
(y2_axis.label_shift?.x ?? 0)}
|
|
1014
|
+
label_x={y2_axis_label_x(y2_axis, width, pad.r, tick_label_widths.y2_max)}
|
|
1562
1015
|
label_y={pad.t + chart_height / 2 + (y2_axis.label_shift?.y ?? 0)}
|
|
1563
1016
|
axis_loading={axis_loading === `y2`}
|
|
1564
1017
|
on_axis_change={(key) => handle_axis_change(`y2`, key)}
|
|
@@ -1572,7 +1025,10 @@
|
|
|
1572
1025
|
</clipPath>
|
|
1573
1026
|
</defs>
|
|
1574
1027
|
|
|
1575
|
-
<!--
|
|
1028
|
+
<!-- Chart content is clipped in two groups so reference lines can interleave
|
|
1029
|
+
at their z positions while staying outside the chart clip: each line still
|
|
1030
|
+
self-clips to the plot area inside ReferenceLine, only its annotation text
|
|
1031
|
+
is allowed to overflow the plot edges. -->
|
|
1576
1032
|
<g clip-path="url(#{clip_path_id})">
|
|
1577
1033
|
<ZeroLines
|
|
1578
1034
|
{display}
|
|
@@ -1596,11 +1052,12 @@
|
|
|
1596
1052
|
{height}
|
|
1597
1053
|
{pad}
|
|
1598
1054
|
/>
|
|
1055
|
+
</g>
|
|
1599
1056
|
|
|
1600
|
-
|
|
1601
|
-
{@render ref_lines_layer(ref_lines_by_z.below_lines)}
|
|
1057
|
+
{@render ref_lines_layer(ref_lines_by_z.below_lines)}
|
|
1602
1058
|
|
|
1603
|
-
|
|
1059
|
+
<!-- Bars and Lines -->
|
|
1060
|
+
<g clip-path="url(#{clip_path_id})">
|
|
1604
1061
|
{#each internal_series as srs, series_idx (srs?.id ?? series_idx)}
|
|
1605
1062
|
{#if srs?.visible ?? true}
|
|
1606
1063
|
{@const is_line = srs.render_mode === `line`}
|
|
@@ -1626,42 +1083,14 @@
|
|
|
1626
1083
|
series_markers === `line+points`}
|
|
1627
1084
|
{@const show_points = series_markers === `points` ||
|
|
1628
1085
|
series_markers === `line+points`}
|
|
1629
|
-
{@const points =
|
|
1630
|
-
|
|
1631
|
-
|
|
1632
|
-
|
|
1633
|
-
|
|
1634
|
-
|
|
1635
|
-
|
|
1636
|
-
|
|
1637
|
-
: scales.y(x_val)
|
|
1638
|
-
// Create internal point with all needed data
|
|
1639
|
-
const color_value = srs.color_values?.[idx] ?? null
|
|
1640
|
-
const size_value = srs.size_values?.[idx] ?? null
|
|
1641
|
-
const point_style = process_prop(srs.point_style, idx)
|
|
1642
|
-
const point_hover = process_prop(srs.point_hover, idx)
|
|
1643
|
-
const point_label = process_prop(srs.point_label, idx)
|
|
1644
|
-
const point_offset = process_prop(srs.point_offset, idx)
|
|
1645
|
-
const metadata = Array.isArray(srs.metadata)
|
|
1646
|
-
? srs.metadata[idx]
|
|
1647
|
-
: srs.metadata
|
|
1648
|
-
return {
|
|
1649
|
-
x: plot_x,
|
|
1650
|
-
y: plot_y,
|
|
1651
|
-
data_x: x_val,
|
|
1652
|
-
data_y: y_val,
|
|
1653
|
-
idx,
|
|
1654
|
-
color_value,
|
|
1655
|
-
size_value,
|
|
1656
|
-
point_style,
|
|
1657
|
-
point_hover,
|
|
1658
|
-
point_label,
|
|
1659
|
-
point_offset,
|
|
1660
|
-
metadata,
|
|
1661
|
-
series_idx,
|
|
1662
|
-
point_idx: idx,
|
|
1663
|
-
} as LineSeriesPoint
|
|
1664
|
-
}).filter((pt) => isFinite(pt.x) && isFinite(pt.y))}
|
|
1086
|
+
{@const points = compute_line_points({
|
|
1087
|
+
series: srs,
|
|
1088
|
+
series_idx,
|
|
1089
|
+
orientation,
|
|
1090
|
+
x_scale,
|
|
1091
|
+
y_scale,
|
|
1092
|
+
cat_y_scale: scales.y,
|
|
1093
|
+
})}
|
|
1665
1094
|
{@const polyline_str = show_line && points.length > 1
|
|
1666
1095
|
? points.map((pt) => `${pt.x},${pt.y}`).join(` `)
|
|
1667
1096
|
: ``}
|
|
@@ -1826,37 +1255,24 @@
|
|
|
1826
1255
|
{@const bar_width_val = Array.isArray(srs.bar_width)
|
|
1827
1256
|
? (srs.bar_width[bar_idx] ?? 0.5)
|
|
1828
1257
|
: (srs.bar_width ?? 0.5)}
|
|
1829
|
-
{@const half = mode === `grouped` && group_info.bar_series_count > 1
|
|
1830
|
-
? bar_width_val / (2 * group_info.bar_series_count)
|
|
1831
|
-
: bar_width_val / 2}
|
|
1832
|
-
{@const calculate_group_offset = (idx: number) => {
|
|
1833
|
-
const position = group_info.bar_series_indices.indexOf(idx)
|
|
1834
|
-
const offset = position - (group_info.bar_series_count - 1) / 2
|
|
1835
|
-
return offset * (bar_width_val / group_info.bar_series_count)
|
|
1836
|
-
}}
|
|
1837
|
-
{@const group_offset = mode === `grouped` && group_info.bar_series_count > 1
|
|
1838
|
-
? calculate_group_offset(series_idx)
|
|
1839
|
-
: 0}
|
|
1840
1258
|
{@const is_vertical = orientation === `vertical`}
|
|
1841
|
-
{@const
|
|
1842
|
-
{@const val = y_val}
|
|
1843
|
-
{@const use_y2 = srs.y_axis === `y2`}
|
|
1844
|
-
{@const y_scale = use_y2 ? scales.y2 : scales.y}
|
|
1845
|
-
{@const use_x2_bar = srs.x_axis === `x2`}
|
|
1846
|
-
{@const x_scale_bar = use_x2_bar ? scales.x2 : scales.x}
|
|
1259
|
+
{@const x_scale_bar = srs.x_axis === `x2` ? scales.x2 : scales.x}
|
|
1847
1260
|
{@const [cat_scale, val_scale] = is_vertical
|
|
1848
|
-
? [x_scale_bar,
|
|
1261
|
+
? [x_scale_bar, srs.y_axis === `y2` ? scales.y2 : scales.y]
|
|
1849
1262
|
: [scales.y, x_scale_bar]}
|
|
1850
|
-
{@const c0
|
|
1851
|
-
|
|
1852
|
-
|
|
1853
|
-
|
|
1854
|
-
|
|
1855
|
-
|
|
1856
|
-
|
|
1857
|
-
|
|
1858
|
-
|
|
1859
|
-
|
|
1263
|
+
{@const { c0, c1, v0, v1, rect_x, rect_y, rect_w, rect_h } =
|
|
1264
|
+
compute_bar_rect({
|
|
1265
|
+
cat_val: x_val,
|
|
1266
|
+
val: y_val,
|
|
1267
|
+
base,
|
|
1268
|
+
bar_width_val,
|
|
1269
|
+
series_idx,
|
|
1270
|
+
mode,
|
|
1271
|
+
orientation,
|
|
1272
|
+
group_info,
|
|
1273
|
+
cat_scale,
|
|
1274
|
+
val_scale,
|
|
1275
|
+
})}
|
|
1860
1276
|
{#if (is_vertical ? rect_h : rect_w) > 0}
|
|
1861
1277
|
<path
|
|
1862
1278
|
d={bar_path(
|
|
@@ -1914,43 +1330,38 @@
|
|
|
1914
1330
|
</g>
|
|
1915
1331
|
{/if}
|
|
1916
1332
|
{/each}
|
|
1917
|
-
|
|
1918
|
-
<!-- Reference lines: below points -->
|
|
1919
|
-
{@render ref_lines_layer(ref_lines_by_z.below_points)}
|
|
1920
|
-
|
|
1921
|
-
<!-- Reference lines: above all -->
|
|
1922
|
-
{@render ref_lines_layer(ref_lines_by_z.above_all)}
|
|
1923
1333
|
</g>
|
|
1334
|
+
|
|
1335
|
+
{@render ref_lines_layer(ref_lines_by_z.below_points)}
|
|
1336
|
+
{@render ref_lines_layer(ref_lines_by_z.above_all)}
|
|
1924
1337
|
</svg>
|
|
1925
1338
|
|
|
1926
1339
|
<!-- Legend -->
|
|
1927
1340
|
{#if legend && (show_legend !== undefined ? show_legend : series.length > 1)}
|
|
1928
|
-
{@const
|
|
1929
|
-
|
|
1930
|
-
:
|
|
1931
|
-
|
|
1932
|
-
|
|
1933
|
-
{
|
|
1934
|
-
|
|
1935
|
-
: legend_placement
|
|
1936
|
-
? tweened_legend_coords.current.y
|
|
1937
|
-
: pad.t + 10}
|
|
1341
|
+
{@const legend_pos = placed_coords(
|
|
1342
|
+
legend_auto_outside,
|
|
1343
|
+
{ x: legend_outside_x, y: legend_outside_y },
|
|
1344
|
+
legend_placement,
|
|
1345
|
+
legend_tween.coords.current,
|
|
1346
|
+
{ x: pad.l + 10, y: pad.t + 10 },
|
|
1347
|
+
)}
|
|
1938
1348
|
<PlotLegend
|
|
1939
1349
|
bind:root_element={legend_element}
|
|
1940
1350
|
{...legend}
|
|
1941
1351
|
series_data={legend_data}
|
|
1942
|
-
on_toggle={legend?.on_toggle
|
|
1943
|
-
on_group_toggle={legend?.on_group_toggle
|
|
1944
|
-
|
|
1945
|
-
|
|
1946
|
-
|
|
1947
|
-
|
|
1352
|
+
on_toggle={legend?.on_toggle ?? legend_vis.on_toggle}
|
|
1353
|
+
on_group_toggle={legend?.on_group_toggle ?? legend_vis.on_group_toggle}
|
|
1354
|
+
on_double_click={legend?.on_double_click ?? legend_vis.on_double_click}
|
|
1355
|
+
on_hover_change={legend_tween.set_locked}
|
|
1356
|
+
on_item_hover={(item) =>
|
|
1357
|
+
(hovered_legend_series_idx = item != null && item.series_idx >= 0
|
|
1358
|
+
? item.series_idx
|
|
1948
1359
|
: null)}
|
|
1949
1360
|
active_series_idx={hover_info?.series_idx ?? hovered_legend_series_idx}
|
|
1950
1361
|
style={`
|
|
1951
1362
|
position: absolute;
|
|
1952
|
-
left: ${
|
|
1953
|
-
top: ${
|
|
1363
|
+
left: ${legend_pos.x}px;
|
|
1364
|
+
top: ${legend_pos.y}px;
|
|
1954
1365
|
pointer-events: auto;
|
|
1955
1366
|
${legend?.style || ``}
|
|
1956
1367
|
`}
|
|
@@ -1963,22 +1374,14 @@
|
|
|
1963
1374
|
)}
|
|
1964
1375
|
{@const cy = (hover_info.active_y_axis === `y2` ? scales.y2 : scales.y)(
|
|
1965
1376
|
hover_info.orient_y,
|
|
1966
|
-
)}
|
|
1967
|
-
{@const tooltip_pos = constrain_tooltip_position(
|
|
1968
|
-
cx,
|
|
1969
|
-
cy,
|
|
1970
|
-
tooltip_el?.offsetWidth ?? 140,
|
|
1971
|
-
tooltip_el?.offsetHeight ?? 50,
|
|
1972
|
-
width,
|
|
1973
|
-
height,
|
|
1974
|
-
{ offset_x: 10, offset_y: 5 },
|
|
1975
1377
|
)}
|
|
1976
1378
|
<PlotTooltip
|
|
1977
|
-
x={
|
|
1978
|
-
y={
|
|
1979
|
-
offset={{ x:
|
|
1379
|
+
x={cx}
|
|
1380
|
+
y={cy}
|
|
1381
|
+
offset={{ x: 10, y: 5 }}
|
|
1382
|
+
constrain_to={{ width, height }}
|
|
1383
|
+
fallback_size={{ width: 140, height: 50 }}
|
|
1980
1384
|
bg_color={hover_info.color}
|
|
1981
|
-
bind:wrapper={tooltip_el}
|
|
1982
1385
|
>
|
|
1983
1386
|
{#if tooltip}
|
|
1984
1387
|
{@render tooltip({ ...hover_info, fullscreen })}
|
|
@@ -2017,9 +1420,9 @@
|
|
|
2017
1420
|
bind:orientation
|
|
2018
1421
|
bind:mode
|
|
2019
1422
|
bind:x_axis
|
|
2020
|
-
bind:x2_axis
|
|
1423
|
+
bind:x2_axis={x2_axis_prop}
|
|
2021
1424
|
bind:y_axis
|
|
2022
|
-
bind:y2_axis
|
|
1425
|
+
bind:y2_axis={y2_axis_prop}
|
|
2023
1426
|
bind:display
|
|
2024
1427
|
auto_x_range={auto_ranges.x as Vec2}
|
|
2025
1428
|
auto_x2_range={auto_ranges.x2 as Vec2}
|
|
@@ -2063,8 +1466,10 @@
|
|
|
2063
1466
|
background: var(--barplot-fullscreen-bg, var(--barplot-bg, var(--plot-bg)));
|
|
2064
1467
|
max-height: none !important;
|
|
2065
1468
|
overflow: hidden;
|
|
2066
|
-
/*
|
|
2067
|
-
|
|
1469
|
+
/* border-top (not padding-top): bind:clientHeight includes padding but excludes
|
|
1470
|
+
borders - padding made the chart overflow + clip its bottom 2em (x-axis title) */
|
|
1471
|
+
border-top: var(--plot-fullscreen-padding-top, 2em) solid
|
|
1472
|
+
var(--barplot-fullscreen-bg, var(--barplot-bg, var(--plot-bg, transparent)));
|
|
2068
1473
|
box-sizing: border-box;
|
|
2069
1474
|
}
|
|
2070
1475
|
.header-controls {
|