@gravity-ui/charts 1.30.1 → 1.32.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cjs/components/AxisX/AxisX.js +6 -4
- package/dist/cjs/components/AxisX/prepare-axis-data.js +2 -0
- package/dist/cjs/components/AxisX/types.d.ts +1 -0
- package/dist/cjs/components/AxisY/AxisY.js +4 -2
- package/dist/cjs/components/AxisY/prepare-axis-data.js +2 -0
- package/dist/cjs/components/AxisY/types.d.ts +1 -0
- package/dist/cjs/components/ChartInner/index.js +7 -1
- package/dist/cjs/components/ChartInner/types.d.ts +6 -0
- package/dist/cjs/components/index.d.ts +1 -0
- package/dist/cjs/components/index.js +4 -4
- package/dist/cjs/components/utils.js +2 -2
- package/dist/cjs/constants/line-styles.d.ts +6 -0
- package/dist/cjs/constants/line-styles.js +7 -0
- package/dist/cjs/hooks/useAxis/types.d.ts +2 -0
- package/dist/cjs/hooks/useAxis/utils.d.ts +1 -0
- package/dist/cjs/hooks/useAxis/utils.js +2 -1
- package/dist/cjs/hooks/useChartOptions/title.js +1 -1
- package/dist/cjs/hooks/useSeries/prepare-line.js +8 -1
- package/dist/cjs/hooks/useSeries/types.d.ts +2 -1
- package/dist/cjs/hooks/useShapes/area/prepare-data.d.ts +1 -0
- package/dist/cjs/hooks/useShapes/area/prepare-data.js +2 -2
- package/dist/cjs/hooks/useShapes/bar-x/prepare-data.d.ts +1 -0
- package/dist/cjs/hooks/useShapes/bar-x/prepare-data.js +15 -6
- package/dist/cjs/hooks/useShapes/index.js +2 -0
- package/dist/cjs/hooks/useShapes/line/index.js +1 -1
- package/dist/cjs/hooks/useShapes/line/prepare-data.js +2 -1
- package/dist/cjs/hooks/useShapes/line/types.d.ts +2 -1
- package/dist/cjs/types/chart/axis.d.ts +3 -0
- package/dist/cjs/types/chart/line.d.ts +3 -1
- package/dist/cjs/types/chart/series.d.ts +6 -1
- package/dist/cjs/utils/chart/index.d.ts +1 -1
- package/dist/cjs/utils/chart/index.js +23 -19
- package/dist/esm/components/AxisX/AxisX.js +6 -4
- package/dist/esm/components/AxisX/prepare-axis-data.js +2 -0
- package/dist/esm/components/AxisX/types.d.ts +1 -0
- package/dist/esm/components/AxisY/AxisY.js +4 -2
- package/dist/esm/components/AxisY/prepare-axis-data.js +2 -0
- package/dist/esm/components/AxisY/types.d.ts +1 -0
- package/dist/esm/components/ChartInner/index.js +7 -1
- package/dist/esm/components/ChartInner/types.d.ts +6 -0
- package/dist/esm/components/index.d.ts +1 -0
- package/dist/esm/components/index.js +4 -4
- package/dist/esm/components/utils.js +2 -2
- package/dist/esm/constants/line-styles.d.ts +6 -0
- package/dist/esm/constants/line-styles.js +7 -0
- package/dist/esm/hooks/useAxis/types.d.ts +2 -0
- package/dist/esm/hooks/useAxis/utils.d.ts +1 -0
- package/dist/esm/hooks/useAxis/utils.js +2 -1
- package/dist/esm/hooks/useChartOptions/title.js +1 -1
- package/dist/esm/hooks/useSeries/prepare-line.js +8 -1
- package/dist/esm/hooks/useSeries/types.d.ts +2 -1
- package/dist/esm/hooks/useShapes/area/prepare-data.d.ts +1 -0
- package/dist/esm/hooks/useShapes/area/prepare-data.js +2 -2
- package/dist/esm/hooks/useShapes/bar-x/prepare-data.d.ts +1 -0
- package/dist/esm/hooks/useShapes/bar-x/prepare-data.js +15 -6
- package/dist/esm/hooks/useShapes/index.js +2 -0
- package/dist/esm/hooks/useShapes/line/index.js +1 -1
- package/dist/esm/hooks/useShapes/line/prepare-data.js +2 -1
- package/dist/esm/hooks/useShapes/line/types.d.ts +2 -1
- package/dist/esm/types/chart/axis.d.ts +3 -0
- package/dist/esm/types/chart/line.d.ts +3 -1
- package/dist/esm/types/chart/series.d.ts +6 -1
- package/dist/esm/utils/chart/index.d.ts +1 -1
- package/dist/esm/utils/chart/index.js +23 -19
- package/package.json +1 -1
|
@@ -112,7 +112,7 @@ export const AxisX = (props) => {
|
|
|
112
112
|
.attr('fill', (d) => d.color)
|
|
113
113
|
.attr('opacity', (d) => d.opacity);
|
|
114
114
|
plotBandsSelection.each(function () {
|
|
115
|
-
var _a, _b;
|
|
115
|
+
var _a, _b, _c;
|
|
116
116
|
const plotBandSelection = select(this);
|
|
117
117
|
const band = plotBandSelection.datum();
|
|
118
118
|
const label = band.label;
|
|
@@ -125,7 +125,8 @@ export const AxisX = (props) => {
|
|
|
125
125
|
.style('font-weight', (_b = label.style.fontWeight) !== null && _b !== void 0 ? _b : '')
|
|
126
126
|
.style('dominant-baseline', 'text-before-edge')
|
|
127
127
|
.style('text-anchor', 'start')
|
|
128
|
-
.style('transform', `translate(${label.x}px, ${label.y}px) rotate(${label.rotate}deg)`)
|
|
128
|
+
.style('transform', `translate(${label.x}px, ${label.y}px) rotate(${label.rotate}deg)`)
|
|
129
|
+
.attr('data-qa', (_c = label.qa) !== null && _c !== void 0 ? _c : null);
|
|
129
130
|
}
|
|
130
131
|
});
|
|
131
132
|
};
|
|
@@ -153,7 +154,7 @@ export const AxisX = (props) => {
|
|
|
153
154
|
.attr('stroke-dasharray', (d) => getLineDashArray(d.dashStyle, d.lineWidth))
|
|
154
155
|
.attr('opacity', (d) => d.opacity);
|
|
155
156
|
plotLinesSelection.each(function () {
|
|
156
|
-
var _a, _b;
|
|
157
|
+
var _a, _b, _c;
|
|
157
158
|
const itemSelection = select(this);
|
|
158
159
|
const plotLine = itemSelection.datum();
|
|
159
160
|
const label = plotLine.label;
|
|
@@ -166,7 +167,8 @@ export const AxisX = (props) => {
|
|
|
166
167
|
.style('font-weight', (_b = label.style.fontWeight) !== null && _b !== void 0 ? _b : '')
|
|
167
168
|
.style('dominant-baseline', 'text-before-edge')
|
|
168
169
|
.style('text-anchor', 'start')
|
|
169
|
-
.style('transform', `translate(${label.x}px, ${label.y}px) rotate(${label.rotate}deg)`)
|
|
170
|
+
.style('transform', `translate(${label.x}px, ${label.y}px) rotate(${label.rotate}deg)`)
|
|
171
|
+
.attr('data-qa', (_c = label.qa) !== null && _c !== void 0 ? _c : null);
|
|
170
172
|
}
|
|
171
173
|
});
|
|
172
174
|
};
|
|
@@ -263,6 +263,7 @@ export async function prepareXAxisData({ axis, yAxis, scale, boundsWidth, bounds
|
|
|
263
263
|
x: plotBand.label.padding,
|
|
264
264
|
y: plotBand.label.padding + ((_f = labelSize === null || labelSize === void 0 ? void 0 : labelSize.width) !== null && _f !== void 0 ? _f : 0),
|
|
265
265
|
rotate: -90,
|
|
266
|
+
qa: plotBand.label.qa,
|
|
266
267
|
}
|
|
267
268
|
: null,
|
|
268
269
|
});
|
|
@@ -289,6 +290,7 @@ export async function prepareXAxisData({ axis, yAxis, scale, boundsWidth, bounds
|
|
|
289
290
|
x: plotLineValue - plotLine.label.padding - size.height,
|
|
290
291
|
y: plotLine.label.padding + size.width,
|
|
291
292
|
rotate: -90,
|
|
293
|
+
qa: plotLine.label.qa,
|
|
292
294
|
};
|
|
293
295
|
}
|
|
294
296
|
plotLines.push({
|
|
@@ -118,7 +118,7 @@ export const AxisY = (props) => {
|
|
|
118
118
|
.attr('fill', (d) => d.color)
|
|
119
119
|
.attr('opacity', (d) => d.opacity);
|
|
120
120
|
plotBandsSelection.each(function () {
|
|
121
|
-
var _a, _b;
|
|
121
|
+
var _a, _b, _c;
|
|
122
122
|
const plotBandSelection = select(this);
|
|
123
123
|
const band = plotBandSelection.datum();
|
|
124
124
|
const label = band.label;
|
|
@@ -130,6 +130,7 @@ export const AxisY = (props) => {
|
|
|
130
130
|
.style('font-size', label.style.fontSize)
|
|
131
131
|
.style('font-weight', (_b = label.style.fontWeight) !== null && _b !== void 0 ? _b : '')
|
|
132
132
|
.style('dominant-baseline', 'text-before-edge')
|
|
133
|
+
.attr('data-qa', (_c = label.qa) !== null && _c !== void 0 ? _c : null)
|
|
133
134
|
.attr('x', label.x)
|
|
134
135
|
.attr('y', label.y);
|
|
135
136
|
}
|
|
@@ -159,7 +160,7 @@ export const AxisY = (props) => {
|
|
|
159
160
|
.attr('stroke-dasharray', (d) => getLineDashArray(d.dashStyle, d.lineWidth))
|
|
160
161
|
.attr('opacity', (d) => d.opacity);
|
|
161
162
|
plotLinesSelection.each(function () {
|
|
162
|
-
var _a, _b;
|
|
163
|
+
var _a, _b, _c;
|
|
163
164
|
const itemSelection = select(this);
|
|
164
165
|
const plotLine = itemSelection.datum();
|
|
165
166
|
const label = plotLine.label;
|
|
@@ -171,6 +172,7 @@ export const AxisY = (props) => {
|
|
|
171
172
|
.style('font-size', label.style.fontSize)
|
|
172
173
|
.style('font-weight', (_b = label.style.fontWeight) !== null && _b !== void 0 ? _b : '')
|
|
173
174
|
.style('dominant-baseline', 'text-before-edge')
|
|
175
|
+
.attr('data-qa', (_c = label.qa) !== null && _c !== void 0 ? _c : null)
|
|
174
176
|
.attr('x', label.x)
|
|
175
177
|
.attr('y', label.y);
|
|
176
178
|
}
|
|
@@ -229,6 +229,7 @@ export async function prepareYAxisData({ axis, split, scale, top: topOffset, wid
|
|
|
229
229
|
style: plotBand.label.style,
|
|
230
230
|
x: plotBand.label.padding,
|
|
231
231
|
y: plotBand.label.padding,
|
|
232
|
+
qa: plotBand.label.qa,
|
|
232
233
|
}
|
|
233
234
|
: null,
|
|
234
235
|
});
|
|
@@ -254,6 +255,7 @@ export async function prepareYAxisData({ axis, split, scale, top: topOffset, wid
|
|
|
254
255
|
style: plotLine.label.style,
|
|
255
256
|
x: plotLine.label.padding,
|
|
256
257
|
y: Math.max(0, plotLineValue - size.height - plotLine.label.padding),
|
|
258
|
+
qa: plotLine.label.qa,
|
|
257
259
|
};
|
|
258
260
|
}
|
|
259
261
|
plotLines.push({
|
|
@@ -26,7 +26,7 @@ const b = block('chart');
|
|
|
26
26
|
const DEBOUNCED_VALUE_DELAY = 10;
|
|
27
27
|
export const ChartInner = (props) => {
|
|
28
28
|
var _a, _b, _c, _d, _e, _f;
|
|
29
|
-
const { width, height, data } = props;
|
|
29
|
+
const { width, height, data, onReady } = props;
|
|
30
30
|
const svgRef = React.useRef(null);
|
|
31
31
|
const resetZoomButtonRef = React.useRef(null);
|
|
32
32
|
const [htmlLayout, setHtmlLayout] = React.useState(null);
|
|
@@ -206,6 +206,12 @@ export const ChartInner = (props) => {
|
|
|
206
206
|
updateRangeSliderState,
|
|
207
207
|
xScale,
|
|
208
208
|
]);
|
|
209
|
+
const areShapesReady = shapes.length > 0;
|
|
210
|
+
React.useEffect(() => {
|
|
211
|
+
if (areShapesReady) {
|
|
212
|
+
onReady === null || onReady === void 0 ? void 0 : onReady({ dimensions: { width, height } });
|
|
213
|
+
}
|
|
214
|
+
}, [height, areShapesReady, onReady, width]);
|
|
209
215
|
const chartContent = (React.createElement(React.Fragment, null,
|
|
210
216
|
React.createElement("defs", null,
|
|
211
217
|
React.createElement("clipPath", { id: clipPathId },
|
|
@@ -7,7 +7,7 @@ import { validateData } from '../validation';
|
|
|
7
7
|
import { ChartInner } from './ChartInner';
|
|
8
8
|
export * from './Tooltip/ChartTooltipContent';
|
|
9
9
|
export const Chart = React.forwardRef(function Chart(props, forwardedRef) {
|
|
10
|
-
const { data, lang, onResize } = props;
|
|
10
|
+
const { data, lang, onResize, onReady } = props;
|
|
11
11
|
const validatedData = React.useRef();
|
|
12
12
|
const ref = React.useRef(null);
|
|
13
13
|
const debounced = React.useRef();
|
|
@@ -36,8 +36,8 @@ export const Chart = React.forwardRef(function Chart(props, forwardedRef) {
|
|
|
36
36
|
}), [debuncedHandleResize]);
|
|
37
37
|
React.useEffect(() => {
|
|
38
38
|
// dimensions initialize
|
|
39
|
-
|
|
40
|
-
}, [
|
|
39
|
+
handleResize();
|
|
40
|
+
}, [handleResize]);
|
|
41
41
|
React.useEffect(() => {
|
|
42
42
|
const selection = select(window);
|
|
43
43
|
// https://github.com/d3/d3-selection/blob/main/README.md#handling-events
|
|
@@ -62,5 +62,5 @@ export const Chart = React.forwardRef(function Chart(props, forwardedRef) {
|
|
|
62
62
|
width: (dimensions === null || dimensions === void 0 ? void 0 : dimensions.width) || '100%',
|
|
63
63
|
height: (dimensions === null || dimensions === void 0 ? void 0 : dimensions.height) || '100%',
|
|
64
64
|
position: 'relative',
|
|
65
|
-
} }, (dimensions === null || dimensions === void 0 ? void 0 : dimensions.height) && (dimensions === null || dimensions === void 0 ? void 0 : dimensions.width) && (React.createElement(ChartInner, { height: dimensions === null || dimensions === void 0 ? void 0 : dimensions.height, width: dimensions === null || dimensions === void 0 ? void 0 : dimensions.width, data: data }))));
|
|
65
|
+
} }, (dimensions === null || dimensions === void 0 ? void 0 : dimensions.height) && (dimensions === null || dimensions === void 0 ? void 0 : dimensions.width) && (React.createElement(ChartInner, { height: dimensions === null || dimensions === void 0 ? void 0 : dimensions.height, width: dimensions === null || dimensions === void 0 ? void 0 : dimensions.width, data: data, onReady: onReady }))));
|
|
66
66
|
});
|
|
@@ -49,8 +49,8 @@ export function appendLinePathElement({ svgRootElement, height, width, x = 0, li
|
|
|
49
49
|
.attr('d', legendSymbolGenerator(points))
|
|
50
50
|
.attr('fill', 'none')
|
|
51
51
|
.attr('stroke-width', lineWidth)
|
|
52
|
-
.attr('
|
|
53
|
-
.
|
|
52
|
+
.attr('stroke', color !== null && color !== void 0 ? color : '')
|
|
53
|
+
.attr('class', className !== null && className !== void 0 ? className : null);
|
|
54
54
|
if (dashStyle) {
|
|
55
55
|
pathElement.attr('stroke-dasharray', getLineDashArray(dashStyle, lineWidth));
|
|
56
56
|
}
|
|
@@ -18,3 +18,10 @@ export var LineCap;
|
|
|
18
18
|
LineCap["Square"] = "square";
|
|
19
19
|
LineCap["None"] = "none";
|
|
20
20
|
})(LineCap || (LineCap = {}));
|
|
21
|
+
export var LineJoin;
|
|
22
|
+
(function (LineJoin) {
|
|
23
|
+
LineJoin["Round"] = "round";
|
|
24
|
+
LineJoin["Bevel"] = "bevel";
|
|
25
|
+
LineJoin["Miter"] = "miter";
|
|
26
|
+
LineJoin["None"] = "unset";
|
|
27
|
+
})(LineJoin || (LineJoin = {}));
|
|
@@ -13,6 +13,7 @@ export type PreparedAxisPlotBand = Required<AxisPlotBand> & {
|
|
|
13
13
|
text: string;
|
|
14
14
|
style: BaseTextStyle;
|
|
15
15
|
padding: number;
|
|
16
|
+
qa?: string;
|
|
16
17
|
};
|
|
17
18
|
};
|
|
18
19
|
type PreparedAxisCrosshair = Required<AxisCrosshair>;
|
|
@@ -27,6 +28,7 @@ export type PreparedAxisPlotLine = {
|
|
|
27
28
|
text: string;
|
|
28
29
|
style: BaseTextStyle;
|
|
29
30
|
padding: number;
|
|
31
|
+
qa?: string;
|
|
30
32
|
};
|
|
31
33
|
};
|
|
32
34
|
export type PreparedRangeSlider = DeepRequired<Omit<ChartAxisRangeSlider, 'defaultRange'>> & {
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import { DEFAULT_AXIS_LABEL_FONT_SIZE } from '../../constants';
|
|
2
2
|
export function prepareAxisPlotLabel(d) {
|
|
3
|
-
var _a, _b, _c, _d, _e;
|
|
3
|
+
var _a, _b, _c, _d, _e, _f;
|
|
4
4
|
return {
|
|
5
5
|
text: (_b = (_a = d.label) === null || _a === void 0 ? void 0 : _a.text) !== null && _b !== void 0 ? _b : '',
|
|
6
6
|
style: Object.assign({ fontSize: DEFAULT_AXIS_LABEL_FONT_SIZE, fontColor: 'var(--g-color-text-secondary)' }, (_c = d.label) === null || _c === void 0 ? void 0 : _c.style),
|
|
7
7
|
padding: (_e = (_d = d.label) === null || _d === void 0 ? void 0 : _d.padding) !== null && _e !== void 0 ? _e : 5,
|
|
8
|
+
qa: (_f = d.label) === null || _f === void 0 ? void 0 : _f.qa,
|
|
8
9
|
};
|
|
9
10
|
}
|
|
@@ -14,7 +14,7 @@ export const getPreparedTitle = ({ title, }) => {
|
|
|
14
14
|
? getHorizontalSvgTextHeight({ text: titleText, style: titleStyle }) + TITLE_PADDINGS
|
|
15
15
|
: 0;
|
|
16
16
|
const preparedTitle = titleText
|
|
17
|
-
? { text: titleText, style: titleStyle, height: titleHeight }
|
|
17
|
+
? { text: titleText, style: titleStyle, height: titleHeight, qa: title === null || title === void 0 ? void 0 : title.qa }
|
|
18
18
|
: undefined;
|
|
19
19
|
return preparedTitle;
|
|
20
20
|
};
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import get from 'lodash/get';
|
|
2
2
|
import merge from 'lodash/merge';
|
|
3
|
-
import { DASH_STYLE, DEFAULT_DATALABELS_STYLE, LineCap, seriesRangeSliderOptionsDefaults, } from '../../constants';
|
|
3
|
+
import { DASH_STYLE, DEFAULT_DATALABELS_STYLE, LineCap, LineJoin, seriesRangeSliderOptionsDefaults, } from '../../constants';
|
|
4
4
|
import { getUniqId } from '../../utils';
|
|
5
5
|
import { DEFAULT_DATALABELS_PADDING, DEFAULT_HALO_OPTIONS, DEFAULT_LEGEND_SYMBOL_PADDING, DEFAULT_POINT_MARKER_OPTIONS, } from './constants';
|
|
6
6
|
export const DEFAULT_LEGEND_SYMBOL_SIZE = 16;
|
|
@@ -12,6 +12,12 @@ function prepareLinecap(dashStyle, series, seriesOptions) {
|
|
|
12
12
|
const lineCapFromSeriesOptions = get(seriesOptions, 'line.linecap', defaultLineCap);
|
|
13
13
|
return get(series, 'linecap', lineCapFromSeriesOptions);
|
|
14
14
|
}
|
|
15
|
+
function prepareLinejoin(dashStyle, series, seriesOptions) {
|
|
16
|
+
var _a, _b, _c;
|
|
17
|
+
const defaultLinejoin = dashStyle === DASH_STYLE.Solid ? LineJoin.Round : LineJoin.None;
|
|
18
|
+
const linejoinFromSeriesOptions = (_b = (_a = seriesOptions === null || seriesOptions === void 0 ? void 0 : seriesOptions.line) === null || _a === void 0 ? void 0 : _a.linejoin) !== null && _b !== void 0 ? _b : defaultLinejoin;
|
|
19
|
+
return ((_c = series === null || series === void 0 ? void 0 : series.linejoin) !== null && _c !== void 0 ? _c : linejoinFromSeriesOptions);
|
|
20
|
+
}
|
|
15
21
|
function prepareLineLegendSymbol(series, seriesOptions) {
|
|
16
22
|
var _a;
|
|
17
23
|
const symbolOptions = ((_a = series.legend) === null || _a === void 0 ? void 0 : _a.symbol) || {};
|
|
@@ -90,6 +96,7 @@ export function prepareLineSeries(args) {
|
|
|
90
96
|
marker: prepareMarker(series, seriesOptions),
|
|
91
97
|
dashStyle: dashStyle,
|
|
92
98
|
linecap: prepareLinecap(dashStyle, series, seriesOptions),
|
|
99
|
+
linejoin: prepareLinejoin(dashStyle, series, seriesOptions),
|
|
93
100
|
opacity: get(series, 'opacity', null),
|
|
94
101
|
cursor: get(series, 'cursor', null),
|
|
95
102
|
yAxis: get(series, 'yAxis', 0),
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { DashStyle, LayoutAlgorithm, LineCap, SeriesOptionsDefaults, SymbolType } from '../../constants';
|
|
1
|
+
import type { DashStyle, LayoutAlgorithm, LineCap, LineJoin, SeriesOptionsDefaults, SymbolType } from '../../constants';
|
|
2
2
|
import type { AreaSeries, AreaSeriesData, BarXSeries, BarXSeriesData, BarYSeries, BarYSeriesData, BaseTextStyle, ChartLegend, ChartSeries, ChartSeriesRangeSliderOptions, ConnectorCurve, ConnectorShape, FunnelSeries, FunnelSeriesData, HeatmapSeries, HeatmapSeriesData, LineSeries, LineSeriesData, LineSeriesLineBaseStyle, PathLegendSymbolOptions, PieSeries, PieSeriesData, RadarSeries, RadarSeriesCategory, RadarSeriesData, RectLegendSymbolOptions, SankeySeries, SankeySeriesData, ScatterSeries, ScatterSeriesData, SymbolLegendSymbolOptions, TreemapSeries, TreemapSeriesData, ValueFormat, WaterfallSeries, WaterfallSeriesData } from '../../types';
|
|
3
3
|
export type RectLegendSymbol = {
|
|
4
4
|
shape: 'rect';
|
|
@@ -222,6 +222,7 @@ export type PreparedLineSeries = {
|
|
|
222
222
|
};
|
|
223
223
|
dashStyle: DashStyle;
|
|
224
224
|
linecap: LineCap;
|
|
225
|
+
linejoin: LineJoin;
|
|
225
226
|
opacity: number | null;
|
|
226
227
|
yAxis: number;
|
|
227
228
|
} & BasePreparedSeries & BasePreparedAxisRelatedSeries;
|
|
@@ -74,7 +74,7 @@ async function prepareDataLabels({ series, points, xMax, yAxisTop, }) {
|
|
|
74
74
|
}
|
|
75
75
|
export const prepareAreaData = async (args) => {
|
|
76
76
|
var _a, _b;
|
|
77
|
-
const { series, xAxis, xScale, yAxis, yScale, boundsHeight: plotHeight, split, isOutsideBounds, } = args;
|
|
77
|
+
const { series, xAxis, xScale, yAxis, yScale, boundsHeight: plotHeight, split, isOutsideBounds, isRangeSlider, } = args;
|
|
78
78
|
const [_xMin, xRangeMax] = xScale.range();
|
|
79
79
|
const xMax = xRangeMax;
|
|
80
80
|
const result = [];
|
|
@@ -147,7 +147,7 @@ export const prepareAreaData = async (args) => {
|
|
|
147
147
|
}, []);
|
|
148
148
|
const labels = [];
|
|
149
149
|
const htmlElements = [];
|
|
150
|
-
if (s.dataLabels.enabled) {
|
|
150
|
+
if (s.dataLabels.enabled && !isRangeSlider) {
|
|
151
151
|
const labelsData = await prepareDataLabels({ series: s, points, xMax, yAxisTop });
|
|
152
152
|
labels.push(...labelsData.svgLabels);
|
|
153
153
|
htmlElements.push(...labelsData.htmlLabels);
|
|
@@ -35,7 +35,7 @@ async function getLabelData(d) {
|
|
|
35
35
|
// eslint-disable-next-line complexity
|
|
36
36
|
export const prepareBarXData = async (args) => {
|
|
37
37
|
var _a, _b, _c, _d;
|
|
38
|
-
const { series, seriesOptions, xAxis, xScale, yAxis, yScale, boundsHeight: plotHeight, split, } = args;
|
|
38
|
+
const { series, seriesOptions, xAxis, xScale, yAxis, yScale, boundsHeight: plotHeight, split, isRangeSlider, } = args;
|
|
39
39
|
const stackGap = seriesOptions['bar-x'].stackGap;
|
|
40
40
|
const categories = (_a = xAxis === null || xAxis === void 0 ? void 0 : xAxis.categories) !== null && _a !== void 0 ? _a : [];
|
|
41
41
|
const sortingOptions = get(seriesOptions, 'bar-x.dataSorting');
|
|
@@ -99,7 +99,8 @@ export const prepareBarXData = async (args) => {
|
|
|
99
99
|
const currentGroupWidth = rectWidth * stacks.length + rectGap * (stacks.length - 1);
|
|
100
100
|
for (let groupItemIndex = 0; groupItemIndex < stacks.length; groupItemIndex++) {
|
|
101
101
|
const yValues = stacks[groupItemIndex];
|
|
102
|
-
let
|
|
102
|
+
let positiveStackHeight = 0;
|
|
103
|
+
let negativeStackHeight = 0;
|
|
103
104
|
const stackItems = [];
|
|
104
105
|
const sortedData = sortKey
|
|
105
106
|
? sort(yValues, (a, b) => comparator(get(a, sortKey), get(b, sortKey)))
|
|
@@ -117,6 +118,7 @@ export const prepareBarXData = async (args) => {
|
|
|
117
118
|
if (xAxis.type === 'category') {
|
|
118
119
|
const xBandScale = xScale;
|
|
119
120
|
const xBandScaleDomain = xBandScale.domain();
|
|
121
|
+
// eslint-disable-next-line max-depth
|
|
120
122
|
if (xBandScaleDomain.indexOf(xValue) === -1) {
|
|
121
123
|
continue;
|
|
122
124
|
}
|
|
@@ -141,7 +143,9 @@ export const prepareBarXData = async (args) => {
|
|
|
141
143
|
}
|
|
142
144
|
const barData = {
|
|
143
145
|
x,
|
|
144
|
-
y:
|
|
146
|
+
y: yDataValue > 0
|
|
147
|
+
? yAxisTop + y - positiveStackHeight
|
|
148
|
+
: yAxisTop + base + negativeStackHeight,
|
|
145
149
|
width: rectWidth,
|
|
146
150
|
height: shapeHeight,
|
|
147
151
|
opacity: get(yValue.data, 'opacity', null),
|
|
@@ -151,11 +155,16 @@ export const prepareBarXData = async (args) => {
|
|
|
151
155
|
isLastStackItem,
|
|
152
156
|
};
|
|
153
157
|
stackItems.push(barData);
|
|
154
|
-
|
|
158
|
+
if (yDataValue > 0) {
|
|
159
|
+
positiveStackHeight += height;
|
|
160
|
+
}
|
|
161
|
+
else {
|
|
162
|
+
negativeStackHeight += height;
|
|
163
|
+
}
|
|
155
164
|
}
|
|
156
165
|
if (series.some((s) => s.stacking === 'percent')) {
|
|
157
166
|
let acc = 0;
|
|
158
|
-
const ratio = plotHeight / (
|
|
167
|
+
const ratio = plotHeight / (positiveStackHeight - stackItems.length);
|
|
159
168
|
stackItems.forEach((item) => {
|
|
160
169
|
item.height = item.height * ratio;
|
|
161
170
|
item.y = plotHeight - item.height - acc;
|
|
@@ -168,7 +177,7 @@ export const prepareBarXData = async (args) => {
|
|
|
168
177
|
}
|
|
169
178
|
for (let i = 0; i < result.length; i++) {
|
|
170
179
|
const barData = result[i];
|
|
171
|
-
if (barData.series.dataLabels.enabled) {
|
|
180
|
+
if (barData.series.dataLabels.enabled && !isRangeSlider) {
|
|
172
181
|
const label = await getLabelData(barData);
|
|
173
182
|
if (barData.series.dataLabels.html && label) {
|
|
174
183
|
barData.htmlElements.push({
|
|
@@ -58,6 +58,7 @@ export const useShapes = (args) => {
|
|
|
58
58
|
yScale,
|
|
59
59
|
boundsHeight,
|
|
60
60
|
split,
|
|
61
|
+
isRangeSlider,
|
|
61
62
|
});
|
|
62
63
|
shapes.push(React.createElement(BarXSeriesShapes, { key: SERIES_TYPE.BarX, dispatcher: dispatcher, seriesOptions: seriesOptions, preparedData: preparedData, htmlLayout: htmlLayout, clipPathId: clipPathId }));
|
|
63
64
|
shapesData.push(...preparedData);
|
|
@@ -124,6 +125,7 @@ export const useShapes = (args) => {
|
|
|
124
125
|
boundsHeight,
|
|
125
126
|
split,
|
|
126
127
|
isOutsideBounds,
|
|
128
|
+
isRangeSlider,
|
|
127
129
|
});
|
|
128
130
|
shapes.push(React.createElement(AreaSeriesShapes, { key: SERIES_TYPE.Area, dispatcher: dispatcher, seriesOptions: seriesOptions, preparedData: preparedData, htmlLayout: htmlLayout, clipPathId: clipPathId }));
|
|
129
131
|
shapesData.push(...preparedData);
|
|
@@ -34,7 +34,7 @@ export const LineSeriesShapes = (args) => {
|
|
|
34
34
|
.attr('fill', 'none')
|
|
35
35
|
.attr('stroke', (d) => d.color)
|
|
36
36
|
.attr('stroke-width', (d) => d.lineWidth)
|
|
37
|
-
.attr('stroke-linejoin', (d) => d.
|
|
37
|
+
.attr('stroke-linejoin', (d) => d.linejoin)
|
|
38
38
|
.attr('stroke-linecap', (d) => d.linecap)
|
|
39
39
|
.attr('stroke-dasharray', (d) => getLineDashArray(d.dashStyle, d.lineWidth))
|
|
40
40
|
.attr('opacity', (d) => d.opacity)
|
|
@@ -44,7 +44,7 @@ export const prepareLineData = async (args) => {
|
|
|
44
44
|
});
|
|
45
45
|
const htmlElements = [];
|
|
46
46
|
const labels = [];
|
|
47
|
-
if (s.dataLabels.enabled) {
|
|
47
|
+
if (s.dataLabels.enabled && !isRangeSlider) {
|
|
48
48
|
if (s.dataLabels.html) {
|
|
49
49
|
const list = await Promise.all(points.reduce((result, p) => {
|
|
50
50
|
if (p.y === null) {
|
|
@@ -108,6 +108,7 @@ export const prepareLineData = async (args) => {
|
|
|
108
108
|
lineWidth: (_b = (isRangeSlider ? s.rangeSlider.lineWidth : undefined)) !== null && _b !== void 0 ? _b : s.lineWidth,
|
|
109
109
|
dashStyle: s.dashStyle,
|
|
110
110
|
linecap: s.linecap,
|
|
111
|
+
linejoin: s.linejoin,
|
|
111
112
|
opacity: (_c = (isRangeSlider ? s.rangeSlider.opacity : undefined)) !== null && _c !== void 0 ? _c : s.opacity,
|
|
112
113
|
};
|
|
113
114
|
acc.push(result);
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { DashStyle, LineCap } from '../../../constants';
|
|
1
|
+
import type { DashStyle, LineCap, LineJoin } from '../../../constants';
|
|
2
2
|
import type { HtmlItem, LabelData, LineSeriesData, LineSeriesLineBaseStyle } from '../../../types';
|
|
3
3
|
import type { PreparedLineSeries } from '../../useSeries/types';
|
|
4
4
|
export type PointData = {
|
|
@@ -30,4 +30,5 @@ export type PreparedLineData = {
|
|
|
30
30
|
color: string;
|
|
31
31
|
dashStyle: DashStyle;
|
|
32
32
|
linecap: LineCap;
|
|
33
|
+
linejoin: LineJoin;
|
|
33
34
|
} & Required<LineSeriesLineBaseStyle>;
|
|
@@ -194,6 +194,9 @@ export interface AxisPlot {
|
|
|
194
194
|
* @default 5
|
|
195
195
|
*/
|
|
196
196
|
padding?: number;
|
|
197
|
+
/** Can be used for the UI automated test.
|
|
198
|
+
* It is assigned as a data-qa attribute to an element. */
|
|
199
|
+
qa?: string;
|
|
197
200
|
};
|
|
198
201
|
}
|
|
199
202
|
export interface AxisPlotLine extends AxisPlot {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { DashStyle, LineCap, SERIES_TYPE } from '../../constants';
|
|
1
|
+
import type { DashStyle, LineCap, LineJoin, SERIES_TYPE } from '../../constants';
|
|
2
2
|
import type { MeaningfulAny } from '../misc';
|
|
3
3
|
import type { BaseSeries, BaseSeriesData, BaseSeriesLegend } from './base';
|
|
4
4
|
import type { RectLegendSymbolOptions } from './legend';
|
|
@@ -53,6 +53,8 @@ export interface LineSeries<T = MeaningfulAny> extends BaseSeries, LineSeriesLin
|
|
|
53
53
|
dashStyle?: DashStyle;
|
|
54
54
|
/** Option for line cap style */
|
|
55
55
|
linecap?: `${LineCap}`;
|
|
56
|
+
/** Defines the shape to be used at the corners of the line */
|
|
57
|
+
linejoin?: `${LineJoin}`;
|
|
56
58
|
/** Individual series legend options. Has higher priority than legend options in widget data */
|
|
57
59
|
legend?: BaseSeriesLegend & {
|
|
58
60
|
symbol?: RectLegendSymbolOptions;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type React from 'react';
|
|
2
|
-
import type { DashStyle, LineCap } from '../../constants';
|
|
2
|
+
import type { DashStyle, LineCap, LineJoin } from '../../constants';
|
|
3
3
|
import type { MeaningfulAny } from '../misc';
|
|
4
4
|
import type { AreaSeries, AreaSeriesData } from './area';
|
|
5
5
|
import type { BarXSeries, BarXSeriesData } from './bar-x';
|
|
@@ -211,6 +211,11 @@ export interface ChartSeriesOptions {
|
|
|
211
211
|
* @default 'round' when dashStyle is not 'solid', 'none' when dashStyle is not 'solid'
|
|
212
212
|
* */
|
|
213
213
|
linecap?: `${LineCap}`;
|
|
214
|
+
/** Defines the shape to be used at the corners of the line
|
|
215
|
+
*
|
|
216
|
+
* @default 'round' when dashStyle is not 'solid', 'unset' when dashStyle is not 'solid'
|
|
217
|
+
* */
|
|
218
|
+
linejoin?: `${LineJoin}`;
|
|
214
219
|
};
|
|
215
220
|
area?: {
|
|
216
221
|
/** Pixel width of the graph line.
|
|
@@ -46,8 +46,8 @@ export declare function isSeriesWithCategoryValues(series: UnknownSeries): serie
|
|
|
46
46
|
export declare const getDomainDataXBySeries: (series: UnknownSeries[]) => ({} | undefined)[];
|
|
47
47
|
export declare function getDefaultMaxXAxisValue(series: UnknownSeries[]): 0 | undefined;
|
|
48
48
|
export declare function getDefaultMinXAxisValue(series: UnknownSeries[]): number | undefined;
|
|
49
|
-
export declare function getDefaultMinYAxisValue(series?: UnknownSeries[]): number | undefined;
|
|
50
49
|
export declare const getDomainDataYBySeries: (series: UnknownSeries[]) => unknown[];
|
|
50
|
+
export declare function getDefaultMinYAxisValue(series?: UnknownSeries[]): number | undefined;
|
|
51
51
|
export declare const getSeriesNames: (series: ChartSeries[]) => string[];
|
|
52
52
|
export declare const getOnlyVisibleSeries: <T extends {
|
|
53
53
|
visible: boolean;
|
|
@@ -46,7 +46,8 @@ function getDomainDataForStackedSeries(seriesList, keyAttr = 'x', valueAttr = 'y
|
|
|
46
46
|
const acc = [];
|
|
47
47
|
const stackedSeries = group(seriesList, getSeriesStackId);
|
|
48
48
|
Array.from(stackedSeries).forEach(([_stackId, seriesStack]) => {
|
|
49
|
-
const
|
|
49
|
+
const positiveValues = {};
|
|
50
|
+
const negativeValues = {};
|
|
50
51
|
seriesStack.forEach((singleSeries) => {
|
|
51
52
|
const data = new Map();
|
|
52
53
|
singleSeries.data.forEach((point) => {
|
|
@@ -65,10 +66,15 @@ function getDomainDataForStackedSeries(seriesList, keyAttr = 'x', valueAttr = 'y
|
|
|
65
66
|
data.set(key, value);
|
|
66
67
|
});
|
|
67
68
|
Array.from(data).forEach(([key, value]) => {
|
|
68
|
-
|
|
69
|
+
if (value >= 0) {
|
|
70
|
+
positiveValues[key] = (positiveValues[key] || 0) + value;
|
|
71
|
+
}
|
|
72
|
+
if (value < 0) {
|
|
73
|
+
negativeValues[key] = (negativeValues[key] || 0) + value;
|
|
74
|
+
}
|
|
69
75
|
});
|
|
70
76
|
});
|
|
71
|
-
acc.push(...Object.values(values));
|
|
77
|
+
acc.push(...Object.values(negativeValues), ...Object.values(positiveValues));
|
|
72
78
|
});
|
|
73
79
|
return acc;
|
|
74
80
|
}
|
|
@@ -107,22 +113,6 @@ export function getDefaultMinXAxisValue(series) {
|
|
|
107
113
|
}
|
|
108
114
|
return undefined;
|
|
109
115
|
}
|
|
110
|
-
export function getDefaultMinYAxisValue(series) {
|
|
111
|
-
if (series === null || series === void 0 ? void 0 : series.some((s) => CHART_SERIES_WITH_VOLUME_ON_Y_AXIS.includes(s.type))) {
|
|
112
|
-
if (series.some((s) => s.type === SERIES_TYPE.Waterfall)) {
|
|
113
|
-
const seriesData = series.map((s) => s.data).flat();
|
|
114
|
-
const minSubTotal = seriesData.reduce((res, d) => Math.min(res, getWaterfallPointSubtotal(d, seriesData) || 0), 0);
|
|
115
|
-
return Math.min(0, minSubTotal);
|
|
116
|
-
}
|
|
117
|
-
return series.reduce((minValue, s) => {
|
|
118
|
-
// https://github.com/gravity-ui/charts/issues/160
|
|
119
|
-
// @ts-expect-error
|
|
120
|
-
const minYValue = s.data.reduce((res, d) => Math.min(res, get(d, 'y', 0)), 0);
|
|
121
|
-
return Math.min(minValue, minYValue);
|
|
122
|
-
}, 0);
|
|
123
|
-
}
|
|
124
|
-
return undefined;
|
|
125
|
-
}
|
|
126
116
|
export const getDomainDataYBySeries = (series) => {
|
|
127
117
|
const groupedSeries = group(series, (item) => item.type);
|
|
128
118
|
const items = Array.from(groupedSeries).reduce((acc, [type, seriesList]) => {
|
|
@@ -151,6 +141,20 @@ export const getDomainDataYBySeries = (series) => {
|
|
|
151
141
|
}, []);
|
|
152
142
|
return Array.from(new Set(items));
|
|
153
143
|
};
|
|
144
|
+
export function getDefaultMinYAxisValue(series) {
|
|
145
|
+
if (series === null || series === void 0 ? void 0 : series.some((s) => CHART_SERIES_WITH_VOLUME_ON_Y_AXIS.includes(s.type))) {
|
|
146
|
+
if (series.some((s) => s.type === SERIES_TYPE.Waterfall)) {
|
|
147
|
+
const seriesData = series.map((s) => s.data).flat();
|
|
148
|
+
const minSubTotal = seriesData.reduce((res, d) => Math.min(res, getWaterfallPointSubtotal(d, seriesData) || 0), 0);
|
|
149
|
+
return Math.min(0, minSubTotal);
|
|
150
|
+
}
|
|
151
|
+
const domainData = getDomainDataYBySeries(series);
|
|
152
|
+
return domainData.reduce((minValue, d) => {
|
|
153
|
+
return Math.min(minValue, d);
|
|
154
|
+
}, 0);
|
|
155
|
+
}
|
|
156
|
+
return undefined;
|
|
157
|
+
}
|
|
154
158
|
// Uses to get all series names array (except `pie` charts)
|
|
155
159
|
export const getSeriesNames = (series) => {
|
|
156
160
|
return series.reduce((acc, s) => {
|