@coinbase/cds-web-visualization 3.4.0-beta.23 → 3.4.0-beta.25
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 +14 -0
- package/dts/chart/Path.d.ts +4 -2
- package/dts/chart/Path.d.ts.map +1 -1
- package/dts/chart/PeriodSelector.d.ts +1 -1
- package/dts/chart/bar/Bar.d.ts +18 -54
- package/dts/chart/bar/Bar.d.ts.map +1 -1
- package/dts/chart/bar/BarPlot.d.ts.map +1 -1
- package/dts/chart/bar/BarStack.d.ts +4 -4
- package/dts/chart/bar/BarStack.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/point/Point.d.ts +2 -1
- package/dts/chart/point/Point.d.ts.map +1 -1
- package/dts/chart/scrubber/Scrubber.d.ts +4 -2
- package/dts/chart/scrubber/Scrubber.d.ts.map +1 -1
- package/dts/chart/utils/bar.d.ts +153 -0
- package/dts/chart/utils/bar.d.ts.map +1 -1
- package/dts/chart/utils/chart.d.ts +2 -1
- package/dts/chart/utils/chart.d.ts.map +1 -1
- package/dts/chart/utils/path.d.ts.map +1 -1
- package/dts/sparkline/Sparkline.d.ts +2 -1
- package/dts/sparkline/Sparkline.d.ts.map +1 -1
- package/dts/sparkline/SparklineArea.d.ts +2 -1
- package/dts/sparkline/SparklineArea.d.ts.map +1 -1
- package/dts/sparkline/SparklineGradient.d.ts +2 -1
- package/dts/sparkline/SparklineGradient.d.ts.map +1 -1
- package/dts/sparkline/sparkline-interactive/SparklineInteractive.d.ts +2 -1
- package/dts/sparkline/sparkline-interactive/SparklineInteractive.d.ts.map +1 -1
- package/esm/chart/Path.js +2 -1
- package/esm/chart/bar/Bar.js +4 -6
- package/esm/chart/bar/BarChart.js +7 -7
- package/esm/chart/bar/BarPlot.js +17 -27
- package/esm/chart/bar/BarStack.js +90 -295
- package/esm/chart/bar/DefaultBar.js +13 -19
- package/esm/chart/bar/DefaultBarStack.js +12 -19
- package/esm/chart/utils/bar.js +813 -0
- package/esm/chart/utils/chart.js +2 -1
- package/esm/chart/utils/path.js +5 -13
- package/esm/sparkline/Sparkline.js +2 -1
- package/esm/sparkline/SparklineArea.js +2 -1
- package/esm/sparkline/SparklineGradient.js +2 -1
- package/esm/sparkline/sparkline-interactive/SparklineInteractive.js +2 -1
- package/package.json +5 -5
package/esm/chart/bar/Bar.js
CHANGED
|
@@ -33,6 +33,7 @@ export const Bar = /*#__PURE__*/memo(_ref => {
|
|
|
33
33
|
borderRadius = 4,
|
|
34
34
|
roundTop = true,
|
|
35
35
|
roundBottom = true,
|
|
36
|
+
minSize,
|
|
36
37
|
transitions,
|
|
37
38
|
transition
|
|
38
39
|
} = _ref;
|
|
@@ -42,12 +43,8 @@ export const Bar = /*#__PURE__*/memo(_ref => {
|
|
|
42
43
|
const barPath = useMemo(() => {
|
|
43
44
|
return getBarPath(x, y, width, height, borderRadius, !!roundTop, !!roundBottom, layout);
|
|
44
45
|
}, [x, y, width, height, borderRadius, roundTop, roundBottom, layout]);
|
|
45
|
-
const origin = useMemo(() =>
|
|
46
|
-
|
|
47
|
-
}, [originProp, layout, x, y, height]);
|
|
48
|
-
if (!barPath) {
|
|
49
|
-
return null;
|
|
50
|
-
}
|
|
46
|
+
const origin = useMemo(() => originProp !== null && originProp !== void 0 ? originProp : layout === 'horizontal' ? x : y + height, [originProp, layout, x, y, height]);
|
|
47
|
+
if (!barPath) return;
|
|
51
48
|
return /*#__PURE__*/_jsx(BarComponent, {
|
|
52
49
|
borderRadius: borderRadius,
|
|
53
50
|
d: barPath,
|
|
@@ -56,6 +53,7 @@ export const Bar = /*#__PURE__*/memo(_ref => {
|
|
|
56
53
|
fill: fill,
|
|
57
54
|
fillOpacity: fillOpacity,
|
|
58
55
|
height: height,
|
|
56
|
+
minSize: minSize,
|
|
59
57
|
origin: origin,
|
|
60
58
|
roundBottom: roundBottom,
|
|
61
59
|
roundTop: roundTop,
|
|
@@ -49,9 +49,9 @@ export const BarChart = /*#__PURE__*/memo(/*#__PURE__*/forwardRef((_ref, ref) =>
|
|
|
49
49
|
});
|
|
50
50
|
}, [seriesProp, stacked]);
|
|
51
51
|
const seriesIds = useMemo(() => series === null || series === void 0 ? void 0 : series.map(s => s.id), [series]);
|
|
52
|
-
const
|
|
53
|
-
const defaultXScaleType =
|
|
54
|
-
const defaultYScaleType =
|
|
52
|
+
const isHorizontalLayout = chartProps.layout === 'horizontal';
|
|
53
|
+
const defaultXScaleType = isHorizontalLayout ? 'linear' : 'band';
|
|
54
|
+
const defaultYScaleType = isHorizontalLayout ? 'band' : 'linear';
|
|
55
55
|
|
|
56
56
|
// Split axis props into config props for Chart and visual props for axis components
|
|
57
57
|
const _ref2 = xAxis || {},
|
|
@@ -87,24 +87,24 @@ export const BarChart = /*#__PURE__*/memo(/*#__PURE__*/forwardRef((_ref, ref) =>
|
|
|
87
87
|
scaleType: xScaleType !== null && xScaleType !== void 0 ? xScaleType : defaultXScaleType,
|
|
88
88
|
data: xData,
|
|
89
89
|
categoryPadding: xCategoryPadding,
|
|
90
|
-
domain:
|
|
90
|
+
domain: isHorizontalLayout && !hasNegativeValues ? _objectSpread({
|
|
91
91
|
min: 0
|
|
92
92
|
}, xDomain) : xDomain,
|
|
93
93
|
domainLimit: xDomainLimit,
|
|
94
94
|
range: xRange
|
|
95
|
-
}), [xScaleType,
|
|
95
|
+
}), [xScaleType, isHorizontalLayout, xData, xCategoryPadding, hasNegativeValues, xDomain, xDomainLimit, xRange, defaultXScaleType]);
|
|
96
96
|
|
|
97
97
|
// Set default min domain to 0 for bar chart, but only if there are no negative values
|
|
98
98
|
const yAxisConfig = useMemo(() => ({
|
|
99
99
|
scaleType: yScaleType !== null && yScaleType !== void 0 ? yScaleType : defaultYScaleType,
|
|
100
100
|
data: yData,
|
|
101
101
|
categoryPadding: yCategoryPadding,
|
|
102
|
-
domain: !
|
|
102
|
+
domain: !isHorizontalLayout && !hasNegativeValues ? _objectSpread({
|
|
103
103
|
min: 0
|
|
104
104
|
}, yDomain) : yDomain,
|
|
105
105
|
domainLimit: yDomainLimit,
|
|
106
106
|
range: yRange
|
|
107
|
-
}), [yScaleType,
|
|
107
|
+
}), [yScaleType, isHorizontalLayout, yData, yCategoryPadding, hasNegativeValues, yDomain, yDomainLimit, yRange, defaultYScaleType]);
|
|
108
108
|
return /*#__PURE__*/_jsxs(CartesianChart, _objectSpread(_objectSpread({}, chartProps), {}, {
|
|
109
109
|
ref: ref,
|
|
110
110
|
inset: inset,
|
package/esm/chart/bar/BarPlot.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { memo, useId, useMemo } from 'react';
|
|
2
|
+
import { m as motion } from 'framer-motion';
|
|
2
3
|
import { useCartesianChartContext } from '../ChartProvider';
|
|
3
|
-
import {
|
|
4
|
+
import { getStackGroups, instantTransition } from '../utils';
|
|
4
5
|
import { BarStackGroup } from './BarStackGroup';
|
|
5
6
|
import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
|
|
6
7
|
/**
|
|
@@ -10,6 +11,7 @@ import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-run
|
|
|
10
11
|
* cross-axis stacking (e.g., comparing $1M vs $1B companies on different scales).
|
|
11
12
|
*/
|
|
12
13
|
export const BarPlot = /*#__PURE__*/memo(_ref => {
|
|
14
|
+
var _transitions$update;
|
|
13
15
|
let {
|
|
14
16
|
seriesIds,
|
|
15
17
|
barPadding = 0.1,
|
|
@@ -27,6 +29,7 @@ export const BarPlot = /*#__PURE__*/memo(_ref => {
|
|
|
27
29
|
transition
|
|
28
30
|
} = _ref;
|
|
29
31
|
const {
|
|
32
|
+
animate,
|
|
30
33
|
series: allSeries,
|
|
31
34
|
drawingArea
|
|
32
35
|
} = useCartesianChartContext();
|
|
@@ -38,37 +41,24 @@ export const BarPlot = /*#__PURE__*/memo(_ref => {
|
|
|
38
41
|
}
|
|
39
42
|
return allSeries;
|
|
40
43
|
}, [allSeries, seriesIds]);
|
|
41
|
-
const stackGroups = useMemo(() =>
|
|
42
|
-
|
|
44
|
+
const stackGroups = useMemo(() => getStackGroups(targetSeries), [targetSeries]);
|
|
45
|
+
if (!drawingArea) return;
|
|
46
|
+
|
|
47
|
+
// Clip path animation for bar is just for chart size changes, not for
|
|
48
|
+
// enter transition. One caveat, bar update transitions are staggered
|
|
49
|
+
// but clip path is not, so some bars could be clipped in rare cases
|
|
43
50
|
|
|
44
|
-
// Group series into stacks based on stackId + axis ID combination
|
|
45
|
-
targetSeries.forEach(series => {
|
|
46
|
-
var _series$xAxisId, _series$yAxisId;
|
|
47
|
-
const xAxisId = (_series$xAxisId = series.xAxisId) !== null && _series$xAxisId !== void 0 ? _series$xAxisId : defaultAxisId;
|
|
48
|
-
const yAxisId = (_series$yAxisId = series.yAxisId) !== null && _series$yAxisId !== void 0 ? _series$yAxisId : defaultAxisId;
|
|
49
|
-
const stackId = series.stackId || "individual-".concat(series.id);
|
|
50
|
-
const stackKey = "".concat(stackId, ":").concat(xAxisId, ":").concat(yAxisId);
|
|
51
|
-
if (!groups.has(stackKey)) {
|
|
52
|
-
groups.set(stackKey, {
|
|
53
|
-
stackId: stackKey,
|
|
54
|
-
series: [],
|
|
55
|
-
xAxisId: series.xAxisId,
|
|
56
|
-
yAxisId: series.yAxisId
|
|
57
|
-
});
|
|
58
|
-
}
|
|
59
|
-
const group = groups.get(stackKey);
|
|
60
|
-
group.series.push(series);
|
|
61
|
-
});
|
|
62
|
-
return Array.from(groups.values());
|
|
63
|
-
}, [targetSeries]);
|
|
64
|
-
if (!drawingArea) {
|
|
65
|
-
return null;
|
|
66
|
-
}
|
|
67
51
|
return /*#__PURE__*/_jsxs(_Fragment, {
|
|
68
52
|
children: [/*#__PURE__*/_jsx("defs", {
|
|
69
53
|
children: /*#__PURE__*/_jsx("clipPath", {
|
|
70
54
|
id: clipPathId,
|
|
71
|
-
children: /*#__PURE__*/_jsx(
|
|
55
|
+
children: animate ? /*#__PURE__*/_jsx(motion.rect, {
|
|
56
|
+
height: drawingArea.height,
|
|
57
|
+
transition: (_transitions$update = transitions === null || transitions === void 0 ? void 0 : transitions.update) !== null && _transitions$update !== void 0 ? _transitions$update : instantTransition,
|
|
58
|
+
width: drawingArea.width,
|
|
59
|
+
x: drawingArea.x,
|
|
60
|
+
y: drawingArea.y
|
|
61
|
+
}) : /*#__PURE__*/_jsx("rect", {
|
|
72
62
|
height: drawingArea.height,
|
|
73
63
|
width: drawingArea.width,
|
|
74
64
|
x: drawingArea.x,
|
|
@@ -1,20 +1,14 @@
|
|
|
1
|
-
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; }
|
|
2
|
-
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; }
|
|
3
|
-
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; }
|
|
4
|
-
function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == typeof i ? i : i + ""; }
|
|
5
|
-
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); }
|
|
6
1
|
import React, { memo, useMemo } from 'react';
|
|
7
2
|
import { useCartesianChartContext } from '../ChartProvider';
|
|
8
|
-
import {
|
|
3
|
+
import { EPSILON, getBars, getStackBaseline, getStackOrigin } from '../utils/bar';
|
|
4
|
+
import { getGradientConfig } from '../utils/gradient';
|
|
9
5
|
import { Bar } from './Bar';
|
|
10
6
|
import { DefaultBarStack } from './DefaultBarStack';
|
|
11
|
-
import { jsx as _jsx } from "react/jsx-runtime";
|
|
12
|
-
const EPSILON = 1e-4;
|
|
13
7
|
|
|
14
8
|
/**
|
|
15
9
|
* Extended series type that includes bar-specific properties.
|
|
16
10
|
*/
|
|
17
|
-
|
|
11
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
18
12
|
/**
|
|
19
13
|
* BarStack component that renders a single stack of bars at a specific category index.
|
|
20
14
|
* Handles the stacking logic for bars within a single category.
|
|
@@ -29,6 +23,7 @@ export const BarStack = /*#__PURE__*/memo(_ref => {
|
|
|
29
23
|
valueScale,
|
|
30
24
|
rect,
|
|
31
25
|
xAxisId,
|
|
26
|
+
yAxisId,
|
|
32
27
|
BarComponent: defaultBarComponent,
|
|
33
28
|
fillOpacity: defaultFillOpacity,
|
|
34
29
|
stroke: defaultStroke,
|
|
@@ -46,36 +41,21 @@ export const BarStack = /*#__PURE__*/memo(_ref => {
|
|
|
46
41
|
layout,
|
|
47
42
|
getSeriesData,
|
|
48
43
|
getXAxis,
|
|
49
|
-
|
|
44
|
+
getYAxis
|
|
50
45
|
} = useCartesianChartContext();
|
|
51
|
-
const barMinSizePx = barMinSize;
|
|
52
|
-
const stackMinSizePx = stackMinSize;
|
|
53
46
|
const xAxis = getXAxis(xAxisId);
|
|
54
|
-
const
|
|
47
|
+
const yAxis = getYAxis(yAxisId);
|
|
55
48
|
const baseline = useMemo(() => {
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
const [domainMin, domainMax] = domain;
|
|
59
|
-
const baselineValue = domainMin >= 0 ? domainMin : domainMax <= 0 ? domainMax : 0;
|
|
60
|
-
const pos = (_valueScale = valueScale(baselineValue)) !== null && _valueScale !== void 0 ? _valueScale : 0;
|
|
61
|
-
|
|
62
|
-
// In vertical layout (bars grow up), value scale is Y. In horizontal, it's X.
|
|
63
|
-
const fallback = barsGrowVertically ? rect.y + rect.height : rect.x;
|
|
64
|
-
const baselinePos = (_valueScale2 = valueScale(baselineValue)) !== null && _valueScale2 !== void 0 ? _valueScale2 : fallback;
|
|
65
|
-
if (barsGrowVertically) {
|
|
66
|
-
return Math.max(rect.y, Math.min(baselinePos, rect.y + rect.height));
|
|
67
|
-
} else {
|
|
68
|
-
return Math.max(rect.x, Math.min(baselinePos, rect.x + rect.width));
|
|
69
|
-
}
|
|
70
|
-
}, [rect, valueScale, barsGrowVertically]);
|
|
49
|
+
return getStackBaseline(valueScale, rect, layout);
|
|
50
|
+
}, [rect, valueScale, layout]);
|
|
71
51
|
const seriesGradients = useMemo(() => {
|
|
72
52
|
return series.map(s => {
|
|
73
53
|
if (!s.gradient) return null;
|
|
74
|
-
const evalScale = s.gradient.axis === 'x' ?
|
|
54
|
+
const evalScale = s.gradient.axis === 'x' ? layout === 'vertical' ? indexScale : valueScale : layout === 'vertical' ? valueScale : indexScale;
|
|
75
55
|
|
|
76
56
|
// We need to pass original xScale/yScale to getGradientConfig for legacy reasons
|
|
77
57
|
// For now let's assume getGradientConfig can handle these scales if we pass them correctly.
|
|
78
|
-
const stops = getGradientConfig(s.gradient,
|
|
58
|
+
const stops = getGradientConfig(s.gradient, layout === 'vertical' ? indexScale : valueScale, layout === 'vertical' ? valueScale : indexScale);
|
|
79
59
|
if (!stops) return null;
|
|
80
60
|
return {
|
|
81
61
|
seriesId: s.id,
|
|
@@ -84,279 +64,95 @@ export const BarStack = /*#__PURE__*/memo(_ref => {
|
|
|
84
64
|
stops
|
|
85
65
|
};
|
|
86
66
|
});
|
|
87
|
-
}, [series, indexScale, valueScale,
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
const
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
// - edgeBottom is max Y (bottom face)
|
|
126
|
-
// In horizontal layout (bars grow sideways):
|
|
127
|
-
// - edgeTop is max X (right face)
|
|
128
|
-
// - edgeBottom is min X (left face)
|
|
129
|
-
// However, edgeTop/edgeBottom here are values from the scale.
|
|
130
|
-
// For positive bars: edgeTop = scale(value), edgeBottom = scale(0).
|
|
131
|
-
// For horizontal: edgeTop > edgeBottom (X increases right).
|
|
132
|
-
// For vertical: edgeTop < edgeBottom (Y increases down).
|
|
133
|
-
|
|
134
|
-
const roundingEndA = roundBaseline || Math.abs(edgeTop - baseline) >= EPSILON;
|
|
135
|
-
const roundingEndB = roundBaseline || Math.abs(edgeBottom - baseline) >= EPSILON;
|
|
136
|
-
|
|
137
|
-
// In horizontal layout: roundTop is Right (edgeTop), roundBottom is Left (edgeBottom)
|
|
138
|
-
// getBarPath already handles the mapping of roundTop/roundBottom to coordinates.
|
|
139
|
-
const roundTop = roundingEndA;
|
|
140
|
-
const roundBottom = roundingEndB;
|
|
141
|
-
|
|
142
|
-
// Track bar counts for later gap calculations
|
|
143
|
-
if (shouldApplyGap) {
|
|
144
|
-
if (isAboveBaseline) {
|
|
145
|
-
positiveBarCount++;
|
|
146
|
-
} else if (isBelowBaseline) {
|
|
147
|
-
negativeBarCount++;
|
|
148
|
-
}
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
// Calculate length (measured along the value axis)
|
|
152
|
-
const length = Math.abs(edgeBottom - edgeTop);
|
|
153
|
-
const valuePos = Math.min(edgeBottom, edgeTop);
|
|
154
|
-
|
|
155
|
-
// Skip bars that would have zero or negative height
|
|
156
|
-
if (length <= 0) {
|
|
157
|
-
return;
|
|
158
|
-
}
|
|
159
|
-
|
|
160
|
-
// Update stack bounds
|
|
161
|
-
minValuePos = Math.min(minValuePos, valuePos);
|
|
162
|
-
maxValuePos = Math.max(maxValuePos, valuePos + length);
|
|
163
|
-
let barFill = (_s$color = s.color) !== null && _s$color !== void 0 ? _s$color : 'var(--color-fgPrimary)';
|
|
164
|
-
|
|
165
|
-
// Evaluate gradient if provided (using precomputed stops)
|
|
166
|
-
const seriesGradientConfig = seriesGradients.find(g => (g === null || g === void 0 ? void 0 : g.seriesId) === s.id);
|
|
167
|
-
if (seriesGradientConfig && originalValue !== null && originalValue !== undefined) {
|
|
168
|
-
var _seriesGradientConfig;
|
|
169
|
-
const axis = (_seriesGradientConfig = seriesGradientConfig.gradient.axis) !== null && _seriesGradientConfig !== void 0 ? _seriesGradientConfig : 'y';
|
|
170
|
-
let evalValue;
|
|
171
|
-
if (axis === 'x') {
|
|
172
|
-
// X-axis gradient: In vertical it's the index, in horizontal it's the value.
|
|
173
|
-
evalValue = barsGrowVertically ? categoryIndex : Array.isArray(originalValue) ? originalValue[1] : originalValue;
|
|
174
|
-
} else {
|
|
175
|
-
// Y-axis gradient: In vertical it's the value, in horizontal it's the index.
|
|
176
|
-
evalValue = barsGrowVertically ? Array.isArray(originalValue) ? originalValue[1] : originalValue : categoryIndex;
|
|
177
|
-
}
|
|
178
|
-
const evaluatedColor = evaluateGradientAtValue(seriesGradientConfig.stops, evalValue, seriesGradientConfig.scale);
|
|
179
|
-
if (evaluatedColor) {
|
|
180
|
-
barFill = evaluatedColor;
|
|
181
|
-
}
|
|
182
|
-
}
|
|
183
|
-
allBars.push({
|
|
184
|
-
seriesId: s.id,
|
|
185
|
-
indexPos,
|
|
186
|
-
valuePos,
|
|
187
|
-
thickness,
|
|
188
|
-
length,
|
|
189
|
-
dataValue: value,
|
|
190
|
-
fill: barFill,
|
|
191
|
-
roundTop,
|
|
192
|
-
roundBottom,
|
|
193
|
-
shouldApplyGap,
|
|
194
|
-
BarComponent: s.BarComponent
|
|
195
|
-
});
|
|
196
|
-
});
|
|
197
|
-
|
|
198
|
-
// Apply proportional gap distribution to maintain total stack length
|
|
199
|
-
if (stackGap && allBars.length > 1) {
|
|
200
|
-
// Separate bars by baseline side
|
|
201
|
-
const barsAboveBaseline = allBars.filter(bar => {
|
|
202
|
-
const [bottom, top] = bar.dataValue.sort((a, b) => a - b);
|
|
203
|
-
return bottom >= 0 && top !== bottom && bar.shouldApplyGap;
|
|
204
|
-
});
|
|
205
|
-
const barsBelowBaseline = allBars.filter(bar => {
|
|
206
|
-
const [bottom, top] = bar.dataValue.sort((a, b) => a - b);
|
|
207
|
-
return bottom <= 0 && bottom !== top && bar.shouldApplyGap;
|
|
208
|
-
});
|
|
209
|
-
|
|
210
|
-
// Apply proportional gaps to bars above baseline
|
|
211
|
-
if (barsAboveBaseline.length > 1) {
|
|
212
|
-
const totalGapSpace = stackGap * (barsAboveBaseline.length - 1);
|
|
213
|
-
const totalDataLength = barsAboveBaseline.reduce((sum, bar) => sum + bar.length, 0);
|
|
214
|
-
const lengthReduction = totalGapSpace / totalDataLength;
|
|
215
|
-
|
|
216
|
-
// In SVG, for Y axis positive values go up (decreasing Y)
|
|
217
|
-
// For X axis positive values go right (increasing X)
|
|
218
|
-
const sortedBars = barsGrowVertically ? barsAboveBaseline.sort((a, b) => b.valuePos - a.valuePos) // Higher Y first
|
|
219
|
-
: barsAboveBaseline.sort((a, b) => a.valuePos - b.valuePos); // Higher X last
|
|
220
|
-
|
|
221
|
-
let currentEdge = baseline;
|
|
222
|
-
sortedBars.forEach((bar, index) => {
|
|
223
|
-
const newLength = bar.length * (1 - lengthReduction);
|
|
224
|
-
let newValuePos;
|
|
225
|
-
if (barsGrowVertically) {
|
|
226
|
-
newValuePos = currentEdge - newLength;
|
|
227
|
-
currentEdge = newValuePos - (index < sortedBars.length - 1 ? stackGap : 0);
|
|
228
|
-
} else {
|
|
229
|
-
newValuePos = currentEdge;
|
|
230
|
-
currentEdge = newValuePos + newLength + (index < sortedBars.length - 1 ? stackGap : 0);
|
|
231
|
-
}
|
|
232
|
-
const barIndex = allBars.findIndex(b => b.seriesId === bar.seriesId);
|
|
233
|
-
if (barIndex !== -1) {
|
|
234
|
-
allBars[barIndex] = _objectSpread(_objectSpread({}, allBars[barIndex]), {}, {
|
|
235
|
-
length: newLength,
|
|
236
|
-
valuePos: newValuePos
|
|
237
|
-
});
|
|
238
|
-
}
|
|
239
|
-
});
|
|
240
|
-
}
|
|
241
|
-
|
|
242
|
-
// Apply proportional gaps to bars below baseline
|
|
243
|
-
if (barsBelowBaseline.length > 1) {
|
|
244
|
-
const totalGapSpace = stackGap * (barsBelowBaseline.length - 1);
|
|
245
|
-
const totalDataLength = barsBelowBaseline.reduce((sum, bar) => sum + bar.length, 0);
|
|
246
|
-
const lengthReduction = totalGapSpace / totalDataLength;
|
|
247
|
-
const sortedBars = barsGrowVertically ? barsBelowBaseline.sort((a, b) => a.valuePos - b.valuePos) : barsBelowBaseline.sort((a, b) => b.valuePos - a.valuePos);
|
|
248
|
-
let currentEdge = baseline;
|
|
249
|
-
sortedBars.forEach((bar, index) => {
|
|
250
|
-
const newLength = bar.length * (1 - lengthReduction);
|
|
251
|
-
let newValuePos;
|
|
252
|
-
if (barsGrowVertically) {
|
|
253
|
-
newValuePos = currentEdge;
|
|
254
|
-
currentEdge = newValuePos + newLength + (index < sortedBars.length - 1 ? stackGap : 0);
|
|
255
|
-
} else {
|
|
256
|
-
newValuePos = currentEdge - newLength;
|
|
257
|
-
currentEdge = newValuePos - (index < sortedBars.length - 1 ? stackGap : 0);
|
|
258
|
-
}
|
|
259
|
-
const barIndex = allBars.findIndex(b => b.seriesId === bar.seriesId);
|
|
260
|
-
if (barIndex !== -1) {
|
|
261
|
-
allBars[barIndex] = _objectSpread(_objectSpread({}, allBars[barIndex]), {}, {
|
|
262
|
-
length: newLength,
|
|
263
|
-
valuePos: newValuePos
|
|
264
|
-
});
|
|
265
|
-
}
|
|
266
|
-
});
|
|
267
|
-
}
|
|
268
|
-
|
|
269
|
-
// Recalculate stack bounds after gap adjustments
|
|
270
|
-
if (allBars.length > 0) {
|
|
271
|
-
minValuePos = Math.min(...allBars.map(bar => bar.valuePos));
|
|
272
|
-
maxValuePos = Math.max(...allBars.map(bar => bar.valuePos + bar.length));
|
|
273
|
-
}
|
|
274
|
-
}
|
|
275
|
-
|
|
276
|
-
// Apply barMinSize constraints
|
|
277
|
-
if (barMinSizePx) {
|
|
278
|
-
// ... (Skipping full complex logic for brevity, but it should be layout-aware)
|
|
279
|
-
// For now let's assume it's correctly handled similar to above by using length and valuePos
|
|
67
|
+
}, [series, indexScale, valueScale, layout]);
|
|
68
|
+
const categoryAxis = layout === 'vertical' ? xAxis : yAxis;
|
|
69
|
+
const categoryData = categoryAxis !== null && categoryAxis !== void 0 && categoryAxis.data && Array.isArray(categoryAxis.data) && typeof categoryAxis.data[0] === 'number' ? categoryAxis.data : undefined;
|
|
70
|
+
const categoryValue = categoryData ? categoryData[categoryIndex] : categoryIndex;
|
|
71
|
+
const seriesData = useMemo(() => Object.fromEntries(series.map(s => {
|
|
72
|
+
var _getSeriesData;
|
|
73
|
+
return [s.id, (_getSeriesData = getSeriesData(s.id)) !== null && _getSeriesData !== void 0 ? _getSeriesData : []];
|
|
74
|
+
})), [series, getSeriesData]);
|
|
75
|
+
const bars = useMemo(() => getBars({
|
|
76
|
+
series,
|
|
77
|
+
seriesData,
|
|
78
|
+
categoryIndex,
|
|
79
|
+
categoryValue,
|
|
80
|
+
indexPos,
|
|
81
|
+
thickness,
|
|
82
|
+
valueScale,
|
|
83
|
+
seriesGradients,
|
|
84
|
+
roundBaseline,
|
|
85
|
+
layout,
|
|
86
|
+
baseline,
|
|
87
|
+
stackGap,
|
|
88
|
+
barMinSize,
|
|
89
|
+
stackMinSize,
|
|
90
|
+
defaultFill: 'var(--color-fgPrimary)',
|
|
91
|
+
borderRadius,
|
|
92
|
+
defaultFillOpacity,
|
|
93
|
+
defaultStroke,
|
|
94
|
+
defaultStrokeWidth,
|
|
95
|
+
defaultBarComponent
|
|
96
|
+
}), [series, seriesData, stackGap, barMinSize, stackMinSize, indexPos, baseline, thickness, categoryIndex, categoryValue, valueScale, seriesGradients, roundBaseline, layout, borderRadius, defaultFillOpacity, defaultStroke, defaultStrokeWidth, defaultBarComponent]);
|
|
97
|
+
const stackRect = useMemo(() => {
|
|
98
|
+
if (bars.length === 0) {
|
|
99
|
+
return {
|
|
100
|
+
x: layout === 'vertical' ? indexPos : baseline,
|
|
101
|
+
y: layout === 'vertical' ? baseline : indexPos,
|
|
102
|
+
width: layout === 'vertical' ? thickness : 0,
|
|
103
|
+
height: layout === 'vertical' ? 0 : thickness
|
|
104
|
+
};
|
|
280
105
|
}
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
const
|
|
284
|
-
|
|
285
|
-
// Vertical (Y axis): Max Y (bottom) to Min Y (top)
|
|
286
|
-
// Horizontal (X axis): Min X (left) to Max X (right)
|
|
287
|
-
const sortedBars = barsGrowVertically ? [...bars].sort((a, b) => b.valuePos - a.valuePos) : [...bars].sort((a, b) => a.valuePos - b.valuePos);
|
|
288
|
-
return sortedBars.map((a, index) => {
|
|
289
|
-
const barBefore = index > 0 ? sortedBars[index - 1] : null;
|
|
290
|
-
const barAfter = index < sortedBars.length - 1 ? sortedBars[index + 1] : null;
|
|
291
|
-
|
|
292
|
-
// shouldRoundLower: the face with the smaller coordinate (Top in vertical, Left in horizontal)
|
|
293
|
-
const shouldRoundLower = (barsGrowVertically ? index === sortedBars.length - 1 : index === 0) || a.shouldApplyGap && stackGap || !a.shouldApplyGap && barAfter && barAfter.valuePos + barAfter.length !== a.valuePos;
|
|
294
|
-
|
|
295
|
-
// shouldRoundHigher: the face with the larger coordinate (Bottom in vertical, Right in horizontal)
|
|
296
|
-
const shouldRoundHigher = (barsGrowVertically ? index === 0 : index === sortedBars.length - 1) || a.shouldApplyGap && stackGap || !a.shouldApplyGap && barBefore && barBefore.valuePos !== a.valuePos + a.length;
|
|
297
|
-
return _objectSpread(_objectSpread({}, a), {}, {
|
|
298
|
-
roundTop: Boolean(a.roundTop && (barsGrowVertically ? shouldRoundLower : shouldRoundHigher)),
|
|
299
|
-
roundBottom: Boolean(a.roundBottom && (barsGrowVertically ? shouldRoundHigher : shouldRoundLower))
|
|
300
|
-
});
|
|
301
|
-
});
|
|
302
|
-
};
|
|
303
|
-
allBars = applyBorderRadiusLogic(allBars);
|
|
304
|
-
|
|
305
|
-
// Calculate the bounding rect for the entire stack
|
|
306
|
-
const stackBounds = {
|
|
307
|
-
x: barsGrowVertically ? indexPos : minValuePos === Infinity ? baseline : minValuePos,
|
|
308
|
-
y: barsGrowVertically ? minValuePos === Infinity ? baseline : minValuePos : indexPos,
|
|
309
|
-
width: barsGrowVertically ? thickness : maxValuePos === -Infinity ? 0 : maxValuePos - minValuePos,
|
|
310
|
-
height: barsGrowVertically ? maxValuePos === -Infinity ? 0 : maxValuePos - minValuePos : thickness
|
|
311
|
-
};
|
|
106
|
+
const minX = Math.min(...bars.map(b => b.x));
|
|
107
|
+
const minY = Math.min(...bars.map(b => b.y));
|
|
108
|
+
const maxX = Math.max(...bars.map(b => b.x + b.width));
|
|
109
|
+
const maxY = Math.max(...bars.map(b => b.y + b.height));
|
|
312
110
|
return {
|
|
313
|
-
|
|
314
|
-
|
|
111
|
+
x: minX,
|
|
112
|
+
y: minY,
|
|
113
|
+
width: maxX - minX,
|
|
114
|
+
height: maxY - minY
|
|
315
115
|
};
|
|
316
|
-
}, [
|
|
317
|
-
const
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
const edge = barsGrowVertically ? stackRect.y : stackRect.x;
|
|
348
|
-
const size = barsGrowVertically ? stackRect.height : stackRect.width;
|
|
349
|
-
|
|
350
|
-
// stackRoundLower: face at smaller coordinate (Top in vertical, Left in horizontal)
|
|
351
|
-
// stackRoundHigher: face at larger coordinate (Bottom in vertical, Right in horizontal)
|
|
116
|
+
}, [bars, baseline, indexPos, layout, thickness]);
|
|
117
|
+
const stackOrigin = useMemo(() => {
|
|
118
|
+
var _getStackOrigin;
|
|
119
|
+
return (_getStackOrigin = getStackOrigin(bars.map(b => b.origin), bars.map(b => {
|
|
120
|
+
var _b$minSize;
|
|
121
|
+
return (_b$minSize = b.minSize) !== null && _b$minSize !== void 0 ? _b$minSize : 0;
|
|
122
|
+
}))) !== null && _getStackOrigin !== void 0 ? _getStackOrigin : baseline;
|
|
123
|
+
}, [bars, baseline]);
|
|
124
|
+
const barElements = bars.map((bar, index) => /*#__PURE__*/_jsx(Bar, {
|
|
125
|
+
BarComponent: bar.BarComponent,
|
|
126
|
+
borderRadius: bar.borderRadius,
|
|
127
|
+
dataX: bar.dataX,
|
|
128
|
+
dataY: bar.dataY,
|
|
129
|
+
fill: bar.fill,
|
|
130
|
+
fillOpacity: bar.fillOpacity,
|
|
131
|
+
height: bar.height,
|
|
132
|
+
minSize: bar.minSize,
|
|
133
|
+
origin: bar.origin,
|
|
134
|
+
roundBottom: bar.roundBottom,
|
|
135
|
+
roundTop: bar.roundTop,
|
|
136
|
+
seriesId: bar.seriesId,
|
|
137
|
+
stroke: bar.stroke,
|
|
138
|
+
strokeWidth: bar.strokeWidth,
|
|
139
|
+
transition: transition,
|
|
140
|
+
transitions: transitions,
|
|
141
|
+
width: bar.width,
|
|
142
|
+
x: bar.x,
|
|
143
|
+
y: bar.y
|
|
144
|
+
}, "".concat(bar.seriesId, "-").concat(categoryIndex, "-").concat(index)));
|
|
145
|
+
const edge = layout === 'vertical' ? stackRect.y : stackRect.x;
|
|
146
|
+
const size = layout === 'vertical' ? stackRect.height : stackRect.width;
|
|
352
147
|
const stackRoundLower = roundBaseline || Math.abs(edge - baseline) >= EPSILON;
|
|
353
148
|
const stackRoundHigher = roundBaseline || Math.abs(edge + size - baseline) >= EPSILON;
|
|
354
|
-
const stackRoundTop =
|
|
355
|
-
const stackRoundBottom =
|
|
149
|
+
const stackRoundTop = layout === 'vertical' ? stackRoundLower : stackRoundHigher;
|
|
150
|
+
const stackRoundBottom = layout === 'vertical' ? stackRoundHigher : stackRoundLower;
|
|
356
151
|
return /*#__PURE__*/_jsx(BarStackComponent, {
|
|
357
152
|
borderRadius: borderRadius,
|
|
358
153
|
categoryIndex: categoryIndex,
|
|
359
154
|
height: stackRect.height,
|
|
155
|
+
origin: stackOrigin,
|
|
360
156
|
roundBottom: stackRoundBottom,
|
|
361
157
|
roundTop: stackRoundTop,
|
|
362
158
|
transition: transition,
|
|
@@ -364,7 +160,6 @@ export const BarStack = /*#__PURE__*/memo(_ref => {
|
|
|
364
160
|
width: stackRect.width,
|
|
365
161
|
x: stackRect.x,
|
|
366
162
|
y: stackRect.y,
|
|
367
|
-
yOrigin: baseline,
|
|
368
163
|
children: barElements
|
|
369
164
|
});
|
|
370
165
|
});
|