@coinbase/cds-web-visualization 3.4.0-beta.8 → 3.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +130 -0
- package/dts/chart/CartesianChart.d.ts +40 -4
- 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 +51 -12
- package/dts/chart/Path.d.ts.map +1 -1
- package/dts/chart/PeriodSelector.d.ts +25 -4
- package/dts/chart/PeriodSelector.d.ts.map +1 -1
- package/dts/chart/area/Area.d.ts +13 -11
- package/dts/chart/area/Area.d.ts.map +1 -1
- package/dts/chart/area/AreaChart.d.ts +18 -5
- package/dts/chart/area/AreaChart.d.ts.map +1 -1
- package/dts/chart/area/DottedArea.d.ts.map +1 -1
- package/dts/chart/area/GradientArea.d.ts.map +1 -1
- package/dts/chart/area/SolidArea.d.ts.map +1 -1
- package/dts/chart/axis/Axis.d.ts +29 -29
- package/dts/chart/axis/Axis.d.ts.map +1 -1
- package/dts/chart/axis/XAxis.d.ts +6 -0
- package/dts/chart/axis/XAxis.d.ts.map +1 -1
- package/dts/chart/axis/YAxis.d.ts +2 -1
- package/dts/chart/axis/YAxis.d.ts.map +1 -1
- package/dts/chart/bar/Bar.d.ts +51 -51
- package/dts/chart/bar/Bar.d.ts.map +1 -1
- package/dts/chart/bar/BarChart.d.ts +29 -6
- package/dts/chart/bar/BarChart.d.ts.map +1 -1
- package/dts/chart/bar/BarPlot.d.ts +2 -1
- package/dts/chart/bar/BarPlot.d.ts.map +1 -1
- package/dts/chart/bar/BarStack.d.ts +58 -20
- package/dts/chart/bar/BarStack.d.ts.map +1 -1
- package/dts/chart/bar/BarStackGroup.d.ts +2 -1
- 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 +7 -0
- package/dts/chart/gradient/Gradient.d.ts.map +1 -1
- package/dts/chart/index.d.ts +1 -0
- 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/DottedLine.d.ts.map +1 -1
- package/dts/chart/line/Line.d.ts +45 -24
- package/dts/chart/line/Line.d.ts.map +1 -1
- package/dts/chart/line/LineChart.d.ts +5 -3
- package/dts/chart/line/LineChart.d.ts.map +1 -1
- package/dts/chart/line/ReferenceLine.d.ts +9 -0
- package/dts/chart/line/ReferenceLine.d.ts.map +1 -1
- package/dts/chart/line/SolidLine.d.ts.map +1 -1
- package/dts/chart/point/Point.d.ts +26 -2
- package/dts/chart/point/Point.d.ts.map +1 -1
- package/dts/chart/scrubber/DefaultScrubberBeacon.d.ts +34 -17
- package/dts/chart/scrubber/DefaultScrubberBeacon.d.ts.map +1 -1
- package/dts/chart/scrubber/DefaultScrubberBeaconLabel.d.ts.map +1 -1
- package/dts/chart/scrubber/DefaultScrubberLabel.d.ts +2 -1
- package/dts/chart/scrubber/DefaultScrubberLabel.d.ts.map +1 -1
- package/dts/chart/scrubber/Scrubber.d.ts +148 -46
- package/dts/chart/scrubber/Scrubber.d.ts.map +1 -1
- package/dts/chart/scrubber/ScrubberBeaconGroup.d.ts +10 -0
- package/dts/chart/scrubber/ScrubberBeaconGroup.d.ts.map +1 -1
- package/dts/chart/scrubber/ScrubberBeaconLabelGroup.d.ts +25 -1
- package/dts/chart/scrubber/ScrubberBeaconLabelGroup.d.ts.map +1 -1
- package/dts/chart/scrubber/ScrubberProvider.d.ts.map +1 -1
- package/dts/chart/text/ChartText.d.ts.map +1 -1
- package/dts/chart/utils/axis.d.ts +48 -9
- package/dts/chart/utils/axis.d.ts.map +1 -1
- package/dts/chart/utils/bar.d.ts +188 -0
- package/dts/chart/utils/bar.d.ts.map +1 -1
- package/dts/chart/utils/chart.d.ts +32 -0
- package/dts/chart/utils/chart.d.ts.map +1 -1
- package/dts/chart/utils/context.d.ts +20 -4
- package/dts/chart/utils/context.d.ts.map +1 -1
- package/dts/chart/utils/gradient.d.ts +3 -1
- package/dts/chart/utils/gradient.d.ts.map +1 -1
- package/dts/chart/utils/path.d.ts +26 -0
- package/dts/chart/utils/path.d.ts.map +1 -1
- package/dts/chart/utils/point.d.ts +18 -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 +2 -1
- package/dts/chart/utils/scrubber.d.ts.map +1 -1
- package/dts/chart/utils/transition.d.ts +50 -14
- package/dts/chart/utils/transition.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/CartesianChart.js +154 -90
- package/esm/chart/ChartProvider.js +2 -2
- package/esm/chart/Path.js +35 -19
- package/esm/chart/PeriodSelector.js +33 -15
- package/esm/chart/area/Area.js +21 -9
- package/esm/chart/area/AreaChart.js +28 -25
- package/esm/chart/area/DottedArea.js +18 -9
- package/esm/chart/area/GradientArea.js +16 -8
- package/esm/chart/area/SolidArea.js +8 -3
- package/esm/chart/axis/Axis.js +3 -17
- package/esm/chart/axis/XAxis.js +153 -50
- package/esm/chart/axis/YAxis.js +146 -36
- package/esm/chart/bar/Bar.js +16 -8
- package/esm/chart/bar/BarChart.js +38 -33
- package/esm/chart/bar/BarPlot.js +20 -25
- package/esm/chart/bar/BarStack.js +109 -505
- package/esm/chart/bar/BarStackGroup.js +36 -27
- package/esm/chart/bar/DefaultBar.js +34 -26
- package/esm/chart/bar/DefaultBarStack.js +31 -18
- package/esm/chart/gradient/Gradient.js +3 -2
- package/esm/chart/index.js +1 -0
- 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/DottedLine.js +7 -2
- package/esm/chart/line/Line.js +41 -42
- package/esm/chart/line/LineChart.js +18 -13
- package/esm/chart/line/ReferenceLine.js +6 -2
- package/esm/chart/line/SolidLine.js +8 -3
- package/esm/chart/point/Point.js +41 -24
- package/esm/chart/scrubber/DefaultScrubberBeacon.js +64 -65
- package/esm/chart/scrubber/DefaultScrubberBeaconLabel.js +25 -14
- package/esm/chart/scrubber/DefaultScrubberLabel.js +26 -8
- package/esm/chart/scrubber/Scrubber.js +54 -43
- package/esm/chart/scrubber/ScrubberBeaconGroup.js +60 -35
- package/esm/chart/scrubber/ScrubberBeaconLabelGroup.js +31 -8
- package/esm/chart/scrubber/ScrubberProvider.js +44 -39
- package/esm/chart/text/ChartText.js +3 -2
- package/esm/chart/utils/axis.js +90 -43
- package/esm/chart/utils/bar.js +863 -0
- package/esm/chart/utils/chart.js +34 -7
- package/esm/chart/utils/context.js +7 -0
- package/esm/chart/utils/gradient.js +6 -4
- package/esm/chart/utils/path.js +88 -61
- package/esm/chart/utils/point.js +57 -30
- package/esm/chart/utils/scale.js +13 -2
- package/esm/chart/utils/scrubber.js +9 -4
- package/esm/chart/utils/transition.js +68 -41
- package/esm/sparkline/Sparkline.js +2 -1
- package/esm/sparkline/SparklineArea.js +2 -1
- package/esm/sparkline/SparklineGradient.js +2 -1
- package/esm/sparkline/__figma__/Sparkline.figma.js +1 -1
- package/esm/sparkline/sparkline-interactive/SparklineInteractive.js +2 -1
- 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/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
|
|
@@ -32,15 +45,16 @@ export const getChartDomain = (series, min, max) => {
|
|
|
32
45
|
};
|
|
33
46
|
|
|
34
47
|
/**
|
|
35
|
-
* Creates a composite stack key that includes
|
|
36
|
-
* This ensures series with different
|
|
48
|
+
* Creates a composite stack key that includes stack ID and axis IDs.
|
|
49
|
+
* This ensures series with different scales don't get stacked together.
|
|
37
50
|
*/
|
|
38
51
|
const createStackKey = series => {
|
|
39
52
|
if (series.stackId === undefined) return undefined;
|
|
40
53
|
|
|
41
|
-
// Include
|
|
54
|
+
// Include axis IDs to prevent cross-scale stacking
|
|
55
|
+
const xAxisId = series.xAxisId || 'default';
|
|
42
56
|
const yAxisId = series.yAxisId || 'default';
|
|
43
|
-
return "".concat(series.stackId, ":").concat(yAxisId);
|
|
57
|
+
return "".concat(series.stackId, ":").concat(xAxisId, ":").concat(yAxisId);
|
|
44
58
|
};
|
|
45
59
|
|
|
46
60
|
/**
|
|
@@ -126,9 +140,9 @@ export const getLineData = data => {
|
|
|
126
140
|
const firstNonNull = data.find(d => d !== null);
|
|
127
141
|
if (Array.isArray(firstNonNull)) {
|
|
128
142
|
return data.map(d => {
|
|
129
|
-
var _d
|
|
143
|
+
var _d;
|
|
130
144
|
if (d === null) return null;
|
|
131
|
-
if (Array.isArray(d)) return (_d
|
|
145
|
+
if (Array.isArray(d)) return (_d = d[d.length - 1]) !== null && _d !== void 0 ? _d : null;
|
|
132
146
|
return d;
|
|
133
147
|
});
|
|
134
148
|
}
|
|
@@ -211,12 +225,25 @@ export const getChartRange = (series, min, max) => {
|
|
|
211
225
|
}
|
|
212
226
|
return range;
|
|
213
227
|
};
|
|
214
|
-
export const
|
|
228
|
+
export const defaultVerticalLayoutChartInset = {
|
|
215
229
|
top: 32,
|
|
216
230
|
left: 16,
|
|
217
231
|
bottom: 16,
|
|
218
232
|
right: 16
|
|
219
233
|
};
|
|
234
|
+
export const defaultHorizontalLayoutChartInset = {
|
|
235
|
+
top: 16,
|
|
236
|
+
left: 16,
|
|
237
|
+
bottom: 16,
|
|
238
|
+
right: 48
|
|
239
|
+
};
|
|
240
|
+
|
|
241
|
+
/**
|
|
242
|
+
* @deprecated Use `defaultVerticalLayoutChartInset` for vertical layout charts or. This will be removed in a future major release.
|
|
243
|
+
* @deprecationExpectedRemoval v4
|
|
244
|
+
* `defaultHorizontalLayoutChartInset` for horizontal layout charts.
|
|
245
|
+
*/
|
|
246
|
+
export const defaultChartInset = defaultVerticalLayoutChartInset;
|
|
220
247
|
|
|
221
248
|
/**
|
|
222
249
|
* Normalize padding to include all sides with a value.
|
|
@@ -1,5 +1,12 @@
|
|
|
1
1
|
import { createContext, useContext } from 'react';
|
|
2
2
|
|
|
3
|
+
/**
|
|
4
|
+
* Chart layout for Cartesian charts.
|
|
5
|
+
* Describes the direction bars/areas grow.
|
|
6
|
+
* - 'vertical': Bars grow vertically (up/down). X is category axis, Y is value axis.
|
|
7
|
+
* - 'horizontal': Bars grow horizontally (left/right). Y is category axis, X is value axis.
|
|
8
|
+
*/
|
|
9
|
+
|
|
3
10
|
/**
|
|
4
11
|
* Context value for Cartesian (X/Y) coordinate charts.
|
|
5
12
|
* Contains axis-specific methods and properties for rectangular coordinate systems.
|
|
@@ -214,9 +214,11 @@ export const getBaseline = function (axisBounds) {
|
|
|
214
214
|
* @param fill - The color to use for the gradient
|
|
215
215
|
* @param peakOpacity - Opacity at the peak of the gradient
|
|
216
216
|
* @param baselineOpacity - Opacity at the baseline
|
|
217
|
-
* @
|
|
217
|
+
* @param axis - The axis the gradient maps to ('y' for vertical, 'x' for horizontal layout)
|
|
218
|
+
* @returns A gradient definition with stops in ascending order
|
|
218
219
|
*/
|
|
219
|
-
export const createGradient = (axisBounds, baselineValue, fill, peakOpacity, baselineOpacity)
|
|
220
|
+
export const createGradient = function (axisBounds, baselineValue, fill, peakOpacity, baselineOpacity) {
|
|
221
|
+
let axis = arguments.length > 5 && arguments[5] !== undefined ? arguments[5] : 'y';
|
|
220
222
|
const {
|
|
221
223
|
min,
|
|
222
224
|
max
|
|
@@ -225,7 +227,7 @@ export const createGradient = (axisBounds, baselineValue, fill, peakOpacity, bas
|
|
|
225
227
|
const upperBound = Math.max(min, max);
|
|
226
228
|
if (lowerBound < baselineValue && baselineValue < upperBound) {
|
|
227
229
|
return {
|
|
228
|
-
axis
|
|
230
|
+
axis,
|
|
229
231
|
stops: [{
|
|
230
232
|
offset: lowerBound,
|
|
231
233
|
color: fill,
|
|
@@ -243,7 +245,7 @@ export const createGradient = (axisBounds, baselineValue, fill, peakOpacity, bas
|
|
|
243
245
|
}
|
|
244
246
|
const peakValue = Math.abs(min - baselineValue) > Math.abs(max - baselineValue) ? min : max;
|
|
245
247
|
return {
|
|
246
|
-
axis
|
|
248
|
+
axis,
|
|
247
249
|
stops: [{
|
|
248
250
|
offset: peakValue,
|
|
249
251
|
color: fill,
|
package/esm/chart/utils/path.js
CHANGED
|
@@ -1,20 +1,32 @@
|
|
|
1
|
-
import { area as d3Area, curveBumpX, curveCatmullRom, curveLinear, curveLinearClosed, curveMonotoneX, curveNatural, curveStep, curveStepAfter, curveStepBefore, line as d3Line } from 'd3-shape';
|
|
2
|
-
import {
|
|
1
|
+
import { area as d3Area, curveBumpX, curveBumpY, curveCatmullRom, curveLinear, curveLinearClosed, curveMonotoneX, curveMonotoneY, curveNatural, curveStep, curveStepAfter, curveStepBefore, line as d3Line } from 'd3-shape';
|
|
2
|
+
import { getPointOnScale, projectPoints } from './point';
|
|
3
3
|
import { isCategoricalScale } from './scale';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Default enter transition for path-based components (Line, Area).
|
|
7
|
+
* `{ type: 'tween', duration: 0.5 }`
|
|
8
|
+
*/
|
|
9
|
+
export const defaultPathEnterTransition = {
|
|
10
|
+
type: 'tween',
|
|
11
|
+
duration: 0.5
|
|
12
|
+
};
|
|
4
13
|
/**
|
|
5
14
|
* Get the d3 curve function for a path.
|
|
6
15
|
* See https://d3js.org/d3-shape/curve
|
|
7
16
|
* @param curve - The curve type. Defaults to 'linear'.
|
|
17
|
+
* @param layout - The chart layout. Defaults to 'vertical'.
|
|
8
18
|
* @returns The d3 curve function.
|
|
9
19
|
*/
|
|
10
20
|
export const getPathCurveFunction = function () {
|
|
11
21
|
let curve = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 'linear';
|
|
22
|
+
let layout = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 'vertical';
|
|
12
23
|
switch (curve) {
|
|
13
24
|
case 'catmullRom':
|
|
14
25
|
return curveCatmullRom;
|
|
15
26
|
case 'monotone':
|
|
16
|
-
//
|
|
17
|
-
|
|
27
|
+
// For vertical layout, X is the independent axis (category/index), so use MonotoneX
|
|
28
|
+
// For horizontal layout, Y is the independent axis (category/index), so use MonotoneY
|
|
29
|
+
return layout !== 'horizontal' ? curveMonotoneX : curveMonotoneY;
|
|
18
30
|
case 'natural':
|
|
19
31
|
return curveNatural;
|
|
20
32
|
case 'step':
|
|
@@ -24,8 +36,9 @@ export const getPathCurveFunction = function () {
|
|
|
24
36
|
case 'stepAfter':
|
|
25
37
|
return curveStepAfter;
|
|
26
38
|
case 'bump':
|
|
27
|
-
//
|
|
28
|
-
|
|
39
|
+
// For vertical layout, X is the independent axis (category/index), so use BumpX
|
|
40
|
+
// For horizontal layout, Y is the independent axis (category/index), so use BumpY
|
|
41
|
+
return layout !== 'horizontal' ? curveBumpX : curveBumpY;
|
|
29
42
|
case 'linearClosed':
|
|
30
43
|
return curveLinearClosed;
|
|
31
44
|
case 'linear':
|
|
@@ -51,17 +64,21 @@ export const getLinePath = _ref => {
|
|
|
51
64
|
xScale,
|
|
52
65
|
yScale,
|
|
53
66
|
xData,
|
|
54
|
-
|
|
67
|
+
yData,
|
|
68
|
+
connectNulls,
|
|
69
|
+
layout = 'vertical'
|
|
55
70
|
} = _ref;
|
|
56
71
|
if (data.length === 0) {
|
|
57
72
|
return '';
|
|
58
73
|
}
|
|
59
|
-
const curveFunction = getPathCurveFunction(curve);
|
|
74
|
+
const curveFunction = getPathCurveFunction(curve, layout);
|
|
60
75
|
const dataPoints = projectPoints({
|
|
61
76
|
data,
|
|
62
77
|
xScale,
|
|
63
78
|
yScale,
|
|
64
|
-
xData
|
|
79
|
+
xData,
|
|
80
|
+
yData,
|
|
81
|
+
layout
|
|
65
82
|
});
|
|
66
83
|
|
|
67
84
|
// When connectNulls is true, filter out null values before rendering
|
|
@@ -100,15 +117,21 @@ export const getAreaPath = _ref2 => {
|
|
|
100
117
|
xScale,
|
|
101
118
|
yScale,
|
|
102
119
|
xData,
|
|
103
|
-
|
|
120
|
+
yData,
|
|
121
|
+
connectNulls,
|
|
122
|
+
layout = 'vertical'
|
|
104
123
|
} = _ref2;
|
|
105
124
|
if (data.length === 0) {
|
|
106
125
|
return '';
|
|
107
126
|
}
|
|
108
|
-
const curveFunction = getPathCurveFunction(curve);
|
|
109
|
-
const
|
|
110
|
-
|
|
111
|
-
|
|
127
|
+
const curveFunction = getPathCurveFunction(curve, layout);
|
|
128
|
+
const categoryAxisIsX = layout !== 'horizontal';
|
|
129
|
+
|
|
130
|
+
// Determine baseline from the value scale
|
|
131
|
+
const valueScale = categoryAxisIsX ? yScale : xScale;
|
|
132
|
+
const domain = valueScale.domain();
|
|
133
|
+
const min = Math.min(...domain);
|
|
134
|
+
const normalizedData = data.map(item => {
|
|
112
135
|
if (item === null) {
|
|
113
136
|
return null;
|
|
114
137
|
}
|
|
@@ -119,7 +142,7 @@ export const getAreaPath = _ref2 => {
|
|
|
119
142
|
return null;
|
|
120
143
|
}
|
|
121
144
|
if (typeof item === 'number') {
|
|
122
|
-
return [
|
|
145
|
+
return [min, item];
|
|
123
146
|
}
|
|
124
147
|
return null;
|
|
125
148
|
});
|
|
@@ -127,37 +150,28 @@ export const getAreaPath = _ref2 => {
|
|
|
127
150
|
if (range === null) {
|
|
128
151
|
return {
|
|
129
152
|
x: 0,
|
|
153
|
+
y: 0,
|
|
130
154
|
low: null,
|
|
131
155
|
high: null,
|
|
132
156
|
isValid: false
|
|
133
157
|
};
|
|
134
158
|
}
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
159
|
+
|
|
160
|
+
// Determine the position along the independent (index) axis
|
|
161
|
+
let indexValue = index;
|
|
162
|
+
const indexScale = categoryAxisIsX ? xScale : yScale;
|
|
163
|
+
const indexData = categoryAxisIsX ? xData : yData;
|
|
164
|
+
if (!isCategoricalScale(indexScale) && indexData && indexData[index] !== undefined) {
|
|
165
|
+
indexValue = indexData[index];
|
|
138
166
|
}
|
|
139
|
-
const
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
xScale,
|
|
143
|
-
yScale
|
|
144
|
-
});
|
|
145
|
-
const lowPoint = projectPoint({
|
|
146
|
-
x: xValue,
|
|
147
|
-
y: range[0],
|
|
148
|
-
xScale,
|
|
149
|
-
yScale
|
|
150
|
-
});
|
|
151
|
-
const highPoint = projectPoint({
|
|
152
|
-
x: xValue,
|
|
153
|
-
y: range[1],
|
|
154
|
-
xScale,
|
|
155
|
-
yScale
|
|
156
|
-
});
|
|
167
|
+
const pos = getPointOnScale(indexValue, indexScale);
|
|
168
|
+
const low = getPointOnScale(range[0], valueScale);
|
|
169
|
+
const high = getPointOnScale(range[1], valueScale);
|
|
157
170
|
return {
|
|
158
|
-
x:
|
|
159
|
-
|
|
160
|
-
|
|
171
|
+
x: categoryAxisIsX ? pos : 0,
|
|
172
|
+
y: !categoryAxisIsX ? pos : 0,
|
|
173
|
+
low,
|
|
174
|
+
high,
|
|
161
175
|
isValid: true
|
|
162
176
|
};
|
|
163
177
|
});
|
|
@@ -165,16 +179,25 @@ export const getAreaPath = _ref2 => {
|
|
|
165
179
|
// When connectNulls is true, filter out invalid points before rendering
|
|
166
180
|
// When false, use defined() to create gaps in the area
|
|
167
181
|
const filteredPoints = connectNulls ? dataPoints.filter(d => d.isValid) : dataPoints;
|
|
168
|
-
const areaGenerator = d3Area()
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
182
|
+
const areaGenerator = d3Area();
|
|
183
|
+
if (categoryAxisIsX) {
|
|
184
|
+
areaGenerator.x(d => d.x).y0(d => {
|
|
185
|
+
var _d$low;
|
|
186
|
+
return (_d$low = d.low) !== null && _d$low !== void 0 ? _d$low : 0;
|
|
187
|
+
}).y1(d => {
|
|
188
|
+
var _d$high;
|
|
189
|
+
return (_d$high = d.high) !== null && _d$high !== void 0 ? _d$high : 0;
|
|
190
|
+
});
|
|
191
|
+
} else {
|
|
192
|
+
areaGenerator.y(d => d.y).x0(d => {
|
|
193
|
+
var _d$low2;
|
|
194
|
+
return (_d$low2 = d.low) !== null && _d$low2 !== void 0 ? _d$low2 : 0;
|
|
195
|
+
}).x1(d => {
|
|
196
|
+
var _d$high2;
|
|
197
|
+
return (_d$high2 = d.high) !== null && _d$high2 !== void 0 ? _d$high2 : 0;
|
|
198
|
+
});
|
|
199
|
+
}
|
|
200
|
+
areaGenerator.curve(curveFunction).defined(d => connectNulls || d.isValid && d.low != null && d.high != null);
|
|
178
201
|
const result = areaGenerator(filteredPoints);
|
|
179
202
|
return result !== null && result !== void 0 ? result : '';
|
|
180
203
|
};
|
|
@@ -206,22 +229,26 @@ export const lineToPath = (x1, y1, x2, y2) => {
|
|
|
206
229
|
* const roundedPath = getBarPath(10, 20, 50, 100, 8, true, false);
|
|
207
230
|
* ```
|
|
208
231
|
*/
|
|
209
|
-
export const getBarPath = (x, y, width, height, radius, roundTop, roundBottom)
|
|
232
|
+
export const getBarPath = function (x, y, width, height, radius, roundTop, roundBottom) {
|
|
233
|
+
let layout = arguments.length > 7 && arguments[7] !== undefined ? arguments[7] : 'vertical';
|
|
234
|
+
const isVerticalLayout = layout === 'vertical';
|
|
210
235
|
const roundBothSides = roundTop && roundBottom;
|
|
211
236
|
const r = Math.min(radius, width / 2, roundBothSides ? height / 2 : height);
|
|
212
|
-
const
|
|
213
|
-
const
|
|
237
|
+
const rTL = isVerticalLayout ? roundTop ? r : 0 : roundBottom ? r : 0;
|
|
238
|
+
const rTR = isVerticalLayout ? roundTop ? r : 0 : roundTop ? r : 0;
|
|
239
|
+
const rBR = isVerticalLayout ? roundBottom ? r : 0 : roundTop ? r : 0;
|
|
240
|
+
const rBL = isVerticalLayout ? roundBottom ? r : 0 : roundBottom ? r : 0;
|
|
214
241
|
|
|
215
242
|
// Build path with selective rounding
|
|
216
|
-
let path = "M ".concat(x +
|
|
217
|
-
path += " L ".concat(x + width -
|
|
218
|
-
path += " A ".concat(
|
|
219
|
-
path += " L ".concat(x + width, " ").concat(y + height -
|
|
220
|
-
path += " A ".concat(
|
|
221
|
-
path += " L ".concat(x +
|
|
222
|
-
path += " A ".concat(
|
|
223
|
-
path += " L ".concat(x, " ").concat(y +
|
|
224
|
-
path += " A ".concat(
|
|
243
|
+
let path = "M ".concat(x + rTL, " ").concat(y);
|
|
244
|
+
path += " L ".concat(x + width - rTR, " ").concat(y);
|
|
245
|
+
path += " A ".concat(rTR, " ").concat(rTR, " 0 0 1 ").concat(x + width, " ").concat(y + rTR);
|
|
246
|
+
path += " L ".concat(x + width, " ").concat(y + height - rBR);
|
|
247
|
+
path += " A ".concat(rBR, " ").concat(rBR, " 0 0 1 ").concat(x + width - rBR, " ").concat(y + height);
|
|
248
|
+
path += " L ".concat(x + rBL, " ").concat(y + height);
|
|
249
|
+
path += " A ".concat(rBL, " ").concat(rBL, " 0 0 1 ").concat(x, " ").concat(y + height - rBL);
|
|
250
|
+
path += " L ".concat(x, " ").concat(y + rTL);
|
|
251
|
+
path += " A ".concat(rTL, " ").concat(rTL, " 0 0 1 ").concat(x + rTL, " ").concat(y);
|
|
225
252
|
path += ' Z';
|
|
226
253
|
return path;
|
|
227
254
|
};
|
package/esm/chart/utils/point.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { isCategoricalScale, isLogScale
|
|
1
|
+
import { isCategoricalScale, isLogScale } from './scale';
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
4
|
* Position a label should be placed relative to the point
|
|
@@ -10,19 +10,36 @@ import { isCategoricalScale, isLogScale, isNumericScale } from './scale';
|
|
|
10
10
|
|
|
11
11
|
/**
|
|
12
12
|
* Get a point from a data value and a scale.
|
|
13
|
-
*
|
|
14
|
-
* @
|
|
15
|
-
* @param
|
|
16
|
-
* @param
|
|
17
|
-
* @returns
|
|
13
|
+
*
|
|
14
|
+
* @param dataValue - The data value to convert to a pixel position.
|
|
15
|
+
* @param scale - The scale function.
|
|
16
|
+
* @param anchor (@default 'middle') - For band scales, where to anchor the point within the band.
|
|
17
|
+
* @returns The pixel value (@default 0 if data value is not defined in scale).
|
|
18
18
|
*/
|
|
19
|
-
export const getPointOnScale = (dataValue, scale)
|
|
20
|
-
var
|
|
19
|
+
export const getPointOnScale = function (dataValue, scale) {
|
|
20
|
+
var _scale;
|
|
21
|
+
let anchor = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 'middle';
|
|
21
22
|
if (isCategoricalScale(scale)) {
|
|
22
|
-
var
|
|
23
|
-
const
|
|
24
|
-
const
|
|
25
|
-
|
|
23
|
+
var _bandScale$bandwidth, _bandScale$bandwidth2, _bandScale$step, _bandScale$step2;
|
|
24
|
+
const bandScale = scale;
|
|
25
|
+
const bandStart = bandScale(dataValue);
|
|
26
|
+
if (bandStart === undefined) return 0;
|
|
27
|
+
const bandwidth = (_bandScale$bandwidth = (_bandScale$bandwidth2 = bandScale.bandwidth) === null || _bandScale$bandwidth2 === void 0 ? void 0 : _bandScale$bandwidth2.call(bandScale)) !== null && _bandScale$bandwidth !== void 0 ? _bandScale$bandwidth : 0;
|
|
28
|
+
const step = (_bandScale$step = (_bandScale$step2 = bandScale.step) === null || _bandScale$step2 === void 0 ? void 0 : _bandScale$step2.call(bandScale)) !== null && _bandScale$step !== void 0 ? _bandScale$step : bandwidth;
|
|
29
|
+
const paddingOffset = (step - bandwidth) / 2;
|
|
30
|
+
const stepStart = bandStart - paddingOffset;
|
|
31
|
+
switch (anchor) {
|
|
32
|
+
case 'stepStart':
|
|
33
|
+
return stepStart;
|
|
34
|
+
case 'bandStart':
|
|
35
|
+
return bandStart;
|
|
36
|
+
case 'middle':
|
|
37
|
+
return bandStart + bandwidth / 2;
|
|
38
|
+
case 'bandEnd':
|
|
39
|
+
return bandStart + bandwidth;
|
|
40
|
+
case 'stepEnd':
|
|
41
|
+
return stepStart + step;
|
|
42
|
+
}
|
|
26
43
|
}
|
|
27
44
|
|
|
28
45
|
// For log scales, ensure the value is positive
|
|
@@ -30,7 +47,7 @@ export const getPointOnScale = (dataValue, scale) => {
|
|
|
30
47
|
if (isLogScale(scale) && dataValue <= 0) {
|
|
31
48
|
adjustedValue = 0.001; // Use a small positive value for log scales
|
|
32
49
|
}
|
|
33
|
-
return (
|
|
50
|
+
return (_scale = scale(adjustedValue)) !== null && _scale !== void 0 ? _scale : 0;
|
|
34
51
|
};
|
|
35
52
|
|
|
36
53
|
/**
|
|
@@ -79,7 +96,8 @@ export const projectPoints = _ref2 => {
|
|
|
79
96
|
xScale,
|
|
80
97
|
yScale,
|
|
81
98
|
xData,
|
|
82
|
-
yData
|
|
99
|
+
yData,
|
|
100
|
+
layout = 'vertical'
|
|
83
101
|
} = _ref2;
|
|
84
102
|
if (data.length === 0) {
|
|
85
103
|
return [];
|
|
@@ -97,28 +115,37 @@ export const projectPoints = _ref2 => {
|
|
|
97
115
|
});
|
|
98
116
|
}
|
|
99
117
|
|
|
100
|
-
//
|
|
101
|
-
|
|
118
|
+
// Determine values/scales based on role (index vs value) and layout.
|
|
119
|
+
const categoryAxisIsX = layout !== 'horizontal';
|
|
120
|
+
const indexScale = categoryAxisIsX ? xScale : yScale;
|
|
121
|
+
const indexData = categoryAxisIsX ? xData : yData;
|
|
102
122
|
|
|
103
|
-
//
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
if (
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
const numericXData = xData;
|
|
111
|
-
xValue = (_numericXData$index = numericXData[index]) !== null && _numericXData$index !== void 0 ? _numericXData$index : index;
|
|
123
|
+
// 1. Calculate position along the index axis (categorical or numeric domain).
|
|
124
|
+
let indexValue = index;
|
|
125
|
+
if (!isCategoricalScale(indexScale)) {
|
|
126
|
+
if (indexData && Array.isArray(indexData) && indexData.length > 0) {
|
|
127
|
+
if (typeof indexData[0] === 'number') {
|
|
128
|
+
var _index;
|
|
129
|
+
indexValue = (_index = indexData[index]) !== null && _index !== void 0 ? _index : index;
|
|
112
130
|
}
|
|
113
131
|
}
|
|
114
132
|
}
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
133
|
+
|
|
134
|
+
// 2. Calculate position along the value axis (measured magnitude).
|
|
135
|
+
const valueAsNumber = value;
|
|
136
|
+
|
|
137
|
+
// 3. Project final coordinates based on layout.
|
|
138
|
+
if (categoryAxisIsX) {
|
|
139
|
+
return projectPoint({
|
|
140
|
+
x: indexValue,
|
|
141
|
+
y: valueAsNumber,
|
|
142
|
+
xScale,
|
|
143
|
+
yScale
|
|
144
|
+
});
|
|
118
145
|
}
|
|
119
146
|
return projectPoint({
|
|
120
|
-
x:
|
|
121
|
-
y:
|
|
147
|
+
x: valueAsNumber,
|
|
148
|
+
y: indexValue,
|
|
122
149
|
xScale,
|
|
123
150
|
yScale
|
|
124
151
|
});
|
package/esm/chart/utils/scale.js
CHANGED
|
@@ -43,6 +43,17 @@ export const getCategoricalScale = _ref2 => {
|
|
|
43
43
|
const domainArray = Array.from({
|
|
44
44
|
length: domain.max - domain.min + 1
|
|
45
45
|
}, (_, i) => i);
|
|
46
|
-
const scale = scaleBand().domain(domainArray).range([range.min, range.max]).padding(padding);
|
|
46
|
+
const scale = scaleBand().domain(domainArray).range([range.min, range.max]).paddingInner(padding).paddingOuter(padding / 2);
|
|
47
47
|
return scale;
|
|
48
|
-
};
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Anchor position for points on a scale. Currently used only for band scales.
|
|
52
|
+
*
|
|
53
|
+
* For band scales, this determines where within the band to position a point:
|
|
54
|
+
* - `'stepStart'` - At the start of the step
|
|
55
|
+
* - `'bandStart'` - At the start of the band
|
|
56
|
+
* - `'middle'` - At the center of the band
|
|
57
|
+
* - `'bandEnd'` - At the end of the band
|
|
58
|
+
* - `'stepEnd'` - At the end of the step
|
|
59
|
+
*/
|
|
@@ -1,15 +1,20 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Determines which side (left/right) to place scrubber labels based on available space.
|
|
3
|
-
*
|
|
3
|
+
* Honors the preferred side when there's enough space, otherwise switches to the opposite side.
|
|
4
4
|
*/
|
|
5
5
|
export const getLabelPosition = function (beaconX, maxLabelWidth, drawingArea) {
|
|
6
6
|
let xOffset = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : 16;
|
|
7
|
+
let preferredSide = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : 'right';
|
|
7
8
|
if (drawingArea.width <= 0 || drawingArea.height <= 0) {
|
|
8
|
-
return
|
|
9
|
+
return preferredSide;
|
|
9
10
|
}
|
|
10
|
-
const availableRightSpace = drawingArea.x + drawingArea.width - beaconX;
|
|
11
11
|
const requiredSpace = maxLabelWidth + xOffset;
|
|
12
|
-
|
|
12
|
+
if (preferredSide === 'right') {
|
|
13
|
+
const availableSpace = drawingArea.x + drawingArea.width - beaconX;
|
|
14
|
+
return requiredSpace <= availableSpace ? 'right' : 'left';
|
|
15
|
+
}
|
|
16
|
+
const availableSpace = beaconX - drawingArea.x;
|
|
17
|
+
return requiredSpace <= availableSpace ? 'left' : 'right';
|
|
13
18
|
};
|
|
14
19
|
/**
|
|
15
20
|
* Calculates Y positions for all labels avoiding overlaps while maintaining order.
|