@gravity-ui/chartkit 5.15.0 → 5.16.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/plugins/d3/renderer/components/Legend.js +129 -66
- package/build/plugins/d3/renderer/components/styles.css +8 -0
- package/build/plugins/d3/renderer/constants/defaults/legend.d.ts +12 -4
- package/build/plugins/d3/renderer/constants/defaults/legend.js +4 -0
- package/build/plugins/d3/renderer/hooks/useSeries/prepare-area.js +1 -0
- package/build/plugins/d3/renderer/hooks/useSeries/prepare-bar-x.js +1 -0
- package/build/plugins/d3/renderer/hooks/useSeries/prepare-bar-y.js +8 -6
- package/build/plugins/d3/renderer/hooks/useSeries/prepare-legend.js +58 -11
- package/build/plugins/d3/renderer/hooks/useSeries/prepare-line.js +1 -0
- package/build/plugins/d3/renderer/hooks/useSeries/prepare-treemap.js +1 -0
- package/build/plugins/d3/renderer/hooks/useSeries/prepare-waterfall.js +1 -0
- package/build/plugins/d3/renderer/hooks/useSeries/types.d.ts +23 -1
- package/build/plugins/d3/renderer/hooks/useShapes/HtmlLayer.d.ts +8 -0
- package/build/plugins/d3/renderer/hooks/useShapes/HtmlLayer.js +22 -0
- package/build/plugins/d3/renderer/hooks/useShapes/area/index.d.ts +1 -0
- package/build/plugins/d3/renderer/hooks/useShapes/area/index.js +5 -2
- package/build/plugins/d3/renderer/hooks/useShapes/area/prepare-data.js +18 -3
- package/build/plugins/d3/renderer/hooks/useShapes/area/types.d.ts +2 -1
- package/build/plugins/d3/renderer/hooks/useShapes/bar-x/index.d.ts +1 -0
- package/build/plugins/d3/renderer/hooks/useShapes/bar-x/index.js +5 -2
- package/build/plugins/d3/renderer/hooks/useShapes/bar-x/prepare-data.js +21 -4
- package/build/plugins/d3/renderer/hooks/useShapes/bar-x/types.d.ts +2 -1
- package/build/plugins/d3/renderer/hooks/useShapes/bar-y/index.d.ts +1 -0
- package/build/plugins/d3/renderer/hooks/useShapes/bar-y/index.js +18 -23
- package/build/plugins/d3/renderer/hooks/useShapes/bar-y/prepare-data.js +44 -3
- package/build/plugins/d3/renderer/hooks/useShapes/bar-y/types.d.ts +3 -0
- package/build/plugins/d3/renderer/hooks/useShapes/index.js +7 -7
- package/build/plugins/d3/renderer/hooks/useShapes/line/index.d.ts +1 -0
- package/build/plugins/d3/renderer/hooks/useShapes/line/index.js +5 -2
- package/build/plugins/d3/renderer/hooks/useShapes/line/prepare-data.js +17 -1
- package/build/plugins/d3/renderer/hooks/useShapes/line/types.d.ts +2 -1
- package/build/plugins/d3/renderer/hooks/useShapes/pie/index.js +2 -10
- package/build/plugins/d3/renderer/hooks/useShapes/pie/prepare-data.js +0 -1
- package/build/plugins/d3/renderer/hooks/useShapes/scatter/index.d.ts +1 -0
- package/build/plugins/d3/renderer/hooks/useShapes/scatter/index.js +5 -2
- package/build/plugins/d3/renderer/hooks/useShapes/scatter/prepare-data.js +1 -0
- package/build/plugins/d3/renderer/hooks/useShapes/scatter/types.d.ts +2 -0
- package/build/plugins/d3/renderer/hooks/useShapes/treemap/index.d.ts +1 -0
- package/build/plugins/d3/renderer/hooks/useShapes/treemap/index.js +5 -2
- package/build/plugins/d3/renderer/hooks/useShapes/treemap/prepare-data.js +1 -1
- package/build/plugins/d3/renderer/hooks/useShapes/treemap/types.d.ts +2 -0
- package/build/plugins/d3/renderer/hooks/useShapes/waterfall/index.d.ts +1 -0
- package/build/plugins/d3/renderer/hooks/useShapes/waterfall/index.js +5 -2
- package/build/plugins/d3/renderer/hooks/useShapes/waterfall/prepare-data.js +1 -0
- package/build/plugins/d3/renderer/hooks/useShapes/waterfall/types.d.ts +2 -1
- package/build/plugins/d3/renderer/types/index.d.ts +3 -1
- package/build/plugins/d3/renderer/utils/axis-generators/bottom.d.ts +5 -4
- package/build/plugins/d3/renderer/utils/axis-generators/bottom.js +11 -7
- package/build/plugins/d3/renderer/utils/axis.d.ts +1 -1
- package/build/plugins/d3/renderer/utils/axis.js +1 -1
- package/build/plugins/d3/renderer/utils/color.d.ts +10 -0
- package/build/plugins/d3/renderer/utils/color.js +43 -0
- package/build/plugins/d3/renderer/utils/index.d.ts +2 -0
- package/build/plugins/d3/renderer/utils/index.js +2 -0
- package/build/plugins/d3/renderer/utils/legend.d.ts +8 -0
- package/build/plugins/d3/renderer/utils/legend.js +23 -0
- package/build/plugins/d3/renderer/utils/text.js +17 -10
- package/build/types/widget-data/bar-x.d.ts +1 -1
- package/build/types/widget-data/legend.d.ts +24 -0
- package/package.json +1 -1
|
@@ -3,11 +3,12 @@ import { color, select } from 'd3';
|
|
|
3
3
|
import get from 'lodash/get';
|
|
4
4
|
import { block } from '../../../../../../utils/cn';
|
|
5
5
|
import { filterOverlappingLabels } from '../../../utils';
|
|
6
|
+
import { HtmlLayer } from '../HtmlLayer';
|
|
6
7
|
export { prepareBarXData } from './prepare-data';
|
|
7
8
|
export * from './types';
|
|
8
9
|
const b = block('d3-bar-x');
|
|
9
10
|
export const BarXSeriesShapes = (args) => {
|
|
10
|
-
const { dispatcher, preparedData, seriesOptions } = args;
|
|
11
|
+
const { dispatcher, preparedData, seriesOptions, htmlLayout } = args;
|
|
11
12
|
const ref = React.useRef(null);
|
|
12
13
|
React.useEffect(() => {
|
|
13
14
|
var _a;
|
|
@@ -89,5 +90,7 @@ export const BarXSeriesShapes = (args) => {
|
|
|
89
90
|
dispatcher.on('hover-shape.bar-x', null);
|
|
90
91
|
};
|
|
91
92
|
}, [dispatcher, preparedData, seriesOptions]);
|
|
92
|
-
return React.createElement(
|
|
93
|
+
return (React.createElement(React.Fragment, null,
|
|
94
|
+
React.createElement("g", { ref: ref, className: b() }),
|
|
95
|
+
React.createElement(HtmlLayer, { preparedData: preparedData, htmlLayout: htmlLayout })));
|
|
93
96
|
};
|
|
@@ -8,15 +8,21 @@ function getLabelData(d) {
|
|
|
8
8
|
}
|
|
9
9
|
const text = String(d.data.label || d.data.y);
|
|
10
10
|
const style = d.series.dataLabels.style;
|
|
11
|
-
const
|
|
11
|
+
const html = d.series.dataLabels.html;
|
|
12
|
+
const { maxHeight: height, maxWidth: width } = getLabelsSize({
|
|
13
|
+
labels: [text],
|
|
14
|
+
style,
|
|
15
|
+
html,
|
|
16
|
+
});
|
|
12
17
|
let y = Math.max(height, d.y - d.series.dataLabels.padding);
|
|
13
18
|
if (d.series.dataLabels.inside) {
|
|
14
19
|
y = d.y + d.height / 2;
|
|
15
20
|
}
|
|
21
|
+
const x = d.x + d.width / 2;
|
|
16
22
|
return {
|
|
17
23
|
text,
|
|
18
|
-
x:
|
|
19
|
-
y,
|
|
24
|
+
x: html ? x - width / 2 : x,
|
|
25
|
+
y: html ? y - height : y,
|
|
20
26
|
style,
|
|
21
27
|
size: { width, height },
|
|
22
28
|
textAnchor: 'middle',
|
|
@@ -122,8 +128,19 @@ export const prepareBarXData = (args) => {
|
|
|
122
128
|
opacity: get(yValue.data, 'opacity', null),
|
|
123
129
|
data: yValue.data,
|
|
124
130
|
series: yValue.series,
|
|
131
|
+
htmlElements: [],
|
|
125
132
|
};
|
|
126
|
-
|
|
133
|
+
const label = getLabelData(barData);
|
|
134
|
+
if (yValue.series.dataLabels.html && label) {
|
|
135
|
+
barData.htmlElements.push({
|
|
136
|
+
x: label.x,
|
|
137
|
+
y: label.y,
|
|
138
|
+
content: label.text,
|
|
139
|
+
});
|
|
140
|
+
}
|
|
141
|
+
else {
|
|
142
|
+
barData.label = getLabelData(barData);
|
|
143
|
+
}
|
|
127
144
|
stackItems.push(barData);
|
|
128
145
|
stackHeight += height + 1;
|
|
129
146
|
});
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { TooltipDataChunkBarX } from '../../../../../../types';
|
|
2
|
-
import { LabelData } from '../../../types';
|
|
2
|
+
import { HtmlItem, LabelData } from '../../../types';
|
|
3
3
|
import { PreparedBarXSeries } from '../../useSeries/types';
|
|
4
4
|
export type PreparedBarXData = Omit<TooltipDataChunkBarX, 'series'> & {
|
|
5
5
|
x: number;
|
|
@@ -9,4 +9,5 @@ export type PreparedBarXData = Omit<TooltipDataChunkBarX, 'series'> & {
|
|
|
9
9
|
opacity: number | null;
|
|
10
10
|
series: PreparedBarXSeries;
|
|
11
11
|
label?: LabelData;
|
|
12
|
+
htmlElements: HtmlItem[];
|
|
12
13
|
};
|
|
@@ -2,11 +2,11 @@ import React from 'react';
|
|
|
2
2
|
import { color, select } from 'd3';
|
|
3
3
|
import get from 'lodash/get';
|
|
4
4
|
import { block } from '../../../../../../utils/cn';
|
|
5
|
+
import { HtmlLayer } from '../HtmlLayer';
|
|
5
6
|
export { prepareBarYData } from './prepare-data';
|
|
6
|
-
const DEFAULT_LABEL_PADDING = 7;
|
|
7
7
|
const b = block('d3-bar-y');
|
|
8
8
|
export const BarYSeriesShapes = (args) => {
|
|
9
|
-
const { dispatcher, preparedData, seriesOptions } = args;
|
|
9
|
+
const { dispatcher, preparedData, seriesOptions, htmlLayout } = args;
|
|
10
10
|
const ref = React.useRef(null);
|
|
11
11
|
React.useEffect(() => {
|
|
12
12
|
if (!ref.current) {
|
|
@@ -26,31 +26,24 @@ export const BarYSeriesShapes = (args) => {
|
|
|
26
26
|
.attr('fill', (d) => d.color)
|
|
27
27
|
.attr('opacity', (d) => d.data.opacity || null)
|
|
28
28
|
.attr('cursor', (d) => d.series.cursor);
|
|
29
|
-
const dataLabels = preparedData.
|
|
29
|
+
const dataLabels = preparedData.reduce((acc, d) => {
|
|
30
|
+
if (d.label) {
|
|
31
|
+
acc.push(d.label);
|
|
32
|
+
}
|
|
33
|
+
return acc;
|
|
34
|
+
}, []);
|
|
30
35
|
const labelSelection = svgElement
|
|
31
36
|
.selectAll('text')
|
|
32
37
|
.data(dataLabels)
|
|
33
38
|
.join('text')
|
|
34
|
-
.text((d) =>
|
|
39
|
+
.text((d) => d.text)
|
|
35
40
|
.attr('class', b('label'))
|
|
36
|
-
.attr('x', (d) =>
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
.attr('y', (d) => {
|
|
43
|
-
return d.y + d.height / 2 + d.series.dataLabels.maxHeight / 2;
|
|
44
|
-
})
|
|
45
|
-
.attr('text-anchor', (d) => {
|
|
46
|
-
if (d.series.dataLabels.inside) {
|
|
47
|
-
return 'middle';
|
|
48
|
-
}
|
|
49
|
-
return 'right';
|
|
50
|
-
})
|
|
51
|
-
.style('font-size', (d) => d.series.dataLabels.style.fontSize)
|
|
52
|
-
.style('font-weight', (d) => d.series.dataLabels.style.fontWeight || null)
|
|
53
|
-
.style('fill', (d) => d.series.dataLabels.style.fontColor || null);
|
|
41
|
+
.attr('x', (d) => d.x)
|
|
42
|
+
.attr('y', (d) => d.y)
|
|
43
|
+
.attr('text-anchor', (d) => d.textAnchor)
|
|
44
|
+
.style('font-size', (d) => d.style.fontSize)
|
|
45
|
+
.style('font-weight', (d) => d.style.fontWeight || null)
|
|
46
|
+
.style('fill', (d) => d.style.fontColor || null);
|
|
54
47
|
const hoverOptions = get(seriesOptions, 'bar-y.states.hover');
|
|
55
48
|
const inactiveOptions = get(seriesOptions, 'bar-y.states.inactive');
|
|
56
49
|
dispatcher.on('hover-shape.bar-y', (data) => {
|
|
@@ -85,5 +78,7 @@ export const BarYSeriesShapes = (args) => {
|
|
|
85
78
|
dispatcher.on('hover-shape.bar-y', null);
|
|
86
79
|
};
|
|
87
80
|
}, [dispatcher, preparedData, seriesOptions]);
|
|
88
|
-
return React.createElement(
|
|
81
|
+
return (React.createElement(React.Fragment, null,
|
|
82
|
+
React.createElement("g", { ref: ref, className: b() }),
|
|
83
|
+
React.createElement(HtmlLayer, { preparedData: preparedData, htmlLayout: htmlLayout })));
|
|
89
84
|
};
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { ascending, descending, max, sort } from 'd3';
|
|
2
2
|
import get from 'lodash/get';
|
|
3
|
-
import { getDataCategoryValue } from '../../../utils';
|
|
3
|
+
import { getDataCategoryValue, getLabelsSize } from '../../../utils';
|
|
4
4
|
import { MIN_BAR_GAP, MIN_BAR_GROUP_GAP, MIN_BAR_WIDTH } from '../constants';
|
|
5
|
+
const DEFAULT_LABEL_PADDING = 7;
|
|
5
6
|
function groupByYValue(series, yAxis) {
|
|
6
7
|
const data = {};
|
|
7
8
|
series.forEach((s) => {
|
|
@@ -47,6 +48,41 @@ function getBandWidth(series, yAxis, yScale) {
|
|
|
47
48
|
}
|
|
48
49
|
return bandWidth;
|
|
49
50
|
}
|
|
51
|
+
function setLabel(prepared) {
|
|
52
|
+
const dataLabels = prepared.series.dataLabels;
|
|
53
|
+
if (!dataLabels.enabled) {
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
56
|
+
const data = prepared.data;
|
|
57
|
+
const content = String(data.label || data.x);
|
|
58
|
+
const { maxHeight: height, maxWidth: width } = getLabelsSize({
|
|
59
|
+
labels: [content],
|
|
60
|
+
style: dataLabels.style,
|
|
61
|
+
html: dataLabels.html,
|
|
62
|
+
});
|
|
63
|
+
const x = dataLabels.inside
|
|
64
|
+
? prepared.x + prepared.width / 2
|
|
65
|
+
: prepared.x + prepared.width + DEFAULT_LABEL_PADDING;
|
|
66
|
+
const y = prepared.y + prepared.height / 2;
|
|
67
|
+
if (dataLabels.html) {
|
|
68
|
+
prepared.htmlElements.push({
|
|
69
|
+
x,
|
|
70
|
+
y: y - height / 2,
|
|
71
|
+
content,
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
else {
|
|
75
|
+
prepared.label = {
|
|
76
|
+
x,
|
|
77
|
+
y: y + height / 2,
|
|
78
|
+
text: content,
|
|
79
|
+
textAnchor: dataLabels.inside ? 'middle' : 'right',
|
|
80
|
+
style: dataLabels.style,
|
|
81
|
+
series: prepared.series,
|
|
82
|
+
size: { width, height },
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
}
|
|
50
86
|
export const prepareBarYData = (args) => {
|
|
51
87
|
const { series, seriesOptions, yAxis, xScale, yScale: [yScale], } = args;
|
|
52
88
|
const xLinearScale = xScale;
|
|
@@ -100,7 +136,7 @@ export const prepareBarYData = (args) => {
|
|
|
100
136
|
const y = center - currentBarHeight / 2 + (barHeight + rectGap) * groupItemIndex;
|
|
101
137
|
const xValue = Number(data.x);
|
|
102
138
|
const width = xValue > 0 ? xLinearScale(xValue) - base : base - xLinearScale(xValue);
|
|
103
|
-
|
|
139
|
+
const item = {
|
|
104
140
|
x: xValue > 0 ? stackSum : stackSum - width,
|
|
105
141
|
y,
|
|
106
142
|
width,
|
|
@@ -109,7 +145,9 @@ export const prepareBarYData = (args) => {
|
|
|
109
145
|
opacity: get(data, 'opacity', null),
|
|
110
146
|
data,
|
|
111
147
|
series: s,
|
|
112
|
-
|
|
148
|
+
htmlElements: [],
|
|
149
|
+
};
|
|
150
|
+
stackItems.push(item);
|
|
113
151
|
stackSum += width + 1;
|
|
114
152
|
});
|
|
115
153
|
if (series.some((s) => s.stacking === 'percent')) {
|
|
@@ -124,5 +162,8 @@ export const prepareBarYData = (args) => {
|
|
|
124
162
|
result.push(...stackItems);
|
|
125
163
|
});
|
|
126
164
|
});
|
|
165
|
+
result.forEach((d) => {
|
|
166
|
+
setLabel(d);
|
|
167
|
+
});
|
|
127
168
|
return result;
|
|
128
169
|
};
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { TooltipDataChunkBarX } from '../../../../../../types';
|
|
2
|
+
import { HtmlItem, LabelData } from '../../../types';
|
|
2
3
|
import { PreparedBarYSeries } from '../../useSeries/types';
|
|
3
4
|
export type PreparedBarYData = Omit<TooltipDataChunkBarX, 'series'> & {
|
|
4
5
|
x: number;
|
|
@@ -8,4 +9,6 @@ export type PreparedBarYData = Omit<TooltipDataChunkBarX, 'series'> & {
|
|
|
8
9
|
color: string;
|
|
9
10
|
opacity: number | null;
|
|
10
11
|
series: PreparedBarYSeries;
|
|
12
|
+
label?: LabelData;
|
|
13
|
+
htmlElements: HtmlItem[];
|
|
11
14
|
};
|
|
@@ -34,7 +34,7 @@ export const useShapes = (args) => {
|
|
|
34
34
|
yScale,
|
|
35
35
|
boundsHeight,
|
|
36
36
|
});
|
|
37
|
-
acc.push(React.createElement(BarXSeriesShapes, { key: "bar-x", dispatcher: dispatcher, seriesOptions: seriesOptions, preparedData: preparedData }));
|
|
37
|
+
acc.push(React.createElement(BarXSeriesShapes, { key: "bar-x", dispatcher: dispatcher, seriesOptions: seriesOptions, preparedData: preparedData, htmlLayout: htmlLayout }));
|
|
38
38
|
shapesData.push(...preparedData);
|
|
39
39
|
}
|
|
40
40
|
break;
|
|
@@ -49,7 +49,7 @@ export const useShapes = (args) => {
|
|
|
49
49
|
yAxis,
|
|
50
50
|
yScale,
|
|
51
51
|
});
|
|
52
|
-
acc.push(React.createElement(BarYSeriesShapes, { key: "bar-y", dispatcher: dispatcher, seriesOptions: seriesOptions, preparedData: preparedData }));
|
|
52
|
+
acc.push(React.createElement(BarYSeriesShapes, { key: "bar-y", dispatcher: dispatcher, seriesOptions: seriesOptions, preparedData: preparedData, htmlLayout: htmlLayout }));
|
|
53
53
|
shapesData.push(...preparedData);
|
|
54
54
|
}
|
|
55
55
|
break;
|
|
@@ -64,7 +64,7 @@ export const useShapes = (args) => {
|
|
|
64
64
|
yAxis,
|
|
65
65
|
yScale,
|
|
66
66
|
});
|
|
67
|
-
acc.push(React.createElement(WaterfallSeriesShapes, { key: "waterfall", dispatcher: dispatcher, seriesOptions: seriesOptions, preparedData: preparedData }));
|
|
67
|
+
acc.push(React.createElement(WaterfallSeriesShapes, { key: "waterfall", dispatcher: dispatcher, seriesOptions: seriesOptions, preparedData: preparedData, htmlLayout: htmlLayout }));
|
|
68
68
|
shapesData.push(...preparedData);
|
|
69
69
|
}
|
|
70
70
|
break;
|
|
@@ -79,7 +79,7 @@ export const useShapes = (args) => {
|
|
|
79
79
|
yScale,
|
|
80
80
|
split,
|
|
81
81
|
});
|
|
82
|
-
acc.push(React.createElement(LineSeriesShapes, { key: "line", dispatcher: dispatcher, seriesOptions: seriesOptions, preparedData: preparedData }));
|
|
82
|
+
acc.push(React.createElement(LineSeriesShapes, { key: "line", dispatcher: dispatcher, seriesOptions: seriesOptions, preparedData: preparedData, htmlLayout: htmlLayout }));
|
|
83
83
|
shapesData.push(...preparedData);
|
|
84
84
|
}
|
|
85
85
|
break;
|
|
@@ -94,7 +94,7 @@ export const useShapes = (args) => {
|
|
|
94
94
|
yScale,
|
|
95
95
|
boundsHeight,
|
|
96
96
|
});
|
|
97
|
-
acc.push(React.createElement(AreaSeriesShapes, { key: "area", dispatcher: dispatcher, seriesOptions: seriesOptions, preparedData: preparedData }));
|
|
97
|
+
acc.push(React.createElement(AreaSeriesShapes, { key: "area", dispatcher: dispatcher, seriesOptions: seriesOptions, preparedData: preparedData, htmlLayout: htmlLayout }));
|
|
98
98
|
shapesData.push(...preparedData);
|
|
99
99
|
}
|
|
100
100
|
break;
|
|
@@ -108,7 +108,7 @@ export const useShapes = (args) => {
|
|
|
108
108
|
yAxis,
|
|
109
109
|
yScale,
|
|
110
110
|
});
|
|
111
|
-
acc.push(React.createElement(ScatterSeriesShape, { key: "scatter", dispatcher: dispatcher, preparedData: preparedData, seriesOptions: seriesOptions }));
|
|
111
|
+
acc.push(React.createElement(ScatterSeriesShape, { key: "scatter", dispatcher: dispatcher, preparedData: preparedData, seriesOptions: seriesOptions, htmlLayout: htmlLayout }));
|
|
112
112
|
shapesData.push(...preparedData);
|
|
113
113
|
}
|
|
114
114
|
break;
|
|
@@ -131,7 +131,7 @@ export const useShapes = (args) => {
|
|
|
131
131
|
width: boundsWidth,
|
|
132
132
|
height: boundsHeight,
|
|
133
133
|
});
|
|
134
|
-
acc.push(React.createElement(TreemapSeriesShape, { key: "treemap", dispatcher: dispatcher, preparedData: preparedData, seriesOptions: seriesOptions }));
|
|
134
|
+
acc.push(React.createElement(TreemapSeriesShape, { key: "treemap", dispatcher: dispatcher, preparedData: preparedData, seriesOptions: seriesOptions, htmlLayout: htmlLayout }));
|
|
135
135
|
shapesData.push(preparedData);
|
|
136
136
|
}
|
|
137
137
|
}
|
|
@@ -3,11 +3,12 @@ import { color, line as lineGenerator, select } from 'd3';
|
|
|
3
3
|
import get from 'lodash/get';
|
|
4
4
|
import { block } from '../../../../../../utils/cn';
|
|
5
5
|
import { filterOverlappingLabels } from '../../../utils';
|
|
6
|
+
import { HtmlLayer } from '../HtmlLayer';
|
|
6
7
|
import { getMarkerHaloVisibility, getMarkerVisibility, renderMarker, selectMarkerHalo, selectMarkerSymbol, setMarker, } from '../marker';
|
|
7
8
|
import { getLineDashArray, setActiveState } from '../utils';
|
|
8
9
|
const b = block('d3-line');
|
|
9
10
|
export const LineSeriesShapes = (args) => {
|
|
10
|
-
const { dispatcher, preparedData, seriesOptions } = args;
|
|
11
|
+
const { dispatcher, preparedData, seriesOptions, htmlLayout } = args;
|
|
11
12
|
const ref = React.useRef(null);
|
|
12
13
|
React.useEffect(() => {
|
|
13
14
|
var _a;
|
|
@@ -124,5 +125,7 @@ export const LineSeriesShapes = (args) => {
|
|
|
124
125
|
dispatcher.on('hover-shape.line', null);
|
|
125
126
|
};
|
|
126
127
|
}, [dispatcher, preparedData, seriesOptions]);
|
|
127
|
-
return React.createElement(
|
|
128
|
+
return (React.createElement(React.Fragment, null,
|
|
129
|
+
React.createElement("g", { ref: ref, className: b() }),
|
|
130
|
+
React.createElement(HtmlLayer, { preparedData: preparedData, htmlLayout: htmlLayout })));
|
|
128
131
|
};
|
|
@@ -26,6 +26,15 @@ function getLabelData(point, series, xMax) {
|
|
|
26
26
|
}
|
|
27
27
|
return labelData;
|
|
28
28
|
}
|
|
29
|
+
function getHtmlLabel(point, series, xMax) {
|
|
30
|
+
const content = String(point.data.label || point.data.y);
|
|
31
|
+
const size = getLabelsSize({ labels: [content], html: true });
|
|
32
|
+
return {
|
|
33
|
+
x: Math.min(xMax - size.maxWidth, Math.max(0, point.x)),
|
|
34
|
+
y: Math.max(0, point.y - series.dataLabels.padding - size.maxHeight),
|
|
35
|
+
content,
|
|
36
|
+
};
|
|
37
|
+
}
|
|
29
38
|
export const prepareLineData = (args) => {
|
|
30
39
|
const { series, xAxis, yAxis, xScale, yScale, split } = args;
|
|
31
40
|
const [_xMin, xRangeMax] = xScale.range();
|
|
@@ -43,9 +52,15 @@ export const prepareLineData = (args) => {
|
|
|
43
52
|
data: d,
|
|
44
53
|
series: s,
|
|
45
54
|
}));
|
|
55
|
+
const htmlElements = [];
|
|
46
56
|
let labels = [];
|
|
47
57
|
if (s.dataLabels.enabled) {
|
|
48
|
-
|
|
58
|
+
if (s.dataLabels.html) {
|
|
59
|
+
htmlElements.push(...points.map((p) => getHtmlLabel(p, s, xMax)));
|
|
60
|
+
}
|
|
61
|
+
else {
|
|
62
|
+
labels = points.map((p) => getLabelData(p, s, xMax));
|
|
63
|
+
}
|
|
49
64
|
}
|
|
50
65
|
let markers = [];
|
|
51
66
|
if (s.marker.states.normal.enabled || s.marker.states.hover.enabled) {
|
|
@@ -68,6 +83,7 @@ export const prepareLineData = (args) => {
|
|
|
68
83
|
dashStyle: s.dashStyle,
|
|
69
84
|
linecap: s.linecap,
|
|
70
85
|
opacity: s.opacity,
|
|
86
|
+
htmlElements,
|
|
71
87
|
};
|
|
72
88
|
acc.push(result);
|
|
73
89
|
return acc;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { DashStyle, LineCap } from '../../../../../../constants';
|
|
2
2
|
import { LineSeriesData } from '../../../../../../types';
|
|
3
|
-
import { LabelData } from '../../../types';
|
|
3
|
+
import { HtmlItem, LabelData } from '../../../types';
|
|
4
4
|
import { PreparedLineSeries } from '../../useSeries/types';
|
|
5
5
|
export type PointData = {
|
|
6
6
|
x: number;
|
|
@@ -26,4 +26,5 @@ export type PreparedLineData = {
|
|
|
26
26
|
dashStyle: DashStyle;
|
|
27
27
|
linecap: LineCap;
|
|
28
28
|
opacity: number | null;
|
|
29
|
+
htmlElements: HtmlItem[];
|
|
29
30
|
};
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
|
-
import { Portal } from '@gravity-ui/uikit';
|
|
3
2
|
import { arc, color, select } from 'd3';
|
|
4
3
|
import get from 'lodash/get';
|
|
5
4
|
import { block } from '../../../../../../utils/cn';
|
|
6
5
|
import { setEllipsisForOverflowTexts } from '../../../utils';
|
|
6
|
+
import { HtmlLayer } from '../HtmlLayer';
|
|
7
7
|
import { setActiveState } from '../utils';
|
|
8
8
|
const b = block('d3-pie');
|
|
9
9
|
export function getHaloVisibility(d) {
|
|
@@ -13,12 +13,6 @@ export function getHaloVisibility(d) {
|
|
|
13
13
|
export function PieSeriesShapes(args) {
|
|
14
14
|
const { dispatcher, preparedData, seriesOptions, htmlLayout } = args;
|
|
15
15
|
const ref = React.useRef(null);
|
|
16
|
-
const htmlItems = React.useMemo(() => {
|
|
17
|
-
return preparedData.reduce((result, d) => {
|
|
18
|
-
result.push(...d.htmlElements);
|
|
19
|
-
return result;
|
|
20
|
-
}, []);
|
|
21
|
-
}, [preparedData]);
|
|
22
16
|
React.useEffect(() => {
|
|
23
17
|
if (!ref.current) {
|
|
24
18
|
return () => { };
|
|
@@ -174,7 +168,5 @@ export function PieSeriesShapes(args) {
|
|
|
174
168
|
}, [dispatcher, preparedData, seriesOptions]);
|
|
175
169
|
return (React.createElement(React.Fragment, null,
|
|
176
170
|
React.createElement("g", { ref: ref, className: b(), style: { zIndex: 9 } }),
|
|
177
|
-
|
|
178
|
-
return (React.createElement("div", { key: index, dangerouslySetInnerHTML: { __html: item.content }, style: { position: 'absolute', left: item.x, top: item.y } }));
|
|
179
|
-
})))));
|
|
171
|
+
React.createElement(HtmlLayer, { preparedData: preparedData, htmlLayout: htmlLayout })));
|
|
180
172
|
}
|
|
@@ -7,5 +7,6 @@ type ScatterSeriesShapeProps = {
|
|
|
7
7
|
dispatcher: Dispatch<object>;
|
|
8
8
|
preparedData: PreparedScatterData[];
|
|
9
9
|
seriesOptions: PreparedSeriesOptions;
|
|
10
|
+
htmlLayout: HTMLElement | null;
|
|
10
11
|
};
|
|
11
12
|
export declare function ScatterSeriesShape(props: ScatterSeriesShapeProps): React.JSX.Element;
|
|
@@ -2,12 +2,13 @@ import React from 'react';
|
|
|
2
2
|
import { select } from 'd3';
|
|
3
3
|
import get from 'lodash/get';
|
|
4
4
|
import { block } from '../../../../../../utils/cn';
|
|
5
|
+
import { HtmlLayer } from '../HtmlLayer';
|
|
5
6
|
import { getMarkerHaloVisibility, renderMarker, selectMarkerHalo, selectMarkerSymbol, setMarker, } from '../marker';
|
|
6
7
|
import { setActiveState, shapeKey } from '../utils';
|
|
7
8
|
export { prepareScatterData } from './prepare-data';
|
|
8
9
|
const b = block('d3-scatter');
|
|
9
10
|
export function ScatterSeriesShape(props) {
|
|
10
|
-
const { dispatcher, preparedData, seriesOptions } = props;
|
|
11
|
+
const { dispatcher, preparedData, seriesOptions, htmlLayout } = props;
|
|
11
12
|
const ref = React.useRef(null);
|
|
12
13
|
React.useEffect(() => {
|
|
13
14
|
if (!ref.current) {
|
|
@@ -62,5 +63,7 @@ export function ScatterSeriesShape(props) {
|
|
|
62
63
|
dispatcher.on('hover-shape.scatter', null);
|
|
63
64
|
};
|
|
64
65
|
}, [dispatcher, preparedData, seriesOptions]);
|
|
65
|
-
return React.createElement(
|
|
66
|
+
return (React.createElement(React.Fragment, null,
|
|
67
|
+
React.createElement("g", { ref: ref, className: b() }),
|
|
68
|
+
React.createElement(HtmlLayer, { preparedData: preparedData, htmlLayout: htmlLayout })));
|
|
66
69
|
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { ScatterSeriesData } from '../../../../../../types';
|
|
2
|
+
import { HtmlItem } from '../../../types';
|
|
2
3
|
import { PreparedScatterSeries } from '../../useSeries/types';
|
|
3
4
|
type PointData = {
|
|
4
5
|
x: number;
|
|
@@ -11,6 +12,7 @@ export type MarkerData = {
|
|
|
11
12
|
point: PointData;
|
|
12
13
|
active: boolean;
|
|
13
14
|
hovered: boolean;
|
|
15
|
+
htmlElements: HtmlItem[];
|
|
14
16
|
};
|
|
15
17
|
export type PreparedScatterData = MarkerData;
|
|
16
18
|
export {};
|
|
@@ -6,6 +6,7 @@ type ShapeProps = {
|
|
|
6
6
|
dispatcher: Dispatch<object>;
|
|
7
7
|
preparedData: PreparedTreemapData;
|
|
8
8
|
seriesOptions: PreparedSeriesOptions;
|
|
9
|
+
htmlLayout: HTMLElement | null;
|
|
9
10
|
};
|
|
10
11
|
export declare const TreemapSeriesShape: (props: ShapeProps) => React.JSX.Element;
|
|
11
12
|
export {};
|
|
@@ -3,9 +3,10 @@ import { color, select } from 'd3';
|
|
|
3
3
|
import get from 'lodash/get';
|
|
4
4
|
import { block } from '../../../../../../utils/cn';
|
|
5
5
|
import { setEllipsisForOverflowTexts } from '../../../utils';
|
|
6
|
+
import { HtmlLayer } from '../HtmlLayer';
|
|
6
7
|
const b = block('d3-treemap');
|
|
7
8
|
export const TreemapSeriesShape = (props) => {
|
|
8
|
-
const { dispatcher, preparedData, seriesOptions } = props;
|
|
9
|
+
const { dispatcher, preparedData, seriesOptions, htmlLayout } = props;
|
|
9
10
|
const ref = React.useRef(null);
|
|
10
11
|
React.useEffect(() => {
|
|
11
12
|
if (!ref.current) {
|
|
@@ -92,5 +93,7 @@ export const TreemapSeriesShape = (props) => {
|
|
|
92
93
|
dispatcher.on(eventName, null);
|
|
93
94
|
};
|
|
94
95
|
}, [dispatcher, preparedData, seriesOptions]);
|
|
95
|
-
return React.createElement(
|
|
96
|
+
return (React.createElement(React.Fragment, null,
|
|
97
|
+
React.createElement("g", { ref: ref, className: b() }),
|
|
98
|
+
React.createElement(HtmlLayer, { preparedData: preparedData, htmlLayout: htmlLayout })));
|
|
96
99
|
};
|
|
@@ -51,7 +51,7 @@ export function prepareTreemapData(args) {
|
|
|
51
51
|
})(hierarchy);
|
|
52
52
|
const leaves = root.leaves();
|
|
53
53
|
const labelData = ((_a = series.dataLabels) === null || _a === void 0 ? void 0 : _a.enabled) ? getLabelData(leaves) : [];
|
|
54
|
-
return { labelData, leaves, series };
|
|
54
|
+
return { labelData, leaves, series, htmlElements: [] };
|
|
55
55
|
}
|
|
56
56
|
function getSeriesDataWithRootNode(series) {
|
|
57
57
|
return series.data.reduce((acc, d) => {
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { HierarchyRectangularNode } from 'd3';
|
|
2
2
|
import type { TreemapSeriesData } from '../../../../../../types';
|
|
3
|
+
import { HtmlItem } from '../../../types';
|
|
3
4
|
import type { PreparedTreemapSeries } from '../../useSeries/types';
|
|
4
5
|
export type TreemapLabelData = {
|
|
5
6
|
text: string;
|
|
@@ -12,4 +13,5 @@ export type PreparedTreemapData = {
|
|
|
12
13
|
labelData: TreemapLabelData[];
|
|
13
14
|
leaves: HierarchyRectangularNode<TreemapSeriesData<any>>[];
|
|
14
15
|
series: PreparedTreemapSeries;
|
|
16
|
+
htmlElements: HtmlItem[];
|
|
15
17
|
};
|
|
@@ -4,12 +4,13 @@ import get from 'lodash/get';
|
|
|
4
4
|
import { DashStyle } from '../../../../../../constants';
|
|
5
5
|
import { block } from '../../../../../../utils/cn';
|
|
6
6
|
import { filterOverlappingLabels, getWaterfallPointColor } from '../../../utils';
|
|
7
|
+
import { HtmlLayer } from '../HtmlLayer';
|
|
7
8
|
import { getLineDashArray } from '../utils';
|
|
8
9
|
export { prepareWaterfallData } from './prepare-data';
|
|
9
10
|
export * from './types';
|
|
10
11
|
const b = block('d3-waterfall');
|
|
11
12
|
export const WaterfallSeriesShapes = (args) => {
|
|
12
|
-
const { dispatcher, preparedData, seriesOptions } = args;
|
|
13
|
+
const { dispatcher, preparedData, seriesOptions, htmlLayout } = args;
|
|
13
14
|
const ref = React.useRef(null);
|
|
14
15
|
const connectorSelector = `.${b('connector')}`;
|
|
15
16
|
React.useEffect(() => {
|
|
@@ -121,5 +122,7 @@ export const WaterfallSeriesShapes = (args) => {
|
|
|
121
122
|
dispatcher.on('hover-shape.waterfall', null);
|
|
122
123
|
};
|
|
123
124
|
}, [dispatcher, preparedData, seriesOptions]);
|
|
124
|
-
return React.createElement(
|
|
125
|
+
return (React.createElement(React.Fragment, null,
|
|
126
|
+
React.createElement("g", { ref: ref, className: b() }),
|
|
127
|
+
React.createElement(HtmlLayer, { preparedData: preparedData, htmlLayout: htmlLayout })));
|
|
125
128
|
};
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { WaterfallSeriesData } from '../../../../../../types';
|
|
2
|
-
import { LabelData } from '../../../types';
|
|
2
|
+
import { HtmlItem, LabelData } from '../../../types';
|
|
3
3
|
import { PreparedWaterfallSeries } from '../../useSeries/types';
|
|
4
4
|
export type PreparedWaterfallData = {
|
|
5
5
|
x: number;
|
|
@@ -11,4 +11,5 @@ export type PreparedWaterfallData = {
|
|
|
11
11
|
data: WaterfallSeriesData;
|
|
12
12
|
label?: LabelData;
|
|
13
13
|
subTotal: number;
|
|
14
|
+
htmlElements: HtmlItem[];
|
|
14
15
|
};
|
|
@@ -13,10 +13,12 @@ export type LabelData = {
|
|
|
13
13
|
id: string;
|
|
14
14
|
};
|
|
15
15
|
active?: boolean;
|
|
16
|
-
html?: boolean;
|
|
17
16
|
};
|
|
18
17
|
export type HtmlItem = {
|
|
19
18
|
x: number;
|
|
20
19
|
y: number;
|
|
21
20
|
content: string;
|
|
22
21
|
};
|
|
22
|
+
export type ShapeDataWithHtmlItems = {
|
|
23
|
+
htmlElements: HtmlItem[];
|
|
24
|
+
};
|
|
@@ -4,15 +4,16 @@ type AxisBottomArgs = {
|
|
|
4
4
|
scale: AxisScale<AxisDomain>;
|
|
5
5
|
ticks: {
|
|
6
6
|
count?: number;
|
|
7
|
-
maxTickCount
|
|
8
|
-
labelFormat
|
|
7
|
+
maxTickCount?: number;
|
|
8
|
+
labelFormat?: (value: any) => string;
|
|
9
9
|
labelsPaddings?: number;
|
|
10
10
|
labelsMargin?: number;
|
|
11
11
|
labelsStyle?: BaseTextStyle;
|
|
12
12
|
labelsMaxWidth?: number;
|
|
13
13
|
labelsLineHeight: number;
|
|
14
|
-
items
|
|
15
|
-
rotation
|
|
14
|
+
items?: [number, number][];
|
|
15
|
+
rotation?: number;
|
|
16
|
+
tickColor?: string;
|
|
16
17
|
};
|
|
17
18
|
domain: {
|
|
18
19
|
size: number;
|