@gravity-ui/charts 0.5.0 → 0.6.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/ChartInner/index.d.ts +2 -8
- package/dist/cjs/components/ChartInner/index.js +22 -117
- package/dist/cjs/components/ChartInner/types.d.ts +6 -0
- package/dist/cjs/components/ChartInner/useChartInnerHandlers.d.ts +26 -0
- package/dist/cjs/components/ChartInner/useChartInnerHandlers.js +94 -0
- package/dist/cjs/components/ChartInner/useChartInnerProps.d.ts +43 -0
- package/dist/cjs/components/ChartInner/useChartInnerProps.js +81 -0
- package/dist/cjs/components/ChartInner/useChartInnerState.d.ts +13 -0
- package/dist/cjs/components/ChartInner/useChartInnerState.js +34 -0
- package/dist/cjs/components/Legend/index.d.ts +1 -0
- package/dist/cjs/components/Legend/index.js +3 -2
- package/dist/cjs/components/Tooltip/index.d.ts +2 -0
- package/dist/cjs/components/Tooltip/index.js +10 -4
- package/dist/cjs/components/Tooltip/styles.css +13 -8
- package/dist/cjs/hooks/index.d.ts +2 -1
- package/dist/cjs/hooks/index.js +2 -1
- package/dist/cjs/hooks/usePrevious/index.d.ts +1 -0
- package/dist/cjs/hooks/usePrevious/index.js +8 -0
- package/dist/cjs/hooks/useShapes/area/index.js +8 -2
- package/dist/cjs/hooks/useShapes/area/prepare-data.js +4 -0
- package/dist/cjs/hooks/useShapes/bar-x/index.js +8 -2
- package/dist/cjs/hooks/useShapes/bar-x/prepare-data.js +1 -0
- package/dist/cjs/hooks/useShapes/bar-y/index.js +8 -2
- package/dist/cjs/hooks/useShapes/bar-y/prepare-data.js +1 -0
- package/dist/cjs/hooks/useShapes/line/index.js +8 -2
- package/dist/cjs/hooks/useShapes/line/prepare-data.js +1 -0
- package/dist/cjs/hooks/useShapes/pie/index.js +2 -1
- package/dist/cjs/hooks/useShapes/pie/prepare-data.js +159 -111
- package/dist/cjs/hooks/useShapes/pie/types.d.ts +1 -1
- package/dist/cjs/hooks/useShapes/scatter/index.js +8 -2
- package/dist/cjs/hooks/useShapes/treemap/index.js +8 -2
- package/dist/cjs/hooks/useShapes/treemap/prepare-data.js +1 -0
- package/dist/cjs/hooks/useShapes/utils.d.ts +2 -2
- package/dist/cjs/hooks/useShapes/utils.js +5 -3
- package/dist/cjs/hooks/useShapes/waterfall/index.js +8 -2
- package/dist/cjs/hooks/useTooltip/index.d.ts +2 -3
- package/dist/cjs/types/chart/chart.d.ts +2 -2
- package/dist/cjs/types/chart/series.d.ts +1 -2
- package/dist/cjs/types/chart/tooltip.d.ts +6 -6
- package/dist/cjs/types/chart-ui.d.ts +4 -0
- package/dist/cjs/types/misc.d.ts +1 -0
- package/dist/cjs/utils/misc.d.ts +10 -2
- package/dist/cjs/utils/misc.js +15 -3
- package/dist/esm/components/ChartInner/index.d.ts +2 -8
- package/dist/esm/components/ChartInner/index.js +22 -117
- package/dist/esm/components/ChartInner/types.d.ts +6 -0
- package/dist/esm/components/ChartInner/useChartInnerHandlers.d.ts +26 -0
- package/dist/esm/components/ChartInner/useChartInnerHandlers.js +94 -0
- package/dist/esm/components/ChartInner/useChartInnerProps.d.ts +43 -0
- package/dist/esm/components/ChartInner/useChartInnerProps.js +81 -0
- package/dist/esm/components/ChartInner/useChartInnerState.d.ts +13 -0
- package/dist/esm/components/ChartInner/useChartInnerState.js +34 -0
- package/dist/esm/components/Legend/index.d.ts +1 -0
- package/dist/esm/components/Legend/index.js +3 -2
- package/dist/esm/components/Tooltip/index.d.ts +2 -0
- package/dist/esm/components/Tooltip/index.js +10 -4
- package/dist/esm/components/Tooltip/styles.css +13 -8
- package/dist/esm/hooks/index.d.ts +2 -1
- package/dist/esm/hooks/index.js +2 -1
- package/dist/esm/hooks/usePrevious/index.d.ts +1 -0
- package/dist/esm/hooks/usePrevious/index.js +8 -0
- package/dist/esm/hooks/useShapes/area/index.js +8 -2
- package/dist/esm/hooks/useShapes/area/prepare-data.js +4 -0
- package/dist/esm/hooks/useShapes/bar-x/index.js +8 -2
- package/dist/esm/hooks/useShapes/bar-x/prepare-data.js +1 -0
- package/dist/esm/hooks/useShapes/bar-y/index.js +8 -2
- package/dist/esm/hooks/useShapes/bar-y/prepare-data.js +1 -0
- package/dist/esm/hooks/useShapes/line/index.js +8 -2
- package/dist/esm/hooks/useShapes/line/prepare-data.js +1 -0
- package/dist/esm/hooks/useShapes/pie/index.js +2 -1
- package/dist/esm/hooks/useShapes/pie/prepare-data.js +159 -111
- package/dist/esm/hooks/useShapes/pie/types.d.ts +1 -1
- package/dist/esm/hooks/useShapes/scatter/index.js +8 -2
- package/dist/esm/hooks/useShapes/treemap/index.js +8 -2
- package/dist/esm/hooks/useShapes/treemap/prepare-data.js +1 -0
- package/dist/esm/hooks/useShapes/utils.d.ts +2 -2
- package/dist/esm/hooks/useShapes/utils.js +5 -3
- package/dist/esm/hooks/useShapes/waterfall/index.js +8 -2
- package/dist/esm/hooks/useTooltip/index.d.ts +2 -3
- package/dist/esm/types/chart/chart.d.ts +2 -2
- package/dist/esm/types/chart/series.d.ts +1 -2
- package/dist/esm/types/chart/tooltip.d.ts +6 -6
- package/dist/esm/types/chart-ui.d.ts +4 -0
- package/dist/esm/types/misc.d.ts +1 -0
- package/dist/esm/utils/misc.d.ts +10 -2
- package/dist/esm/utils/misc.js +15 -3
- package/package.json +1 -1
- package/dist/cjs/hooks/useTooltip/types.d.ts +0 -1
- package/dist/esm/hooks/useTooltip/types.d.ts +0 -1
- /package/dist/cjs/{hooks/useTooltip → components/ChartInner}/types.js +0 -0
- /package/dist/esm/{hooks/useTooltip → components/ChartInner}/types.js +0 -0
|
@@ -8,6 +8,7 @@ import { setActiveState } from '../utils';
|
|
|
8
8
|
const b = block('d3-area');
|
|
9
9
|
export const AreaSeriesShapes = (args) => {
|
|
10
10
|
const { dispatcher, preparedData, seriesOptions, htmlLayout } = args;
|
|
11
|
+
const hoveredDataRef = React.useRef(null);
|
|
11
12
|
const ref = React.useRef(null);
|
|
12
13
|
React.useEffect(() => {
|
|
13
14
|
var _a;
|
|
@@ -72,7 +73,8 @@ export const AreaSeriesShapes = (args) => {
|
|
|
72
73
|
.call(renderMarker);
|
|
73
74
|
const hoverEnabled = hoverOptions === null || hoverOptions === void 0 ? void 0 : hoverOptions.enabled;
|
|
74
75
|
const inactiveEnabled = inactiveOptions === null || inactiveOptions === void 0 ? void 0 : inactiveOptions.enabled;
|
|
75
|
-
|
|
76
|
+
function handleShapeHover(data) {
|
|
77
|
+
hoveredDataRef.current = data;
|
|
76
78
|
const selected = (data === null || data === void 0 ? void 0 : data.filter((d) => d.series.type === 'area')) || [];
|
|
77
79
|
const selectedDataItems = selected.map((d) => d.data);
|
|
78
80
|
const selectedSeriesIds = selected.map((d) => { var _a; return (_a = d.series) === null || _a === void 0 ? void 0 : _a.id; });
|
|
@@ -132,7 +134,11 @@ export const AreaSeriesShapes = (args) => {
|
|
|
132
134
|
}
|
|
133
135
|
return d;
|
|
134
136
|
});
|
|
135
|
-
}
|
|
137
|
+
}
|
|
138
|
+
if (hoveredDataRef.current !== null) {
|
|
139
|
+
handleShapeHover(hoveredDataRef.current);
|
|
140
|
+
}
|
|
141
|
+
dispatcher.on('hover-shape.area', handleShapeHover);
|
|
136
142
|
return () => {
|
|
137
143
|
dispatcher.on('hover-shape.area', null);
|
|
138
144
|
};
|
|
@@ -102,10 +102,14 @@ export const prepareAreaData = (args) => {
|
|
|
102
102
|
const labelItems = points.map((p) => getLabelData(p, s, xMax));
|
|
103
103
|
if (s.dataLabels.html) {
|
|
104
104
|
const htmlLabels = labelItems.map((l) => {
|
|
105
|
+
var _a;
|
|
106
|
+
const style = (_a = l.style) !== null && _a !== void 0 ? _a : s.dataLabels.style;
|
|
107
|
+
const labelSize = getLabelsSize({ labels: [l.text], style, html: true });
|
|
105
108
|
return {
|
|
106
109
|
x: l.x - l.size.width / 2,
|
|
107
110
|
y: l.y,
|
|
108
111
|
content: l.text,
|
|
112
|
+
size: { width: labelSize.maxWidth, height: labelSize.maxHeight },
|
|
109
113
|
};
|
|
110
114
|
});
|
|
111
115
|
htmlElements.push(...htmlLabels);
|
|
@@ -8,6 +8,7 @@ export * from './types';
|
|
|
8
8
|
const b = block('d3-bar-x');
|
|
9
9
|
export const BarXSeriesShapes = (args) => {
|
|
10
10
|
const { dispatcher, preparedData, seriesOptions, htmlLayout } = args;
|
|
11
|
+
const hoveredDataRef = React.useRef(null);
|
|
11
12
|
const ref = React.useRef(null);
|
|
12
13
|
React.useEffect(() => {
|
|
13
14
|
var _a;
|
|
@@ -46,7 +47,8 @@ export const BarXSeriesShapes = (args) => {
|
|
|
46
47
|
.style('font-size', (d) => d.style.fontSize)
|
|
47
48
|
.style('font-weight', (d) => d.style.fontWeight || null)
|
|
48
49
|
.style('fill', (d) => d.style.fontColor || null);
|
|
49
|
-
|
|
50
|
+
function handleShapeHover(data) {
|
|
51
|
+
hoveredDataRef.current = data;
|
|
50
52
|
const hoverEnabled = hoverOptions === null || hoverOptions === void 0 ? void 0 : hoverOptions.enabled;
|
|
51
53
|
const inactiveEnabled = inactiveOptions === null || inactiveOptions === void 0 ? void 0 : inactiveOptions.enabled;
|
|
52
54
|
if (!data) {
|
|
@@ -84,7 +86,11 @@ export const BarXSeriesShapes = (args) => {
|
|
|
84
86
|
: (inactiveOptions === null || inactiveOptions === void 0 ? void 0 : inactiveOptions.opacity) || null;
|
|
85
87
|
});
|
|
86
88
|
}
|
|
87
|
-
}
|
|
89
|
+
}
|
|
90
|
+
if (hoveredDataRef.current !== null) {
|
|
91
|
+
handleShapeHover(hoveredDataRef.current);
|
|
92
|
+
}
|
|
93
|
+
dispatcher.on('hover-shape.bar-x', handleShapeHover);
|
|
88
94
|
return () => {
|
|
89
95
|
dispatcher.on('hover-shape.bar-x', null);
|
|
90
96
|
};
|
|
@@ -7,6 +7,7 @@ export { prepareBarYData } from './prepare-data';
|
|
|
7
7
|
const b = block('d3-bar-y');
|
|
8
8
|
export const BarYSeriesShapes = (args) => {
|
|
9
9
|
const { dispatcher, preparedData, seriesOptions, htmlLayout } = args;
|
|
10
|
+
const hoveredDataRef = React.useRef(null);
|
|
10
11
|
const ref = React.useRef(null);
|
|
11
12
|
React.useEffect(() => {
|
|
12
13
|
if (!ref.current) {
|
|
@@ -46,7 +47,8 @@ export const BarYSeriesShapes = (args) => {
|
|
|
46
47
|
.style('fill', (d) => d.style.fontColor || null);
|
|
47
48
|
const hoverOptions = get(seriesOptions, 'bar-y.states.hover');
|
|
48
49
|
const inactiveOptions = get(seriesOptions, 'bar-y.states.inactive');
|
|
49
|
-
|
|
50
|
+
function handleShapeHover(data) {
|
|
51
|
+
hoveredDataRef.current = data;
|
|
50
52
|
if (hoverOptions === null || hoverOptions === void 0 ? void 0 : hoverOptions.enabled) {
|
|
51
53
|
const hovered = data === null || data === void 0 ? void 0 : data.reduce((acc, d) => {
|
|
52
54
|
acc.add(d.data.y);
|
|
@@ -73,7 +75,11 @@ export const BarYSeriesShapes = (args) => {
|
|
|
73
75
|
rectSelection.attr('opacity', newOpacity);
|
|
74
76
|
labelSelection.attr('opacity', newOpacity);
|
|
75
77
|
}
|
|
76
|
-
}
|
|
78
|
+
}
|
|
79
|
+
if (hoveredDataRef.current !== null) {
|
|
80
|
+
handleShapeHover(hoveredDataRef.current);
|
|
81
|
+
}
|
|
82
|
+
dispatcher.on('hover-shape.bar-y', handleShapeHover);
|
|
77
83
|
return () => {
|
|
78
84
|
dispatcher.on('hover-shape.bar-y', null);
|
|
79
85
|
};
|
|
@@ -8,6 +8,7 @@ import { getLineDashArray, setActiveState } from '../utils';
|
|
|
8
8
|
const b = block('d3-line');
|
|
9
9
|
export const LineSeriesShapes = (args) => {
|
|
10
10
|
const { dispatcher, preparedData, seriesOptions, htmlLayout } = args;
|
|
11
|
+
const hoveredDataRef = React.useRef(null);
|
|
11
12
|
const ref = React.useRef(null);
|
|
12
13
|
React.useEffect(() => {
|
|
13
14
|
var _a;
|
|
@@ -60,7 +61,8 @@ export const LineSeriesShapes = (args) => {
|
|
|
60
61
|
.call(renderMarker);
|
|
61
62
|
const hoverEnabled = hoverOptions === null || hoverOptions === void 0 ? void 0 : hoverOptions.enabled;
|
|
62
63
|
const inactiveEnabled = inactiveOptions === null || inactiveOptions === void 0 ? void 0 : inactiveOptions.enabled;
|
|
63
|
-
|
|
64
|
+
function handleShapeHover(data) {
|
|
65
|
+
hoveredDataRef.current = data;
|
|
64
66
|
const selected = (data === null || data === void 0 ? void 0 : data.filter((d) => d.series.type === 'line')) || [];
|
|
65
67
|
const selectedDataItems = selected.map((d) => d.data);
|
|
66
68
|
const selectedSeriesIds = selected.map((d) => { var _a; return (_a = d.series) === null || _a === void 0 ? void 0 : _a.id; });
|
|
@@ -119,7 +121,11 @@ export const LineSeriesShapes = (args) => {
|
|
|
119
121
|
}
|
|
120
122
|
return d;
|
|
121
123
|
});
|
|
122
|
-
}
|
|
124
|
+
}
|
|
125
|
+
if (hoveredDataRef.current !== null) {
|
|
126
|
+
handleShapeHover(hoveredDataRef.current);
|
|
127
|
+
}
|
|
128
|
+
dispatcher.on('hover-shape.line', handleShapeHover);
|
|
123
129
|
return () => {
|
|
124
130
|
dispatcher.on('hover-shape.line', null);
|
|
125
131
|
};
|
|
@@ -33,6 +33,7 @@ function getHtmlLabel(point, series, xMax) {
|
|
|
33
33
|
x: Math.min(xMax - size.maxWidth, Math.max(0, point.x)),
|
|
34
34
|
y: Math.max(0, point.y - series.dataLabels.padding - size.maxHeight),
|
|
35
35
|
content,
|
|
36
|
+
size: { width: size.maxWidth, height: size.maxHeight },
|
|
36
37
|
};
|
|
37
38
|
}
|
|
38
39
|
export const prepareLineData = (args) => {
|
|
@@ -165,7 +165,8 @@ export function PieSeriesShapes(args) {
|
|
|
165
165
|
dispatcher.on(eventName, null);
|
|
166
166
|
};
|
|
167
167
|
}, [dispatcher, preparedData, seriesOptions]);
|
|
168
|
+
const htmlElements = preparedData.map((d) => d.htmlLabels).flat();
|
|
168
169
|
return (React.createElement(React.Fragment, null,
|
|
169
170
|
React.createElement("g", { ref: ref, className: b(), style: { zIndex: 9 } }),
|
|
170
|
-
React.createElement(HtmlLayer, { preparedData:
|
|
171
|
+
React.createElement(HtmlLayer, { preparedData: { htmlElements }, htmlLayout: htmlLayout })));
|
|
171
172
|
}
|
|
@@ -18,7 +18,7 @@ export function preparePieData(args) {
|
|
|
18
18
|
const { series: preparedSeries, boundsWidth, boundsHeight } = args;
|
|
19
19
|
const maxRadius = Math.min(boundsWidth, boundsHeight) / 2;
|
|
20
20
|
const groupedPieSeries = group(preparedSeries, (pieSeries) => pieSeries.stackId);
|
|
21
|
-
|
|
21
|
+
const prepareItem = (stackId, items) => {
|
|
22
22
|
var _a, _b, _c;
|
|
23
23
|
const series = items[0];
|
|
24
24
|
const { center, borderWidth, borderColor, borderRadius, radius: seriesRadius, innerRadius: seriesInnerRadius, dataLabels, } = series;
|
|
@@ -30,6 +30,7 @@ export function preparePieData(args) {
|
|
|
30
30
|
radius,
|
|
31
31
|
segments: [],
|
|
32
32
|
labels: [],
|
|
33
|
+
htmlLabels: [],
|
|
33
34
|
connectors: [],
|
|
34
35
|
borderColor,
|
|
35
36
|
borderWidth,
|
|
@@ -41,7 +42,6 @@ export function preparePieData(args) {
|
|
|
41
42
|
opacity: series.states.hover.halo.opacity,
|
|
42
43
|
size: series.states.hover.halo.size,
|
|
43
44
|
},
|
|
44
|
-
htmlElements: [],
|
|
45
45
|
};
|
|
46
46
|
const segments = items.map((item) => {
|
|
47
47
|
return {
|
|
@@ -55,132 +55,180 @@ export function preparePieData(args) {
|
|
|
55
55
|
};
|
|
56
56
|
});
|
|
57
57
|
data.segments = pieGenerator(segments);
|
|
58
|
-
let line = lineGenerator();
|
|
59
|
-
const curveFactory = getCurveFactory(data);
|
|
60
|
-
if (curveFactory) {
|
|
61
|
-
line = line.curve(curveFactory);
|
|
62
|
-
}
|
|
63
58
|
if (dataLabels.enabled) {
|
|
64
59
|
const { style, connectorPadding, distance } = dataLabels;
|
|
65
60
|
const { maxHeight: labelHeight } = getLabelsSize({ labels: ['Some Label'], style });
|
|
66
|
-
const minSegmentRadius = maxRadius -
|
|
61
|
+
const minSegmentRadius = maxRadius - distance - connectorPadding - labelHeight;
|
|
67
62
|
if (data.radius > minSegmentRadius) {
|
|
68
63
|
data.radius = minSegmentRadius;
|
|
69
64
|
data.innerRadius =
|
|
70
65
|
(_c = calculateNumericProperty({ value: seriesInnerRadius, base: data.radius })) !== null && _c !== void 0 ? _c : 0;
|
|
71
66
|
}
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
67
|
+
}
|
|
68
|
+
return data;
|
|
69
|
+
};
|
|
70
|
+
const prepareLabels = (prepareLabelsArgs) => {
|
|
71
|
+
const { data, series } = prepareLabelsArgs;
|
|
72
|
+
const { dataLabels } = series[0];
|
|
73
|
+
const labels = [];
|
|
74
|
+
const htmlLabels = [];
|
|
75
|
+
const connectors = [];
|
|
76
|
+
if (!dataLabels.enabled) {
|
|
77
|
+
return { labels, htmlLabels, connectors };
|
|
78
|
+
}
|
|
79
|
+
let line = lineGenerator();
|
|
80
|
+
const curveFactory = getCurveFactory(data);
|
|
81
|
+
if (curveFactory) {
|
|
82
|
+
line = line.curve(curveFactory);
|
|
83
|
+
}
|
|
84
|
+
const { style, connectorPadding, distance } = dataLabels;
|
|
85
|
+
const { maxHeight: labelHeight } = getLabelsSize({ labels: ['Some Label'], style });
|
|
86
|
+
const connectorStartPointGenerator = arc()
|
|
87
|
+
.innerRadius(data.radius)
|
|
88
|
+
.outerRadius(data.radius);
|
|
89
|
+
const connectorMidPointRadius = data.radius + distance / 2;
|
|
90
|
+
const connectorMidPointGenerator = arc()
|
|
91
|
+
.innerRadius(connectorMidPointRadius)
|
|
92
|
+
.outerRadius(connectorMidPointRadius);
|
|
93
|
+
const connectorArcRadius = data.radius + distance;
|
|
94
|
+
const connectorEndPointGenerator = arc()
|
|
95
|
+
.innerRadius(connectorArcRadius)
|
|
96
|
+
.outerRadius(connectorArcRadius);
|
|
97
|
+
const labelArcRadius = connectorArcRadius + connectorPadding;
|
|
98
|
+
const labelArcGenerator = arc()
|
|
99
|
+
.innerRadius(labelArcRadius)
|
|
100
|
+
.outerRadius(labelArcRadius);
|
|
101
|
+
series.forEach((d, index) => {
|
|
102
|
+
const prevLabel = labels[labels.length - 1];
|
|
103
|
+
const text = String(d.data.label || d.data.value);
|
|
104
|
+
const shouldUseHtml = dataLabels.html;
|
|
105
|
+
const labelSize = getLabelsSize({ labels: [text], style, html: shouldUseHtml });
|
|
106
|
+
const labelWidth = labelSize.maxWidth;
|
|
107
|
+
const relatedSegment = data.segments[index];
|
|
108
|
+
const getLabelPosition = (angle) => {
|
|
109
|
+
let [x, y] = labelArcGenerator.centroid(Object.assign(Object.assign({}, relatedSegment), { startAngle: angle, endAngle: angle }));
|
|
110
|
+
if (shouldUseHtml) {
|
|
111
|
+
x = x < 0 ? x - labelWidth : x;
|
|
112
|
+
y = y - labelSize.maxHeight;
|
|
113
|
+
}
|
|
114
|
+
else {
|
|
97
115
|
y = y < 0 ? y - labelHeight : y;
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
const
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
if (
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
const
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
116
|
+
}
|
|
117
|
+
x = Math.max(-boundsWidth / 2, x);
|
|
118
|
+
return [x, y];
|
|
119
|
+
};
|
|
120
|
+
const getConnectorPoints = (angle) => {
|
|
121
|
+
const connectorStartPoint = connectorStartPointGenerator.centroid(relatedSegment);
|
|
122
|
+
const connectorEndPoint = connectorEndPointGenerator.centroid(Object.assign(Object.assign({}, relatedSegment), { startAngle: angle, endAngle: angle }));
|
|
123
|
+
if (dataLabels.connectorShape === 'straight-line') {
|
|
124
|
+
return [connectorStartPoint, connectorEndPoint];
|
|
125
|
+
}
|
|
126
|
+
const connectorMidPoint = connectorMidPointGenerator.centroid(relatedSegment);
|
|
127
|
+
return [connectorStartPoint, connectorMidPoint, connectorEndPoint];
|
|
128
|
+
};
|
|
129
|
+
const midAngle = Math.max((prevLabel === null || prevLabel === void 0 ? void 0 : prevLabel.angle) || 0, relatedSegment.startAngle +
|
|
130
|
+
(relatedSegment.endAngle - relatedSegment.startAngle) / 2);
|
|
131
|
+
const [x, y] = getLabelPosition(midAngle);
|
|
132
|
+
const label = {
|
|
133
|
+
text,
|
|
134
|
+
x,
|
|
135
|
+
y,
|
|
136
|
+
style,
|
|
137
|
+
size: { width: labelWidth, height: labelHeight },
|
|
138
|
+
maxWidth: labelWidth,
|
|
139
|
+
textAnchor: midAngle < Math.PI ? 'start' : 'end',
|
|
140
|
+
series: { id: d.id },
|
|
141
|
+
active: true,
|
|
142
|
+
segment: relatedSegment.data,
|
|
143
|
+
angle: midAngle,
|
|
144
|
+
};
|
|
145
|
+
let overlap = false;
|
|
146
|
+
if (prevLabel) {
|
|
147
|
+
overlap = isLabelsOverlapping(prevLabel, label, dataLabels.padding);
|
|
148
|
+
if (overlap) {
|
|
149
|
+
let shouldAdjustAngle = true;
|
|
150
|
+
const step = Math.PI / 180;
|
|
151
|
+
while (shouldAdjustAngle) {
|
|
152
|
+
const newAngle = label.angle + step;
|
|
153
|
+
if (newAngle > FULL_CIRCLE && newAngle % FULL_CIRCLE > labels[0].angle) {
|
|
154
|
+
shouldAdjustAngle = false;
|
|
155
|
+
}
|
|
156
|
+
else {
|
|
157
|
+
label.angle = newAngle;
|
|
158
|
+
const [newX, newY] = getLabelPosition(newAngle);
|
|
159
|
+
label.x = newX;
|
|
160
|
+
label.y = newY;
|
|
161
|
+
if (!isLabelsOverlapping(prevLabel, label, dataLabels.padding)) {
|
|
139
162
|
shouldAdjustAngle = false;
|
|
140
|
-
|
|
141
|
-
else {
|
|
142
|
-
label.angle = newAngle;
|
|
143
|
-
const [newX, newY] = getLabelPosition(newAngle);
|
|
144
|
-
label.x = newX;
|
|
145
|
-
label.y = newY;
|
|
146
|
-
if (!isLabelsOverlapping(prevLabel, label, dataLabels.padding)) {
|
|
147
|
-
shouldAdjustAngle = false;
|
|
148
|
-
overlap = false;
|
|
149
|
-
}
|
|
163
|
+
overlap = false;
|
|
150
164
|
}
|
|
151
165
|
}
|
|
152
166
|
}
|
|
153
167
|
}
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
}
|
|
165
|
-
if (shouldUseHtml) {
|
|
166
|
-
data.htmlElements.push({
|
|
167
|
-
x: boundsWidth / 2 + label.x,
|
|
168
|
-
y: boundsHeight / 2 + label.y,
|
|
169
|
-
content: label.text,
|
|
170
|
-
});
|
|
171
|
-
}
|
|
172
|
-
else {
|
|
173
|
-
labels.push(label);
|
|
168
|
+
}
|
|
169
|
+
if (dataLabels.allowOverlap || !overlap) {
|
|
170
|
+
const left = getLeftPosition(label);
|
|
171
|
+
if (Math.abs(left) > boundsWidth / 2) {
|
|
172
|
+
label.maxWidth = label.size.width - (Math.abs(left) - boundsWidth / 2);
|
|
173
|
+
}
|
|
174
|
+
else {
|
|
175
|
+
const right = left + label.size.width;
|
|
176
|
+
if (right > boundsWidth / 2) {
|
|
177
|
+
label.maxWidth = label.size.width - (right - boundsWidth / 2);
|
|
174
178
|
}
|
|
175
|
-
const connector = {
|
|
176
|
-
path: line(getConnectorPoints(midAngle)),
|
|
177
|
-
color: relatedSegment.data.color,
|
|
178
|
-
};
|
|
179
|
-
data.connectors.push(connector);
|
|
180
179
|
}
|
|
181
|
-
|
|
182
|
-
|
|
180
|
+
if (shouldUseHtml) {
|
|
181
|
+
htmlLabels.push({
|
|
182
|
+
x: boundsWidth / 2 + label.x,
|
|
183
|
+
y: boundsHeight / 2 + label.y,
|
|
184
|
+
content: label.text,
|
|
185
|
+
size: label.size,
|
|
186
|
+
});
|
|
187
|
+
}
|
|
188
|
+
else {
|
|
189
|
+
labels.push(label);
|
|
190
|
+
}
|
|
191
|
+
const connector = {
|
|
192
|
+
path: line(getConnectorPoints(midAngle)),
|
|
193
|
+
color: relatedSegment.data.color,
|
|
194
|
+
};
|
|
195
|
+
connectors.push(connector);
|
|
196
|
+
}
|
|
197
|
+
});
|
|
198
|
+
return {
|
|
199
|
+
labels,
|
|
200
|
+
htmlLabels,
|
|
201
|
+
connectors,
|
|
202
|
+
};
|
|
203
|
+
};
|
|
204
|
+
return Array.from(groupedPieSeries).map(([stackId, items]) => {
|
|
205
|
+
const data = prepareItem(stackId, items);
|
|
206
|
+
const preparedLabels = prepareLabels({
|
|
207
|
+
data,
|
|
208
|
+
series: items,
|
|
209
|
+
});
|
|
210
|
+
const allPreparedLabels = [...preparedLabels.labels, ...preparedLabels.htmlLabels];
|
|
211
|
+
const top = Math.min(data.center[1] - data.radius, ...allPreparedLabels.map((l) => l.y + data.center[1]));
|
|
212
|
+
const bottom = Math.max(data.center[1] + data.radius, ...allPreparedLabels.map((l) => data.center[1] + l.y + l.size.height));
|
|
213
|
+
const topAdjustment = Math.floor(top - data.halo.size);
|
|
214
|
+
if (topAdjustment > 0) {
|
|
215
|
+
// should adjust top position and height
|
|
216
|
+
data.radius += topAdjustment / 2;
|
|
217
|
+
data.center[1] -= topAdjustment / 2;
|
|
183
218
|
}
|
|
219
|
+
const bottomAdjustment = Math.floor(boundsHeight - bottom - data.halo.size);
|
|
220
|
+
if (bottomAdjustment > 0) {
|
|
221
|
+
// should adjust position and radius
|
|
222
|
+
data.radius += bottomAdjustment / 2;
|
|
223
|
+
data.center[1] += bottomAdjustment / 2;
|
|
224
|
+
}
|
|
225
|
+
const { labels, htmlLabels, connectors } = prepareLabels({
|
|
226
|
+
data,
|
|
227
|
+
series: items,
|
|
228
|
+
});
|
|
229
|
+
data.labels = labels;
|
|
230
|
+
data.htmlLabels = htmlLabels;
|
|
231
|
+
data.connectors = connectors;
|
|
184
232
|
return data;
|
|
185
233
|
});
|
|
186
234
|
}
|
|
@@ -9,6 +9,7 @@ export { prepareScatterData } from './prepare-data';
|
|
|
9
9
|
const b = block('d3-scatter');
|
|
10
10
|
export function ScatterSeriesShape(props) {
|
|
11
11
|
const { dispatcher, preparedData, seriesOptions, htmlLayout } = props;
|
|
12
|
+
const hoveredDataRef = React.useRef(null);
|
|
12
13
|
const ref = React.useRef(null);
|
|
13
14
|
React.useEffect(() => {
|
|
14
15
|
if (!ref.current) {
|
|
@@ -28,8 +29,9 @@ export function ScatterSeriesShape(props) {
|
|
|
28
29
|
.attr('cursor', (d) => d.point.series.cursor);
|
|
29
30
|
const hoverEnabled = hoverOptions === null || hoverOptions === void 0 ? void 0 : hoverOptions.enabled;
|
|
30
31
|
const inactiveEnabled = inactiveOptions === null || inactiveOptions === void 0 ? void 0 : inactiveOptions.enabled;
|
|
31
|
-
|
|
32
|
+
function handleShapeHover(data) {
|
|
32
33
|
var _a;
|
|
34
|
+
hoveredDataRef.current = data;
|
|
33
35
|
const selected = data === null || data === void 0 ? void 0 : data.find((d) => d.series.type === 'scatter');
|
|
34
36
|
const selectedDataItem = selected === null || selected === void 0 ? void 0 : selected.data;
|
|
35
37
|
const selectedSeriesId = (_a = selected === null || selected === void 0 ? void 0 : selected.series) === null || _a === void 0 ? void 0 : _a.id;
|
|
@@ -58,7 +60,11 @@ export function ScatterSeriesShape(props) {
|
|
|
58
60
|
}
|
|
59
61
|
return d;
|
|
60
62
|
});
|
|
61
|
-
}
|
|
63
|
+
}
|
|
64
|
+
if (hoveredDataRef.current !== null) {
|
|
65
|
+
handleShapeHover(hoveredDataRef.current);
|
|
66
|
+
}
|
|
67
|
+
dispatcher.on('hover-shape.scatter', handleShapeHover);
|
|
62
68
|
return () => {
|
|
63
69
|
dispatcher.on('hover-shape.scatter', null);
|
|
64
70
|
};
|
|
@@ -6,6 +6,7 @@ import { HtmlLayer } from '../HtmlLayer';
|
|
|
6
6
|
const b = block('d3-treemap');
|
|
7
7
|
export const TreemapSeriesShape = (props) => {
|
|
8
8
|
const { dispatcher, preparedData, seriesOptions, htmlLayout } = props;
|
|
9
|
+
const hoveredDataRef = React.useRef(null);
|
|
9
10
|
const ref = React.useRef(null);
|
|
10
11
|
React.useEffect(() => {
|
|
11
12
|
if (!ref.current) {
|
|
@@ -48,8 +49,9 @@ export const TreemapSeriesShape = (props) => {
|
|
|
48
49
|
const eventName = `hover-shape.treemap`;
|
|
49
50
|
const hoverOptions = get(seriesOptions, 'treemap.states.hover');
|
|
50
51
|
const inactiveOptions = get(seriesOptions, 'treemap.states.inactive');
|
|
51
|
-
|
|
52
|
+
function handleShapeHover(data) {
|
|
52
53
|
var _a;
|
|
54
|
+
hoveredDataRef.current = data;
|
|
53
55
|
const hoverEnabled = hoverOptions === null || hoverOptions === void 0 ? void 0 : hoverOptions.enabled;
|
|
54
56
|
const inactiveEnabled = inactiveOptions === null || inactiveOptions === void 0 ? void 0 : inactiveOptions.enabled;
|
|
55
57
|
const hoveredData = (_a = data === null || data === void 0 ? void 0 : data[0]) === null || _a === void 0 ? void 0 : _a.data;
|
|
@@ -87,7 +89,11 @@ export const TreemapSeriesShape = (props) => {
|
|
|
87
89
|
});
|
|
88
90
|
return d;
|
|
89
91
|
});
|
|
90
|
-
}
|
|
92
|
+
}
|
|
93
|
+
if (hoveredDataRef.current !== null) {
|
|
94
|
+
handleShapeHover(hoveredDataRef.current);
|
|
95
|
+
}
|
|
96
|
+
dispatcher.on(eventName, handleShapeHover);
|
|
91
97
|
return () => {
|
|
92
98
|
dispatcher.on(eventName, null);
|
|
93
99
|
};
|
|
@@ -17,7 +17,7 @@ export declare function getYValue(args: {
|
|
|
17
17
|
yAxis: PreparedAxis;
|
|
18
18
|
yScale: ChartScale;
|
|
19
19
|
}): number;
|
|
20
|
-
export declare
|
|
20
|
+
export declare function shapeKey(d: unknown): string | -1;
|
|
21
21
|
export declare function setActiveState<T extends {
|
|
22
22
|
active?: boolean;
|
|
23
23
|
}>(args: {
|
|
@@ -26,4 +26,4 @@ export declare function setActiveState<T extends {
|
|
|
26
26
|
state: BasicInactiveState | undefined;
|
|
27
27
|
active: boolean;
|
|
28
28
|
}): T;
|
|
29
|
-
export declare
|
|
29
|
+
export declare function getLineDashArray(dashStyle: DashStyle, strokeWidth?: number): string;
|
|
@@ -23,7 +23,9 @@ export function getYValue(args) {
|
|
|
23
23
|
const yLinearScale = yScale;
|
|
24
24
|
return yLinearScale(point.y);
|
|
25
25
|
}
|
|
26
|
-
export
|
|
26
|
+
export function shapeKey(d) {
|
|
27
|
+
return d.id || -1;
|
|
28
|
+
}
|
|
27
29
|
export function setActiveState(args) {
|
|
28
30
|
const { element, datum, state, active } = args;
|
|
29
31
|
const elementSelection = select(element);
|
|
@@ -34,7 +36,7 @@ export function setActiveState(args) {
|
|
|
34
36
|
}
|
|
35
37
|
return datum;
|
|
36
38
|
}
|
|
37
|
-
export
|
|
39
|
+
export function getLineDashArray(dashStyle, strokeWidth = 2) {
|
|
38
40
|
const value = dashStyle.toLowerCase();
|
|
39
41
|
const arrayValue = value
|
|
40
42
|
.replace('shortdashdotdot', '3,1,1,1,1,1,')
|
|
@@ -50,4 +52,4 @@ export const getLineDashArray = (dashStyle, strokeWidth = 2) => {
|
|
|
50
52
|
return `${parseInt(part, 10) * strokeWidth}`;
|
|
51
53
|
});
|
|
52
54
|
return arrayValue.join(',').replace(/NaN/g, 'none');
|
|
53
|
-
}
|
|
55
|
+
}
|
|
@@ -10,6 +10,7 @@ export * from './types';
|
|
|
10
10
|
const b = block('d3-waterfall');
|
|
11
11
|
export const WaterfallSeriesShapes = (args) => {
|
|
12
12
|
const { dispatcher, preparedData, seriesOptions, htmlLayout } = args;
|
|
13
|
+
const hoveredDataRef = React.useRef(null);
|
|
13
14
|
const ref = React.useRef(null);
|
|
14
15
|
const connectorSelector = `.${b('connector')}`;
|
|
15
16
|
React.useEffect(() => {
|
|
@@ -78,7 +79,8 @@ export const WaterfallSeriesShapes = (args) => {
|
|
|
78
79
|
})
|
|
79
80
|
.attr('stroke-width', 1)
|
|
80
81
|
.attr('stroke-dasharray', () => getLineDashArray(DashStyle.Dash, 1));
|
|
81
|
-
|
|
82
|
+
function handleShapeHover(data) {
|
|
83
|
+
hoveredDataRef.current = data;
|
|
82
84
|
const hoverEnabled = hoverOptions === null || hoverOptions === void 0 ? void 0 : hoverOptions.enabled;
|
|
83
85
|
const inactiveEnabled = inactiveOptions === null || inactiveOptions === void 0 ? void 0 : inactiveOptions.enabled;
|
|
84
86
|
if (!data) {
|
|
@@ -116,7 +118,11 @@ export const WaterfallSeriesShapes = (args) => {
|
|
|
116
118
|
: (inactiveOptions === null || inactiveOptions === void 0 ? void 0 : inactiveOptions.opacity) || null;
|
|
117
119
|
});
|
|
118
120
|
}
|
|
119
|
-
}
|
|
121
|
+
}
|
|
122
|
+
if (hoveredDataRef.current !== null) {
|
|
123
|
+
handleShapeHover(hoveredDataRef.current);
|
|
124
|
+
}
|
|
125
|
+
dispatcher.on('hover-shape.waterfall', handleShapeHover);
|
|
120
126
|
return () => {
|
|
121
127
|
dispatcher.on('hover-shape.waterfall', null);
|
|
122
128
|
};
|