@gravity-ui/charts 1.11.0 → 1.11.1
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/Axis/AxisY.js +3 -0
- package/dist/cjs/components/ChartInner/useChartInnerProps.js +2 -0
- package/dist/cjs/components/Legend/index.js +4 -1
- package/dist/cjs/hooks/useSeries/prepare-area.js +2 -1
- package/dist/cjs/hooks/useSeries/prepare-legend.js +2 -2
- package/dist/cjs/hooks/useShapes/area/prepare-data.js +2 -2
- package/dist/cjs/hooks/useShapes/index.js +143 -139
- package/dist/esm/components/Axis/AxisY.js +3 -0
- package/dist/esm/components/ChartInner/useChartInnerProps.js +2 -0
- package/dist/esm/components/Legend/index.js +4 -1
- package/dist/esm/hooks/useSeries/prepare-area.js +2 -1
- package/dist/esm/hooks/useSeries/prepare-legend.js +2 -2
- package/dist/esm/hooks/useShapes/area/prepare-data.js +2 -2
- package/dist/esm/hooks/useShapes/index.js +143 -139
- package/package.json +1 -1
|
@@ -125,6 +125,9 @@ export const AxisY = (props) => {
|
|
|
125
125
|
scale: seriesScale,
|
|
126
126
|
});
|
|
127
127
|
yAxisGenerator(axisItem);
|
|
128
|
+
// because the standard generator interrupts the desired font
|
|
129
|
+
// https://github.com/d3/d3-axis/blob/main/src/axis.js#L110
|
|
130
|
+
axisItem.attr('font-family', null);
|
|
128
131
|
if (d.labels.enabled) {
|
|
129
132
|
const labels = axisItem.selectAll('.tick text');
|
|
130
133
|
const tickTexts = labels
|
|
@@ -23,10 +23,12 @@ export function useChartInnerProps(props) {
|
|
|
23
23
|
}, [data.series.data, data.xAxis, data.yAxis, zoomState]);
|
|
24
24
|
const [xAxis, setXAxis] = React.useState(null);
|
|
25
25
|
React.useEffect(() => {
|
|
26
|
+
setXAxis(null);
|
|
26
27
|
getPreparedXAxis({ xAxis: data.xAxis, width, seriesData: zoomedSeriesData }).then((val) => setXAxis(val));
|
|
27
28
|
}, [data.xAxis, width, zoomedSeriesData]);
|
|
28
29
|
const [yAxis, setYAxis] = React.useState([]);
|
|
29
30
|
React.useEffect(() => {
|
|
31
|
+
setYAxis([]);
|
|
30
32
|
getPreparedYAxis({ yAxis: data.yAxis, height, seriesData: zoomedSeriesData }).then((val) => setYAxis(val));
|
|
31
33
|
}, [data.yAxis, height, zoomedSeriesData]);
|
|
32
34
|
const { legendItems, legendConfig, preparedSeries, preparedSeriesOptions, preparedLegend, handleLegendItemClick, } = useSeries({
|
|
@@ -321,6 +321,7 @@ export const Legend = (props) => {
|
|
|
321
321
|
.call(xAxisGenerator);
|
|
322
322
|
legendWidth = legend.width;
|
|
323
323
|
}
|
|
324
|
+
const legendTitleClassname = b('title');
|
|
324
325
|
if (legend.title.enable) {
|
|
325
326
|
const { maxWidth: titleWidth } = await getLabelsSize({
|
|
326
327
|
labels: [legend.title.text],
|
|
@@ -342,7 +343,6 @@ export const Legend = (props) => {
|
|
|
342
343
|
break;
|
|
343
344
|
}
|
|
344
345
|
}
|
|
345
|
-
const legendTitleClassname = b('title');
|
|
346
346
|
svgElement.selectAll(`.${legendTitleClassname}`).remove();
|
|
347
347
|
svgElement
|
|
348
348
|
.append('g')
|
|
@@ -355,6 +355,9 @@ export const Legend = (props) => {
|
|
|
355
355
|
.style('dominant-baseline', 'text-before-edge')
|
|
356
356
|
.html(legend.title.text);
|
|
357
357
|
}
|
|
358
|
+
else {
|
|
359
|
+
svgElement.selectAll(`.${legendTitleClassname}`).remove();
|
|
360
|
+
}
|
|
358
361
|
const { left } = getLegendPosition({
|
|
359
362
|
align: legend.align,
|
|
360
363
|
width: boundsWidth,
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { sort } from 'd3';
|
|
1
2
|
import get from 'lodash/get';
|
|
2
3
|
import merge from 'lodash/merge';
|
|
3
4
|
import { DEFAULT_DATALABELS_STYLE } from '../../constants';
|
|
@@ -45,7 +46,7 @@ export function prepareArea(args) {
|
|
|
45
46
|
enabled: get(series, 'legend.enabled', legend.enabled),
|
|
46
47
|
symbol: prepareLegendSymbol(series),
|
|
47
48
|
},
|
|
48
|
-
data: series.data,
|
|
49
|
+
data: sort(series.data, (d) => d.x),
|
|
49
50
|
stacking: series.stacking,
|
|
50
51
|
stackId: getSeriesStackId(series),
|
|
51
52
|
dataLabels: {
|
|
@@ -3,7 +3,7 @@ import clone from 'lodash/clone';
|
|
|
3
3
|
import get from 'lodash/get';
|
|
4
4
|
import merge from 'lodash/merge';
|
|
5
5
|
import { CONTINUOUS_LEGEND_SIZE, legendDefaults } from '../../constants';
|
|
6
|
-
import { getDefaultColorStops, getDomainForContinuousColorScale,
|
|
6
|
+
import { getDefaultColorStops, getDomainForContinuousColorScale, getLabelsSize } from '../../utils';
|
|
7
7
|
import { getBoundsWidth } from '../useChartDimensions';
|
|
8
8
|
import { getYAxisWidth } from '../useChartDimensions/utils';
|
|
9
9
|
export async function getPreparedLegend(args) {
|
|
@@ -13,7 +13,7 @@ export async function getPreparedLegend(args) {
|
|
|
13
13
|
const defaultItemStyle = clone(legendDefaults.itemStyle);
|
|
14
14
|
const itemStyle = get(legend, 'itemStyle');
|
|
15
15
|
const computedItemStyle = merge(defaultItemStyle, itemStyle);
|
|
16
|
-
const lineHeight =
|
|
16
|
+
const lineHeight = (await getLabelsSize({ labels: ['Tmp'], style: computedItemStyle })).maxHeight;
|
|
17
17
|
const legendType = get(legend, 'type', 'discrete');
|
|
18
18
|
const isTitleEnabled = Boolean((_a = legend === null || legend === void 0 ? void 0 : legend.title) === null || _a === void 0 ? void 0 : _a.text);
|
|
19
19
|
const titleMargin = isTitleEnabled ? get(legend, 'title.margin', 4) : 0;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { group
|
|
1
|
+
import { group } from 'd3';
|
|
2
2
|
import { getDataCategoryValue, getLabelsSize, getLeftPosition } from '../../../utils';
|
|
3
3
|
import { getFormattedValue } from '../../../utils/chart/format';
|
|
4
4
|
import { getXValue, getYValue } from '../utils';
|
|
@@ -50,7 +50,7 @@ function getXValues(series, xAxis, xScale) {
|
|
|
50
50
|
return acc;
|
|
51
51
|
}, []);
|
|
52
52
|
}
|
|
53
|
-
return
|
|
53
|
+
return Array.from(xValues);
|
|
54
54
|
}
|
|
55
55
|
export const prepareAreaData = async (args) => {
|
|
56
56
|
const { series, xAxis, xScale, yAxis, yScale, boundsHeight: plotHeight, isOutsideBounds } = args;
|
|
@@ -23,160 +23,167 @@ export const useShapes = (args) => {
|
|
|
23
23
|
const { boundsWidth, boundsHeight, dispatcher, series, seriesOptions, xAxis, xScale, yAxis, yScale, split, htmlLayout, clipPathId, isOutsideBounds, } = args;
|
|
24
24
|
const [shapesElemens, setShapesElements] = React.useState([]);
|
|
25
25
|
const [shapesElemensData, setShapesElemensData] = React.useState([]);
|
|
26
|
-
const
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
const
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
26
|
+
const countedRef = React.useRef(0);
|
|
27
|
+
React.useEffect(() => {
|
|
28
|
+
countedRef.current++;
|
|
29
|
+
(async () => {
|
|
30
|
+
const currentRun = countedRef.current;
|
|
31
|
+
const visibleSeries = getOnlyVisibleSeries(series);
|
|
32
|
+
const groupedSeries = group(visibleSeries, (item) => item.type);
|
|
33
|
+
const shapesData = [];
|
|
34
|
+
const shapes = [];
|
|
35
|
+
await Promise.all(
|
|
36
|
+
// eslint-disable-next-line complexity
|
|
37
|
+
Array.from(groupedSeries).map(async (item) => {
|
|
38
|
+
const [seriesType, chartSeries] = item;
|
|
39
|
+
switch (seriesType) {
|
|
40
|
+
case 'bar-x': {
|
|
41
|
+
if (xAxis && xScale && (yScale === null || yScale === void 0 ? void 0 : yScale.length)) {
|
|
42
|
+
const preparedData = await prepareBarXData({
|
|
43
|
+
series: chartSeries,
|
|
44
|
+
seriesOptions,
|
|
45
|
+
xAxis,
|
|
46
|
+
xScale,
|
|
47
|
+
yAxis,
|
|
48
|
+
yScale,
|
|
49
|
+
boundsHeight,
|
|
50
|
+
});
|
|
51
|
+
shapes.push(React.createElement(BarXSeriesShapes, { key: "bar-x", dispatcher: dispatcher, seriesOptions: seriesOptions, preparedData: preparedData, htmlLayout: htmlLayout, clipPathId: clipPathId }));
|
|
52
|
+
shapesData.push(...preparedData);
|
|
53
|
+
}
|
|
54
|
+
break;
|
|
49
55
|
}
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
56
|
+
case 'bar-y': {
|
|
57
|
+
if (xAxis && xScale && (yScale === null || yScale === void 0 ? void 0 : yScale.length)) {
|
|
58
|
+
const preparedData = await prepareBarYData({
|
|
59
|
+
series: chartSeries,
|
|
60
|
+
seriesOptions,
|
|
61
|
+
xAxis,
|
|
62
|
+
xScale,
|
|
63
|
+
yAxis,
|
|
64
|
+
yScale,
|
|
65
|
+
});
|
|
66
|
+
shapes.push(React.createElement(BarYSeriesShapes, { key: "bar-y", dispatcher: dispatcher, seriesOptions: seriesOptions, preparedData: preparedData, htmlLayout: htmlLayout, clipPathId: clipPathId }));
|
|
67
|
+
shapesData.push(...preparedData);
|
|
68
|
+
}
|
|
69
|
+
break;
|
|
70
|
+
}
|
|
71
|
+
case 'waterfall': {
|
|
72
|
+
if (xAxis && xScale && (yScale === null || yScale === void 0 ? void 0 : yScale.length)) {
|
|
73
|
+
const preparedData = await prepareWaterfallData({
|
|
74
|
+
series: chartSeries,
|
|
75
|
+
seriesOptions,
|
|
76
|
+
xAxis,
|
|
77
|
+
xScale,
|
|
78
|
+
yAxis,
|
|
79
|
+
yScale,
|
|
80
|
+
});
|
|
81
|
+
shapes.push(React.createElement(WaterfallSeriesShapes, { key: "waterfall", dispatcher: dispatcher, seriesOptions: seriesOptions, preparedData: preparedData, htmlLayout: htmlLayout, clipPathId: clipPathId }));
|
|
82
|
+
shapesData.push(...preparedData);
|
|
83
|
+
}
|
|
84
|
+
break;
|
|
85
|
+
}
|
|
86
|
+
case 'line': {
|
|
87
|
+
if (xAxis && xScale && (yScale === null || yScale === void 0 ? void 0 : yScale.length)) {
|
|
88
|
+
const preparedData = await prepareLineData({
|
|
89
|
+
series: chartSeries,
|
|
90
|
+
xAxis,
|
|
91
|
+
xScale,
|
|
92
|
+
yAxis,
|
|
93
|
+
yScale,
|
|
94
|
+
split,
|
|
95
|
+
isOutsideBounds,
|
|
96
|
+
});
|
|
97
|
+
shapes.push(React.createElement(LineSeriesShapes, { key: "line", dispatcher: dispatcher, seriesOptions: seriesOptions, preparedData: preparedData, htmlLayout: htmlLayout, clipPathId: clipPathId }));
|
|
98
|
+
shapesData.push(...preparedData);
|
|
99
|
+
}
|
|
100
|
+
break;
|
|
101
|
+
}
|
|
102
|
+
case 'area': {
|
|
103
|
+
if (xAxis && xScale && (yScale === null || yScale === void 0 ? void 0 : yScale.length)) {
|
|
104
|
+
const preparedData = await prepareAreaData({
|
|
105
|
+
series: chartSeries,
|
|
106
|
+
xAxis,
|
|
107
|
+
xScale,
|
|
108
|
+
yAxis,
|
|
109
|
+
yScale,
|
|
110
|
+
boundsHeight,
|
|
111
|
+
isOutsideBounds,
|
|
112
|
+
});
|
|
113
|
+
shapes.push(React.createElement(AreaSeriesShapes, { key: "area", dispatcher: dispatcher, seriesOptions: seriesOptions, preparedData: preparedData, htmlLayout: htmlLayout, clipPathId: clipPathId }));
|
|
114
|
+
shapesData.push(...preparedData);
|
|
115
|
+
}
|
|
116
|
+
break;
|
|
117
|
+
}
|
|
118
|
+
case 'scatter': {
|
|
119
|
+
if (xAxis && xScale && (yScale === null || yScale === void 0 ? void 0 : yScale.length)) {
|
|
120
|
+
const preparedData = prepareScatterData({
|
|
121
|
+
series: chartSeries,
|
|
122
|
+
xAxis,
|
|
123
|
+
xScale,
|
|
124
|
+
yAxis,
|
|
125
|
+
yScale,
|
|
126
|
+
isOutsideBounds,
|
|
127
|
+
});
|
|
128
|
+
shapes.push(React.createElement(ScatterSeriesShape, { key: "scatter", dispatcher: dispatcher, preparedData: preparedData, seriesOptions: seriesOptions, htmlLayout: htmlLayout }));
|
|
129
|
+
shapesData.push(...preparedData);
|
|
130
|
+
}
|
|
131
|
+
break;
|
|
132
|
+
}
|
|
133
|
+
case 'pie': {
|
|
134
|
+
const preparedData = await preparePieData({
|
|
55
135
|
series: chartSeries,
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
xScale,
|
|
59
|
-
yAxis,
|
|
60
|
-
yScale,
|
|
136
|
+
boundsWidth,
|
|
137
|
+
boundsHeight,
|
|
61
138
|
});
|
|
62
|
-
shapes.push(React.createElement(
|
|
139
|
+
shapes.push(React.createElement(PieSeriesShapes, { key: "pie", dispatcher: dispatcher, preparedData: preparedData, seriesOptions: seriesOptions, htmlLayout: htmlLayout }));
|
|
63
140
|
shapesData.push(...preparedData);
|
|
141
|
+
break;
|
|
64
142
|
}
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
xAxis,
|
|
73
|
-
xScale,
|
|
74
|
-
yAxis,
|
|
75
|
-
yScale,
|
|
143
|
+
case 'treemap': {
|
|
144
|
+
const preparedData = await prepareTreemapData({
|
|
145
|
+
// We should have exactly one series with "treemap" type
|
|
146
|
+
// Otherwise data validation should emit an error
|
|
147
|
+
series: chartSeries[0],
|
|
148
|
+
width: boundsWidth,
|
|
149
|
+
height: boundsHeight,
|
|
76
150
|
});
|
|
77
|
-
shapes.push(React.createElement(
|
|
78
|
-
shapesData.push(
|
|
151
|
+
shapes.push(React.createElement(TreemapSeriesShape, { key: "treemap", dispatcher: dispatcher, preparedData: preparedData, seriesOptions: seriesOptions, htmlLayout: htmlLayout }));
|
|
152
|
+
shapesData.push(preparedData);
|
|
153
|
+
break;
|
|
79
154
|
}
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
series: chartSeries,
|
|
86
|
-
xAxis,
|
|
87
|
-
xScale,
|
|
88
|
-
yAxis,
|
|
89
|
-
yScale,
|
|
90
|
-
split,
|
|
91
|
-
isOutsideBounds,
|
|
155
|
+
case 'sankey': {
|
|
156
|
+
const preparedData = prepareSankeyData({
|
|
157
|
+
series: chartSeries[0],
|
|
158
|
+
width: boundsWidth,
|
|
159
|
+
height: boundsHeight,
|
|
92
160
|
});
|
|
93
|
-
shapes.push(React.createElement(
|
|
94
|
-
shapesData.push(
|
|
161
|
+
shapes.push(React.createElement(SankeySeriesShape, { key: "sankey", dispatcher: dispatcher, preparedData: preparedData, seriesOptions: seriesOptions, htmlLayout: htmlLayout }));
|
|
162
|
+
shapesData.push(preparedData);
|
|
163
|
+
break;
|
|
95
164
|
}
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
case 'area': {
|
|
99
|
-
if (xAxis && xScale && yScale) {
|
|
100
|
-
const preparedData = await prepareAreaData({
|
|
165
|
+
case 'radar': {
|
|
166
|
+
const preparedData = await prepareRadarData({
|
|
101
167
|
series: chartSeries,
|
|
102
|
-
|
|
103
|
-
xScale,
|
|
104
|
-
yAxis,
|
|
105
|
-
yScale,
|
|
168
|
+
boundsWidth,
|
|
106
169
|
boundsHeight,
|
|
107
|
-
isOutsideBounds,
|
|
108
170
|
});
|
|
109
|
-
shapes.push(React.createElement(
|
|
171
|
+
shapes.push(React.createElement(RadarSeriesShapes, { key: "radar", dispatcher: dispatcher, series: preparedData, seriesOptions: seriesOptions, htmlLayout: htmlLayout }));
|
|
110
172
|
shapesData.push(...preparedData);
|
|
173
|
+
break;
|
|
111
174
|
}
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
if (xAxis && xScale && yScale) {
|
|
116
|
-
const preparedData = prepareScatterData({
|
|
117
|
-
series: chartSeries,
|
|
118
|
-
xAxis,
|
|
119
|
-
xScale,
|
|
120
|
-
yAxis,
|
|
121
|
-
yScale,
|
|
122
|
-
isOutsideBounds,
|
|
175
|
+
default: {
|
|
176
|
+
throw new ChartError({
|
|
177
|
+
message: `The display method is not defined for a series with type "${seriesType}"`,
|
|
123
178
|
});
|
|
124
|
-
shapes.push(React.createElement(ScatterSeriesShape, { key: "scatter", dispatcher: dispatcher, preparedData: preparedData, seriesOptions: seriesOptions, htmlLayout: htmlLayout }));
|
|
125
|
-
shapesData.push(...preparedData);
|
|
126
179
|
}
|
|
127
|
-
break;
|
|
128
|
-
}
|
|
129
|
-
case 'pie': {
|
|
130
|
-
const preparedData = await preparePieData({
|
|
131
|
-
series: chartSeries,
|
|
132
|
-
boundsWidth,
|
|
133
|
-
boundsHeight,
|
|
134
|
-
});
|
|
135
|
-
shapes.push(React.createElement(PieSeriesShapes, { key: "pie", dispatcher: dispatcher, preparedData: preparedData, seriesOptions: seriesOptions, htmlLayout: htmlLayout }));
|
|
136
|
-
shapesData.push(...preparedData);
|
|
137
|
-
break;
|
|
138
|
-
}
|
|
139
|
-
case 'treemap': {
|
|
140
|
-
const preparedData = await prepareTreemapData({
|
|
141
|
-
// We should have exactly one series with "treemap" type
|
|
142
|
-
// Otherwise data validation should emit an error
|
|
143
|
-
series: chartSeries[0],
|
|
144
|
-
width: boundsWidth,
|
|
145
|
-
height: boundsHeight,
|
|
146
|
-
});
|
|
147
|
-
shapes.push(React.createElement(TreemapSeriesShape, { key: "treemap", dispatcher: dispatcher, preparedData: preparedData, seriesOptions: seriesOptions, htmlLayout: htmlLayout }));
|
|
148
|
-
shapesData.push(preparedData);
|
|
149
|
-
break;
|
|
150
|
-
}
|
|
151
|
-
case 'sankey': {
|
|
152
|
-
const preparedData = prepareSankeyData({
|
|
153
|
-
series: chartSeries[0],
|
|
154
|
-
width: boundsWidth,
|
|
155
|
-
height: boundsHeight,
|
|
156
|
-
});
|
|
157
|
-
shapes.push(React.createElement(SankeySeriesShape, { key: "sankey", dispatcher: dispatcher, preparedData: preparedData, seriesOptions: seriesOptions, htmlLayout: htmlLayout }));
|
|
158
|
-
shapesData.push(preparedData);
|
|
159
|
-
break;
|
|
160
|
-
}
|
|
161
|
-
case 'radar': {
|
|
162
|
-
const preparedData = await prepareRadarData({
|
|
163
|
-
series: chartSeries,
|
|
164
|
-
boundsWidth,
|
|
165
|
-
boundsHeight,
|
|
166
|
-
});
|
|
167
|
-
shapes.push(React.createElement(RadarSeriesShapes, { key: "radar", dispatcher: dispatcher, series: preparedData, seriesOptions: seriesOptions, htmlLayout: htmlLayout }));
|
|
168
|
-
shapesData.push(...preparedData);
|
|
169
|
-
break;
|
|
170
|
-
}
|
|
171
|
-
default: {
|
|
172
|
-
throw new ChartError({
|
|
173
|
-
message: `The display method is not defined for a series with type "${seriesType}"`,
|
|
174
|
-
});
|
|
175
180
|
}
|
|
181
|
+
}));
|
|
182
|
+
if (countedRef.current === currentRun) {
|
|
183
|
+
setShapesElements(shapes);
|
|
184
|
+
setShapesElemensData(shapesData);
|
|
176
185
|
}
|
|
177
|
-
}));
|
|
178
|
-
setShapesElements(shapes);
|
|
179
|
-
setShapesElemensData(shapesData);
|
|
186
|
+
})();
|
|
180
187
|
}, [
|
|
181
188
|
boundsHeight,
|
|
182
189
|
boundsWidth,
|
|
@@ -192,8 +199,5 @@ export const useShapes = (args) => {
|
|
|
192
199
|
clipPathId,
|
|
193
200
|
isOutsideBounds,
|
|
194
201
|
]);
|
|
195
|
-
React.useEffect(() => {
|
|
196
|
-
setShapes();
|
|
197
|
-
}, [setShapes]);
|
|
198
202
|
return { shapes: shapesElemens, shapesData: shapesElemensData };
|
|
199
203
|
};
|
|
@@ -125,6 +125,9 @@ export const AxisY = (props) => {
|
|
|
125
125
|
scale: seriesScale,
|
|
126
126
|
});
|
|
127
127
|
yAxisGenerator(axisItem);
|
|
128
|
+
// because the standard generator interrupts the desired font
|
|
129
|
+
// https://github.com/d3/d3-axis/blob/main/src/axis.js#L110
|
|
130
|
+
axisItem.attr('font-family', null);
|
|
128
131
|
if (d.labels.enabled) {
|
|
129
132
|
const labels = axisItem.selectAll('.tick text');
|
|
130
133
|
const tickTexts = labels
|
|
@@ -23,10 +23,12 @@ export function useChartInnerProps(props) {
|
|
|
23
23
|
}, [data.series.data, data.xAxis, data.yAxis, zoomState]);
|
|
24
24
|
const [xAxis, setXAxis] = React.useState(null);
|
|
25
25
|
React.useEffect(() => {
|
|
26
|
+
setXAxis(null);
|
|
26
27
|
getPreparedXAxis({ xAxis: data.xAxis, width, seriesData: zoomedSeriesData }).then((val) => setXAxis(val));
|
|
27
28
|
}, [data.xAxis, width, zoomedSeriesData]);
|
|
28
29
|
const [yAxis, setYAxis] = React.useState([]);
|
|
29
30
|
React.useEffect(() => {
|
|
31
|
+
setYAxis([]);
|
|
30
32
|
getPreparedYAxis({ yAxis: data.yAxis, height, seriesData: zoomedSeriesData }).then((val) => setYAxis(val));
|
|
31
33
|
}, [data.yAxis, height, zoomedSeriesData]);
|
|
32
34
|
const { legendItems, legendConfig, preparedSeries, preparedSeriesOptions, preparedLegend, handleLegendItemClick, } = useSeries({
|
|
@@ -321,6 +321,7 @@ export const Legend = (props) => {
|
|
|
321
321
|
.call(xAxisGenerator);
|
|
322
322
|
legendWidth = legend.width;
|
|
323
323
|
}
|
|
324
|
+
const legendTitleClassname = b('title');
|
|
324
325
|
if (legend.title.enable) {
|
|
325
326
|
const { maxWidth: titleWidth } = await getLabelsSize({
|
|
326
327
|
labels: [legend.title.text],
|
|
@@ -342,7 +343,6 @@ export const Legend = (props) => {
|
|
|
342
343
|
break;
|
|
343
344
|
}
|
|
344
345
|
}
|
|
345
|
-
const legendTitleClassname = b('title');
|
|
346
346
|
svgElement.selectAll(`.${legendTitleClassname}`).remove();
|
|
347
347
|
svgElement
|
|
348
348
|
.append('g')
|
|
@@ -355,6 +355,9 @@ export const Legend = (props) => {
|
|
|
355
355
|
.style('dominant-baseline', 'text-before-edge')
|
|
356
356
|
.html(legend.title.text);
|
|
357
357
|
}
|
|
358
|
+
else {
|
|
359
|
+
svgElement.selectAll(`.${legendTitleClassname}`).remove();
|
|
360
|
+
}
|
|
358
361
|
const { left } = getLegendPosition({
|
|
359
362
|
align: legend.align,
|
|
360
363
|
width: boundsWidth,
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { sort } from 'd3';
|
|
1
2
|
import get from 'lodash/get';
|
|
2
3
|
import merge from 'lodash/merge';
|
|
3
4
|
import { DEFAULT_DATALABELS_STYLE } from '../../constants';
|
|
@@ -45,7 +46,7 @@ export function prepareArea(args) {
|
|
|
45
46
|
enabled: get(series, 'legend.enabled', legend.enabled),
|
|
46
47
|
symbol: prepareLegendSymbol(series),
|
|
47
48
|
},
|
|
48
|
-
data: series.data,
|
|
49
|
+
data: sort(series.data, (d) => d.x),
|
|
49
50
|
stacking: series.stacking,
|
|
50
51
|
stackId: getSeriesStackId(series),
|
|
51
52
|
dataLabels: {
|
|
@@ -3,7 +3,7 @@ import clone from 'lodash/clone';
|
|
|
3
3
|
import get from 'lodash/get';
|
|
4
4
|
import merge from 'lodash/merge';
|
|
5
5
|
import { CONTINUOUS_LEGEND_SIZE, legendDefaults } from '../../constants';
|
|
6
|
-
import { getDefaultColorStops, getDomainForContinuousColorScale,
|
|
6
|
+
import { getDefaultColorStops, getDomainForContinuousColorScale, getLabelsSize } from '../../utils';
|
|
7
7
|
import { getBoundsWidth } from '../useChartDimensions';
|
|
8
8
|
import { getYAxisWidth } from '../useChartDimensions/utils';
|
|
9
9
|
export async function getPreparedLegend(args) {
|
|
@@ -13,7 +13,7 @@ export async function getPreparedLegend(args) {
|
|
|
13
13
|
const defaultItemStyle = clone(legendDefaults.itemStyle);
|
|
14
14
|
const itemStyle = get(legend, 'itemStyle');
|
|
15
15
|
const computedItemStyle = merge(defaultItemStyle, itemStyle);
|
|
16
|
-
const lineHeight =
|
|
16
|
+
const lineHeight = (await getLabelsSize({ labels: ['Tmp'], style: computedItemStyle })).maxHeight;
|
|
17
17
|
const legendType = get(legend, 'type', 'discrete');
|
|
18
18
|
const isTitleEnabled = Boolean((_a = legend === null || legend === void 0 ? void 0 : legend.title) === null || _a === void 0 ? void 0 : _a.text);
|
|
19
19
|
const titleMargin = isTitleEnabled ? get(legend, 'title.margin', 4) : 0;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { group
|
|
1
|
+
import { group } from 'd3';
|
|
2
2
|
import { getDataCategoryValue, getLabelsSize, getLeftPosition } from '../../../utils';
|
|
3
3
|
import { getFormattedValue } from '../../../utils/chart/format';
|
|
4
4
|
import { getXValue, getYValue } from '../utils';
|
|
@@ -50,7 +50,7 @@ function getXValues(series, xAxis, xScale) {
|
|
|
50
50
|
return acc;
|
|
51
51
|
}, []);
|
|
52
52
|
}
|
|
53
|
-
return
|
|
53
|
+
return Array.from(xValues);
|
|
54
54
|
}
|
|
55
55
|
export const prepareAreaData = async (args) => {
|
|
56
56
|
const { series, xAxis, xScale, yAxis, yScale, boundsHeight: plotHeight, isOutsideBounds } = args;
|
|
@@ -23,160 +23,167 @@ export const useShapes = (args) => {
|
|
|
23
23
|
const { boundsWidth, boundsHeight, dispatcher, series, seriesOptions, xAxis, xScale, yAxis, yScale, split, htmlLayout, clipPathId, isOutsideBounds, } = args;
|
|
24
24
|
const [shapesElemens, setShapesElements] = React.useState([]);
|
|
25
25
|
const [shapesElemensData, setShapesElemensData] = React.useState([]);
|
|
26
|
-
const
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
const
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
26
|
+
const countedRef = React.useRef(0);
|
|
27
|
+
React.useEffect(() => {
|
|
28
|
+
countedRef.current++;
|
|
29
|
+
(async () => {
|
|
30
|
+
const currentRun = countedRef.current;
|
|
31
|
+
const visibleSeries = getOnlyVisibleSeries(series);
|
|
32
|
+
const groupedSeries = group(visibleSeries, (item) => item.type);
|
|
33
|
+
const shapesData = [];
|
|
34
|
+
const shapes = [];
|
|
35
|
+
await Promise.all(
|
|
36
|
+
// eslint-disable-next-line complexity
|
|
37
|
+
Array.from(groupedSeries).map(async (item) => {
|
|
38
|
+
const [seriesType, chartSeries] = item;
|
|
39
|
+
switch (seriesType) {
|
|
40
|
+
case 'bar-x': {
|
|
41
|
+
if (xAxis && xScale && (yScale === null || yScale === void 0 ? void 0 : yScale.length)) {
|
|
42
|
+
const preparedData = await prepareBarXData({
|
|
43
|
+
series: chartSeries,
|
|
44
|
+
seriesOptions,
|
|
45
|
+
xAxis,
|
|
46
|
+
xScale,
|
|
47
|
+
yAxis,
|
|
48
|
+
yScale,
|
|
49
|
+
boundsHeight,
|
|
50
|
+
});
|
|
51
|
+
shapes.push(React.createElement(BarXSeriesShapes, { key: "bar-x", dispatcher: dispatcher, seriesOptions: seriesOptions, preparedData: preparedData, htmlLayout: htmlLayout, clipPathId: clipPathId }));
|
|
52
|
+
shapesData.push(...preparedData);
|
|
53
|
+
}
|
|
54
|
+
break;
|
|
49
55
|
}
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
56
|
+
case 'bar-y': {
|
|
57
|
+
if (xAxis && xScale && (yScale === null || yScale === void 0 ? void 0 : yScale.length)) {
|
|
58
|
+
const preparedData = await prepareBarYData({
|
|
59
|
+
series: chartSeries,
|
|
60
|
+
seriesOptions,
|
|
61
|
+
xAxis,
|
|
62
|
+
xScale,
|
|
63
|
+
yAxis,
|
|
64
|
+
yScale,
|
|
65
|
+
});
|
|
66
|
+
shapes.push(React.createElement(BarYSeriesShapes, { key: "bar-y", dispatcher: dispatcher, seriesOptions: seriesOptions, preparedData: preparedData, htmlLayout: htmlLayout, clipPathId: clipPathId }));
|
|
67
|
+
shapesData.push(...preparedData);
|
|
68
|
+
}
|
|
69
|
+
break;
|
|
70
|
+
}
|
|
71
|
+
case 'waterfall': {
|
|
72
|
+
if (xAxis && xScale && (yScale === null || yScale === void 0 ? void 0 : yScale.length)) {
|
|
73
|
+
const preparedData = await prepareWaterfallData({
|
|
74
|
+
series: chartSeries,
|
|
75
|
+
seriesOptions,
|
|
76
|
+
xAxis,
|
|
77
|
+
xScale,
|
|
78
|
+
yAxis,
|
|
79
|
+
yScale,
|
|
80
|
+
});
|
|
81
|
+
shapes.push(React.createElement(WaterfallSeriesShapes, { key: "waterfall", dispatcher: dispatcher, seriesOptions: seriesOptions, preparedData: preparedData, htmlLayout: htmlLayout, clipPathId: clipPathId }));
|
|
82
|
+
shapesData.push(...preparedData);
|
|
83
|
+
}
|
|
84
|
+
break;
|
|
85
|
+
}
|
|
86
|
+
case 'line': {
|
|
87
|
+
if (xAxis && xScale && (yScale === null || yScale === void 0 ? void 0 : yScale.length)) {
|
|
88
|
+
const preparedData = await prepareLineData({
|
|
89
|
+
series: chartSeries,
|
|
90
|
+
xAxis,
|
|
91
|
+
xScale,
|
|
92
|
+
yAxis,
|
|
93
|
+
yScale,
|
|
94
|
+
split,
|
|
95
|
+
isOutsideBounds,
|
|
96
|
+
});
|
|
97
|
+
shapes.push(React.createElement(LineSeriesShapes, { key: "line", dispatcher: dispatcher, seriesOptions: seriesOptions, preparedData: preparedData, htmlLayout: htmlLayout, clipPathId: clipPathId }));
|
|
98
|
+
shapesData.push(...preparedData);
|
|
99
|
+
}
|
|
100
|
+
break;
|
|
101
|
+
}
|
|
102
|
+
case 'area': {
|
|
103
|
+
if (xAxis && xScale && (yScale === null || yScale === void 0 ? void 0 : yScale.length)) {
|
|
104
|
+
const preparedData = await prepareAreaData({
|
|
105
|
+
series: chartSeries,
|
|
106
|
+
xAxis,
|
|
107
|
+
xScale,
|
|
108
|
+
yAxis,
|
|
109
|
+
yScale,
|
|
110
|
+
boundsHeight,
|
|
111
|
+
isOutsideBounds,
|
|
112
|
+
});
|
|
113
|
+
shapes.push(React.createElement(AreaSeriesShapes, { key: "area", dispatcher: dispatcher, seriesOptions: seriesOptions, preparedData: preparedData, htmlLayout: htmlLayout, clipPathId: clipPathId }));
|
|
114
|
+
shapesData.push(...preparedData);
|
|
115
|
+
}
|
|
116
|
+
break;
|
|
117
|
+
}
|
|
118
|
+
case 'scatter': {
|
|
119
|
+
if (xAxis && xScale && (yScale === null || yScale === void 0 ? void 0 : yScale.length)) {
|
|
120
|
+
const preparedData = prepareScatterData({
|
|
121
|
+
series: chartSeries,
|
|
122
|
+
xAxis,
|
|
123
|
+
xScale,
|
|
124
|
+
yAxis,
|
|
125
|
+
yScale,
|
|
126
|
+
isOutsideBounds,
|
|
127
|
+
});
|
|
128
|
+
shapes.push(React.createElement(ScatterSeriesShape, { key: "scatter", dispatcher: dispatcher, preparedData: preparedData, seriesOptions: seriesOptions, htmlLayout: htmlLayout }));
|
|
129
|
+
shapesData.push(...preparedData);
|
|
130
|
+
}
|
|
131
|
+
break;
|
|
132
|
+
}
|
|
133
|
+
case 'pie': {
|
|
134
|
+
const preparedData = await preparePieData({
|
|
55
135
|
series: chartSeries,
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
xScale,
|
|
59
|
-
yAxis,
|
|
60
|
-
yScale,
|
|
136
|
+
boundsWidth,
|
|
137
|
+
boundsHeight,
|
|
61
138
|
});
|
|
62
|
-
shapes.push(React.createElement(
|
|
139
|
+
shapes.push(React.createElement(PieSeriesShapes, { key: "pie", dispatcher: dispatcher, preparedData: preparedData, seriesOptions: seriesOptions, htmlLayout: htmlLayout }));
|
|
63
140
|
shapesData.push(...preparedData);
|
|
141
|
+
break;
|
|
64
142
|
}
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
xAxis,
|
|
73
|
-
xScale,
|
|
74
|
-
yAxis,
|
|
75
|
-
yScale,
|
|
143
|
+
case 'treemap': {
|
|
144
|
+
const preparedData = await prepareTreemapData({
|
|
145
|
+
// We should have exactly one series with "treemap" type
|
|
146
|
+
// Otherwise data validation should emit an error
|
|
147
|
+
series: chartSeries[0],
|
|
148
|
+
width: boundsWidth,
|
|
149
|
+
height: boundsHeight,
|
|
76
150
|
});
|
|
77
|
-
shapes.push(React.createElement(
|
|
78
|
-
shapesData.push(
|
|
151
|
+
shapes.push(React.createElement(TreemapSeriesShape, { key: "treemap", dispatcher: dispatcher, preparedData: preparedData, seriesOptions: seriesOptions, htmlLayout: htmlLayout }));
|
|
152
|
+
shapesData.push(preparedData);
|
|
153
|
+
break;
|
|
79
154
|
}
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
series: chartSeries,
|
|
86
|
-
xAxis,
|
|
87
|
-
xScale,
|
|
88
|
-
yAxis,
|
|
89
|
-
yScale,
|
|
90
|
-
split,
|
|
91
|
-
isOutsideBounds,
|
|
155
|
+
case 'sankey': {
|
|
156
|
+
const preparedData = prepareSankeyData({
|
|
157
|
+
series: chartSeries[0],
|
|
158
|
+
width: boundsWidth,
|
|
159
|
+
height: boundsHeight,
|
|
92
160
|
});
|
|
93
|
-
shapes.push(React.createElement(
|
|
94
|
-
shapesData.push(
|
|
161
|
+
shapes.push(React.createElement(SankeySeriesShape, { key: "sankey", dispatcher: dispatcher, preparedData: preparedData, seriesOptions: seriesOptions, htmlLayout: htmlLayout }));
|
|
162
|
+
shapesData.push(preparedData);
|
|
163
|
+
break;
|
|
95
164
|
}
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
case 'area': {
|
|
99
|
-
if (xAxis && xScale && yScale) {
|
|
100
|
-
const preparedData = await prepareAreaData({
|
|
165
|
+
case 'radar': {
|
|
166
|
+
const preparedData = await prepareRadarData({
|
|
101
167
|
series: chartSeries,
|
|
102
|
-
|
|
103
|
-
xScale,
|
|
104
|
-
yAxis,
|
|
105
|
-
yScale,
|
|
168
|
+
boundsWidth,
|
|
106
169
|
boundsHeight,
|
|
107
|
-
isOutsideBounds,
|
|
108
170
|
});
|
|
109
|
-
shapes.push(React.createElement(
|
|
171
|
+
shapes.push(React.createElement(RadarSeriesShapes, { key: "radar", dispatcher: dispatcher, series: preparedData, seriesOptions: seriesOptions, htmlLayout: htmlLayout }));
|
|
110
172
|
shapesData.push(...preparedData);
|
|
173
|
+
break;
|
|
111
174
|
}
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
if (xAxis && xScale && yScale) {
|
|
116
|
-
const preparedData = prepareScatterData({
|
|
117
|
-
series: chartSeries,
|
|
118
|
-
xAxis,
|
|
119
|
-
xScale,
|
|
120
|
-
yAxis,
|
|
121
|
-
yScale,
|
|
122
|
-
isOutsideBounds,
|
|
175
|
+
default: {
|
|
176
|
+
throw new ChartError({
|
|
177
|
+
message: `The display method is not defined for a series with type "${seriesType}"`,
|
|
123
178
|
});
|
|
124
|
-
shapes.push(React.createElement(ScatterSeriesShape, { key: "scatter", dispatcher: dispatcher, preparedData: preparedData, seriesOptions: seriesOptions, htmlLayout: htmlLayout }));
|
|
125
|
-
shapesData.push(...preparedData);
|
|
126
179
|
}
|
|
127
|
-
break;
|
|
128
|
-
}
|
|
129
|
-
case 'pie': {
|
|
130
|
-
const preparedData = await preparePieData({
|
|
131
|
-
series: chartSeries,
|
|
132
|
-
boundsWidth,
|
|
133
|
-
boundsHeight,
|
|
134
|
-
});
|
|
135
|
-
shapes.push(React.createElement(PieSeriesShapes, { key: "pie", dispatcher: dispatcher, preparedData: preparedData, seriesOptions: seriesOptions, htmlLayout: htmlLayout }));
|
|
136
|
-
shapesData.push(...preparedData);
|
|
137
|
-
break;
|
|
138
|
-
}
|
|
139
|
-
case 'treemap': {
|
|
140
|
-
const preparedData = await prepareTreemapData({
|
|
141
|
-
// We should have exactly one series with "treemap" type
|
|
142
|
-
// Otherwise data validation should emit an error
|
|
143
|
-
series: chartSeries[0],
|
|
144
|
-
width: boundsWidth,
|
|
145
|
-
height: boundsHeight,
|
|
146
|
-
});
|
|
147
|
-
shapes.push(React.createElement(TreemapSeriesShape, { key: "treemap", dispatcher: dispatcher, preparedData: preparedData, seriesOptions: seriesOptions, htmlLayout: htmlLayout }));
|
|
148
|
-
shapesData.push(preparedData);
|
|
149
|
-
break;
|
|
150
|
-
}
|
|
151
|
-
case 'sankey': {
|
|
152
|
-
const preparedData = prepareSankeyData({
|
|
153
|
-
series: chartSeries[0],
|
|
154
|
-
width: boundsWidth,
|
|
155
|
-
height: boundsHeight,
|
|
156
|
-
});
|
|
157
|
-
shapes.push(React.createElement(SankeySeriesShape, { key: "sankey", dispatcher: dispatcher, preparedData: preparedData, seriesOptions: seriesOptions, htmlLayout: htmlLayout }));
|
|
158
|
-
shapesData.push(preparedData);
|
|
159
|
-
break;
|
|
160
|
-
}
|
|
161
|
-
case 'radar': {
|
|
162
|
-
const preparedData = await prepareRadarData({
|
|
163
|
-
series: chartSeries,
|
|
164
|
-
boundsWidth,
|
|
165
|
-
boundsHeight,
|
|
166
|
-
});
|
|
167
|
-
shapes.push(React.createElement(RadarSeriesShapes, { key: "radar", dispatcher: dispatcher, series: preparedData, seriesOptions: seriesOptions, htmlLayout: htmlLayout }));
|
|
168
|
-
shapesData.push(...preparedData);
|
|
169
|
-
break;
|
|
170
|
-
}
|
|
171
|
-
default: {
|
|
172
|
-
throw new ChartError({
|
|
173
|
-
message: `The display method is not defined for a series with type "${seriesType}"`,
|
|
174
|
-
});
|
|
175
180
|
}
|
|
181
|
+
}));
|
|
182
|
+
if (countedRef.current === currentRun) {
|
|
183
|
+
setShapesElements(shapes);
|
|
184
|
+
setShapesElemensData(shapesData);
|
|
176
185
|
}
|
|
177
|
-
}));
|
|
178
|
-
setShapesElements(shapes);
|
|
179
|
-
setShapesElemensData(shapesData);
|
|
186
|
+
})();
|
|
180
187
|
}, [
|
|
181
188
|
boundsHeight,
|
|
182
189
|
boundsWidth,
|
|
@@ -192,8 +199,5 @@ export const useShapes = (args) => {
|
|
|
192
199
|
clipPathId,
|
|
193
200
|
isOutsideBounds,
|
|
194
201
|
]);
|
|
195
|
-
React.useEffect(() => {
|
|
196
|
-
setShapes();
|
|
197
|
-
}, [setShapes]);
|
|
198
202
|
return { shapes: shapesElemens, shapesData: shapesElemensData };
|
|
199
203
|
};
|