@gravity-ui/chartkit 4.12.0 → 4.14.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/build/i18n/keysets/en.json +6 -1
- package/build/i18n/keysets/ru.json +6 -1
- package/build/libs/chartkit-error/chartkit-error.d.ts +1 -0
- package/build/libs/chartkit-error/chartkit-error.js +1 -0
- package/build/plugins/d3/examples/area/Basic.d.ts +2 -0
- package/build/plugins/d3/examples/area/Basic.js +35 -0
- package/build/plugins/d3/examples/area/StackedArea.d.ts +2 -0
- package/build/plugins/d3/examples/area/StackedArea.js +48 -0
- package/build/plugins/d3/examples/bar-x/Basic.js +11 -5
- package/build/plugins/d3/examples/line/LineWithMarkers.d.ts +2 -0
- package/build/plugins/d3/examples/line/LineWithMarkers.js +67 -0
- package/build/plugins/d3/renderer/D3Widget.js +27 -23
- package/build/plugins/d3/renderer/components/Tooltip/DefaultContent.js +1 -0
- package/build/plugins/d3/renderer/components/Tooltip/TooltipTriggerArea.js +1 -1
- package/build/plugins/d3/renderer/constants/defaults/axis.d.ts +2 -0
- package/build/plugins/d3/renderer/constants/defaults/axis.js +1 -0
- package/build/plugins/d3/renderer/constants/defaults/series-options.js +16 -4
- package/build/plugins/d3/renderer/hooks/useAxisScales/index.js +3 -2
- package/build/plugins/d3/renderer/hooks/useChartOptions/y-axis.js +2 -1
- package/build/plugins/d3/renderer/hooks/useSeries/constants.d.ts +3 -1
- package/build/plugins/d3/renderer/hooks/useSeries/constants.js +5 -0
- package/build/plugins/d3/renderer/hooks/useSeries/prepare-area.d.ts +19 -0
- package/build/plugins/d3/renderer/hooks/useSeries/prepare-area.js +66 -0
- package/build/plugins/d3/renderer/hooks/useSeries/prepare-bar-x.js +2 -7
- package/build/plugins/d3/renderer/hooks/useSeries/prepare-bar-y.js +2 -7
- package/build/plugins/d3/renderer/hooks/useSeries/prepare-line-series.d.ts +9 -2
- package/build/plugins/d3/renderer/hooks/useSeries/prepare-line-series.js +30 -2
- package/build/plugins/d3/renderer/hooks/useSeries/prepareSeries.js +9 -0
- package/build/plugins/d3/renderer/hooks/useSeries/types.d.ts +61 -2
- package/build/plugins/d3/renderer/hooks/useSeries/utils.d.ts +2 -1
- package/build/plugins/d3/renderer/hooks/useSeries/utils.js +10 -0
- package/build/plugins/d3/renderer/hooks/useShapes/area/index.d.ts +11 -0
- package/build/plugins/d3/renderer/hooks/useShapes/area/index.js +194 -0
- package/build/plugins/d3/renderer/hooks/useShapes/area/prepare-data.d.ts +11 -0
- package/build/plugins/d3/renderer/hooks/useShapes/area/prepare-data.js +114 -0
- package/build/plugins/d3/renderer/hooks/useShapes/area/types.d.ts +27 -0
- package/build/plugins/d3/renderer/hooks/useShapes/area/types.js +1 -0
- package/build/plugins/d3/renderer/hooks/useShapes/index.d.ts +2 -1
- package/build/plugins/d3/renderer/hooks/useShapes/index.js +16 -0
- package/build/plugins/d3/renderer/hooks/useShapes/line/index.js +91 -3
- package/build/plugins/d3/renderer/hooks/useShapes/line/prepare-data.js +11 -0
- package/build/plugins/d3/renderer/hooks/useShapes/line/types.d.ts +7 -0
- package/build/plugins/d3/renderer/utils/index.d.ts +1 -1
- package/build/plugins/d3/renderer/utils/index.js +16 -9
- package/build/plugins/d3/renderer/validation/__mocks__/index.d.ts +3 -0
- package/build/plugins/d3/renderer/validation/__mocks__/index.js +44 -0
- package/build/plugins/d3/renderer/validation/index.d.ts +2 -0
- package/build/plugins/d3/renderer/validation/index.js +145 -0
- package/build/types/widget-data/area.d.ts +57 -0
- package/build/types/widget-data/area.js +1 -0
- package/build/types/widget-data/index.d.ts +1 -0
- package/build/types/widget-data/index.js +1 -0
- package/build/types/widget-data/line.d.ts +9 -2
- package/build/types/widget-data/marker.d.ts +18 -0
- package/build/types/widget-data/marker.js +1 -0
- package/build/types/widget-data/series.d.ts +32 -4
- package/build/types/widget-data/tooltip.d.ts +10 -1
- package/package.json +2 -2
|
@@ -1,10 +1,43 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
|
-
import {
|
|
2
|
+
import { color, line as lineGenerator, select, symbol, symbolCircle, symbolSquare } from 'd3';
|
|
3
3
|
import get from 'lodash/get';
|
|
4
4
|
import { block } from '../../../../../../utils/cn';
|
|
5
5
|
import { filterOverlappingLabels } from '../../../utils';
|
|
6
6
|
import { setActiveState } from '../utils';
|
|
7
7
|
const b = block('d3-line');
|
|
8
|
+
function setMarker(selection, state) {
|
|
9
|
+
selection
|
|
10
|
+
.attr('d', (d) => {
|
|
11
|
+
const radius = d.point.series.marker.states[state].radius +
|
|
12
|
+
d.point.series.marker.states[state].borderWidth;
|
|
13
|
+
return getMarkerSymbol(d.point.series.marker.states.normal.symbol, radius);
|
|
14
|
+
})
|
|
15
|
+
.attr('stroke-width', (d) => d.point.series.marker.states[state].borderWidth)
|
|
16
|
+
.attr('stroke', (d) => d.point.series.marker.states[state].borderColor);
|
|
17
|
+
}
|
|
18
|
+
function getMarkerSymbol(type, radius) {
|
|
19
|
+
switch (type) {
|
|
20
|
+
case 'square': {
|
|
21
|
+
const size = Math.pow(radius, 2) * Math.PI;
|
|
22
|
+
return symbol(symbolSquare, size)();
|
|
23
|
+
}
|
|
24
|
+
case 'circle':
|
|
25
|
+
default: {
|
|
26
|
+
const size = Math.pow(radius, 2) * Math.PI;
|
|
27
|
+
return symbol(symbolCircle, size)();
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
const getMarkerVisibility = (d) => {
|
|
32
|
+
const markerStates = d.point.series.marker.states;
|
|
33
|
+
const enabled = (markerStates.hover.enabled && d.hovered) || markerStates.normal.enabled;
|
|
34
|
+
return enabled ? '' : 'hidden';
|
|
35
|
+
};
|
|
36
|
+
const getMarkerHaloVisibility = (d) => {
|
|
37
|
+
const markerStates = d.point.series.marker.states;
|
|
38
|
+
const enabled = markerStates.hover.halo.enabled && d.hovered;
|
|
39
|
+
return enabled ? '' : 'hidden';
|
|
40
|
+
};
|
|
8
41
|
export const LineSeriesShapes = (args) => {
|
|
9
42
|
const { dispatcher, preparedData, seriesOptions } = args;
|
|
10
43
|
const ref = React.useRef(null);
|
|
@@ -48,11 +81,40 @@ export const LineSeriesShapes = (args) => {
|
|
|
48
81
|
.style('font-size', (d) => d.style.fontSize)
|
|
49
82
|
.style('font-weight', (d) => d.style.fontWeight || null)
|
|
50
83
|
.style('fill', (d) => d.style.fontColor || null);
|
|
84
|
+
const markers = preparedData.reduce((acc, d) => acc.concat(d.markers), []);
|
|
85
|
+
const markerSelection = svgElement
|
|
86
|
+
.selectAll('marker')
|
|
87
|
+
.data(markers)
|
|
88
|
+
.join('g')
|
|
89
|
+
.attr('class', b('marker'))
|
|
90
|
+
.attr('visibility', getMarkerVisibility)
|
|
91
|
+
.attr('transform', (d) => {
|
|
92
|
+
return `translate(${d.point.x},${d.point.y})`;
|
|
93
|
+
});
|
|
94
|
+
markerSelection
|
|
95
|
+
.append('path')
|
|
96
|
+
.attr('class', b('marker-halo'))
|
|
97
|
+
.attr('d', (d) => {
|
|
98
|
+
const type = d.point.series.marker.states.normal.symbol;
|
|
99
|
+
const radius = d.point.series.marker.states.hover.halo.radius;
|
|
100
|
+
return getMarkerSymbol(type, radius);
|
|
101
|
+
})
|
|
102
|
+
.attr('fill', (d) => d.point.series.color)
|
|
103
|
+
.attr('opacity', (d) => d.point.series.marker.states.hover.halo.opacity)
|
|
104
|
+
.attr('z-index', -1)
|
|
105
|
+
.attr('visibility', getMarkerHaloVisibility);
|
|
106
|
+
markerSelection
|
|
107
|
+
.append('path')
|
|
108
|
+
.attr('class', b('marker-symbol'))
|
|
109
|
+
.call(setMarker, 'normal')
|
|
110
|
+
.attr('fill', (d) => d.point.series.color);
|
|
51
111
|
const hoverEnabled = hoverOptions === null || hoverOptions === void 0 ? void 0 : hoverOptions.enabled;
|
|
52
112
|
const inactiveEnabled = inactiveOptions === null || inactiveOptions === void 0 ? void 0 : inactiveOptions.enabled;
|
|
53
113
|
dispatcher.on('hover-shape.line', (data) => {
|
|
54
|
-
var _a
|
|
55
|
-
const
|
|
114
|
+
var _a;
|
|
115
|
+
const selected = data === null || data === void 0 ? void 0 : data.find((d) => d.series.type === 'line');
|
|
116
|
+
const selectedDataItem = selected === null || selected === void 0 ? void 0 : selected.data;
|
|
117
|
+
const selectedSeriesId = (_a = selected === null || selected === void 0 ? void 0 : selected.series) === null || _a === void 0 ? void 0 : _a.id;
|
|
56
118
|
lineSelection.datum((d, index, list) => {
|
|
57
119
|
const elementSelection = select(list[index]);
|
|
58
120
|
const hovered = Boolean(hoverEnabled && d.id === selectedSeriesId);
|
|
@@ -82,6 +144,32 @@ export const LineSeriesShapes = (args) => {
|
|
|
82
144
|
datum: d,
|
|
83
145
|
});
|
|
84
146
|
});
|
|
147
|
+
markerSelection.datum((d, index, list) => {
|
|
148
|
+
const elementSelection = select(list[index]);
|
|
149
|
+
const hovered = Boolean(hoverEnabled && d.point.data === selectedDataItem);
|
|
150
|
+
if (d.hovered !== hovered) {
|
|
151
|
+
d.hovered = hovered;
|
|
152
|
+
elementSelection.attr('visibility', getMarkerVisibility(d));
|
|
153
|
+
elementSelection
|
|
154
|
+
.select(`.${b('marker-halo')}`)
|
|
155
|
+
.attr('visibility', getMarkerHaloVisibility);
|
|
156
|
+
elementSelection
|
|
157
|
+
.select(`.${b('marker-symbol')}`)
|
|
158
|
+
.call(setMarker, hovered ? 'hover' : 'normal');
|
|
159
|
+
}
|
|
160
|
+
if (d.point.series.marker.states.normal.enabled) {
|
|
161
|
+
const isActive = Boolean(!inactiveEnabled ||
|
|
162
|
+
!selectedSeriesId ||
|
|
163
|
+
selectedSeriesId === d.point.series.id);
|
|
164
|
+
setActiveState({
|
|
165
|
+
element: list[index],
|
|
166
|
+
state: inactiveOptions,
|
|
167
|
+
active: isActive,
|
|
168
|
+
datum: d,
|
|
169
|
+
});
|
|
170
|
+
}
|
|
171
|
+
return d;
|
|
172
|
+
});
|
|
85
173
|
});
|
|
86
174
|
return () => {
|
|
87
175
|
dispatcher.on('hover-shape.line', null);
|
|
@@ -35,14 +35,25 @@ export const prepareLineData = (args) => {
|
|
|
35
35
|
const points = s.data.map((d) => ({
|
|
36
36
|
x: getXValue({ point: d, xAxis, xScale }),
|
|
37
37
|
y: getYValue({ point: d, yAxis, yScale }),
|
|
38
|
+
active: true,
|
|
38
39
|
data: d,
|
|
40
|
+
series: s,
|
|
39
41
|
}));
|
|
40
42
|
let labels = [];
|
|
41
43
|
if (s.dataLabels.enabled) {
|
|
42
44
|
labels = points.map((p) => getLabelData(p, s, xMax));
|
|
43
45
|
}
|
|
46
|
+
let markers = [];
|
|
47
|
+
if (s.marker.states.normal.enabled || s.marker.states.hover.enabled) {
|
|
48
|
+
markers = points.map((p) => ({
|
|
49
|
+
point: p,
|
|
50
|
+
active: true,
|
|
51
|
+
hovered: false,
|
|
52
|
+
}));
|
|
53
|
+
}
|
|
44
54
|
acc.push({
|
|
45
55
|
points,
|
|
56
|
+
markers,
|
|
46
57
|
labels,
|
|
47
58
|
color: s.color,
|
|
48
59
|
width: s.lineWidth,
|
|
@@ -5,10 +5,17 @@ export type PointData = {
|
|
|
5
5
|
x: number;
|
|
6
6
|
y: number;
|
|
7
7
|
data: LineSeriesData;
|
|
8
|
+
series: PreparedLineSeries;
|
|
9
|
+
};
|
|
10
|
+
export type MarkerData = {
|
|
11
|
+
point: PointData;
|
|
12
|
+
active: boolean;
|
|
13
|
+
hovered: boolean;
|
|
8
14
|
};
|
|
9
15
|
export type PreparedLineData = {
|
|
10
16
|
id: string;
|
|
11
17
|
points: PointData[];
|
|
18
|
+
markers: MarkerData[];
|
|
12
19
|
color: string;
|
|
13
20
|
width: number;
|
|
14
21
|
series: PreparedLineSeries;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { AxisDomain } from 'd3';
|
|
2
|
-
import type { BaseTextStyle, ChartKitWidgetSeries, ChartKitWidgetSeriesData } from '../../../../types
|
|
2
|
+
import type { BaseTextStyle, ChartKitWidgetSeries, ChartKitWidgetSeriesData } from '../../../../types';
|
|
3
3
|
import { PreparedAxis } from '../hooks';
|
|
4
4
|
export * from './math';
|
|
5
5
|
export * from './text';
|
|
@@ -6,6 +6,7 @@ import { formatNumber } from '../../../shared';
|
|
|
6
6
|
import { DEFAULT_AXIS_LABEL_FONT_SIZE } from '../constants';
|
|
7
7
|
import { getNumberUnitRate } from '../../../shared/format-number/format-number';
|
|
8
8
|
import { getDefaultDateFormat } from './time';
|
|
9
|
+
import { getSeriesStackId } from '../hooks/useSeries/utils';
|
|
9
10
|
export * from './math';
|
|
10
11
|
export * from './text';
|
|
11
12
|
export * from './time';
|
|
@@ -42,20 +43,26 @@ export const getDomainDataYBySeries = (series) => {
|
|
|
42
43
|
const groupedSeries = group(series, (item) => item.type);
|
|
43
44
|
return Array.from(groupedSeries).reduce((acc, [type, seriesList]) => {
|
|
44
45
|
switch (type) {
|
|
46
|
+
case 'area':
|
|
45
47
|
case 'bar-x': {
|
|
46
|
-
const
|
|
47
|
-
|
|
48
|
-
Array.from(stackedSeries).forEach(([, stack]) => {
|
|
48
|
+
const stackedSeries = group(seriesList, getSeriesStackId);
|
|
49
|
+
Array.from(stackedSeries).forEach(([_stackId, seriesStack]) => {
|
|
49
50
|
const values = {};
|
|
50
|
-
|
|
51
|
+
seriesStack.forEach((singleSeries) => {
|
|
52
|
+
const data = new Map();
|
|
51
53
|
singleSeries.data.forEach((point) => {
|
|
52
|
-
const key = String(point.x
|
|
53
|
-
|
|
54
|
-
values[key] = 0;
|
|
55
|
-
}
|
|
54
|
+
const key = String(point.x);
|
|
55
|
+
let value = 0;
|
|
56
56
|
if (point.y && typeof point.y === 'number') {
|
|
57
|
-
|
|
57
|
+
value = point.y;
|
|
58
|
+
}
|
|
59
|
+
if (data.has(key)) {
|
|
60
|
+
value = Math.max(value, data.get(key));
|
|
58
61
|
}
|
|
62
|
+
data.set(key, value);
|
|
63
|
+
});
|
|
64
|
+
Array.from(data).forEach(([key, value]) => {
|
|
65
|
+
values[key] = (values[key] || 0) + value;
|
|
59
66
|
});
|
|
60
67
|
});
|
|
61
68
|
acc.push(...Object.values(values));
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
export const XY_SERIES = {
|
|
2
|
+
INVALID_CATEGORY_X: {
|
|
3
|
+
series: {
|
|
4
|
+
data: [{ type: 'scatter', data: [{ x: undefined, y: 1 }], name: 'Series' }],
|
|
5
|
+
},
|
|
6
|
+
xAxis: { type: 'category' },
|
|
7
|
+
},
|
|
8
|
+
INVALID_CATEGORY_Y: {
|
|
9
|
+
series: {
|
|
10
|
+
data: [{ type: 'scatter', data: [{ x: 1, y: undefined }], name: 'Series' }],
|
|
11
|
+
},
|
|
12
|
+
yAxis: [{ type: 'category' }],
|
|
13
|
+
},
|
|
14
|
+
INVALID_DATETIME_X: {
|
|
15
|
+
series: {
|
|
16
|
+
data: [{ type: 'scatter', data: [{ x: undefined, y: 1 }], name: 'Series' }],
|
|
17
|
+
},
|
|
18
|
+
xAxis: { type: 'datetime' },
|
|
19
|
+
},
|
|
20
|
+
INVALID_DATETIME_Y: {
|
|
21
|
+
series: {
|
|
22
|
+
data: [{ type: 'scatter', data: [{ x: undefined, y: 1 }], name: 'Series' }],
|
|
23
|
+
},
|
|
24
|
+
yAxis: [{ type: 'datetime' }],
|
|
25
|
+
},
|
|
26
|
+
INVALID_LINEAR_X: {
|
|
27
|
+
series: {
|
|
28
|
+
data: [{ type: 'scatter', data: [{ x: 'str', y: 1 }], name: 'Series' }],
|
|
29
|
+
},
|
|
30
|
+
},
|
|
31
|
+
INVALID_LINEAR_Y: {
|
|
32
|
+
series: {
|
|
33
|
+
data: [{ type: 'scatter', data: [{ x: 1, y: 'str' }], name: 'Series' }],
|
|
34
|
+
},
|
|
35
|
+
},
|
|
36
|
+
};
|
|
37
|
+
export const PIE_SERIES = {
|
|
38
|
+
INVALID_VALUE: {
|
|
39
|
+
series: {
|
|
40
|
+
// @ts-expect-error
|
|
41
|
+
data: [{ type: 'pie', data: [{ value: undefined, name: 'Series' }] }],
|
|
42
|
+
},
|
|
43
|
+
},
|
|
44
|
+
};
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
import get from 'lodash/get';
|
|
2
|
+
import isEmpty from 'lodash/isEmpty';
|
|
3
|
+
import { ChartKitError, CHARTKIT_ERROR_CODE } from '../../../../libs';
|
|
4
|
+
import { i18n } from '../../../../i18n';
|
|
5
|
+
import { DEFAULT_AXIS_TYPE } from '../constants';
|
|
6
|
+
const AVAILABLE_SERIES_TYPES = [
|
|
7
|
+
'area',
|
|
8
|
+
'bar-x',
|
|
9
|
+
'bar-y',
|
|
10
|
+
'line',
|
|
11
|
+
'pie',
|
|
12
|
+
'scatter',
|
|
13
|
+
];
|
|
14
|
+
const validateXYSeries = (args) => {
|
|
15
|
+
const { series, xAxis, yAxis } = args;
|
|
16
|
+
const xType = get(xAxis, 'type', DEFAULT_AXIS_TYPE);
|
|
17
|
+
const yType = get(yAxis, 'type', DEFAULT_AXIS_TYPE);
|
|
18
|
+
series.data.forEach(({ x, y }) => {
|
|
19
|
+
switch (xType) {
|
|
20
|
+
case 'category': {
|
|
21
|
+
if (typeof x !== 'string' && typeof x !== 'number') {
|
|
22
|
+
throw new ChartKitError({
|
|
23
|
+
code: CHARTKIT_ERROR_CODE.INVALID_DATA,
|
|
24
|
+
message: i18n('error', 'label_invalid-axis-category-data-point', {
|
|
25
|
+
key: 'x',
|
|
26
|
+
seriesName: series.name,
|
|
27
|
+
}),
|
|
28
|
+
});
|
|
29
|
+
}
|
|
30
|
+
break;
|
|
31
|
+
}
|
|
32
|
+
case 'datetime': {
|
|
33
|
+
if (typeof x !== 'number') {
|
|
34
|
+
throw new ChartKitError({
|
|
35
|
+
code: CHARTKIT_ERROR_CODE.INVALID_DATA,
|
|
36
|
+
message: i18n('error', 'label_invalid-axis-datetime-data-point', {
|
|
37
|
+
key: 'x',
|
|
38
|
+
seriesName: series.name,
|
|
39
|
+
}),
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
break;
|
|
43
|
+
}
|
|
44
|
+
case 'linear': {
|
|
45
|
+
if (typeof x !== 'number' && x !== null) {
|
|
46
|
+
throw new ChartKitError({
|
|
47
|
+
code: CHARTKIT_ERROR_CODE.INVALID_DATA,
|
|
48
|
+
message: i18n('error', 'label_invalid-axis-linear-data-point', {
|
|
49
|
+
key: 'x',
|
|
50
|
+
seriesName: series.name,
|
|
51
|
+
}),
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
switch (yType) {
|
|
57
|
+
case 'category': {
|
|
58
|
+
if (typeof y !== 'string' && typeof y !== 'number') {
|
|
59
|
+
throw new ChartKitError({
|
|
60
|
+
code: CHARTKIT_ERROR_CODE.INVALID_DATA,
|
|
61
|
+
message: i18n('error', 'label_invalid-axis-category-data-point', {
|
|
62
|
+
key: 'y',
|
|
63
|
+
seriesName: series.name,
|
|
64
|
+
}),
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
break;
|
|
68
|
+
}
|
|
69
|
+
case 'datetime': {
|
|
70
|
+
if (typeof y !== 'number') {
|
|
71
|
+
throw new ChartKitError({
|
|
72
|
+
code: CHARTKIT_ERROR_CODE.INVALID_DATA,
|
|
73
|
+
message: i18n('error', 'label_invalid-axis-datetime-data-point', {
|
|
74
|
+
key: 'y',
|
|
75
|
+
seriesName: series.name,
|
|
76
|
+
}),
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
break;
|
|
80
|
+
}
|
|
81
|
+
case 'linear': {
|
|
82
|
+
if (typeof y !== 'number' && y !== null) {
|
|
83
|
+
throw new ChartKitError({
|
|
84
|
+
code: CHARTKIT_ERROR_CODE.INVALID_DATA,
|
|
85
|
+
message: i18n('error', 'label_invalid-axis-linear-data-point', {
|
|
86
|
+
key: 'y',
|
|
87
|
+
seriesName: series.name,
|
|
88
|
+
}),
|
|
89
|
+
});
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
});
|
|
94
|
+
};
|
|
95
|
+
const validatePieSeries = ({ series }) => {
|
|
96
|
+
series.data.forEach(({ value }) => {
|
|
97
|
+
if (typeof value !== 'number') {
|
|
98
|
+
throw new ChartKitError({
|
|
99
|
+
code: CHARTKIT_ERROR_CODE.INVALID_DATA,
|
|
100
|
+
message: i18n('error', 'label_invalid-pie-data-value'),
|
|
101
|
+
});
|
|
102
|
+
}
|
|
103
|
+
});
|
|
104
|
+
};
|
|
105
|
+
const validateSeries = (args) => {
|
|
106
|
+
const { series, xAxis, yAxis } = args;
|
|
107
|
+
if (!AVAILABLE_SERIES_TYPES.includes(series.type)) {
|
|
108
|
+
throw new ChartKitError({
|
|
109
|
+
code: CHARTKIT_ERROR_CODE.INVALID_DATA,
|
|
110
|
+
message: i18n('error', 'label_invalid-series-type', {
|
|
111
|
+
types: AVAILABLE_SERIES_TYPES.join(', '),
|
|
112
|
+
}),
|
|
113
|
+
});
|
|
114
|
+
}
|
|
115
|
+
switch (series.type) {
|
|
116
|
+
case 'bar-x':
|
|
117
|
+
case 'bar-y':
|
|
118
|
+
case 'line':
|
|
119
|
+
case 'scatter': {
|
|
120
|
+
validateXYSeries({ series, xAxis, yAxis });
|
|
121
|
+
break;
|
|
122
|
+
}
|
|
123
|
+
case 'pie': {
|
|
124
|
+
validatePieSeries({ series });
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
};
|
|
128
|
+
export const validateData = (data) => {
|
|
129
|
+
if (isEmpty(data) || isEmpty(data.series) || isEmpty(data.series.data)) {
|
|
130
|
+
throw new ChartKitError({
|
|
131
|
+
code: CHARTKIT_ERROR_CODE.NO_DATA,
|
|
132
|
+
message: i18n('error', 'label_no-data'),
|
|
133
|
+
});
|
|
134
|
+
}
|
|
135
|
+
if (data.series.data.some((s) => isEmpty(s.data))) {
|
|
136
|
+
throw new ChartKitError({
|
|
137
|
+
code: CHARTKIT_ERROR_CODE.INVALID_DATA,
|
|
138
|
+
message: 'You should specify data for all series',
|
|
139
|
+
});
|
|
140
|
+
}
|
|
141
|
+
data.series.data.forEach((series) => {
|
|
142
|
+
var _a;
|
|
143
|
+
validateSeries({ series, yAxis: (_a = data.yAxis) === null || _a === void 0 ? void 0 : _a[0], xAxis: data.xAxis });
|
|
144
|
+
});
|
|
145
|
+
};
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import type { BaseSeries, BaseSeriesData } from './base';
|
|
2
|
+
import type { ChartKitWidgetLegend, RectLegendSymbolOptions } from './legend';
|
|
3
|
+
import type { PointMarkerOptions } from './marker';
|
|
4
|
+
export type AreaSeriesData<T = any> = BaseSeriesData<T> & {
|
|
5
|
+
/**
|
|
6
|
+
* The `x` value of the point. Depending on the context , it may represents:
|
|
7
|
+
* - numeric value (for `linear` x axis)
|
|
8
|
+
* - timestamp value (for `datetime` x axis)
|
|
9
|
+
* - x axis category value (for `category` x axis). If the type is a string, then it is a category value itself. If the type is a number, then it is the index of an element in the array of categories described in `xAxis.categories`
|
|
10
|
+
*/
|
|
11
|
+
x?: string | number;
|
|
12
|
+
/**
|
|
13
|
+
* The `y` value of the point. Depending on the context , it may represents:
|
|
14
|
+
* - numeric value (for `linear` y axis)
|
|
15
|
+
* - timestamp value (for `datetime` y axis)
|
|
16
|
+
* - y axis category value (for `category` y axis). If the type is a string, then it is a category value itself. If the type is a number, then it is the index of an element in the array of categories described in `yAxis[0].categories`
|
|
17
|
+
*/
|
|
18
|
+
y?: string | number;
|
|
19
|
+
/** Data label value of the point. If not specified, the y value is used. */
|
|
20
|
+
label?: string | number;
|
|
21
|
+
};
|
|
22
|
+
export type AreaMarkerSymbol = 'circle' | 'square';
|
|
23
|
+
export type AreaMarkerOptions = PointMarkerOptions & {
|
|
24
|
+
symbol?: AreaMarkerSymbol;
|
|
25
|
+
};
|
|
26
|
+
export type AreaSeries<T = any> = BaseSeries & {
|
|
27
|
+
type: 'area';
|
|
28
|
+
data: AreaSeriesData<T>[];
|
|
29
|
+
/** The name of the series (used in legend, tooltip etc) */
|
|
30
|
+
name: string;
|
|
31
|
+
/** Whether to stack the values of each series on top of each other.
|
|
32
|
+
* Possible values are undefined to disable, "normal" to stack by value
|
|
33
|
+
*
|
|
34
|
+
* @default undefined
|
|
35
|
+
* */
|
|
36
|
+
stacking?: 'normal';
|
|
37
|
+
/** This option allows grouping series in a stacked chart */
|
|
38
|
+
stackId?: string;
|
|
39
|
+
/** The main color of the series (hex, rgba) */
|
|
40
|
+
color?: string;
|
|
41
|
+
/** Fill opacity for the area
|
|
42
|
+
*
|
|
43
|
+
* @default 0.75
|
|
44
|
+
* */
|
|
45
|
+
opacity?: number;
|
|
46
|
+
/** Pixel width of the graph line.
|
|
47
|
+
*
|
|
48
|
+
* @default 1
|
|
49
|
+
* */
|
|
50
|
+
lineWidth?: number;
|
|
51
|
+
/** Individual series legend options. Has higher priority than legend options in widget data */
|
|
52
|
+
legend?: ChartKitWidgetLegend & {
|
|
53
|
+
symbol?: RectLegendSymbolOptions;
|
|
54
|
+
};
|
|
55
|
+
/** Options for the point markers of line in area series */
|
|
56
|
+
marker?: AreaMarkerOptions;
|
|
57
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import { BaseSeries, BaseSeriesData } from './base';
|
|
2
|
-
import { ChartKitWidgetLegend, RectLegendSymbolOptions } from './legend';
|
|
1
|
+
import type { BaseSeries, BaseSeriesData } from './base';
|
|
2
|
+
import type { ChartKitWidgetLegend, RectLegendSymbolOptions } from './legend';
|
|
3
|
+
import type { PointMarkerOptions } from './marker';
|
|
3
4
|
export type LineSeriesData<T = any> = BaseSeriesData<T> & {
|
|
4
5
|
/**
|
|
5
6
|
* The `x` value of the point. Depending on the context , it may represents:
|
|
@@ -18,6 +19,10 @@ export type LineSeriesData<T = any> = BaseSeriesData<T> & {
|
|
|
18
19
|
/** Data label value of the point. If not specified, the y value is used. */
|
|
19
20
|
label?: string | number;
|
|
20
21
|
};
|
|
22
|
+
export type LineMarkerSymbol = 'circle' | 'square';
|
|
23
|
+
export type LineMarkerOptions = PointMarkerOptions & {
|
|
24
|
+
symbol?: LineMarkerSymbol;
|
|
25
|
+
};
|
|
21
26
|
export type LineSeries<T = any> = BaseSeries & {
|
|
22
27
|
type: 'line';
|
|
23
28
|
data: LineSeriesData<T>[];
|
|
@@ -34,4 +39,6 @@ export type LineSeries<T = any> = BaseSeries & {
|
|
|
34
39
|
legend?: ChartKitWidgetLegend & {
|
|
35
40
|
symbol?: RectLegendSymbolOptions;
|
|
36
41
|
};
|
|
42
|
+
/** Options for the point markers of line series */
|
|
43
|
+
marker?: LineMarkerOptions;
|
|
37
44
|
};
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
export type PointMarkerOptions = {
|
|
2
|
+
/** Enable or disable the point marker */
|
|
3
|
+
enabled?: boolean;
|
|
4
|
+
/** The radius of the point marker */
|
|
5
|
+
radius?: number;
|
|
6
|
+
/** The color of the point marker's border */
|
|
7
|
+
borderColor?: string;
|
|
8
|
+
/** The width of the point marker's border */
|
|
9
|
+
borderWidth?: number;
|
|
10
|
+
};
|
|
11
|
+
export type PointMarkerHalo = {
|
|
12
|
+
/** Enable or disable the halo appearing around the point */
|
|
13
|
+
enabled?: boolean;
|
|
14
|
+
/** The Opacity of the point halo */
|
|
15
|
+
opacity?: number;
|
|
16
|
+
/** The radius of the point halo */
|
|
17
|
+
radius?: number;
|
|
18
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -2,10 +2,12 @@ import React from 'react';
|
|
|
2
2
|
import type { PieSeries, PieSeriesData } from './pie';
|
|
3
3
|
import type { ScatterSeries, ScatterSeriesData } from './scatter';
|
|
4
4
|
import type { BarXSeries, BarXSeriesData } from './bar-x';
|
|
5
|
-
import type { LineSeries, LineSeriesData } from './line';
|
|
5
|
+
import type { LineSeries, LineSeriesData, LineMarkerOptions } from './line';
|
|
6
6
|
import type { BarYSeries, BarYSeriesData } from './bar-y';
|
|
7
|
-
|
|
8
|
-
|
|
7
|
+
import type { PointMarkerOptions, PointMarkerHalo } from './marker';
|
|
8
|
+
import type { AreaSeries, AreaSeriesData } from './area';
|
|
9
|
+
export type ChartKitWidgetSeries<T = any> = ScatterSeries<T> | PieSeries<T> | BarXSeries<T> | BarYSeries<T> | LineSeries<T> | AreaSeries<T>;
|
|
10
|
+
export type ChartKitWidgetSeriesData<T = any> = ScatterSeriesData<T> | PieSeriesData<T> | BarXSeriesData<T> | BarYSeriesData<T> | LineSeriesData<T> | AreaSeriesData<T>;
|
|
9
11
|
export type DataLabelRendererData<T = any> = {
|
|
10
12
|
data: ChartKitWidgetSeriesData<T>;
|
|
11
13
|
};
|
|
@@ -142,9 +144,35 @@ export type ChartKitWidgetSeriesOptions = {
|
|
|
142
144
|
lineWidth?: number;
|
|
143
145
|
/** Options for the series states that provide additional styling information to the series. */
|
|
144
146
|
states?: {
|
|
145
|
-
hover?: BasicHoverState
|
|
147
|
+
hover?: BasicHoverState & {
|
|
148
|
+
marker?: PointMarkerOptions & {
|
|
149
|
+
/** Options for the halo appearing around the hovered point */
|
|
150
|
+
halo?: PointMarkerHalo;
|
|
151
|
+
};
|
|
152
|
+
};
|
|
153
|
+
inactive?: BasicInactiveState;
|
|
154
|
+
};
|
|
155
|
+
/** Options for the point markers of line series */
|
|
156
|
+
marker?: LineMarkerOptions;
|
|
157
|
+
};
|
|
158
|
+
area?: {
|
|
159
|
+
/** Pixel width of the graph line.
|
|
160
|
+
*
|
|
161
|
+
* @default 1
|
|
162
|
+
* */
|
|
163
|
+
lineWidth?: number;
|
|
164
|
+
/** Options for the series states that provide additional styling information to the series. */
|
|
165
|
+
states?: {
|
|
166
|
+
hover?: BasicHoverState & {
|
|
167
|
+
marker?: PointMarkerOptions & {
|
|
168
|
+
/** Options for the halo appearing around the hovered point */
|
|
169
|
+
halo?: PointMarkerHalo;
|
|
170
|
+
};
|
|
171
|
+
};
|
|
146
172
|
inactive?: BasicInactiveState;
|
|
147
173
|
};
|
|
174
|
+
/** Options for the point markers of line series */
|
|
175
|
+
marker?: LineMarkerOptions;
|
|
148
176
|
};
|
|
149
177
|
};
|
|
150
178
|
export {};
|
|
@@ -4,6 +4,7 @@ import type { PieSeries, PieSeriesData } from './pie';
|
|
|
4
4
|
import type { ScatterSeries, ScatterSeriesData } from './scatter';
|
|
5
5
|
import type { LineSeries, LineSeriesData } from './line';
|
|
6
6
|
import type { BarYSeries, BarYSeriesData } from './bar-y';
|
|
7
|
+
import type { AreaSeries, AreaSeriesData } from './area';
|
|
7
8
|
export type TooltipDataChunkBarX<T = any> = {
|
|
8
9
|
data: BarXSeriesData<T>;
|
|
9
10
|
series: BarXSeries<T>;
|
|
@@ -32,7 +33,15 @@ export type TooltipDataChunkLine<T = any> = {
|
|
|
32
33
|
name: string;
|
|
33
34
|
};
|
|
34
35
|
};
|
|
35
|
-
export type
|
|
36
|
+
export type TooltipDataChunkArea<T = any> = {
|
|
37
|
+
data: AreaSeriesData<T>;
|
|
38
|
+
series: {
|
|
39
|
+
type: AreaSeries['type'];
|
|
40
|
+
id: string;
|
|
41
|
+
name: string;
|
|
42
|
+
};
|
|
43
|
+
};
|
|
44
|
+
export type TooltipDataChunk<T = any> = TooltipDataChunkBarX<T> | TooltipDataChunkBarY<T> | TooltipDataChunkPie<T> | TooltipDataChunkScatter<T> | TooltipDataChunkLine<T> | TooltipDataChunkArea<T>;
|
|
36
45
|
export type ChartKitWidgetTooltip<T = any> = {
|
|
37
46
|
enabled?: boolean;
|
|
38
47
|
/** Specifies the renderer for the tooltip. If returned null default tooltip renderer will be used. */
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@gravity-ui/chartkit",
|
|
3
|
-
"version": "4.
|
|
3
|
+
"version": "4.14.0",
|
|
4
4
|
"description": "React component used to render charts based on any sources you need",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": "git@github.com:gravity-ui/ChartKit.git",
|
|
@@ -48,7 +48,7 @@
|
|
|
48
48
|
"dependencies": {
|
|
49
49
|
"@bem-react/classname": "^1.6.0",
|
|
50
50
|
"@gravity-ui/date-utils": "^1.4.1",
|
|
51
|
-
"@gravity-ui/yagr": "^4.0
|
|
51
|
+
"@gravity-ui/yagr": "^4.1.0",
|
|
52
52
|
"afterframe": "^1.0.2",
|
|
53
53
|
"d3": "^7.8.5",
|
|
54
54
|
"lodash": "^4.17.21",
|