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
|
@@ -0,0 +1,195 @@
|
|
|
1
|
+
import { LOG_EPS } from '../../math';
|
|
2
|
+
import { get_arcsinh_threshold, get_scale_type_name } from './types';
|
|
3
|
+
// Get coordinates of a mouse event relative to an element (the event's
|
|
4
|
+
// currentTarget by default; pass `element` when the handler is delegated and the
|
|
5
|
+
// reference frame differs, e.g. coordinates relative to the svg root)
|
|
6
|
+
export function get_relative_coords(evt, element = evt.currentTarget) {
|
|
7
|
+
if (!(element instanceof Element))
|
|
8
|
+
return null;
|
|
9
|
+
const box = element.getBoundingClientRect();
|
|
10
|
+
if (!box)
|
|
11
|
+
return null;
|
|
12
|
+
return { x: evt.clientX - box.left, y: evt.clientY - box.top };
|
|
13
|
+
}
|
|
14
|
+
// Resolve a delegated event to the integer value of the nearest ancestor's data
|
|
15
|
+
// attribute (e.g. data-sunburst-node-idx), scoped to `root` so targets outside the
|
|
16
|
+
// component don't leak in. Returns null when the event didn't hit an indexed element.
|
|
17
|
+
export function closest_data_idx(event, attr, root) {
|
|
18
|
+
const target = event.target instanceof Element ? event.target.closest(`[${attr}]`) : null;
|
|
19
|
+
if (!target || (root && !root.contains(target)))
|
|
20
|
+
return null;
|
|
21
|
+
const idx = Number(target.getAttribute(attr));
|
|
22
|
+
return Number.isInteger(idx) ? idx : null;
|
|
23
|
+
}
|
|
24
|
+
// Normalize Y2 sync config (handle shorthand string vs full object)
|
|
25
|
+
export function normalize_y2_sync(sync) {
|
|
26
|
+
if (!sync || sync === `none`)
|
|
27
|
+
return { mode: `none` };
|
|
28
|
+
if (typeof sync === `string`)
|
|
29
|
+
return { mode: sync };
|
|
30
|
+
return sync;
|
|
31
|
+
}
|
|
32
|
+
// Helper to check if all values in ranges are finite
|
|
33
|
+
const all_finite = (...ranges) => ranges.every(([a, b]) => Number.isFinite(a) && Number.isFinite(b));
|
|
34
|
+
// Calculate synced y2 range based on sync mode
|
|
35
|
+
export function sync_y2_range(y1_range, y2_base_range, sync) {
|
|
36
|
+
if (sync.mode === `none`)
|
|
37
|
+
return y2_base_range;
|
|
38
|
+
if (!all_finite(y1_range, y2_base_range))
|
|
39
|
+
return y2_base_range;
|
|
40
|
+
// Synced: Y2 has exact same range as Y1
|
|
41
|
+
if (sync.mode === `synced`) {
|
|
42
|
+
return [y1_range[0], y1_range[1]];
|
|
43
|
+
}
|
|
44
|
+
// Align: Position so align_val (default 0) is at same relative position on both axes
|
|
45
|
+
// Y2 range expands as needed to show all data while maintaining alignment
|
|
46
|
+
if (sync.mode === `align`) {
|
|
47
|
+
const align_val = sync.align_value ?? 0;
|
|
48
|
+
const y1_span = y1_range[1] - y1_range[0];
|
|
49
|
+
if (y1_span === 0)
|
|
50
|
+
return y2_base_range;
|
|
51
|
+
// Where is align_val in Y1's range? (0 = bottom, 1 = top)
|
|
52
|
+
const rel_pos = (align_val - y1_range[0]) / y1_span;
|
|
53
|
+
// Ensure Y2 range includes both align_val and all data
|
|
54
|
+
const y2_min_data = Math.min(y2_base_range[0], align_val);
|
|
55
|
+
const y2_max_data = Math.max(y2_base_range[1], align_val);
|
|
56
|
+
// Calculate minimum span needed to fit all data while keeping align_val at rel_pos
|
|
57
|
+
// Constraints: y2_min <= y2_min_data AND y2_max >= y2_max_data
|
|
58
|
+
let y2_span = y2_max_data - y2_min_data;
|
|
59
|
+
if (rel_pos > 0) {
|
|
60
|
+
y2_span = Math.max(y2_span, (align_val - y2_min_data) / rel_pos);
|
|
61
|
+
}
|
|
62
|
+
if (rel_pos < 1) {
|
|
63
|
+
y2_span = Math.max(y2_span, (y2_max_data - align_val) / (1 - rel_pos));
|
|
64
|
+
}
|
|
65
|
+
const y2_min_computed = align_val - rel_pos * y2_span;
|
|
66
|
+
const y2_max_computed = align_val + (1 - rel_pos) * y2_span;
|
|
67
|
+
// When align_val is outside y1_range (rel_pos < 0 or > 1), the formula can produce
|
|
68
|
+
// a range that omits y2_base_range or align_val. Ensure both are always included.
|
|
69
|
+
const y2_min = Math.min(y2_min_computed, y2_base_range[0], align_val);
|
|
70
|
+
const y2_max = Math.max(y2_max_computed, y2_base_range[1], align_val);
|
|
71
|
+
return [y2_min, y2_max];
|
|
72
|
+
}
|
|
73
|
+
return y2_base_range;
|
|
74
|
+
}
|
|
75
|
+
// Forward/inverse transform pair mapping an axis's data values onto its visual
|
|
76
|
+
// metric (the space where equal pixel steps are equal steps; identity for
|
|
77
|
+
// linear/time). Pan and pinch must be uniform in *screen* space - doing the math
|
|
78
|
+
// linearly on a log axis stretches one end of the view and shifts past zero into
|
|
79
|
+
// an all-NaN domain. log clamps at LOG_EPS so a non-positive bound (stale explicit
|
|
80
|
+
// range) recovers instead of propagating -Infinity.
|
|
81
|
+
function axis_transform(scale_type) {
|
|
82
|
+
const name = get_scale_type_name(scale_type);
|
|
83
|
+
if (name === `log`) {
|
|
84
|
+
return { to: (val) => Math.log(Math.max(val, LOG_EPS)), from: Math.exp };
|
|
85
|
+
}
|
|
86
|
+
if (name === `arcsinh`) {
|
|
87
|
+
const threshold = get_arcsinh_threshold(scale_type);
|
|
88
|
+
const to = (val) => Math.asinh(val / threshold);
|
|
89
|
+
const from = (val) => Math.sinh(val) * threshold;
|
|
90
|
+
return { to, from };
|
|
91
|
+
}
|
|
92
|
+
return { to: (val) => val, from: (val) => val };
|
|
93
|
+
}
|
|
94
|
+
// Pan a range by a pixel delta, uniformly in screen space: linear axes shift by a
|
|
95
|
+
// constant amount, log axes by a constant factor (which also can't cross zero).
|
|
96
|
+
// `pixel_span` is the plot's pixel extent along the axis.
|
|
97
|
+
export function pan_range_by_pixels(range, pixel_delta, pixel_span, scale_type) {
|
|
98
|
+
if (pixel_span === 0)
|
|
99
|
+
return range;
|
|
100
|
+
const { to, from } = axis_transform(scale_type);
|
|
101
|
+
const [t0, t1] = [to(range[0]), to(range[1])];
|
|
102
|
+
const t_delta = (pixel_delta / pixel_span) * (t1 - t0);
|
|
103
|
+
return [from(t0 + t_delta), from(t1 + t_delta)];
|
|
104
|
+
}
|
|
105
|
+
// Zoom a range about its screen-space center by `factor` (pinch: >1 zooms in).
|
|
106
|
+
// On log axes the fixed point is the geometric mean - the visual center.
|
|
107
|
+
export function zoom_range_by_factor(range, factor, scale_type) {
|
|
108
|
+
// Guard invalid factors (0/negative/NaN) that would emit Infinity/NaN into axis state
|
|
109
|
+
if (!Number.isFinite(factor) || factor <= 0)
|
|
110
|
+
return range;
|
|
111
|
+
const { to, from } = axis_transform(scale_type);
|
|
112
|
+
const [t0, t1] = [to(range[0]), to(range[1])];
|
|
113
|
+
const center = (t0 + t1) / 2;
|
|
114
|
+
const half_span = (t1 - t0) / factor / 2;
|
|
115
|
+
return [from(center - half_span), from(center + half_span)];
|
|
116
|
+
}
|
|
117
|
+
// Coerce a scale.invert result (number, or Date for time scales) to an epoch number
|
|
118
|
+
export const to_epoch_num = (val) => val instanceof Date ? val.getTime() : val;
|
|
119
|
+
// Remove window drag/pan listeners and reset the body cursor. Call from onDestroy:
|
|
120
|
+
// a component unmounting mid-drag would otherwise leak its listeners and leave the
|
|
121
|
+
// cursor stuck (the mouseup that normally cleans up never fires after unmount).
|
|
122
|
+
export function remove_drag_listeners(move_handlers, up_handlers) {
|
|
123
|
+
if (typeof window === `undefined`)
|
|
124
|
+
return;
|
|
125
|
+
for (const handler of move_handlers) {
|
|
126
|
+
window.removeEventListener(`mousemove`, handler);
|
|
127
|
+
}
|
|
128
|
+
for (const handler of up_handlers) {
|
|
129
|
+
window.removeEventListener(`mouseup`, handler);
|
|
130
|
+
}
|
|
131
|
+
document.body.style.cursor = ``;
|
|
132
|
+
}
|
|
133
|
+
// Sorted [min, max] from two scalar bounds (rect-zoom inverts drag start/end,
|
|
134
|
+
// which arrive in either order depending on drag direction)
|
|
135
|
+
export const sorted_range = (a, b) => [Math.min(a, b), Math.max(a, b)];
|
|
136
|
+
// Strict per-bound equality of two [min, max] ranges
|
|
137
|
+
export const vec2_equal = (a, b) => a[0] === b[0] && a[1] === b[1];
|
|
138
|
+
// True when all four axis ranges match. The range-sync effects use this to skip
|
|
139
|
+
// no-op writes that would otherwise re-trigger the effect and loop.
|
|
140
|
+
export const axis_ranges_equal = (a, b) => vec2_equal(a.x, b.x) &&
|
|
141
|
+
vec2_equal(a.x2, b.x2) &&
|
|
142
|
+
vec2_equal(a.y, b.y) &&
|
|
143
|
+
vec2_equal(a.y2, b.y2);
|
|
144
|
+
// Merge each axis's explicit range over its auto range (per-bound: a null bound
|
|
145
|
+
// falls back to the auto value). Returns null if any resolved bound is non-finite so
|
|
146
|
+
// the caller can skip the sync - writing NaN breaks scales and, since NaN !== NaN,
|
|
147
|
+
// makes the change comparison never settle (an infinite effect loop).
|
|
148
|
+
export function resolve_axis_ranges(axes, auto) {
|
|
149
|
+
const resolve = (axis, fallback) => [
|
|
150
|
+
axis.range?.[0] ?? fallback[0],
|
|
151
|
+
axis.range?.[1] ?? fallback[1],
|
|
152
|
+
];
|
|
153
|
+
const next = {
|
|
154
|
+
x: resolve(axes.x, auto.x),
|
|
155
|
+
x2: resolve(axes.x2, auto.x2),
|
|
156
|
+
y: resolve(axes.y, auto.y),
|
|
157
|
+
y2: resolve(axes.y2, auto.y2),
|
|
158
|
+
};
|
|
159
|
+
for (const [lo, hi] of [next.x, next.x2, next.y, next.y2]) {
|
|
160
|
+
if (!Number.isFinite(lo) || !Number.isFinite(hi))
|
|
161
|
+
return null;
|
|
162
|
+
}
|
|
163
|
+
return next;
|
|
164
|
+
}
|
|
165
|
+
// Threshold for distinguishing pinch-zoom from pan in touch gestures
|
|
166
|
+
// Scale change > this value triggers zoom instead of pan
|
|
167
|
+
export const PINCH_ZOOM_THRESHOLD = 0.1;
|
|
168
|
+
// Minimum start distance (px) between two touches to treat the gesture as a valid pinch.
|
|
169
|
+
// Guards curr_dist / start_dist scale from blowing up on near-coincident touches
|
|
170
|
+
export const MIN_TOUCH_DISTANCE_PIXELS = 10;
|
|
171
|
+
// Helper to check if range is the default [0, 1] sentinel (no data)
|
|
172
|
+
// Note: min === 0 handles -0 correctly since -0 === 0 in JavaScript
|
|
173
|
+
const is_default_range = ([min, max]) => min === 0 && max === 1;
|
|
174
|
+
// Adopt the new data range, unless all series were hidden (sentinel [0, 1] fallback).
|
|
175
|
+
// NOTE: [0, 1] is the "no data" sentinel - when all series are hidden, auto ranges
|
|
176
|
+
// fall back to [0, 1]. Actual data spanning exactly [0, 1] is a rare edge case.
|
|
177
|
+
export function expand_range_if_needed(current, new_range) {
|
|
178
|
+
// Guard against NaN/Infinity - prefer valid range, fall back to sentinel [0, 1] if both invalid
|
|
179
|
+
const current_valid = all_finite(current);
|
|
180
|
+
const new_valid = all_finite(new_range);
|
|
181
|
+
if (!current_valid && !new_valid)
|
|
182
|
+
return { range: [0, 1], changed: true };
|
|
183
|
+
if (!new_valid)
|
|
184
|
+
return { range: current, changed: false };
|
|
185
|
+
if (!current_valid)
|
|
186
|
+
return { range: new_range, changed: true };
|
|
187
|
+
// When all series are hidden, auto ranges fall back to [0, 1] sentinel.
|
|
188
|
+
// Don't shrink to that — preserve the current view so it doesn't jump.
|
|
189
|
+
if (!is_default_range(current) && is_default_range(new_range)) {
|
|
190
|
+
return { range: current, changed: false };
|
|
191
|
+
}
|
|
192
|
+
// Otherwise adopt the new range directly (both expand and shrink)
|
|
193
|
+
const changed = new_range[0] !== current[0] || new_range[1] !== current[1];
|
|
194
|
+
return { range: new_range, changed };
|
|
195
|
+
}
|
|
@@ -6,6 +6,7 @@ export type Sides = {
|
|
|
6
6
|
r?: number;
|
|
7
7
|
};
|
|
8
8
|
export declare const LABEL_GAP_DEFAULT = 30;
|
|
9
|
+
export declare function y2_axis_label_x(axis: AxisConfig, width: number, pad_r: number, max_tick_width: number): number;
|
|
9
10
|
export declare const filter_padding: (padding: Partial<Sides> | undefined | null, defaults: Required<Sides>) => Required<Sides>;
|
|
10
11
|
export declare function measure_text_width(text: string, font?: string): number;
|
|
11
12
|
export declare function measure_full_footprint(el: HTMLElement): {
|
|
@@ -1,7 +1,15 @@
|
|
|
1
|
-
import { format_value } from '
|
|
2
|
-
import { euclidean_dist } from '
|
|
1
|
+
import { format_value } from '../../labels';
|
|
2
|
+
import { euclidean_dist } from '../../math';
|
|
3
3
|
// Default gap between tick labels and axis labels
|
|
4
4
|
export const LABEL_GAP_DEFAULT = 30;
|
|
5
|
+
// X position for a right-side (y2) axis label: past the plot edge plus tick shift and
|
|
6
|
+
// measured tick-label width (both zero when tick labels render inside the plot)
|
|
7
|
+
export function y2_axis_label_x(axis, width, pad_r, max_tick_width) {
|
|
8
|
+
const inside = axis.tick?.label?.inside ?? false;
|
|
9
|
+
const tick_shift = inside ? 0 : (axis.tick?.label?.shift?.x ?? 0) + 8;
|
|
10
|
+
const label_offset = (inside ? 0 : max_tick_width) + LABEL_GAP_DEFAULT + (axis.label_shift?.x ?? 0);
|
|
11
|
+
return width - pad_r + tick_shift + label_offset;
|
|
12
|
+
}
|
|
5
13
|
// Filter undefined values from padding to prevent overriding defaults when spreading
|
|
6
14
|
// Guards against undefined/null padding inputs (common for optional props)
|
|
7
15
|
export const filter_padding = (padding, defaults) => ({
|
|
@@ -157,10 +165,9 @@ export function sample_series_obstacle_points(pixel_points, draws_line, step) {
|
|
|
157
165
|
const n_samples = Math.floor(Math.hypot(point.x - prev.x, point.y - prev.y) / step);
|
|
158
166
|
for (let idx = 1; idx < n_samples; idx++) {
|
|
159
167
|
const frac = idx / n_samples;
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
});
|
|
168
|
+
const x = prev.x + (point.x - prev.x) * frac;
|
|
169
|
+
const y = prev.y + (point.y - prev.y) * frac;
|
|
170
|
+
obstacles.push({ x, y });
|
|
164
171
|
}
|
|
165
172
|
}
|
|
166
173
|
prev = point;
|
|
@@ -254,8 +261,9 @@ export function compute_element_placement(config) {
|
|
|
254
261
|
const min_distance = min_distance_sq === Infinity ? 0 : Math.sqrt(min_distance_sq);
|
|
255
262
|
// Corner preference: use element's actual corner (not center) for distance
|
|
256
263
|
// This ensures a wide element at the left edge gets proper corner credit
|
|
257
|
-
|
|
258
|
-
const
|
|
264
|
+
// (measured footprint, same as cand_rect — not the element_size fallback)
|
|
265
|
+
const elem_right = cand_x + elem_width;
|
|
266
|
+
const elem_bottom = cand_y + elem_height;
|
|
259
267
|
// Distance from element's matching corner to each plot corner
|
|
260
268
|
const min_corner_dist = Math.min(euclidean_dist([cand_x, cand_y], [plot_left, plot_top]), // top-left
|
|
261
269
|
euclidean_dist([elem_right, cand_y], [plot_right, plot_top]), // top-right
|
|
@@ -2,7 +2,7 @@ import type { RefLine, RefLineValue } from './types';
|
|
|
2
2
|
export type IndexedRefLine = RefLine & {
|
|
3
3
|
idx: number;
|
|
4
4
|
};
|
|
5
|
-
export declare
|
|
5
|
+
export declare const index_ref_lines: (ref_lines: RefLine[] | undefined) => IndexedRefLine[];
|
|
6
6
|
export interface RefLinesByZIndex {
|
|
7
7
|
below_grid: IndexedRefLine[];
|
|
8
8
|
below_lines: IndexedRefLine[];
|
|
@@ -1,9 +1,7 @@
|
|
|
1
1
|
// Create indexed ref_lines, filtering out invisible ones
|
|
2
|
-
export
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
.map((line, idx) => ({ ...line, idx }));
|
|
6
|
-
}
|
|
2
|
+
export const index_ref_lines = (ref_lines) => (ref_lines ?? [])
|
|
3
|
+
.filter((line) => line.visible !== false)
|
|
4
|
+
.map((line, idx) => ({ ...line, idx }));
|
|
7
5
|
// Map z-index type values to object keys
|
|
8
6
|
const Z_INDEX_KEY_MAP = {
|
|
9
7
|
'below-grid': `below_grid`,
|
|
@@ -158,31 +156,18 @@ export function resolve_line_endpoints(ref_line, { x_min, x_max, y_min, y_max, }
|
|
|
158
156
|
}
|
|
159
157
|
}
|
|
160
158
|
if (!handled_as_vertical) {
|
|
161
|
-
//
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
// Clip each endpoint to y bounds
|
|
172
|
-
const clip_y = (x, y, bound) => y < y_min || y > y_max ? [(bound - intercept) / slope, bound] : [x, y];
|
|
173
|
-
[x1, y1] = clip_y(x1, y1, y1 < y_min ? y_min : y_max);
|
|
174
|
-
[x2, y2] = clip_y(x2, y2, y2 < y_min ? y_min : y_max);
|
|
175
|
-
// If both endpoints clipped to same point, line is entirely outside bounds
|
|
176
|
-
if (x1 === x2 && y1 === y2)
|
|
177
|
-
return null;
|
|
178
|
-
}
|
|
179
|
-
// Ensure consistent ordering before applying span constraints
|
|
180
|
-
const [x_lo, x_hi] = x1 <= x2 ? [x1, x2] : [x2, x1];
|
|
181
|
-
const [y_lo, y_hi] = y1 <= y2 ? [y1, y2] : [y2, y1];
|
|
182
|
-
[x1_data, x2_data] = apply_x_span(x_lo, x_hi);
|
|
183
|
-
[y1_data, y2_data] = apply_y_span(y_lo, y_hi);
|
|
184
|
-
if (x1_data > x_max || x2_data < x_min)
|
|
159
|
+
// Intersect bounds with span constraints, then clip the line segment spanning the
|
|
160
|
+
// clipped x-extent to that rect — keeps endpoints paired on y = slope·x + intercept
|
|
161
|
+
const [x_lo, x_hi] = apply_x_span(x_min, x_max);
|
|
162
|
+
const [y_lo, y_hi] = apply_y_span(y_min, y_max);
|
|
163
|
+
if (x_lo > x_hi || y_lo > y_hi)
|
|
164
|
+
return null;
|
|
165
|
+
const [y_at_lo, y_at_hi] = [slope * x_lo + intercept, slope * x_hi + intercept];
|
|
166
|
+
const seg = clip_segment_to_rect(x_lo, y_at_lo, x_hi, y_at_hi, x_lo, x_hi, y_lo, y_hi);
|
|
167
|
+
// Degenerate (single-point) result means the line only grazes a corner
|
|
168
|
+
if (!seg || (seg[0] === seg[2] && seg[1] === seg[3]))
|
|
185
169
|
return null;
|
|
170
|
+
[x1_data, y1_data, x2_data, y2_data] = seg;
|
|
186
171
|
}
|
|
187
172
|
}
|
|
188
173
|
else if (line_type === `segment`) {
|
|
@@ -243,19 +228,21 @@ export function calculate_annotation_position(x1, y1, x2, y2, annotation) {
|
|
|
243
228
|
// Perpendicular vector (normalized)
|
|
244
229
|
const nx = -dy / len;
|
|
245
230
|
const ny = dx / len;
|
|
231
|
+
let sign;
|
|
246
232
|
if (side === `above` || side === `below`) {
|
|
247
233
|
// In SVG, y increases downward. Flip sign if 'above' and perpendicular points down (ny > 0),
|
|
248
234
|
// or if 'below' and perpendicular points up (ny <= 0), to ensure offset is in correct direction
|
|
249
|
-
|
|
250
|
-
perp_x = sign * nx * gap;
|
|
251
|
-
perp_y = sign * ny * gap;
|
|
235
|
+
sign = (side === `above`) === ny > 0 ? -1 : 1;
|
|
252
236
|
}
|
|
253
237
|
else {
|
|
254
|
-
// left
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
238
|
+
// left/right offset to the side of the line in screen space (right -> +x, left -> -x), stable
|
|
239
|
+
// regardless of endpoint order — vertical ref lines are stored bottom->top, which flips the
|
|
240
|
+
// perpendicular. Horizontal lines (nx == 0) fall back to right = up (-y), left = down (+y).
|
|
241
|
+
const want_right = side === `right`;
|
|
242
|
+
sign = Math.abs(nx) > 1e-9 ? (want_right ? 1 : -1) * Math.sign(nx) : want_right ? -1 : 1;
|
|
258
243
|
}
|
|
244
|
+
perp_x = sign * nx * gap;
|
|
245
|
+
perp_y = sign * ny * gap;
|
|
259
246
|
}
|
|
260
247
|
const final_x = base_x + perp_x + offset_x;
|
|
261
248
|
const final_y = base_y + perp_y + offset_y;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import type { D3ColorSchemeName, D3InterpolateName } from '
|
|
2
|
-
import type { Point, ScaleType, TimeInterval } from '
|
|
1
|
+
import type { D3ColorSchemeName, D3InterpolateName } from '../../colors';
|
|
2
|
+
import type { Point, ScaleType, TimeInterval } from '..';
|
|
3
3
|
import type { ScaleContinuousNumeric, ScaleTime } from 'd3-scale';
|
|
4
4
|
export type TicksOption = number | number[] | TimeInterval | Record<number, string>;
|
|
5
5
|
export interface ArcsinhScale {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import * as math from '
|
|
2
|
-
import { get_arcsinh_threshold, get_scale_type_name, is_time_scale } from './types';
|
|
1
|
+
import * as math from '../../math';
|
|
2
|
+
import { get_arcsinh_threshold, get_scale_type_name, is_time_scale, } from './types';
|
|
3
3
|
import { extent, range } from 'd3-array';
|
|
4
4
|
import { scaleLinear, scaleLog, scaleSequential, scaleSequentialLog, scaleTime, } from 'd3-scale';
|
|
5
5
|
import * as d3_sc from 'd3-scale-chromatic';
|
|
@@ -83,9 +83,8 @@ export function scale_arcsinh(threshold = 1) {
|
|
|
83
83
|
return scale;
|
|
84
84
|
}
|
|
85
85
|
// Generate nice tick values for arcsinh scale
|
|
86
|
-
// Strategy: symmetric around zero when possible, with powers of 10 for large values
|
|
87
|
-
//
|
|
88
|
-
// most important tick. E.g., count=1 yields [0], count=2 yields [0] plus one boundary.
|
|
86
|
+
// Strategy: symmetric around zero when possible, with powers of 10 for large values.
|
|
87
|
+
// On mixed ranges, count=1 yields just [0]; count>=2 yields zero plus symmetric powers per side.
|
|
89
88
|
export function generate_arcsinh_ticks(min, max, threshold = 1, count = 10) {
|
|
90
89
|
// Guard against invalid/non-positive threshold to prevent division issues
|
|
91
90
|
const safe_threshold = Math.max(threshold, Number.EPSILON);
|
|
@@ -101,9 +100,10 @@ export function generate_arcsinh_ticks(min, max, threshold = 1, count = 10) {
|
|
|
101
100
|
.map((tick) => -tick)
|
|
102
101
|
.toReversed();
|
|
103
102
|
}
|
|
104
|
-
// Mixed range: symmetric ticks around zero (includes_zero is always
|
|
105
|
-
//
|
|
106
|
-
|
|
103
|
+
// Mixed range: symmetric ticks around zero (includes_zero is always here). Split the budget
|
|
104
|
+
// across both sides (zero is shared/free) so e.g. count=4 yields ~5 ticks (0, ±a, ±b) rather
|
|
105
|
+
// than collapsing to 3 — matching how linear/log colorbars render a similar count.
|
|
106
|
+
const half_count = Math.floor(count / 2);
|
|
107
107
|
const ticks = [0];
|
|
108
108
|
// Add positive ticks
|
|
109
109
|
const pos_ticks = generate_positive_arcsinh_ticks(0, hi, safe_threshold, half_count);
|
|
@@ -111,19 +111,6 @@ export function generate_arcsinh_ticks(min, max, threshold = 1, count = 10) {
|
|
|
111
111
|
// Add negative ticks (mirror of positive)
|
|
112
112
|
const neg_ticks = generate_positive_arcsinh_ticks(0, -lo, safe_threshold, half_count);
|
|
113
113
|
ticks.push(...neg_ticks.filter((tick) => tick > 0).map((tick) => -tick));
|
|
114
|
-
// For small counts where half_count is 0 or 1, ensure at least some boundary coverage
|
|
115
|
-
if (half_count <= 1 && count >= 2) {
|
|
116
|
-
// Add boundaries if not already present and we have room
|
|
117
|
-
const sorted = dedupe_sort(ticks);
|
|
118
|
-
if (sorted.length < count) {
|
|
119
|
-
// Snap the larger-magnitude boundary to a clean power of 10 (raw extremes would render
|
|
120
|
-
// as long unrounded labels); keeps some coverage for very small tick counts.
|
|
121
|
-
const boundary = Math.abs(hi) >= Math.abs(lo) ? hi : lo;
|
|
122
|
-
const nice = Math.sign(boundary) * 10 ** Math.floor(Math.log10(Math.abs(boundary)));
|
|
123
|
-
if (Number.isFinite(nice) && nice !== 0 && !sorted.includes(nice))
|
|
124
|
-
ticks.push(nice);
|
|
125
|
-
}
|
|
126
|
-
}
|
|
127
114
|
return dedupe_sort(ticks);
|
|
128
115
|
}
|
|
129
116
|
// Generate positive arcsinh ticks (helper)
|
|
@@ -133,46 +120,49 @@ function generate_positive_arcsinh_ticks(min, max, threshold, count) {
|
|
|
133
120
|
if (count <= 0 || max <= min)
|
|
134
121
|
return [];
|
|
135
122
|
const ticks = [];
|
|
136
|
-
//
|
|
137
|
-
// For values >> threshold, use log-like spacing (powers of 10)
|
|
123
|
+
// Small range near threshold: use linear-like spacing
|
|
138
124
|
if (max <= threshold * 2) {
|
|
139
|
-
// Small range: use linear ticks
|
|
140
125
|
const step = (max - min) / count;
|
|
141
126
|
for (let idx = 0; idx <= count; idx++) {
|
|
142
127
|
const val = min + step * idx;
|
|
143
128
|
if (val >= min && val <= max)
|
|
144
129
|
ticks.push(val);
|
|
145
130
|
}
|
|
131
|
+
return dedupe_sort(ticks);
|
|
146
132
|
}
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
133
|
+
// Large range: log-like spacing via powers of 10.
|
|
134
|
+
// Domain endpoints are intentionally NOT added as ticks: raw extremes render as long
|
|
135
|
+
// unrounded labels (e.g. 1325.8239811994677). Powers of 10 plus 2x/5x multiples below
|
|
136
|
+
// already give clean round ticks; pass axis.ticks/axis.format for custom labels.
|
|
137
|
+
// Add threshold as a tick if in range
|
|
138
|
+
if (threshold >= min && threshold <= max)
|
|
139
|
+
ticks.push(threshold);
|
|
140
|
+
// Add powers of 10 that are in range. Start at the threshold (not a decade below): values
|
|
141
|
+
// below it sit in arcsinh's near-linear region and map almost onto 0, so sub-threshold powers
|
|
142
|
+
// (e.g. ±1 when threshold=10) would pile up on the zero tick and overlap.
|
|
143
|
+
const min_power = Math.floor(Math.log10(Math.max(min, threshold)));
|
|
144
|
+
const max_power = Math.ceil(Math.log10(max));
|
|
145
|
+
for (let power = min_power; power <= max_power; power++) {
|
|
146
|
+
const val = 10 ** power;
|
|
147
|
+
if (val >= min && val <= max)
|
|
148
|
+
ticks.push(val);
|
|
149
|
+
}
|
|
150
|
+
// Add intermediate values (2x, 5x) for sparser regions
|
|
151
|
+
if (ticks.length < count) {
|
|
152
|
+
for (let power = min_power; power < max_power; power++) {
|
|
153
|
+
const base = 10 ** power;
|
|
154
|
+
for (const mult of [2, 5]) {
|
|
155
|
+
const val = base * mult;
|
|
156
|
+
if (val >= min && val <= max)
|
|
157
|
+
ticks.push(val);
|
|
172
158
|
}
|
|
173
159
|
}
|
|
174
160
|
}
|
|
175
|
-
|
|
161
|
+
const result = dedupe_sort(ticks);
|
|
162
|
+
// Respect `count`: surplus small powers sit near zero in arcsinh space (their values map almost
|
|
163
|
+
// onto 0) and crowd the labels. Keep the largest-magnitude ticks — they anchor the range extent
|
|
164
|
+
// and are the most spread out — dropping near-zero ones first.
|
|
165
|
+
return result.length > count ? result.slice(-count) : result;
|
|
176
166
|
}
|
|
177
167
|
// Create a scale function based on type, domain, and range
|
|
178
168
|
// Note: Time scales are handled separately via create_time_scale() since ScaleTime
|
|
@@ -182,8 +172,13 @@ export function create_scale(scale_type, domain, output_range) {
|
|
|
182
172
|
const [min_val, max_val] = domain;
|
|
183
173
|
const type_name = get_scale_type_name(scale_type);
|
|
184
174
|
if (type_name === `log`) {
|
|
175
|
+
// Clamp BOTH ends to the positive floor: panning shifts ranges linearly, so a
|
|
176
|
+
// log axis panned past zero can arrive with max <= 0 — an unclamped max makes
|
|
177
|
+
// every scale output (and invert) NaN, blanking the chart and polluting axis
|
|
178
|
+
// ranges. A clamped degenerate domain just renders flat and stays recoverable.
|
|
179
|
+
const lo = Math.max(min_val, math.LOG_EPS);
|
|
185
180
|
return scaleLog()
|
|
186
|
-
.domain([Math.max(
|
|
181
|
+
.domain([lo, Math.max(max_val, lo)])
|
|
187
182
|
.range(output_range);
|
|
188
183
|
}
|
|
189
184
|
if (type_name === `arcsinh`) {
|
|
@@ -284,15 +279,15 @@ export function get_nice_data_range(points, get_value, limits, scale_type, paddi
|
|
|
284
279
|
const span = data_max - data_min;
|
|
285
280
|
if (is_time) {
|
|
286
281
|
const padding_ms = span * padding_factor;
|
|
287
|
-
data_min
|
|
288
|
-
data_max
|
|
282
|
+
data_min -= padding_ms;
|
|
283
|
+
data_max += padding_ms;
|
|
289
284
|
}
|
|
290
285
|
else if (type_name === `log`) {
|
|
291
286
|
const log_min = Math.log10(Math.max(data_min, math.LOG_EPS));
|
|
292
287
|
const log_max = Math.log10(Math.max(data_max, math.LOG_EPS));
|
|
293
288
|
const log_span = log_max - log_min;
|
|
294
|
-
data_min =
|
|
295
|
-
data_max =
|
|
289
|
+
data_min = 10 ** (log_min - log_span * padding_factor);
|
|
290
|
+
data_max = 10 ** (log_max + log_span * padding_factor);
|
|
296
291
|
}
|
|
297
292
|
else if (type_name === `arcsinh`) {
|
|
298
293
|
// Arcsinh: apply padding in arcsinh-transformed space
|
|
@@ -307,35 +302,33 @@ export function get_nice_data_range(points, get_value, limits, scale_type, paddi
|
|
|
307
302
|
else {
|
|
308
303
|
// Linear scale
|
|
309
304
|
const padding_abs = span * padding_factor;
|
|
310
|
-
data_min
|
|
311
|
-
data_max
|
|
305
|
+
data_min -= padding_abs;
|
|
306
|
+
data_max += padding_abs;
|
|
312
307
|
}
|
|
308
|
+
// Handle single data point case with fixed relative padding
|
|
309
|
+
}
|
|
310
|
+
else if (is_time) {
|
|
311
|
+
const one_day = 86_400_000; // milliseconds in a day
|
|
312
|
+
data_min -= one_day;
|
|
313
|
+
data_max += one_day;
|
|
314
|
+
}
|
|
315
|
+
else if (type_name === `log`) {
|
|
316
|
+
data_min = Math.max(math.LOG_EPS, data_min / 1.1); // 10% multiplicative padding
|
|
317
|
+
data_max *= 1.1;
|
|
318
|
+
}
|
|
319
|
+
else if (type_name === `arcsinh`) {
|
|
320
|
+
// Arcsinh: 10% padding in transformed space
|
|
321
|
+
// Guard against extremely small thresholds that could cause precision issues
|
|
322
|
+
const threshold = Math.max(get_arcsinh_threshold(scale_type), Number.EPSILON);
|
|
323
|
+
const asinh_val = Math.asinh(data_min / threshold);
|
|
324
|
+
const padding = Math.abs(asinh_val) * 0.1 || 0.1; // Use 0.1 if transformed value is 0 (i.e. data_min = 0)
|
|
325
|
+
data_min = Math.sinh(asinh_val - padding) * threshold;
|
|
326
|
+
data_max = Math.sinh(asinh_val + padding) * threshold;
|
|
313
327
|
}
|
|
314
328
|
else {
|
|
315
|
-
//
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
data_min = data_min - one_day;
|
|
319
|
-
data_max = data_max + one_day;
|
|
320
|
-
}
|
|
321
|
-
else if (type_name === `log`) {
|
|
322
|
-
data_min = Math.max(math.LOG_EPS, data_min / 1.1); // 10% multiplicative padding
|
|
323
|
-
data_max = data_max * 1.1;
|
|
324
|
-
}
|
|
325
|
-
else if (type_name === `arcsinh`) {
|
|
326
|
-
// Arcsinh: 10% padding in transformed space
|
|
327
|
-
// Guard against extremely small thresholds that could cause precision issues
|
|
328
|
-
const threshold = Math.max(get_arcsinh_threshold(scale_type), Number.EPSILON);
|
|
329
|
-
const asinh_val = Math.asinh(data_min / threshold);
|
|
330
|
-
const padding = Math.abs(asinh_val) * 0.1 || 0.1; // Use 0.1 if transformed value is 0 (i.e. data_min = 0)
|
|
331
|
-
data_min = Math.sinh(asinh_val - padding) * threshold;
|
|
332
|
-
data_max = Math.sinh(asinh_val + padding) * threshold;
|
|
333
|
-
}
|
|
334
|
-
else {
|
|
335
|
-
const padding_abs = data_min === 0 ? 1 : Math.abs(data_min * 0.1); // 10% additive padding, or 1 if value is 0
|
|
336
|
-
data_min = data_min - padding_abs;
|
|
337
|
-
data_max = data_max + padding_abs;
|
|
338
|
-
}
|
|
329
|
+
const padding_abs = data_min === 0 ? 1 : Math.abs(data_min * 0.1); // 10% additive padding, or 1 if value is 0
|
|
330
|
+
data_min -= padding_abs;
|
|
331
|
+
data_max += padding_abs;
|
|
339
332
|
}
|
|
340
333
|
}
|
|
341
334
|
// If time or no range after padding, return the (potentially padded) domain directly
|
|
@@ -371,20 +364,26 @@ export function generate_log_ticks(min, max, ticks_option) {
|
|
|
371
364
|
const range_size = max_power - min_power;
|
|
372
365
|
const extended_min_power = range_size <= 2 ? min_power - 1 : min_power - Math.max(1, Math.floor(range_size / 4));
|
|
373
366
|
const extended_max_power = range_size <= 2 ? max_power + 1 : max_power;
|
|
374
|
-
const powers = range(extended_min_power, extended_max_power + 1).map((power) =>
|
|
367
|
+
const powers = range(extended_min_power, extended_max_power + 1).map((power) => 10 ** power);
|
|
375
368
|
// For narrow ranges, include intermediate values
|
|
376
369
|
if (max_power - min_power < 3 && typeof ticks_option === `number` && ticks_option > 5) {
|
|
377
370
|
const detailed_ticks = [];
|
|
378
371
|
powers.forEach((power) => {
|
|
379
372
|
detailed_ticks.push(power);
|
|
380
|
-
if (power * 2 <=
|
|
373
|
+
if (power * 2 <= 10 ** extended_max_power)
|
|
381
374
|
detailed_ticks.push(power * 2);
|
|
382
|
-
if (power * 5 <=
|
|
375
|
+
if (power * 5 <= 10 ** extended_max_power)
|
|
383
376
|
detailed_ticks.push(power * 5);
|
|
384
377
|
});
|
|
385
378
|
return detailed_ticks.filter((tick) => tick >= min && tick <= max);
|
|
386
379
|
}
|
|
387
|
-
|
|
380
|
+
const filtered_powers = powers.filter((power) => power >= min && power <= max);
|
|
381
|
+
if (filtered_powers.length >= 2)
|
|
382
|
+
return filtered_powers;
|
|
383
|
+
// Sub-decade domains (e.g. after zoom) have <2 powers of 10 — use d3's mantissa log ticks
|
|
384
|
+
const tick_count = typeof ticks_option === `number` && ticks_option > 0 ? ticks_option : 5;
|
|
385
|
+
const fallback = scaleLog().domain([min, max]).ticks(tick_count);
|
|
386
|
+
return fallback.length > 0 ? fallback : filtered_powers;
|
|
388
387
|
}
|
|
389
388
|
// Get custom label for a tick value if provided, otherwise return null
|
|
390
389
|
export function get_tick_label(tick_value, ticks_option) {
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
export declare function violin_path(grid_px: readonly number[], half_offsets_px: readonly number[], center: number, side: `both` | `positive` | `negative`, orient: (cross: number, val: number) => [number, number]): string;
|
|
2
|
+
export declare function bar_path(x: number, y: number, w: number, h: number, r: number, vertical?: boolean): string;
|