@coinbase/cds-web-visualization 0.0.0 → 3.4.0-beta.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/CHANGELOG.md +26 -0
- package/README.md +3 -0
- package/dts/chart/CartesianChart.d.ts +36 -0
- package/dts/chart/CartesianChart.d.ts.map +1 -0
- package/dts/chart/ChartProvider.d.ts +6 -0
- package/dts/chart/ChartProvider.d.ts.map +1 -0
- package/dts/chart/Path.d.ts +34 -0
- package/dts/chart/Path.d.ts.map +1 -0
- package/dts/chart/PeriodSelector.d.ts +61 -0
- package/dts/chart/PeriodSelector.d.ts.map +1 -0
- package/dts/chart/Point.d.ts +153 -0
- package/dts/chart/Point.d.ts.map +1 -0
- package/dts/chart/area/Area.d.ts +48 -0
- package/dts/chart/area/Area.d.ts.map +1 -0
- package/dts/chart/area/AreaChart.d.ts +52 -0
- package/dts/chart/area/AreaChart.d.ts.map +1 -0
- package/dts/chart/area/DottedArea.d.ts +68 -0
- package/dts/chart/area/DottedArea.d.ts.map +1 -0
- package/dts/chart/area/GradientArea.d.ts +30 -0
- package/dts/chart/area/GradientArea.d.ts.map +1 -0
- package/dts/chart/area/SolidArea.d.ts +8 -0
- package/dts/chart/area/SolidArea.d.ts.map +1 -0
- package/dts/chart/area/index.d.ts +6 -0
- package/dts/chart/area/index.d.ts.map +1 -0
- package/dts/chart/axis/Axis.d.ts +208 -0
- package/dts/chart/axis/Axis.d.ts.map +1 -0
- package/dts/chart/axis/XAxis.d.ts +16 -0
- package/dts/chart/axis/XAxis.d.ts.map +1 -0
- package/dts/chart/axis/YAxis.d.ts +21 -0
- package/dts/chart/axis/YAxis.d.ts.map +1 -0
- package/dts/chart/axis/index.d.ts +4 -0
- package/dts/chart/axis/index.d.ts.map +1 -0
- package/dts/chart/bar/Bar.d.ts +91 -0
- package/dts/chart/bar/Bar.d.ts.map +1 -0
- package/dts/chart/bar/BarChart.d.ts +53 -0
- package/dts/chart/bar/BarChart.d.ts.map +1 -0
- package/dts/chart/bar/BarPlot.d.ts +29 -0
- package/dts/chart/bar/BarPlot.d.ts.map +1 -0
- package/dts/chart/bar/BarStack.d.ts +111 -0
- package/dts/chart/bar/BarStack.d.ts.map +1 -0
- package/dts/chart/bar/BarStackGroup.d.ts +35 -0
- package/dts/chart/bar/BarStackGroup.d.ts.map +1 -0
- package/dts/chart/bar/DefaultBar.d.ts +17 -0
- package/dts/chart/bar/DefaultBar.d.ts.map +1 -0
- package/dts/chart/bar/DefaultBarStack.d.ts +16 -0
- package/dts/chart/bar/DefaultBarStack.d.ts.map +1 -0
- package/dts/chart/bar/index.d.ts +8 -0
- package/dts/chart/bar/index.d.ts.map +1 -0
- package/dts/chart/index.d.ts +13 -0
- package/dts/chart/index.d.ts.map +1 -0
- package/dts/chart/line/DottedLine.d.ts +14 -0
- package/dts/chart/line/DottedLine.d.ts.map +1 -0
- package/dts/chart/line/GradientLine.d.ts +42 -0
- package/dts/chart/line/GradientLine.d.ts.map +1 -0
- package/dts/chart/line/Line.d.ts +80 -0
- package/dts/chart/line/Line.d.ts.map +1 -0
- package/dts/chart/line/LineChart.d.ts +59 -0
- package/dts/chart/line/LineChart.d.ts.map +1 -0
- package/dts/chart/line/ReferenceLine.d.ts +131 -0
- package/dts/chart/line/ReferenceLine.d.ts.map +1 -0
- package/dts/chart/line/SolidLine.d.ts +14 -0
- package/dts/chart/line/SolidLine.d.ts.map +1 -0
- package/dts/chart/line/index.d.ts +7 -0
- package/dts/chart/line/index.d.ts.map +1 -0
- package/dts/chart/scrubber/Scrubber.d.ts +149 -0
- package/dts/chart/scrubber/Scrubber.d.ts.map +1 -0
- package/dts/chart/scrubber/ScrubberBeacon.d.ts +93 -0
- package/dts/chart/scrubber/ScrubberBeacon.d.ts.map +1 -0
- package/dts/chart/scrubber/ScrubberBeaconLabel.d.ts +7 -0
- package/dts/chart/scrubber/ScrubberBeaconLabel.d.ts.map +1 -0
- package/dts/chart/scrubber/ScrubberProvider.d.ts +17 -0
- package/dts/chart/scrubber/ScrubberProvider.d.ts.map +1 -0
- package/dts/chart/scrubber/index.d.ts +2 -0
- package/dts/chart/scrubber/index.d.ts.map +1 -0
- package/dts/chart/text/ChartText.d.ts +114 -0
- package/dts/chart/text/ChartText.d.ts.map +1 -0
- package/dts/chart/text/SmartChartTextGroup.d.ts +55 -0
- package/dts/chart/text/SmartChartTextGroup.d.ts.map +1 -0
- package/dts/chart/text/index.d.ts +3 -0
- package/dts/chart/text/index.d.ts.map +1 -0
- package/dts/chart/utils/axis.d.ts +342 -0
- package/dts/chart/utils/axis.d.ts.map +1 -0
- package/dts/chart/utils/bar.d.ts +20 -0
- package/dts/chart/utils/bar.d.ts.map +1 -0
- package/dts/chart/utils/chart.d.ts +97 -0
- package/dts/chart/utils/chart.d.ts.map +1 -0
- package/dts/chart/utils/context.d.ts +95 -0
- package/dts/chart/utils/context.d.ts.map +1 -0
- package/dts/chart/utils/index.d.ts +8 -0
- package/dts/chart/utils/index.d.ts.map +1 -0
- package/dts/chart/utils/path.d.ts +107 -0
- package/dts/chart/utils/path.d.ts.map +1 -0
- package/dts/chart/utils/point.d.ts +75 -0
- package/dts/chart/utils/point.d.ts.map +1 -0
- package/dts/chart/utils/scale.d.ts +43 -0
- package/dts/chart/utils/scale.d.ts.map +1 -0
- package/dts/index.d.ts +3 -0
- package/dts/index.d.ts.map +1 -0
- package/dts/sparkline/Counter.d.ts +8 -0
- package/dts/sparkline/Counter.d.ts.map +1 -0
- package/dts/sparkline/Sparkline.d.ts +67 -0
- package/dts/sparkline/Sparkline.d.ts.map +1 -0
- package/dts/sparkline/SparklineArea.d.ts +15 -0
- package/dts/sparkline/SparklineArea.d.ts.map +1 -0
- package/dts/sparkline/SparklineAreaPattern.d.ts +14 -0
- package/dts/sparkline/SparklineAreaPattern.d.ts.map +1 -0
- package/dts/sparkline/SparklineGradient.d.ts +23 -0
- package/dts/sparkline/SparklineGradient.d.ts.map +1 -0
- package/dts/sparkline/SparklinePath.d.ts +12 -0
- package/dts/sparkline/SparklinePath.d.ts.map +1 -0
- package/dts/sparkline/__figma__/Sparkline.figma.d.ts +2 -0
- package/dts/sparkline/__figma__/Sparkline.figma.d.ts.map +1 -0
- package/dts/sparkline/generateSparklineWithId.d.ts +11 -0
- package/dts/sparkline/generateSparklineWithId.d.ts.map +1 -0
- package/dts/sparkline/index.d.ts +6 -0
- package/dts/sparkline/index.d.ts.map +1 -0
- package/dts/sparkline/sparkline-interactive/InnerSparklineInteractiveProvider.d.ts +13 -0
- package/dts/sparkline/sparkline-interactive/InnerSparklineInteractiveProvider.d.ts.map +1 -0
- package/dts/sparkline/sparkline-interactive/SparklineInteractive.d.ts +199 -0
- package/dts/sparkline/sparkline-interactive/SparklineInteractive.d.ts.map +1 -0
- package/dts/sparkline/sparkline-interactive/SparklineInteractiveAnimatedPath.d.ts +26 -0
- package/dts/sparkline/sparkline-interactive/SparklineInteractiveAnimatedPath.d.ts.map +1 -0
- package/dts/sparkline/sparkline-interactive/SparklineInteractiveHoverDate.d.ts +5 -0
- package/dts/sparkline/sparkline-interactive/SparklineInteractiveHoverDate.d.ts.map +1 -0
- package/dts/sparkline/sparkline-interactive/SparklineInteractiveHoverPrice.d.ts +5 -0
- package/dts/sparkline/sparkline-interactive/SparklineInteractiveHoverPrice.d.ts.map +1 -0
- package/dts/sparkline/sparkline-interactive/SparklineInteractiveLineVertical.d.ts +8 -0
- package/dts/sparkline/sparkline-interactive/SparklineInteractiveLineVertical.d.ts.map +1 -0
- package/dts/sparkline/sparkline-interactive/SparklineInteractiveMarkerDates.d.ts +17 -0
- package/dts/sparkline/sparkline-interactive/SparklineInteractiveMarkerDates.d.ts.map +1 -0
- package/dts/sparkline/sparkline-interactive/SparklineInteractivePaths.d.ts +25 -0
- package/dts/sparkline/sparkline-interactive/SparklineInteractivePaths.d.ts.map +1 -0
- package/dts/sparkline/sparkline-interactive/SparklineInteractivePeriodSelector.d.ts +25 -0
- package/dts/sparkline/sparkline-interactive/SparklineInteractivePeriodSelector.d.ts.map +1 -0
- package/dts/sparkline/sparkline-interactive/SparklineInteractiveProvider.d.ts +25 -0
- package/dts/sparkline/sparkline-interactive/SparklineInteractiveProvider.d.ts.map +1 -0
- package/dts/sparkline/sparkline-interactive/SparklineInteractiveScrubHandler.d.ts +30 -0
- package/dts/sparkline/sparkline-interactive/SparklineInteractiveScrubHandler.d.ts.map +1 -0
- package/dts/sparkline/sparkline-interactive/SparklineInteractiveScrubProvider.d.ts +18 -0
- package/dts/sparkline/sparkline-interactive/SparklineInteractiveScrubProvider.d.ts.map +1 -0
- package/dts/sparkline/sparkline-interactive/SparklineInteractiveTimeseriesPaths.d.ts +31 -0
- package/dts/sparkline/sparkline-interactive/SparklineInteractiveTimeseriesPaths.d.ts.map +1 -0
- package/dts/sparkline/sparkline-interactive/__figma__/SparklineInteractive.figma.d.ts +2 -0
- package/dts/sparkline/sparkline-interactive/__figma__/SparklineInteractive.figma.d.ts.map +1 -0
- package/dts/sparkline/sparkline-interactive/fade.d.ts +3 -0
- package/dts/sparkline/sparkline-interactive/fade.d.ts.map +1 -0
- package/dts/sparkline/sparkline-interactive/useSparklineInteractiveConstants.d.ts +13 -0
- package/dts/sparkline/sparkline-interactive/useSparklineInteractiveConstants.d.ts.map +1 -0
- package/dts/sparkline/sparkline-interactive-header/SparklineInteractiveHeader.d.ts +112 -0
- package/dts/sparkline/sparkline-interactive-header/SparklineInteractiveHeader.d.ts.map +1 -0
- package/dts/sparkline/sparkline-interactive-header/__figma__/SparklineInteractiveHeader.figma.d.ts +2 -0
- package/dts/sparkline/sparkline-interactive-header/__figma__/SparklineInteractiveHeader.figma.d.ts.map +1 -0
- package/esm/chart/CartesianChart.css +1 -0
- package/esm/chart/CartesianChart.js +258 -0
- package/esm/chart/ChartProvider.js +10 -0
- package/esm/chart/Path.js +89 -0
- package/esm/chart/PeriodSelector.css +1 -0
- package/esm/chart/PeriodSelector.js +126 -0
- package/esm/chart/Point.css +2 -0
- package/esm/chart/Point.js +171 -0
- package/esm/chart/area/Area.js +85 -0
- package/esm/chart/area/AreaChart.js +164 -0
- package/esm/chart/area/DottedArea.js +141 -0
- package/esm/chart/area/GradientArea.js +111 -0
- package/esm/chart/area/SolidArea.js +29 -0
- package/esm/chart/area/index.js +7 -0
- package/esm/chart/axis/Axis.js +46 -0
- package/esm/chart/axis/XAxis.css +2 -0
- package/esm/chart/axis/XAxis.js +195 -0
- package/esm/chart/axis/YAxis.css +2 -0
- package/esm/chart/axis/YAxis.js +183 -0
- package/esm/chart/axis/index.js +5 -0
- package/esm/chart/bar/Bar.js +59 -0
- package/esm/chart/bar/BarChart.js +147 -0
- package/esm/chart/bar/BarPlot.js +96 -0
- package/esm/chart/bar/BarStack.js +519 -0
- package/esm/chart/bar/BarStackGroup.js +96 -0
- package/esm/chart/bar/DefaultBar.js +64 -0
- package/esm/chart/bar/DefaultBarStack.js +60 -0
- package/esm/chart/bar/index.js +9 -0
- package/esm/chart/index.js +14 -0
- package/esm/chart/line/DottedLine.js +38 -0
- package/esm/chart/line/GradientLine.js +58 -0
- package/esm/chart/line/Line.js +159 -0
- package/esm/chart/line/LineChart.js +120 -0
- package/esm/chart/line/ReferenceLine.js +142 -0
- package/esm/chart/line/SolidLine.js +34 -0
- package/esm/chart/line/index.js +8 -0
- package/esm/chart/scrubber/Scrubber.js +483 -0
- package/esm/chart/scrubber/ScrubberBeacon.js +195 -0
- package/esm/chart/scrubber/ScrubberBeaconLabel.js +33 -0
- package/esm/chart/scrubber/ScrubberProvider.js +228 -0
- package/esm/chart/scrubber/index.js +2 -0
- package/esm/chart/text/ChartText.js +236 -0
- package/esm/chart/text/SmartChartTextGroup.js +226 -0
- package/esm/chart/text/index.js +4 -0
- package/esm/chart/utils/axis.js +593 -0
- package/esm/chart/utils/bar.js +24 -0
- package/esm/chart/utils/chart.js +229 -0
- package/esm/chart/utils/context.js +15 -0
- package/esm/chart/utils/index.js +9 -0
- package/esm/chart/utils/path.js +204 -0
- package/esm/chart/utils/point.js +118 -0
- package/esm/chart/utils/scale.js +48 -0
- package/esm/index.js +4 -0
- package/esm/sparkline/Counter.css +3 -0
- package/esm/sparkline/Counter.js +35 -0
- package/esm/sparkline/Sparkline.js +164 -0
- package/esm/sparkline/SparklineArea.js +18 -0
- package/esm/sparkline/SparklineAreaPattern.js +37 -0
- package/esm/sparkline/SparklineGradient.js +30 -0
- package/esm/sparkline/SparklinePath.js +19 -0
- package/esm/sparkline/__figma__/Sparkline.figma.js +24 -0
- package/esm/sparkline/generateSparklineWithId.js +7 -0
- package/esm/sparkline/index.js +5 -0
- package/esm/sparkline/sparkline-interactive/InnerSparklineInteractiveProvider.js +21 -0
- package/esm/sparkline/sparkline-interactive/SparklineInteractive.js +317 -0
- package/esm/sparkline/sparkline-interactive/SparklineInteractiveAnimatedPath.js +108 -0
- package/esm/sparkline/sparkline-interactive/SparklineInteractiveHoverDate.css +2 -0
- package/esm/sparkline/sparkline-interactive/SparklineInteractiveHoverDate.js +26 -0
- package/esm/sparkline/sparkline-interactive/SparklineInteractiveHoverPrice.css +2 -0
- package/esm/sparkline/sparkline-interactive/SparklineInteractiveHoverPrice.js +24 -0
- package/esm/sparkline/sparkline-interactive/SparklineInteractiveLineVertical.css +4 -0
- package/esm/sparkline/sparkline-interactive/SparklineInteractiveLineVertical.js +65 -0
- package/esm/sparkline/sparkline-interactive/SparklineInteractiveMarkerDates.css +1 -0
- package/esm/sparkline/sparkline-interactive/SparklineInteractiveMarkerDates.js +80 -0
- package/esm/sparkline/sparkline-interactive/SparklineInteractivePaths.js +56 -0
- package/esm/sparkline/sparkline-interactive/SparklineInteractivePeriodSelector.js +70 -0
- package/esm/sparkline/sparkline-interactive/SparklineInteractiveProvider.js +45 -0
- package/esm/sparkline/sparkline-interactive/SparklineInteractiveScrubHandler.css +5 -0
- package/esm/sparkline/sparkline-interactive/SparklineInteractiveScrubHandler.js +199 -0
- package/esm/sparkline/sparkline-interactive/SparklineInteractiveScrubProvider.js +39 -0
- package/esm/sparkline/sparkline-interactive/SparklineInteractiveTimeseriesPaths.js +92 -0
- package/esm/sparkline/sparkline-interactive/__figma__/SparklineInteractive.figma.js +89 -0
- package/esm/sparkline/sparkline-interactive/fade.css +2 -0
- package/esm/sparkline/sparkline-interactive/fade.js +14 -0
- package/esm/sparkline/sparkline-interactive/useSparklineInteractiveConstants.js +28 -0
- package/esm/sparkline/sparkline-interactive-header/SparklineInteractiveHeader.js +225 -0
- package/esm/sparkline/sparkline-interactive-header/__figma__/SparklineInteractiveHeader.figma.js +108 -0
- package/package.json +68 -6
- package/index.js +0 -1
|
@@ -0,0 +1,593 @@
|
|
|
1
|
+
const _excluded = ["id"];
|
|
2
|
+
function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
|
|
3
|
+
function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
|
|
4
|
+
function _defineProperty(e, r, t) { return (r = _toPropertyKey(r)) in e ? Object.defineProperty(e, r, { value: t, enumerable: !0, configurable: !0, writable: !0 }) : e[r] = t, e; }
|
|
5
|
+
function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == typeof i ? i : i + ""; }
|
|
6
|
+
function _toPrimitive(t, r) { if ("object" != typeof t || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != typeof i) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); }
|
|
7
|
+
function _objectWithoutProperties(e, t) { if (null == e) return {}; var o, r, i = _objectWithoutPropertiesLoose(e, t); if (Object.getOwnPropertySymbols) { var n = Object.getOwnPropertySymbols(e); for (r = 0; r < n.length; r++) o = n[r], -1 === t.indexOf(o) && {}.propertyIsEnumerable.call(e, o) && (i[o] = e[o]); } return i; }
|
|
8
|
+
function _objectWithoutPropertiesLoose(r, e) { if (null == r) return {}; var t = {}; for (var n in r) if ({}.hasOwnProperty.call(r, n)) { if (-1 !== e.indexOf(n)) continue; t[n] = r[n]; } return t; }
|
|
9
|
+
import { useCallback, useMemo, useState } from 'react';
|
|
10
|
+
import { getChartDomain, getChartRange, isValidBounds } from './chart';
|
|
11
|
+
import { getCategoricalScale, getNumericScale, isCategoricalScale, isNumericScale } from './scale';
|
|
12
|
+
export const defaultAxisId = 'DEFAULT_AXIS_ID';
|
|
13
|
+
export const defaultAxisScaleType = 'linear';
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Axis configuration with computed bounds
|
|
17
|
+
*/
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Axis configuration without computed bounds (used for input)
|
|
21
|
+
*/
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Gets a D3 scale based on the axis configuration.
|
|
25
|
+
* Handles both numeric (linear/log) and categorical (band) scales.
|
|
26
|
+
*
|
|
27
|
+
* For numeric scales, the domain limit controls whether bounds are "nice" (human-friendly)
|
|
28
|
+
* or "strict" (exact min/max). Range can be customized using function-based configuration.
|
|
29
|
+
*
|
|
30
|
+
* @param params - Scale parameters
|
|
31
|
+
* @returns The D3 scale function
|
|
32
|
+
* @throws An Error if bounds are invalid
|
|
33
|
+
*/
|
|
34
|
+
export const getAxisScale = _ref => {
|
|
35
|
+
var _config$scaleType;
|
|
36
|
+
let {
|
|
37
|
+
config,
|
|
38
|
+
type,
|
|
39
|
+
range,
|
|
40
|
+
dataDomain
|
|
41
|
+
} = _ref;
|
|
42
|
+
const scaleType = (_config$scaleType = config === null || config === void 0 ? void 0 : config.scaleType) !== null && _config$scaleType !== void 0 ? _config$scaleType : 'linear';
|
|
43
|
+
let adjustedRange = range;
|
|
44
|
+
|
|
45
|
+
// Invert range for Y axis for SVG coordinate system
|
|
46
|
+
if (type === 'y') {
|
|
47
|
+
adjustedRange = {
|
|
48
|
+
min: adjustedRange.max,
|
|
49
|
+
max: adjustedRange.min
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
let adjustedDomain = dataDomain;
|
|
53
|
+
if (config !== null && config !== void 0 && config.domain) {
|
|
54
|
+
var _config$domain$min, _config$domain$max;
|
|
55
|
+
adjustedDomain = {
|
|
56
|
+
min: (_config$domain$min = config.domain.min) !== null && _config$domain$min !== void 0 ? _config$domain$min : dataDomain.min,
|
|
57
|
+
max: (_config$domain$max = config.domain.max) !== null && _config$domain$max !== void 0 ? _config$domain$max : dataDomain.max
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
if (!isValidBounds(adjustedDomain)) throw new Error('Invalid domain bounds. See https://cds.coinbase.com/http://localhost:3000/components/graphs/XAxis/#domain');
|
|
61
|
+
if (scaleType === 'band') {
|
|
62
|
+
var _config$categoryPaddi;
|
|
63
|
+
return getCategoricalScale({
|
|
64
|
+
domain: adjustedDomain,
|
|
65
|
+
range: adjustedRange,
|
|
66
|
+
padding: (_config$categoryPaddi = config === null || config === void 0 ? void 0 : config.categoryPadding) !== null && _config$categoryPaddi !== void 0 ? _config$categoryPaddi : 0.3
|
|
67
|
+
});
|
|
68
|
+
} else {
|
|
69
|
+
const scale = getNumericScale({
|
|
70
|
+
domain: adjustedDomain,
|
|
71
|
+
range: adjustedRange,
|
|
72
|
+
scaleType: scaleType
|
|
73
|
+
});
|
|
74
|
+
if ((config === null || config === void 0 ? void 0 : config.domainLimit) === 'nice') scale.nice();
|
|
75
|
+
return scale;
|
|
76
|
+
}
|
|
77
|
+
};
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* Formats the array of user-provided axis configs with default values and validates axis ids.
|
|
81
|
+
* Ensures at least one axis config exists if no input is provided.
|
|
82
|
+
* Requires specific axis ids when there are more than 1 axes.
|
|
83
|
+
* Defaults the axis id for a single axis config if there is no id.
|
|
84
|
+
* @param type - the type of axis, 'x' or 'y'
|
|
85
|
+
* @param axes - array of axis configs or single axis config
|
|
86
|
+
* @param defaultId - the default id to use for the axis
|
|
87
|
+
* @param defaultScaleType - the default scale type to use for the axis
|
|
88
|
+
* @returns array of axis configs with IDs
|
|
89
|
+
*/
|
|
90
|
+
export const getAxisConfig = function (type, axes) {
|
|
91
|
+
let defaultId = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : defaultAxisId;
|
|
92
|
+
let defaultScaleType = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : defaultAxisScaleType;
|
|
93
|
+
const defaultDomainLimit = type === 'x' ? 'strict' : 'nice';
|
|
94
|
+
if (!axes) {
|
|
95
|
+
return [{
|
|
96
|
+
id: defaultId,
|
|
97
|
+
scaleType: defaultScaleType,
|
|
98
|
+
domainLimit: defaultDomainLimit
|
|
99
|
+
}];
|
|
100
|
+
}
|
|
101
|
+
if (Array.isArray(axes)) {
|
|
102
|
+
const axesLength = axes.length;
|
|
103
|
+
// forces id to be defined on every input config when there are multiple axes
|
|
104
|
+
if (axesLength > 1 && axes.some(_ref2 => {
|
|
105
|
+
let {
|
|
106
|
+
id
|
|
107
|
+
} = _ref2;
|
|
108
|
+
return id === undefined;
|
|
109
|
+
})) {
|
|
110
|
+
throw new Error('When defining multiple axes, each must have a unique id. See https://cds.coinbase.com/components/graphs/YAxis/#multiple-y-axes.');
|
|
111
|
+
}
|
|
112
|
+
return axes.map(_ref3 => {
|
|
113
|
+
let {
|
|
114
|
+
id
|
|
115
|
+
} = _ref3,
|
|
116
|
+
axis = _objectWithoutProperties(_ref3, _excluded);
|
|
117
|
+
return _objectSpread({
|
|
118
|
+
// defaults the axis id if only a single axis is provided
|
|
119
|
+
id: axesLength > 1 ? id !== null && id !== void 0 ? id : defaultAxisId : id,
|
|
120
|
+
scaleType: defaultScaleType,
|
|
121
|
+
domainLimit: defaultDomainLimit
|
|
122
|
+
}, axis);
|
|
123
|
+
});
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
// Single axis config
|
|
127
|
+
return [_objectSpread({
|
|
128
|
+
id: defaultId,
|
|
129
|
+
scaleType: defaultScaleType,
|
|
130
|
+
domainLimit: defaultDomainLimit
|
|
131
|
+
}, axes)];
|
|
132
|
+
};
|
|
133
|
+
|
|
134
|
+
/**
|
|
135
|
+
* Calculates the data domain for an axis based on its configuration and series data.
|
|
136
|
+
* Handles both x and y axes, categorical data, custom domain configurations, and stacking.
|
|
137
|
+
*
|
|
138
|
+
* @param axisParam - The axis configuration
|
|
139
|
+
* @param series - Array of series objects (for stacking support)
|
|
140
|
+
* @param axisType - Whether this is an 'x' or 'y' axis
|
|
141
|
+
* @returns The calculated axis bounds
|
|
142
|
+
*/
|
|
143
|
+
export const getAxisDomain = (axisParam, series, axisType) => {
|
|
144
|
+
var _finalDomain$min, _finalDomain$max;
|
|
145
|
+
let dataDomain = null;
|
|
146
|
+
if (axisParam.data && Array.isArray(axisParam.data) && axisParam.data.length > 0) {
|
|
147
|
+
const firstItem = axisParam.data[0];
|
|
148
|
+
if (typeof firstItem === 'number') {
|
|
149
|
+
// Numeric data - use actual min/max values
|
|
150
|
+
const numericData = axisParam.data;
|
|
151
|
+
dataDomain = {
|
|
152
|
+
min: Math.min(...numericData),
|
|
153
|
+
max: Math.max(...numericData)
|
|
154
|
+
};
|
|
155
|
+
} else if (typeof firstItem === 'string') {
|
|
156
|
+
// String labels - use indices as domain (0 to length-1)
|
|
157
|
+
// This allows using string labels with linear scales
|
|
158
|
+
dataDomain = {
|
|
159
|
+
min: 0,
|
|
160
|
+
max: axisParam.data.length - 1
|
|
161
|
+
};
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
// Calculate domain from series data
|
|
166
|
+
const seriesDomain = axisType === 'x' ? getChartDomain(series) : getChartRange(series);
|
|
167
|
+
|
|
168
|
+
// If data sets the domain, use that instead of the series domain
|
|
169
|
+
const preferredDataDomain = dataDomain !== null && dataDomain !== void 0 ? dataDomain : seriesDomain;
|
|
170
|
+
const bounds = axisParam.domain;
|
|
171
|
+
let finalDomain;
|
|
172
|
+
if (typeof bounds === 'function') {
|
|
173
|
+
var _preferredDataDomain$, _preferredDataDomain$2;
|
|
174
|
+
// Apply the transform function to the base domain
|
|
175
|
+
// No need to default to 0 here since we'll do it once at the end
|
|
176
|
+
finalDomain = bounds({
|
|
177
|
+
min: (_preferredDataDomain$ = preferredDataDomain.min) !== null && _preferredDataDomain$ !== void 0 ? _preferredDataDomain$ : 0,
|
|
178
|
+
max: (_preferredDataDomain$2 = preferredDataDomain.max) !== null && _preferredDataDomain$2 !== void 0 ? _preferredDataDomain$2 : 0
|
|
179
|
+
});
|
|
180
|
+
} else if (bounds && typeof bounds === 'object') {
|
|
181
|
+
var _bounds$min, _bounds$max;
|
|
182
|
+
// Merge explicit bounds with calculated domain
|
|
183
|
+
finalDomain = {
|
|
184
|
+
min: (_bounds$min = bounds.min) !== null && _bounds$min !== void 0 ? _bounds$min : preferredDataDomain.min,
|
|
185
|
+
max: (_bounds$max = bounds.max) !== null && _bounds$max !== void 0 ? _bounds$max : preferredDataDomain.max
|
|
186
|
+
};
|
|
187
|
+
} else {
|
|
188
|
+
// Use the base domain as-is
|
|
189
|
+
finalDomain = preferredDataDomain;
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
// Ensure we always return valid bounds with no undefined values
|
|
193
|
+
return {
|
|
194
|
+
min: (_finalDomain$min = finalDomain.min) !== null && _finalDomain$min !== void 0 ? _finalDomain$min : 0,
|
|
195
|
+
max: (_finalDomain$max = finalDomain.max) !== null && _finalDomain$max !== void 0 ? _finalDomain$max : 0
|
|
196
|
+
};
|
|
197
|
+
};
|
|
198
|
+
|
|
199
|
+
/**
|
|
200
|
+
* Calculates the visual range for an axis based on the chart rectangle and configuration.
|
|
201
|
+
* Handles custom range configurations including functions and partial bounds.
|
|
202
|
+
*
|
|
203
|
+
* @param axisParam - The axis configuration
|
|
204
|
+
* @param chartRect - The chart drawing area rectangle
|
|
205
|
+
* @param axisType - Whether this is an 'x' or 'y' axis
|
|
206
|
+
* @returns The calculated axis range bounds
|
|
207
|
+
*/
|
|
208
|
+
export const getAxisRange = (axisParam, chartRect, axisType) => {
|
|
209
|
+
// Calculate base range based on axis type
|
|
210
|
+
let baseRange;
|
|
211
|
+
if (axisType === 'x') {
|
|
212
|
+
baseRange = {
|
|
213
|
+
min: chartRect.x,
|
|
214
|
+
max: chartRect.x + chartRect.width
|
|
215
|
+
};
|
|
216
|
+
} else {
|
|
217
|
+
baseRange = {
|
|
218
|
+
min: chartRect.y,
|
|
219
|
+
max: chartRect.y + chartRect.height
|
|
220
|
+
};
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
// Apply any custom range configuration
|
|
224
|
+
const rangeConfig = axisParam.range;
|
|
225
|
+
if (!rangeConfig) {
|
|
226
|
+
return baseRange;
|
|
227
|
+
}
|
|
228
|
+
if (typeof rangeConfig === 'function') {
|
|
229
|
+
// Apply the transform function to the base range
|
|
230
|
+
return rangeConfig(baseRange);
|
|
231
|
+
} else {
|
|
232
|
+
var _rangeConfig$min, _rangeConfig$max;
|
|
233
|
+
// Merge explicit range values with calculated range
|
|
234
|
+
return {
|
|
235
|
+
min: (_rangeConfig$min = rangeConfig.min) !== null && _rangeConfig$min !== void 0 ? _rangeConfig$min : baseRange.min,
|
|
236
|
+
max: (_rangeConfig$max = rangeConfig.max) !== null && _rangeConfig$max !== void 0 ? _rangeConfig$max : baseRange.max
|
|
237
|
+
};
|
|
238
|
+
}
|
|
239
|
+
};
|
|
240
|
+
|
|
241
|
+
/**
|
|
242
|
+
* Options for tick generation behavior
|
|
243
|
+
*/
|
|
244
|
+
|
|
245
|
+
/**
|
|
246
|
+
* Formats a tick value for display on an axis.
|
|
247
|
+
* Consolidates the identical formatting logic shared between XAxis and YAxis.
|
|
248
|
+
*
|
|
249
|
+
* @param value - The raw tick value to format
|
|
250
|
+
* @param tickFormatter - Optional custom formatter function
|
|
251
|
+
* @returns The formatted tick value as a React node
|
|
252
|
+
*/
|
|
253
|
+
export const formatAxisTick = (value, tickFormatter) => {
|
|
254
|
+
if (tickFormatter) {
|
|
255
|
+
return tickFormatter(value);
|
|
256
|
+
}
|
|
257
|
+
return value;
|
|
258
|
+
};
|
|
259
|
+
|
|
260
|
+
/**
|
|
261
|
+
* Calculates a rounded step size for tick generation.
|
|
262
|
+
* Chooses from multiples of 1, 2, or 5 (scaled by powers of 10).
|
|
263
|
+
*
|
|
264
|
+
* @param roughStep - The approximate step size needed
|
|
265
|
+
* @param minStep - Optional minimum step size constraint
|
|
266
|
+
* @param maxStep - Optional maximum step size constraint
|
|
267
|
+
* @returns rounded step size within the specified constraints
|
|
268
|
+
*/
|
|
269
|
+
const calculateNiceStep = (roughStep, minStep, maxStep) => {
|
|
270
|
+
if (roughStep <= 0) return minStep !== null && minStep !== void 0 ? minStep : 1;
|
|
271
|
+
const magnitude = Math.pow(10, Math.floor(Math.log10(roughStep)));
|
|
272
|
+
const residual = roughStep / magnitude;
|
|
273
|
+
let roundResidual;
|
|
274
|
+
if (residual <= 1) {
|
|
275
|
+
roundResidual = 1;
|
|
276
|
+
} else if (residual <= 2) {
|
|
277
|
+
roundResidual = 2;
|
|
278
|
+
} else if (residual <= 5) {
|
|
279
|
+
roundResidual = 5;
|
|
280
|
+
} else {
|
|
281
|
+
roundResidual = 10;
|
|
282
|
+
}
|
|
283
|
+
let niceStep = roundResidual * magnitude;
|
|
284
|
+
if (minStep !== undefined && niceStep < minStep) {
|
|
285
|
+
niceStep = minStep;
|
|
286
|
+
}
|
|
287
|
+
if (maxStep !== undefined && niceStep > maxStep) {
|
|
288
|
+
niceStep = maxStep;
|
|
289
|
+
}
|
|
290
|
+
return niceStep;
|
|
291
|
+
};
|
|
292
|
+
|
|
293
|
+
/**
|
|
294
|
+
* Generates evenly distributed tick values.
|
|
295
|
+
* Always includes first and last domain values, with intermediate ticks evenly distributed using nice step sizes.
|
|
296
|
+
* Selects from actual data points (possibleTickValues) or generates nice round numbers.
|
|
297
|
+
*
|
|
298
|
+
* @param scale - The numeric scale function
|
|
299
|
+
* @param tickInterval - Space between ticks (in pixels)
|
|
300
|
+
* @param possibleTickValues - Optional array of possible tick values to select from (e.g., data indices). If not provided, generates nice round numbers with guaranteed first/last inclusion.
|
|
301
|
+
* @param options - Options for tick generation behavior
|
|
302
|
+
* @returns Array of tick values, always including first and last domain values
|
|
303
|
+
*/
|
|
304
|
+
const generateEvenlyDistributedTicks = (scale, tickInterval, possibleTickValues, options) => {
|
|
305
|
+
var _options$minTickCount;
|
|
306
|
+
const minTickCount = (_options$minTickCount = options === null || options === void 0 ? void 0 : options.minTickCount) !== null && _options$minTickCount !== void 0 ? _options$minTickCount : 4;
|
|
307
|
+
const [rangeMin, rangeMax] = scale.range();
|
|
308
|
+
const range = Math.abs(rangeMax - rangeMin);
|
|
309
|
+
const tickCountFromSpace = Math.floor(range / tickInterval);
|
|
310
|
+
const tickCount = Math.max(tickCountFromSpace, minTickCount);
|
|
311
|
+
if (tickCount < 1) {
|
|
312
|
+
return [];
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
// If we have possibleTickValues, select evenly from them
|
|
316
|
+
if (possibleTickValues && possibleTickValues.length > 0) {
|
|
317
|
+
// Limit tick count to available values
|
|
318
|
+
const finalTickCount = Math.min(tickCount, possibleTickValues.length);
|
|
319
|
+
const tickValues = [];
|
|
320
|
+
const step = (possibleTickValues.length - 1) / (finalTickCount - 1);
|
|
321
|
+
for (let i = 0; i < finalTickCount; i++) {
|
|
322
|
+
const index = i === finalTickCount - 1 ? possibleTickValues.length - 1 : Math.round(step * i);
|
|
323
|
+
tickValues.push(possibleTickValues[index]);
|
|
324
|
+
}
|
|
325
|
+
return tickValues;
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
// Generate nice round numbers that always include first and last domain values
|
|
329
|
+
const [domainMin, domainMax] = scale.domain();
|
|
330
|
+
if (tickCount === 1) {
|
|
331
|
+
return [domainMin];
|
|
332
|
+
}
|
|
333
|
+
if (tickCount === 2) {
|
|
334
|
+
return [domainMin, domainMax];
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
// Calculate a nice step size
|
|
338
|
+
const domainRange = domainMax - domainMin;
|
|
339
|
+
const roughStep = domainRange / (tickCount - 1);
|
|
340
|
+
const niceStep = calculateNiceStep(roughStep, options === null || options === void 0 ? void 0 : options.minStep, options === null || options === void 0 ? void 0 : options.maxStep);
|
|
341
|
+
|
|
342
|
+
// Generate ticks starting from domainMin and stepping by niceStep
|
|
343
|
+
const tickValues = [domainMin];
|
|
344
|
+
|
|
345
|
+
// Generate intermediate ticks using the nice step, starting from domainMin
|
|
346
|
+
let currentTick = domainMin + niceStep;
|
|
347
|
+
while (currentTick < domainMax) {
|
|
348
|
+
// Avoid floating point precision issues
|
|
349
|
+
const roundedTick = Number(currentTick.toFixed(10));
|
|
350
|
+
tickValues.push(roundedTick);
|
|
351
|
+
currentTick += niceStep;
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
// Only include domainMax if it naturally falls on a step (or very close due to floating point)
|
|
355
|
+
// or if the last tick is far enough away that including max provides useful context
|
|
356
|
+
const lastTick = tickValues[tickValues.length - 1];
|
|
357
|
+
const distanceToMax = domainMax - lastTick;
|
|
358
|
+
|
|
359
|
+
// Include max if:
|
|
360
|
+
// 1. It naturally falls on a step (within floating point tolerance)
|
|
361
|
+
// 2. Or the last tick is more than half a step away (provides meaningful context)
|
|
362
|
+
const tolerance = niceStep * 0.0001; // Floating point tolerance
|
|
363
|
+
const shouldIncludeMax = Math.abs(distanceToMax - niceStep) < tolerance ||
|
|
364
|
+
// Natural step
|
|
365
|
+
distanceToMax > niceStep * 0.5; // Far enough to provide context
|
|
366
|
+
|
|
367
|
+
if (shouldIncludeMax && domainMax !== lastTick) {
|
|
368
|
+
tickValues.push(domainMax);
|
|
369
|
+
}
|
|
370
|
+
return tickValues;
|
|
371
|
+
};
|
|
372
|
+
|
|
373
|
+
/**
|
|
374
|
+
* Processes tick configuration and returns tick data with positions.
|
|
375
|
+
*
|
|
376
|
+
* **Parameter Precedence by Scale Type:**
|
|
377
|
+
*
|
|
378
|
+
* **For Numeric Scales (linear/log):**
|
|
379
|
+
* 1. `ticks` (array) - Explicit tick values override all other options
|
|
380
|
+
* 2. `ticks` (function) - Filter function for tick selection
|
|
381
|
+
* 3. `ticks` (boolean) - Show/hide all possible ticks
|
|
382
|
+
* 4. `requestedTickCount` - D3 automatic tick generation (overrides tickInterval)
|
|
383
|
+
* 5. `tickInterval` - Pixel-based spacing (fallback)
|
|
384
|
+
*
|
|
385
|
+
* **For Categorical Scales (band):**
|
|
386
|
+
* 1. `ticks` (array) - Explicit category indices to display
|
|
387
|
+
* 2. `ticks` (function) - Filter function for category selection
|
|
388
|
+
* 3. `ticks` (boolean) - Show/hide all categories
|
|
389
|
+
* 4. Default - Show all categories (requestedTickCount and tickInterval are ignored)
|
|
390
|
+
*
|
|
391
|
+
* @param params - Tick processing parameters
|
|
392
|
+
* @param params.ticks - Custom tick configuration with multiple formats:
|
|
393
|
+
* - **Array**: For numeric scales: exact tick values; For band scales: category indices
|
|
394
|
+
* - **Function**: Predicate to filter tick values or category indices
|
|
395
|
+
* - **Boolean**: Show all (true) or no ticks (false) for both scale types
|
|
396
|
+
* @param params.scaleFunction - D3 scale function (numeric or band scale)
|
|
397
|
+
* @param params.requestedTickCount - Number of ticks for D3 generation (**numeric scales only**, overrides tickInterval)
|
|
398
|
+
* @param params.categories - Category labels (**band scales only**)
|
|
399
|
+
* @param params.possibleTickValues - Available tick values for filtering/selection (**numeric scales only**)
|
|
400
|
+
* @param params.tickInterval - Pixel spacing between ticks (**numeric scales only**, fallback option)
|
|
401
|
+
* @returns Array of tick data with values and positions
|
|
402
|
+
*
|
|
403
|
+
* @example
|
|
404
|
+
* // Basic usage with tickInterval for pixel-based spacing
|
|
405
|
+
* import { scaleLinear } from 'd3-scale';
|
|
406
|
+
*
|
|
407
|
+
* const numericScale = scaleLinear().domain([0, 10]).range([0, 400]);
|
|
408
|
+
* const result = getAxisTicksData({
|
|
409
|
+
* scaleFunction: numericScale,
|
|
410
|
+
* tickInterval: 80, // 80 pixels between ticks
|
|
411
|
+
* possibleTickValues: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
|
|
412
|
+
* });
|
|
413
|
+
* // Returns: [
|
|
414
|
+
* // { tick: 0, position: 0 }, // Always includes first
|
|
415
|
+
* // { tick: 2, position: 80 },
|
|
416
|
+
* // { tick: 5, position: 200 },
|
|
417
|
+
* // { tick: 7, position: 280 },
|
|
418
|
+
* // { tick: 10, position: 400 } // Always includes last
|
|
419
|
+
* // ]
|
|
420
|
+
*
|
|
421
|
+
* @example
|
|
422
|
+
* // Using requestedTickCount for D3-generated ticks
|
|
423
|
+
* const result = getAxisTicksData({
|
|
424
|
+
* scaleFunction: numericScale,
|
|
425
|
+
* requestedTickCount: 5
|
|
426
|
+
* });
|
|
427
|
+
* // Uses D3's tick generation algorithm
|
|
428
|
+
*
|
|
429
|
+
* @example
|
|
430
|
+
* // Using explicit tick values
|
|
431
|
+
* const result = getAxisTicksData({
|
|
432
|
+
* scaleFunction: numericScale,
|
|
433
|
+
* ticks: [0, 2.5, 5, 7.5, 10]
|
|
434
|
+
* });
|
|
435
|
+
* // Returns exact positions for specified values
|
|
436
|
+
*
|
|
437
|
+
* @example
|
|
438
|
+
* // Using tick filter function
|
|
439
|
+
* const result = getAxisTicksData({
|
|
440
|
+
* scaleFunction: numericScale,
|
|
441
|
+
* ticks: (value) => value % 2 === 0, // Only even numbers
|
|
442
|
+
* possibleTickValues: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
|
|
443
|
+
* });
|
|
444
|
+
* // Returns: [0, 2, 4, 6, 8, 10] with their positions
|
|
445
|
+
*
|
|
446
|
+
* @example
|
|
447
|
+
* // Band scale with categories (requestedTickCount and tickInterval are ignored)
|
|
448
|
+
* import { scaleBand } from 'd3-scale';
|
|
449
|
+
*
|
|
450
|
+
* const bandScale = scaleBand().domain([0, 1, 2, 3, 4]).range([0, 400]).padding(0.1);
|
|
451
|
+
* const result = getAxisTicksData({
|
|
452
|
+
* scaleFunction: bandScale,
|
|
453
|
+
* categories: ['Jan', 'Feb', 'Mar', 'Apr', 'May'],
|
|
454
|
+
* ticks: [0, 2, 4], // Show only Jan (index 0), Mar (index 2), May (index 4)
|
|
455
|
+
* requestedTickCount: 10, // IGNORED for band scales
|
|
456
|
+
* tickInterval: 50 // IGNORED for band scales
|
|
457
|
+
* });
|
|
458
|
+
* // Returns tick positions centered in each selected band
|
|
459
|
+
*/
|
|
460
|
+
export const getAxisTicksData = _ref4 => {
|
|
461
|
+
let {
|
|
462
|
+
ticks,
|
|
463
|
+
scaleFunction,
|
|
464
|
+
requestedTickCount,
|
|
465
|
+
categories = [],
|
|
466
|
+
possibleTickValues,
|
|
467
|
+
tickInterval,
|
|
468
|
+
options
|
|
469
|
+
} = _ref4;
|
|
470
|
+
// Handle band scales
|
|
471
|
+
if (isCategoricalScale(scaleFunction)) {
|
|
472
|
+
// If explicit ticks are provided as array, use them
|
|
473
|
+
if (Array.isArray(ticks)) {
|
|
474
|
+
return ticks.filter(index => index >= 0 && index < categories.length).map(index => {
|
|
475
|
+
var _bandwidth, _bandwidth2, _ref5;
|
|
476
|
+
// Band scales expect numeric indices, not category strings
|
|
477
|
+
const position = scaleFunction(index);
|
|
478
|
+
if (position === undefined) return null;
|
|
479
|
+
return {
|
|
480
|
+
tick: index,
|
|
481
|
+
position: position + ((_bandwidth = (_bandwidth2 = (_ref5 = scaleFunction).bandwidth) === null || _bandwidth2 === void 0 ? void 0 : _bandwidth2.call(_ref5)) !== null && _bandwidth !== void 0 ? _bandwidth : 0) / 2
|
|
482
|
+
};
|
|
483
|
+
}).filter(Boolean);
|
|
484
|
+
}
|
|
485
|
+
|
|
486
|
+
// If a tick function is provided, use it to filter
|
|
487
|
+
if (typeof ticks === 'function') {
|
|
488
|
+
return categories.map((category, index) => {
|
|
489
|
+
var _bandwidth3, _bandwidth4, _ref6;
|
|
490
|
+
if (!ticks(index)) return null;
|
|
491
|
+
|
|
492
|
+
// Band scales expect numeric indices, not category strings
|
|
493
|
+
const position = scaleFunction(index);
|
|
494
|
+
if (position === undefined) return null;
|
|
495
|
+
return {
|
|
496
|
+
tick: index,
|
|
497
|
+
position: position + ((_bandwidth3 = (_bandwidth4 = (_ref6 = scaleFunction).bandwidth) === null || _bandwidth4 === void 0 ? void 0 : _bandwidth4.call(_ref6)) !== null && _bandwidth3 !== void 0 ? _bandwidth3 : 0) / 2
|
|
498
|
+
};
|
|
499
|
+
}).filter(Boolean);
|
|
500
|
+
}
|
|
501
|
+
if (typeof ticks === 'boolean' && !ticks) {
|
|
502
|
+
return [];
|
|
503
|
+
}
|
|
504
|
+
|
|
505
|
+
// For band scales without explicit ticks, show all categories
|
|
506
|
+
// requestedTickCount is ignored for categorical scales - use ticks parameter to control visibility
|
|
507
|
+
return categories.map((category, index) => {
|
|
508
|
+
var _bandwidth5, _bandwidth6, _ref7;
|
|
509
|
+
// Band scales expect numeric indices, not category strings
|
|
510
|
+
const position = scaleFunction(index);
|
|
511
|
+
if (position === undefined) return null;
|
|
512
|
+
return {
|
|
513
|
+
tick: index,
|
|
514
|
+
position: position + ((_bandwidth5 = (_bandwidth6 = (_ref7 = scaleFunction).bandwidth) === null || _bandwidth6 === void 0 ? void 0 : _bandwidth6.call(_ref7)) !== null && _bandwidth5 !== void 0 ? _bandwidth5 : 0) / 2
|
|
515
|
+
};
|
|
516
|
+
}).filter(Boolean);
|
|
517
|
+
}
|
|
518
|
+
|
|
519
|
+
// Handle numeric scales
|
|
520
|
+
if (!isNumericScale(scaleFunction)) {
|
|
521
|
+
console.warn('Scale does not support automatic tick generation');
|
|
522
|
+
return [];
|
|
523
|
+
}
|
|
524
|
+
const numericScale = scaleFunction;
|
|
525
|
+
let tickValues = [];
|
|
526
|
+
if (Array.isArray(ticks)) {
|
|
527
|
+
// Use exact tick values provided
|
|
528
|
+
tickValues = ticks;
|
|
529
|
+
} else if (typeof ticks === 'function') {
|
|
530
|
+
// Filter the possible tick values using the predicate function
|
|
531
|
+
if (possibleTickValues) {
|
|
532
|
+
tickValues = possibleTickValues.filter(ticks);
|
|
533
|
+
} else {
|
|
534
|
+
// Fallback to scale-generated ticks if no possible tick values provided
|
|
535
|
+
const generatedTicks = numericScale.ticks(requestedTickCount);
|
|
536
|
+
tickValues = generatedTicks.filter(ticks);
|
|
537
|
+
}
|
|
538
|
+
} else if (requestedTickCount !== undefined) {
|
|
539
|
+
// Use scale-generated ticks
|
|
540
|
+
tickValues = numericScale.ticks(requestedTickCount);
|
|
541
|
+
} else if (tickInterval !== undefined) {
|
|
542
|
+
tickValues = generateEvenlyDistributedTicks(numericScale, tickInterval, possibleTickValues, options);
|
|
543
|
+
}
|
|
544
|
+
|
|
545
|
+
// Map values to positions using the scale function
|
|
546
|
+
return tickValues.map(tick => ({
|
|
547
|
+
tick,
|
|
548
|
+
position: numericScale(tick)
|
|
549
|
+
}));
|
|
550
|
+
};
|
|
551
|
+
/**
|
|
552
|
+
* Calculates the total amount of padding needed to render a set of axes on the main drawing area of the chart.
|
|
553
|
+
* Returns the registed axes, an API for adding/removing axes as well as the total calculated padding that must be reserved in the drawing area.
|
|
554
|
+
*/
|
|
555
|
+
export const useTotalAxisPadding = () => {
|
|
556
|
+
const [renderedAxes, setRenderedAxes] = useState(new Map());
|
|
557
|
+
const registerAxis = useCallback((id, position, size) => {
|
|
558
|
+
setRenderedAxes(prev => {
|
|
559
|
+
const newMap = new Map(prev);
|
|
560
|
+
newMap.set(id, {
|
|
561
|
+
id,
|
|
562
|
+
position,
|
|
563
|
+
size
|
|
564
|
+
});
|
|
565
|
+
return newMap;
|
|
566
|
+
});
|
|
567
|
+
}, []);
|
|
568
|
+
const unregisterAxis = useCallback(id => {
|
|
569
|
+
setRenderedAxes(prev => {
|
|
570
|
+
const newMap = new Map(prev);
|
|
571
|
+
newMap.delete(id);
|
|
572
|
+
return newMap;
|
|
573
|
+
});
|
|
574
|
+
}, []);
|
|
575
|
+
const axisPadding = useMemo(() => {
|
|
576
|
+
const padding = {
|
|
577
|
+
top: 0,
|
|
578
|
+
right: 0,
|
|
579
|
+
bottom: 0,
|
|
580
|
+
left: 0
|
|
581
|
+
};
|
|
582
|
+
renderedAxes.forEach(axis => {
|
|
583
|
+
padding[axis.position] += axis.size;
|
|
584
|
+
});
|
|
585
|
+
return padding;
|
|
586
|
+
}, [renderedAxes]);
|
|
587
|
+
return {
|
|
588
|
+
renderedAxes,
|
|
589
|
+
axisPadding,
|
|
590
|
+
registerAxis,
|
|
591
|
+
unregisterAxis
|
|
592
|
+
};
|
|
593
|
+
};
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Calculates the size adjustment needed for bars when accounting for gaps between them.
|
|
3
|
+
* This function helps determine how much to reduce each bar's width to accommodate
|
|
4
|
+
* the specified gap size between multiple bars in a group.
|
|
5
|
+
*
|
|
6
|
+
* @param barCount - The number of bars in the group
|
|
7
|
+
* @param gapSize - The desired gap size between bars
|
|
8
|
+
* @returns The amount to reduce each bar's size by, or 0 if there's only one bar
|
|
9
|
+
*
|
|
10
|
+
* @example
|
|
11
|
+
* ```typescript
|
|
12
|
+
* // For 3 bars with 12px gaps, each bar should be reduced by 8px
|
|
13
|
+
* const adjustment = getBarSizeAdjustment(3, 12);
|
|
14
|
+
*
|
|
15
|
+
* // Single bar needs no adjustment
|
|
16
|
+
* const singleBarAdjustment = getBarSizeAdjustment(1, 10);
|
|
17
|
+
* ```
|
|
18
|
+
*/
|
|
19
|
+
export function getBarSizeAdjustment(barCount, gapSize) {
|
|
20
|
+
if (barCount <= 1) {
|
|
21
|
+
return 0;
|
|
22
|
+
}
|
|
23
|
+
return gapSize * (barCount - 1) / barCount;
|
|
24
|
+
}
|