@coinbase/cds-web-visualization 3.4.0-beta.2 → 3.4.0-beta.20
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 +115 -0
- package/dts/chart/CartesianChart.d.ts +56 -3
- package/dts/chart/CartesianChart.d.ts.map +1 -1
- package/dts/chart/ChartProvider.d.ts +3 -0
- package/dts/chart/ChartProvider.d.ts.map +1 -1
- package/dts/chart/Path.d.ts +64 -7
- package/dts/chart/Path.d.ts.map +1 -1
- package/dts/chart/PeriodSelector.d.ts +5 -15
- package/dts/chart/PeriodSelector.d.ts.map +1 -1
- package/dts/chart/area/Area.d.ts +50 -25
- package/dts/chart/area/Area.d.ts.map +1 -1
- package/dts/chart/area/AreaChart.d.ts +46 -6
- package/dts/chart/area/AreaChart.d.ts.map +1 -1
- package/dts/chart/area/DottedArea.d.ts +21 -44
- package/dts/chart/area/DottedArea.d.ts.map +1 -1
- package/dts/chart/area/GradientArea.d.ts +21 -12
- package/dts/chart/area/GradientArea.d.ts.map +1 -1
- package/dts/chart/area/SolidArea.d.ts +16 -1
- package/dts/chart/area/SolidArea.d.ts.map +1 -1
- package/dts/chart/axis/Axis.d.ts +109 -63
- package/dts/chart/axis/Axis.d.ts.map +1 -1
- package/dts/chart/axis/DefaultAxisTickLabel.d.ts +8 -0
- package/dts/chart/axis/DefaultAxisTickLabel.d.ts.map +1 -0
- package/dts/chart/axis/XAxis.d.ts +1 -1
- package/dts/chart/axis/XAxis.d.ts.map +1 -1
- package/dts/chart/axis/YAxis.d.ts +2 -2
- package/dts/chart/axis/YAxis.d.ts.map +1 -1
- package/dts/chart/axis/index.d.ts +1 -0
- package/dts/chart/axis/index.d.ts.map +1 -1
- package/dts/chart/bar/Bar.d.ts +50 -12
- package/dts/chart/bar/Bar.d.ts.map +1 -1
- package/dts/chart/bar/BarChart.d.ts +20 -8
- package/dts/chart/bar/BarChart.d.ts.map +1 -1
- package/dts/chart/bar/BarPlot.d.ts +3 -1
- package/dts/chart/bar/BarPlot.d.ts.map +1 -1
- package/dts/chart/bar/BarStack.d.ts +41 -46
- package/dts/chart/bar/BarStack.d.ts.map +1 -1
- package/dts/chart/bar/BarStackGroup.d.ts +2 -0
- package/dts/chart/bar/BarStackGroup.d.ts.map +1 -1
- package/dts/chart/bar/DefaultBar.d.ts.map +1 -1
- package/dts/chart/bar/DefaultBarStack.d.ts.map +1 -1
- package/dts/chart/gradient/Gradient.d.ts +35 -0
- package/dts/chart/gradient/Gradient.d.ts.map +1 -0
- package/dts/chart/gradient/index.d.ts +2 -0
- package/dts/chart/gradient/index.d.ts.map +1 -0
- package/dts/chart/index.d.ts +3 -1
- package/dts/chart/index.d.ts.map +1 -1
- package/dts/chart/legend/DefaultLegendEntry.d.ts +21 -0
- package/dts/chart/legend/DefaultLegendEntry.d.ts.map +1 -0
- package/dts/chart/legend/DefaultLegendShape.d.ts +7 -0
- package/dts/chart/legend/DefaultLegendShape.d.ts.map +1 -0
- package/dts/chart/legend/Legend.d.ts +169 -0
- package/dts/chart/legend/Legend.d.ts.map +1 -0
- package/dts/chart/legend/index.d.ts +4 -0
- package/dts/chart/legend/index.d.ts.map +1 -0
- package/dts/chart/line/DefaultReferenceLineLabel.d.ts +9 -0
- package/dts/chart/line/DefaultReferenceLineLabel.d.ts.map +1 -0
- package/dts/chart/line/DottedLine.d.ts +15 -3
- package/dts/chart/line/DottedLine.d.ts.map +1 -1
- package/dts/chart/line/Line.d.ts +84 -28
- package/dts/chart/line/Line.d.ts.map +1 -1
- package/dts/chart/line/LineChart.d.ts +28 -8
- package/dts/chart/line/LineChart.d.ts.map +1 -1
- package/dts/chart/line/ReferenceLine.d.ts +91 -44
- package/dts/chart/line/ReferenceLine.d.ts.map +1 -1
- package/dts/chart/line/SolidLine.d.ts +14 -3
- package/dts/chart/line/SolidLine.d.ts.map +1 -1
- package/dts/chart/line/index.d.ts +1 -1
- package/dts/chart/line/index.d.ts.map +1 -1
- package/dts/chart/point/DefaultPointLabel.d.ts +10 -0
- package/dts/chart/point/DefaultPointLabel.d.ts.map +1 -0
- package/dts/chart/point/Point.d.ts +217 -0
- package/dts/chart/point/Point.d.ts.map +1 -0
- package/dts/chart/point/index.d.ts +3 -0
- package/dts/chart/point/index.d.ts.map +1 -0
- package/dts/chart/scrubber/DefaultScrubberBeacon.d.ts +41 -0
- package/dts/chart/scrubber/DefaultScrubberBeacon.d.ts.map +1 -0
- package/dts/chart/scrubber/DefaultScrubberBeaconLabel.d.ts +12 -0
- package/dts/chart/scrubber/DefaultScrubberBeaconLabel.d.ts.map +1 -0
- package/dts/chart/scrubber/DefaultScrubberLabel.d.ts +10 -0
- package/dts/chart/scrubber/DefaultScrubberLabel.d.ts.map +1 -0
- package/dts/chart/scrubber/Scrubber.d.ts +287 -70
- package/dts/chart/scrubber/Scrubber.d.ts.map +1 -1
- package/dts/chart/scrubber/ScrubberBeaconGroup.d.ts +80 -0
- package/dts/chart/scrubber/ScrubberBeaconGroup.d.ts.map +1 -0
- package/dts/chart/scrubber/ScrubberBeaconLabelGroup.d.ts +47 -0
- package/dts/chart/scrubber/ScrubberBeaconLabelGroup.d.ts.map +1 -0
- package/dts/chart/scrubber/index.d.ts +3 -0
- package/dts/chart/scrubber/index.d.ts.map +1 -1
- package/dts/chart/text/ChartText.d.ts +46 -43
- package/dts/chart/text/ChartText.d.ts.map +1 -1
- package/dts/chart/text/{SmartChartTextGroup.d.ts → ChartTextGroup.d.ts} +9 -3
- package/dts/chart/text/ChartTextGroup.d.ts.map +1 -0
- package/dts/chart/text/index.d.ts +1 -1
- package/dts/chart/text/index.d.ts.map +1 -1
- package/dts/chart/utils/axis.d.ts +25 -1
- package/dts/chart/utils/axis.d.ts.map +1 -1
- package/dts/chart/utils/bar.d.ts +34 -0
- package/dts/chart/utils/bar.d.ts.map +1 -1
- package/dts/chart/utils/chart.d.ts +45 -7
- package/dts/chart/utils/chart.d.ts.map +1 -1
- package/dts/chart/utils/context.d.ts +6 -0
- package/dts/chart/utils/context.d.ts.map +1 -1
- package/dts/chart/utils/gradient.d.ts +104 -0
- package/dts/chart/utils/gradient.d.ts.map +1 -0
- package/dts/chart/utils/index.d.ts +4 -0
- package/dts/chart/utils/index.d.ts.map +1 -1
- package/dts/chart/utils/interpolate.d.ts +112 -0
- package/dts/chart/utils/interpolate.d.ts.map +1 -0
- package/dts/chart/utils/path.d.ts +30 -1
- package/dts/chart/utils/path.d.ts.map +1 -1
- package/dts/chart/utils/point.d.ts +40 -7
- package/dts/chart/utils/point.d.ts.map +1 -1
- package/dts/chart/utils/scale.d.ts +11 -0
- package/dts/chart/utils/scale.d.ts.map +1 -1
- package/dts/chart/utils/scrubber.d.ts +40 -0
- package/dts/chart/utils/scrubber.d.ts.map +1 -0
- package/dts/chart/utils/transition.d.ts +101 -0
- package/dts/chart/utils/transition.d.ts.map +1 -0
- package/dts/sparkline/sparkline-interactive/SparklineInteractiveMarkerDates.d.ts.map +1 -1
- package/esm/chart/CartesianChart.js +170 -83
- package/esm/chart/ChartProvider.js +2 -2
- package/esm/chart/Path.js +59 -54
- package/esm/chart/PeriodSelector.js +36 -32
- package/esm/chart/area/Area.js +26 -34
- package/esm/chart/area/AreaChart.js +29 -15
- package/esm/chart/area/DottedArea.js +39 -89
- package/esm/chart/area/GradientArea.js +37 -80
- package/esm/chart/area/SolidArea.js +32 -11
- package/esm/chart/axis/Axis.js +4 -39
- package/esm/chart/axis/DefaultAxisTickLabel.js +15 -0
- package/esm/chart/axis/XAxis.js +184 -63
- package/esm/chart/axis/YAxis.js +190 -57
- package/esm/chart/axis/index.js +1 -0
- package/esm/chart/bar/Bar.js +7 -1
- package/esm/chart/bar/BarChart.js +17 -32
- package/esm/chart/bar/BarPlot.js +5 -2
- package/esm/chart/bar/BarStack.js +74 -22
- package/esm/chart/bar/BarStackGroup.js +8 -18
- package/esm/chart/bar/DefaultBar.js +23 -28
- package/esm/chart/bar/DefaultBarStack.js +24 -20
- package/esm/chart/gradient/Gradient.js +104 -0
- package/esm/chart/gradient/index.js +1 -0
- package/esm/chart/index.js +3 -1
- package/esm/chart/legend/DefaultLegendEntry.css +1 -0
- package/esm/chart/legend/DefaultLegendEntry.js +50 -0
- package/esm/chart/legend/DefaultLegendShape.css +5 -0
- package/esm/chart/legend/DefaultLegendShape.js +47 -0
- package/esm/chart/legend/Legend.js +76 -0
- package/esm/chart/legend/index.js +3 -0
- package/esm/chart/line/DefaultReferenceLineLabel.js +81 -0
- package/esm/chart/line/DottedLine.js +41 -17
- package/esm/chart/line/Line.js +87 -75
- package/esm/chart/line/LineChart.js +24 -8
- package/esm/chart/line/ReferenceLine.js +41 -43
- package/esm/chart/line/SolidLine.js +39 -15
- package/esm/chart/line/index.js +1 -1
- package/esm/chart/{line/GradientLine.js → point/DefaultPointLabel.js} +31 -45
- package/esm/chart/point/Point.css +2 -0
- package/esm/chart/{Point.js → point/Point.js} +87 -62
- package/esm/chart/point/index.js +2 -0
- package/esm/chart/scrubber/DefaultScrubberBeacon.js +154 -0
- package/esm/chart/scrubber/DefaultScrubberBeaconLabel.js +57 -0
- package/esm/chart/scrubber/{ScrubberBeaconLabel.js → DefaultScrubberLabel.js} +15 -18
- package/esm/chart/scrubber/Scrubber.js +97 -392
- package/esm/chart/scrubber/ScrubberBeaconGroup.js +174 -0
- package/esm/chart/scrubber/ScrubberBeaconLabelGroup.js +201 -0
- package/esm/chart/scrubber/index.js +3 -1
- package/esm/chart/text/ChartText.js +15 -20
- package/esm/chart/text/{SmartChartTextGroup.js → ChartTextGroup.js} +4 -3
- package/esm/chart/text/index.js +1 -1
- package/esm/chart/utils/axis.js +47 -31
- package/esm/chart/utils/bar.js +48 -0
- package/esm/chart/utils/chart.js +42 -3
- package/esm/chart/utils/gradient.js +257 -0
- package/esm/chart/utils/index.js +4 -0
- package/esm/chart/utils/interpolate.js +644 -0
- package/esm/chart/utils/path.js +41 -9
- package/esm/chart/utils/point.js +99 -12
- package/esm/chart/utils/scale.js +13 -2
- package/esm/chart/utils/scrubber.js +137 -0
- package/esm/chart/utils/transition.js +133 -0
- package/esm/sparkline/__figma__/Sparkline.figma.js +1 -1
- package/esm/sparkline/sparkline-interactive/SparklineInteractiveMarkerDates.js +8 -4
- package/esm/sparkline/sparkline-interactive/__figma__/SparklineInteractive.figma.js +1 -1
- package/esm/sparkline/sparkline-interactive-header/__figma__/SparklineInteractiveHeader.figma.js +1 -1
- package/package.json +12 -11
- package/dts/chart/Point.d.ts +0 -153
- package/dts/chart/Point.d.ts.map +0 -1
- package/dts/chart/line/GradientLine.d.ts +0 -42
- package/dts/chart/line/GradientLine.d.ts.map +0 -1
- package/dts/chart/scrubber/ScrubberBeacon.d.ts +0 -93
- package/dts/chart/scrubber/ScrubberBeacon.d.ts.map +0 -1
- package/dts/chart/scrubber/ScrubberBeaconLabel.d.ts +0 -7
- package/dts/chart/scrubber/ScrubberBeaconLabel.d.ts.map +0 -1
- package/dts/chart/text/SmartChartTextGroup.d.ts.map +0 -1
- package/esm/chart/Point.css +0 -2
- package/esm/chart/scrubber/ScrubberBeacon.js +0 -195
package/esm/chart/utils/bar.js
CHANGED
|
@@ -1,3 +1,51 @@
|
|
|
1
|
+
const _excluded = ["staggerDelay"];
|
|
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 { defaultTransition } from './transition';
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* A bar-specific transition that extends Transition with stagger support.
|
|
13
|
+
* When `staggerDelay` is provided, bars will animate with increasing delays
|
|
14
|
+
* based on their horizontal position (leftmost starts first, rightmost last).
|
|
15
|
+
*
|
|
16
|
+
* @example
|
|
17
|
+
* // Bars stagger in from left to right over 0.25s, each animating for 0.75s
|
|
18
|
+
* { type: 'tween', duration: 0.75, staggerDelay: 0.25 }
|
|
19
|
+
*/
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Strips `staggerDelay` from a transition and computes a positional delay.
|
|
23
|
+
*
|
|
24
|
+
* @param transition - The transition config (may include staggerDelay)
|
|
25
|
+
* @param normalizedX - The bar's normalized x position (0 = left edge, 1 = right edge)
|
|
26
|
+
* @returns A standard Transition with computed delay
|
|
27
|
+
*/
|
|
28
|
+
export const withStaggerDelayTransition = (transition, normalizedX) => {
|
|
29
|
+
var _baseTransition$delay;
|
|
30
|
+
const {
|
|
31
|
+
staggerDelay
|
|
32
|
+
} = transition,
|
|
33
|
+
baseTransition = _objectWithoutProperties(transition, _excluded);
|
|
34
|
+
if (!staggerDelay) return transition;
|
|
35
|
+
return _objectSpread(_objectSpread({}, baseTransition), {}, {
|
|
36
|
+
delay: ((_baseTransition$delay = baseTransition === null || baseTransition === void 0 ? void 0 : baseTransition.delay) !== null && _baseTransition$delay !== void 0 ? _baseTransition$delay : 0) + normalizedX * staggerDelay
|
|
37
|
+
});
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Default bar enter transition. Uses the default spring with a stagger delay
|
|
42
|
+
* so bars spring into place from left to right.
|
|
43
|
+
* `{ type: 'spring', stiffness: 900, damping: 120, mass: 4, staggerDelay: 0.25 }`
|
|
44
|
+
*/
|
|
45
|
+
export const defaultBarEnterTransition = _objectSpread(_objectSpread({}, defaultTransition), {}, {
|
|
46
|
+
staggerDelay: 0.25
|
|
47
|
+
});
|
|
48
|
+
|
|
1
49
|
/**
|
|
2
50
|
* Calculates the size adjustment needed for bars when accounting for gaps between them.
|
|
3
51
|
* This function helps determine how much to reduce each bar's width to accommodate
|
package/esm/chart/utils/chart.js
CHANGED
|
@@ -1,5 +1,18 @@
|
|
|
1
1
|
import { stack as d3Stack, stackOffsetDiverging, stackOrderNone } from 'd3-shape';
|
|
2
2
|
export const defaultStackId = 'DEFAULT_STACK_ID';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Shape variants available for legend items.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Shape for legend items. Can be a preset variant or a custom ReactNode.
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Position of the legend relative to the chart.
|
|
14
|
+
*/
|
|
15
|
+
|
|
3
16
|
/**
|
|
4
17
|
* Type guard to check if bounds are complete with both min and max values.
|
|
5
18
|
* @param bounds - The bounds to validate
|
|
@@ -19,13 +32,13 @@ export const getChartDomain = (series, min, max) => {
|
|
|
19
32
|
return domain;
|
|
20
33
|
}
|
|
21
34
|
if (series.length > 0) {
|
|
22
|
-
const
|
|
35
|
+
const dataLength = Math.max(...series.map(s => {
|
|
23
36
|
var _s$data;
|
|
24
37
|
return ((_s$data = s.data) === null || _s$data === void 0 ? void 0 : _s$data.length) || 0;
|
|
25
38
|
}));
|
|
26
|
-
if (
|
|
39
|
+
if (dataLength > 0) {
|
|
27
40
|
if (domain.min === undefined) domain.min = 0;
|
|
28
|
-
if (domain.max === undefined) domain.max =
|
|
41
|
+
if (domain.max === undefined) domain.max = dataLength - 1;
|
|
29
42
|
}
|
|
30
43
|
}
|
|
31
44
|
return domain;
|
|
@@ -111,6 +124,32 @@ export const getStackedSeriesData = series => {
|
|
|
111
124
|
return stackedDataMap;
|
|
112
125
|
};
|
|
113
126
|
|
|
127
|
+
/**
|
|
128
|
+
* Extracts line data values from series data that may contain tuples.
|
|
129
|
+
* For tuple data [[baseline, value]], extracts the last value.
|
|
130
|
+
* For numeric data [value], returns as-is.
|
|
131
|
+
*
|
|
132
|
+
* @param data - Array of numbers, tuples, or null values
|
|
133
|
+
* @returns Array of numbers or null values
|
|
134
|
+
*/
|
|
135
|
+
export const getLineData = data => {
|
|
136
|
+
if (!data) return [];
|
|
137
|
+
|
|
138
|
+
// Check if this is tuple data by finding first non-null entry
|
|
139
|
+
const firstNonNull = data.find(d => d !== null);
|
|
140
|
+
if (Array.isArray(firstNonNull)) {
|
|
141
|
+
return data.map(d => {
|
|
142
|
+
var _d$at;
|
|
143
|
+
if (d === null) return null;
|
|
144
|
+
if (Array.isArray(d)) return (_d$at = d.at(-1)) !== null && _d$at !== void 0 ? _d$at : null;
|
|
145
|
+
return d;
|
|
146
|
+
});
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
// Already numeric data
|
|
150
|
+
return data;
|
|
151
|
+
};
|
|
152
|
+
|
|
114
153
|
/**
|
|
115
154
|
* Calculates the range of a chart from series data.
|
|
116
155
|
* Range represents the range of y-values from the data.
|
|
@@ -0,0 +1,257 @@
|
|
|
1
|
+
import { isCategoricalScale } from './scale';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Defines a color transition point in the gradient
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Defines a gradient.
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Resolves gradient stops, handling both static arrays and function forms.
|
|
13
|
+
* When stops is a function, calls it with the domain bounds.
|
|
14
|
+
*/
|
|
15
|
+
const getGradientStops = (stops, domain) => {
|
|
16
|
+
if (typeof stops === 'function') {
|
|
17
|
+
return stops(domain);
|
|
18
|
+
}
|
|
19
|
+
return stops;
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Processes Gradient to gradient configuration for SVG linearGradient.
|
|
24
|
+
* Colors are smoothly interpolated between stops by the browser.
|
|
25
|
+
* Multiple stops at the same offset create hard color transitions.
|
|
26
|
+
*/
|
|
27
|
+
const processGradientStops = (stops, scale) => {
|
|
28
|
+
if (stops.length === 0) {
|
|
29
|
+
console.warn('Gradient has no stops - falling back to default');
|
|
30
|
+
return;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
// Check if stops are in ascending order
|
|
34
|
+
const isOutOfOrder = stops.some((stop, i) => {
|
|
35
|
+
return i > 0 && stop.offset < stops[i - 1].offset;
|
|
36
|
+
});
|
|
37
|
+
if (isOutOfOrder) {
|
|
38
|
+
console.warn("Gradient: stop offsets must be in ascending order");
|
|
39
|
+
return;
|
|
40
|
+
}
|
|
41
|
+
const [rangeMin, rangeMax] = scale.range();
|
|
42
|
+
const rangeSpan = Math.abs(rangeMax - rangeMin);
|
|
43
|
+
|
|
44
|
+
// Convert data value offsets to normalized positions (0-1) using scale
|
|
45
|
+
const normalizedStops = stops.map(stop => {
|
|
46
|
+
var _stop$opacity;
|
|
47
|
+
const stopPosition = scale(stop.offset);
|
|
48
|
+
const normalized = stopPosition === undefined ? 0 : Math.max(0, Math.min(1, Math.abs(stopPosition - rangeMin) / rangeSpan));
|
|
49
|
+
return {
|
|
50
|
+
offset: normalized,
|
|
51
|
+
// Now 0-1 normalized (not data space)
|
|
52
|
+
color: stop.color,
|
|
53
|
+
opacity: (_stop$opacity = stop.opacity) !== null && _stop$opacity !== void 0 ? _stop$opacity : 1
|
|
54
|
+
};
|
|
55
|
+
}).sort((a, b) => a.offset - b.offset);
|
|
56
|
+
return normalizedStops;
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Evaluates the color at a specific data value based on the gradient stops, ignoring opacity.
|
|
61
|
+
* @param stops - The gradient stops configuration
|
|
62
|
+
* @param dataValue - The data value to evaluate (for band scales, this is the index)
|
|
63
|
+
* @param scale - The scale to use for value mapping (handles log scales correctly)
|
|
64
|
+
* @returns The color string at this data value, or undefined if invalid
|
|
65
|
+
*/
|
|
66
|
+
export const evaluateGradientAtValue = (stops, dataValue, scale) => {
|
|
67
|
+
if (stops.length === 0) return;
|
|
68
|
+
|
|
69
|
+
// Use srgb color space to match our linearGradient which uses srgb color space
|
|
70
|
+
// https://www.w3.org/TR/SVG11/painting.html#ColorInterpolationProperty
|
|
71
|
+
const colorSpace = 'srgb';
|
|
72
|
+
|
|
73
|
+
// Use scale to map values to positions (handles log scales correctly)
|
|
74
|
+
// For numeric scales: scale(value) returns pixel position
|
|
75
|
+
// We normalize these positions to 0-1 based on the range
|
|
76
|
+
const scaleRange = scale.range();
|
|
77
|
+
const [rangeMin, rangeMax] = Array.isArray(scaleRange) ? scaleRange : [scaleRange, scaleRange]; // fallback for band scales
|
|
78
|
+
|
|
79
|
+
const rangeSpan = Math.abs(rangeMax - rangeMin);
|
|
80
|
+
if (rangeSpan === 0) return stops[0].color;
|
|
81
|
+
|
|
82
|
+
// Map dataValue through scale to get position
|
|
83
|
+
const dataPosition = scale(dataValue);
|
|
84
|
+
if (dataPosition === undefined) return stops[0].color;
|
|
85
|
+
|
|
86
|
+
// Normalize to 0-1 based on range
|
|
87
|
+
const normalizedValue = Math.max(0, Math.min(1, Math.abs(dataPosition - rangeMin) / rangeSpan));
|
|
88
|
+
|
|
89
|
+
// stops already have normalized offsets (0-1), use them directly
|
|
90
|
+
const positions = stops.map(stop => stop.offset);
|
|
91
|
+
|
|
92
|
+
// Find which segment we're in
|
|
93
|
+
if (normalizedValue < positions[0]) {
|
|
94
|
+
return stops[0].color;
|
|
95
|
+
}
|
|
96
|
+
if (normalizedValue >= positions[positions.length - 1]) {
|
|
97
|
+
return stops[stops.length - 1].color;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
// Check if normalizedValue matches any stop offset exactly (for hard transitions)
|
|
101
|
+
for (let i = 0; i < stops.length; i++) {
|
|
102
|
+
if (Math.abs(normalizedValue - stops[i].offset) < 1e-10) {
|
|
103
|
+
// Found exact match - check if there are multiple stops at this offset (hard transition)
|
|
104
|
+
// Use the LAST color at this offset for hard transitions
|
|
105
|
+
let lastIndexAtOffset = i;
|
|
106
|
+
while (lastIndexAtOffset + 1 < stops.length && Math.abs(stops[lastIndexAtOffset + 1].offset - stops[i].offset) < 1e-10) {
|
|
107
|
+
lastIndexAtOffset++;
|
|
108
|
+
}
|
|
109
|
+
return stops[lastIndexAtOffset].color;
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
// Find the two colors to mix based on normalized positions
|
|
114
|
+
for (let i = 0; i < positions.length - 1; i++) {
|
|
115
|
+
const start = positions[i];
|
|
116
|
+
const end = positions[i + 1];
|
|
117
|
+
if (normalizedValue >= start && normalizedValue <= end) {
|
|
118
|
+
const segmentProgress = (normalizedValue - start) / (end - start);
|
|
119
|
+
return "color-mix(in ".concat(colorSpace, ", ").concat(stops[i + 1].color, " ").concat(segmentProgress * 100, "%, ").concat(stops[i].color, ")");
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
// If we didn't reach any to be mixed, return the last color
|
|
124
|
+
return stops[stops.length - 1].color;
|
|
125
|
+
};
|
|
126
|
+
|
|
127
|
+
/**
|
|
128
|
+
* Creates a gradient configuration for SVG components.
|
|
129
|
+
* Processes a GradientDefinition into a renderable GradientConfig.
|
|
130
|
+
* Supports both numeric scales (linear, log) and categorical scales (band).
|
|
131
|
+
*
|
|
132
|
+
* @param gradient - GradientDefinition configuration (required)
|
|
133
|
+
* @param xScale - X-axis scale (required)
|
|
134
|
+
* @param yScale - Y-axis scale (required)
|
|
135
|
+
* @returns GradientConfig or null if gradient processing fails
|
|
136
|
+
*
|
|
137
|
+
* @example
|
|
138
|
+
* const gradientConfig = useMemo(() => {
|
|
139
|
+
* if (!gradient || !xScale || !yScale) return;
|
|
140
|
+
* return getGradientConfig(gradient, xScale, yScale);
|
|
141
|
+
* }, [gradient, xScale, yScale]);
|
|
142
|
+
*
|
|
143
|
+
* if (gradientConfig) {
|
|
144
|
+
* return (
|
|
145
|
+
* <defs>
|
|
146
|
+
* <Gradient
|
|
147
|
+
* config={gradientConfig}
|
|
148
|
+
* direction={gradient.axis === 'x' ? 'horizontal' : 'vertical'}
|
|
149
|
+
* id={gradientId}
|
|
150
|
+
* />
|
|
151
|
+
* </defs>
|
|
152
|
+
* );
|
|
153
|
+
* }
|
|
154
|
+
*/
|
|
155
|
+
export const getGradientConfig = (gradient, xScale, yScale) => {
|
|
156
|
+
if (!gradient) return;
|
|
157
|
+
|
|
158
|
+
// Get the scale based on axis
|
|
159
|
+
const scale = gradient.axis === 'x' ? xScale : yScale;
|
|
160
|
+
if (!scale) return;
|
|
161
|
+
|
|
162
|
+
// Extract domain from scale
|
|
163
|
+
const scaleDomain = scale.domain();
|
|
164
|
+
let domain;
|
|
165
|
+
if (isCategoricalScale(scale)) {
|
|
166
|
+
const domainArray = scaleDomain;
|
|
167
|
+
domain = {
|
|
168
|
+
min: domainArray[0],
|
|
169
|
+
max: domainArray[domainArray.length - 1]
|
|
170
|
+
};
|
|
171
|
+
} else {
|
|
172
|
+
const [min, max] = scaleDomain;
|
|
173
|
+
domain = {
|
|
174
|
+
min,
|
|
175
|
+
max
|
|
176
|
+
};
|
|
177
|
+
}
|
|
178
|
+
const resolvedStops = getGradientStops(gradient.stops, domain);
|
|
179
|
+
return processGradientStops(resolvedStops, scale);
|
|
180
|
+
};
|
|
181
|
+
|
|
182
|
+
/**
|
|
183
|
+
* Determines the baseline value for the gradient area by finding the value
|
|
184
|
+
* within the axis bounds that is closest to the target baseline.
|
|
185
|
+
*
|
|
186
|
+
* @param axisBounds - The min and max bounds of the axis
|
|
187
|
+
* @param baseline - The target baseline value (defaults to 0)
|
|
188
|
+
* @returns The value within bounds closest to the baseline
|
|
189
|
+
*/
|
|
190
|
+
export const getBaseline = function (axisBounds) {
|
|
191
|
+
let baseline = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 0;
|
|
192
|
+
const {
|
|
193
|
+
min,
|
|
194
|
+
max
|
|
195
|
+
} = axisBounds;
|
|
196
|
+
|
|
197
|
+
// Normalize to ensure lowerBound <= upperBound
|
|
198
|
+
const lowerBound = Math.min(min, max);
|
|
199
|
+
const upperBound = Math.max(min, max);
|
|
200
|
+
|
|
201
|
+
// If baseline is within the range, use it
|
|
202
|
+
if (lowerBound <= baseline && baseline <= upperBound) return baseline;
|
|
203
|
+
|
|
204
|
+
// Otherwise, return the bound closest to baseline
|
|
205
|
+
return Math.abs(lowerBound - baseline) < Math.abs(upperBound - baseline) ? lowerBound : upperBound;
|
|
206
|
+
};
|
|
207
|
+
|
|
208
|
+
/**
|
|
209
|
+
* Generates a gradient definition for the area chart based on the axis bounds
|
|
210
|
+
* and styling parameters. Ensures gradient stops are in ascending order.
|
|
211
|
+
*
|
|
212
|
+
* @param axisBounds - The min and max bounds of the axis
|
|
213
|
+
* @param baselineValue - The baseline value for the gradient
|
|
214
|
+
* @param fill - The color to use for the gradient
|
|
215
|
+
* @param peakOpacity - Opacity at the peak of the gradient
|
|
216
|
+
* @param baselineOpacity - Opacity at the baseline
|
|
217
|
+
* @returns A gradient definition with y-axis stops in ascending order
|
|
218
|
+
*/
|
|
219
|
+
export const createGradient = (axisBounds, baselineValue, fill, peakOpacity, baselineOpacity) => {
|
|
220
|
+
const {
|
|
221
|
+
min,
|
|
222
|
+
max
|
|
223
|
+
} = axisBounds;
|
|
224
|
+
const lowerBound = Math.min(min, max);
|
|
225
|
+
const upperBound = Math.max(min, max);
|
|
226
|
+
if (lowerBound < baselineValue && baselineValue < upperBound) {
|
|
227
|
+
return {
|
|
228
|
+
axis: 'y',
|
|
229
|
+
stops: [{
|
|
230
|
+
offset: lowerBound,
|
|
231
|
+
color: fill,
|
|
232
|
+
opacity: peakOpacity
|
|
233
|
+
}, {
|
|
234
|
+
offset: baselineValue,
|
|
235
|
+
color: fill,
|
|
236
|
+
opacity: baselineOpacity
|
|
237
|
+
}, {
|
|
238
|
+
offset: upperBound,
|
|
239
|
+
color: fill,
|
|
240
|
+
opacity: peakOpacity
|
|
241
|
+
}]
|
|
242
|
+
};
|
|
243
|
+
}
|
|
244
|
+
const peakValue = Math.abs(min - baselineValue) > Math.abs(max - baselineValue) ? min : max;
|
|
245
|
+
return {
|
|
246
|
+
axis: 'y',
|
|
247
|
+
stops: [{
|
|
248
|
+
offset: peakValue,
|
|
249
|
+
color: fill,
|
|
250
|
+
opacity: peakOpacity
|
|
251
|
+
}, {
|
|
252
|
+
offset: baselineValue,
|
|
253
|
+
color: fill,
|
|
254
|
+
opacity: baselineOpacity
|
|
255
|
+
}].sort((a, b) => a.offset - b.offset)
|
|
256
|
+
};
|
|
257
|
+
};
|
package/esm/chart/utils/index.js
CHANGED
|
@@ -3,7 +3,11 @@ export * from './axis';
|
|
|
3
3
|
export * from './bar';
|
|
4
4
|
export * from './chart';
|
|
5
5
|
export * from './context';
|
|
6
|
+
export * from './gradient';
|
|
7
|
+
export * from './interpolate';
|
|
6
8
|
export * from './path';
|
|
7
9
|
export * from './point';
|
|
8
10
|
export * from './scale';
|
|
11
|
+
export * from './scrubber';
|
|
12
|
+
export * from './transition';
|
|
9
13
|
// codegen:end
|