@gravity-ui/charts 1.51.7 → 1.52.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cjs/components/ChartInner/useChartInnerHandlers.d.ts +3 -2
- package/dist/cjs/components/ChartInner/useChartInnerHandlers.js +1 -3
- package/dist/cjs/components/ChartInner/useChartInnerProps.d.ts +3 -2
- package/dist/cjs/components/ChartInner/useDefaultState.d.ts +3 -2
- package/dist/cjs/components/index.d.ts +1 -0
- package/dist/cjs/components/index.js +1 -0
- package/dist/cjs/core/series/plugin.d.ts +47 -2
- package/dist/cjs/core/series/types.d.ts +4 -0
- package/dist/cjs/core/shapes/area/prepare-data.js +29 -19
- package/dist/cjs/core/shapes/area/renderer.d.ts +0 -5
- package/dist/cjs/core/shapes/area/renderer.js +0 -75
- package/dist/cjs/core/shapes/area/types.d.ts +2 -8
- package/dist/cjs/core/shapes/bar-x/prepare-data.js +18 -7
- package/dist/cjs/core/shapes/bar-x/renderer.d.ts +0 -1
- package/dist/cjs/core/shapes/bar-x/renderer.js +0 -18
- package/dist/cjs/core/shapes/bar-x/types.d.ts +2 -1
- package/dist/cjs/core/shapes/bar-y/get-tooltip-data.js +4 -2
- package/dist/cjs/core/shapes/bar-y/prepare-data.js +8 -2
- package/dist/cjs/core/shapes/funnel/prepare-data.js +121 -68
- package/dist/cjs/core/shapes/heatmap/prepare-data.js +11 -2
- package/dist/cjs/core/shapes/line/prepare-data.js +27 -17
- package/dist/cjs/core/shapes/line/renderer.d.ts +0 -5
- package/dist/cjs/core/shapes/line/renderer.js +0 -75
- package/dist/cjs/core/shapes/line/types.d.ts +2 -8
- package/dist/cjs/core/shapes/marker.d.ts +30 -0
- package/dist/cjs/core/shapes/marker.js +68 -0
- package/dist/cjs/core/shapes/pie/prepare-data.js +24 -9
- package/dist/cjs/core/shapes/radar/prepare-data.js +3 -0
- package/dist/cjs/core/shapes/sankey/prepare-data.js +10 -1
- package/dist/cjs/core/shapes/scatter/prepare-data.js +8 -1
- package/dist/cjs/core/shapes/scatter/renderer.js +3 -2
- package/dist/cjs/core/shapes/scatter/types.d.ts +1 -1
- package/dist/cjs/core/shapes/treemap/prepare-data.js +9 -1
- package/dist/cjs/core/shapes/types.d.ts +35 -0
- package/dist/cjs/core/shapes/waterfall/prepare-data.js +5 -2
- package/dist/cjs/core/shapes/x-range/prepare-data.js +7 -2
- package/dist/cjs/core/types/chart/base.d.ts +22 -2
- package/dist/cjs/core/types/chart/funnel.d.ts +25 -1
- package/dist/cjs/core/types/chart/tooltip.d.ts +6 -1
- package/dist/cjs/core/utils/data-labels.d.ts +34 -0
- package/dist/cjs/core/utils/data-labels.js +26 -0
- package/dist/cjs/core/utils/get-closest-data.d.ts +2 -2
- package/dist/cjs/core/utils/get-closest-data.js +14 -34
- package/dist/cjs/core/utils/tooltip-helpers.d.ts +16 -0
- package/dist/cjs/core/utils/tooltip-helpers.js +12 -0
- package/dist/cjs/hooks/useShapes/AnnotationLayer.d.ts +9 -0
- package/dist/cjs/hooks/useShapes/AnnotationLayer.js +17 -0
- package/dist/cjs/hooks/useShapes/HoverMarkerLayer.d.ts +10 -0
- package/dist/cjs/hooks/useShapes/HoverMarkerLayer.js +22 -0
- package/dist/cjs/hooks/useShapes/MarkerLayer.d.ts +7 -0
- package/dist/cjs/hooks/useShapes/MarkerLayer.js +12 -0
- package/dist/cjs/hooks/useShapes/SeriesShapes.d.ts +18 -0
- package/dist/cjs/hooks/useShapes/SeriesShapes.js +32 -0
- package/dist/cjs/hooks/useShapes/index.d.ts +5 -18
- package/dist/cjs/hooks/useShapes/index.js +39 -229
- package/dist/cjs/index.d.ts +0 -1
- package/dist/cjs/index.js +0 -1
- package/dist/cjs/plugins/area/index.js +42 -0
- package/dist/cjs/plugins/bar-x/index.js +42 -0
- package/dist/cjs/plugins/bar-y/index.js +26 -0
- package/dist/cjs/plugins/funnel/index.js +18 -0
- package/dist/cjs/plugins/funnel/prepare.js +17 -12
- package/dist/cjs/plugins/heatmap/index.js +23 -0
- package/dist/cjs/plugins/line/index.js +28 -0
- package/dist/cjs/plugins/pie/index.js +18 -0
- package/dist/cjs/plugins/radar/index.js +18 -0
- package/dist/cjs/plugins/sankey/index.js +18 -0
- package/dist/cjs/plugins/scatter/index.js +26 -0
- package/dist/cjs/plugins/treemap/index.js +18 -0
- package/dist/cjs/plugins/waterfall/index.js +39 -0
- package/dist/cjs/plugins/x-range/index.js +25 -0
- package/dist/cjs/setup-jsdom.d.ts +0 -1
- package/dist/cjs/setup-jsdom.js +1 -1
- package/dist/esm/components/ChartInner/useChartInnerHandlers.d.ts +3 -2
- package/dist/esm/components/ChartInner/useChartInnerHandlers.js +1 -3
- package/dist/esm/components/ChartInner/useChartInnerProps.d.ts +3 -2
- package/dist/esm/components/ChartInner/useDefaultState.d.ts +3 -2
- package/dist/esm/components/index.d.ts +1 -0
- package/dist/esm/components/index.js +1 -0
- package/dist/esm/core/series/plugin.d.ts +47 -2
- package/dist/esm/core/series/types.d.ts +4 -0
- package/dist/esm/core/shapes/area/prepare-data.js +29 -19
- package/dist/esm/core/shapes/area/renderer.d.ts +0 -5
- package/dist/esm/core/shapes/area/renderer.js +0 -75
- package/dist/esm/core/shapes/area/types.d.ts +2 -8
- package/dist/esm/core/shapes/bar-x/prepare-data.js +18 -7
- package/dist/esm/core/shapes/bar-x/renderer.d.ts +0 -1
- package/dist/esm/core/shapes/bar-x/renderer.js +0 -18
- package/dist/esm/core/shapes/bar-x/types.d.ts +2 -1
- package/dist/esm/core/shapes/bar-y/get-tooltip-data.js +4 -2
- package/dist/esm/core/shapes/bar-y/prepare-data.js +8 -2
- package/dist/esm/core/shapes/funnel/prepare-data.js +121 -68
- package/dist/esm/core/shapes/heatmap/prepare-data.js +11 -2
- package/dist/esm/core/shapes/line/prepare-data.js +27 -17
- package/dist/esm/core/shapes/line/renderer.d.ts +0 -5
- package/dist/esm/core/shapes/line/renderer.js +0 -75
- package/dist/esm/core/shapes/line/types.d.ts +2 -8
- package/dist/esm/core/shapes/marker.d.ts +30 -0
- package/dist/esm/core/shapes/marker.js +68 -0
- package/dist/esm/core/shapes/pie/prepare-data.js +24 -9
- package/dist/esm/core/shapes/radar/prepare-data.js +3 -0
- package/dist/esm/core/shapes/sankey/prepare-data.js +10 -1
- package/dist/esm/core/shapes/scatter/prepare-data.js +8 -1
- package/dist/esm/core/shapes/scatter/renderer.js +3 -2
- package/dist/esm/core/shapes/scatter/types.d.ts +1 -1
- package/dist/esm/core/shapes/treemap/prepare-data.js +9 -1
- package/dist/esm/core/shapes/types.d.ts +35 -0
- package/dist/esm/core/shapes/waterfall/prepare-data.js +5 -2
- package/dist/esm/core/shapes/x-range/prepare-data.js +7 -2
- package/dist/esm/core/types/chart/base.d.ts +22 -2
- package/dist/esm/core/types/chart/funnel.d.ts +25 -1
- package/dist/esm/core/types/chart/tooltip.d.ts +6 -1
- package/dist/esm/core/utils/data-labels.d.ts +34 -0
- package/dist/esm/core/utils/data-labels.js +26 -0
- package/dist/esm/core/utils/get-closest-data.d.ts +2 -2
- package/dist/esm/core/utils/get-closest-data.js +14 -34
- package/dist/esm/core/utils/tooltip-helpers.d.ts +16 -0
- package/dist/esm/core/utils/tooltip-helpers.js +12 -0
- package/dist/esm/hooks/useShapes/AnnotationLayer.d.ts +9 -0
- package/dist/esm/hooks/useShapes/AnnotationLayer.js +17 -0
- package/dist/esm/hooks/useShapes/HoverMarkerLayer.d.ts +10 -0
- package/dist/esm/hooks/useShapes/HoverMarkerLayer.js +22 -0
- package/dist/esm/hooks/useShapes/MarkerLayer.d.ts +7 -0
- package/dist/esm/hooks/useShapes/MarkerLayer.js +12 -0
- package/dist/esm/hooks/useShapes/SeriesShapes.d.ts +18 -0
- package/dist/esm/hooks/useShapes/SeriesShapes.js +32 -0
- package/dist/esm/hooks/useShapes/index.d.ts +5 -18
- package/dist/esm/hooks/useShapes/index.js +39 -229
- package/dist/esm/index.d.ts +0 -1
- package/dist/esm/index.js +0 -1
- package/dist/esm/plugins/area/index.js +42 -0
- package/dist/esm/plugins/bar-x/index.js +42 -0
- package/dist/esm/plugins/bar-y/index.js +26 -0
- package/dist/esm/plugins/funnel/index.js +18 -0
- package/dist/esm/plugins/funnel/prepare.js +17 -12
- package/dist/esm/plugins/heatmap/index.js +23 -0
- package/dist/esm/plugins/line/index.js +28 -0
- package/dist/esm/plugins/pie/index.js +18 -0
- package/dist/esm/plugins/radar/index.js +18 -0
- package/dist/esm/plugins/sankey/index.js +18 -0
- package/dist/esm/plugins/scatter/index.js +26 -0
- package/dist/esm/plugins/treemap/index.js +18 -0
- package/dist/esm/plugins/waterfall/index.js +39 -0
- package/dist/esm/plugins/x-range/index.js +25 -0
- package/dist/esm/setup-jsdom.d.ts +0 -1
- package/dist/esm/setup-jsdom.js +1 -1
- package/package.json +2 -3
- package/dist/cjs/hooks/useShapes/area/index.d.ts +0 -15
- package/dist/cjs/hooks/useShapes/area/index.js +0 -52
- package/dist/cjs/hooks/useShapes/bar-x/index.d.ts +0 -16
- package/dist/cjs/hooks/useShapes/bar-x/index.js +0 -45
- package/dist/cjs/hooks/useShapes/bar-y/index.d.ts +0 -13
- package/dist/cjs/hooks/useShapes/bar-y/index.js +0 -19
- package/dist/cjs/hooks/useShapes/funnel/index.d.ts +0 -13
- package/dist/cjs/hooks/useShapes/funnel/index.js +0 -21
- package/dist/cjs/hooks/useShapes/heatmap/index.d.ts +0 -13
- package/dist/cjs/hooks/useShapes/heatmap/index.js +0 -20
- package/dist/cjs/hooks/useShapes/line/index.d.ts +0 -15
- package/dist/cjs/hooks/useShapes/line/index.js +0 -38
- package/dist/cjs/hooks/useShapes/pie/index.d.ts +0 -12
- package/dist/cjs/hooks/useShapes/pie/index.js +0 -20
- package/dist/cjs/hooks/useShapes/radar/index.d.ts +0 -12
- package/dist/cjs/hooks/useShapes/radar/index.js +0 -19
- package/dist/cjs/hooks/useShapes/sankey/index.d.ts +0 -12
- package/dist/cjs/hooks/useShapes/sankey/index.js +0 -18
- package/dist/cjs/hooks/useShapes/scatter/index.d.ts +0 -13
- package/dist/cjs/hooks/useShapes/scatter/index.js +0 -22
- package/dist/cjs/hooks/useShapes/treemap/index.d.ts +0 -12
- package/dist/cjs/hooks/useShapes/treemap/index.js +0 -18
- package/dist/cjs/hooks/useShapes/waterfall/index.d.ts +0 -14
- package/dist/cjs/hooks/useShapes/waterfall/index.js +0 -31
- package/dist/cjs/hooks/useShapes/x-range/index.d.ts +0 -14
- package/dist/cjs/hooks/useShapes/x-range/index.js +0 -20
- package/dist/esm/hooks/useShapes/area/index.d.ts +0 -15
- package/dist/esm/hooks/useShapes/area/index.js +0 -52
- package/dist/esm/hooks/useShapes/bar-x/index.d.ts +0 -16
- package/dist/esm/hooks/useShapes/bar-x/index.js +0 -45
- package/dist/esm/hooks/useShapes/bar-y/index.d.ts +0 -13
- package/dist/esm/hooks/useShapes/bar-y/index.js +0 -19
- package/dist/esm/hooks/useShapes/funnel/index.d.ts +0 -13
- package/dist/esm/hooks/useShapes/funnel/index.js +0 -21
- package/dist/esm/hooks/useShapes/heatmap/index.d.ts +0 -13
- package/dist/esm/hooks/useShapes/heatmap/index.js +0 -20
- package/dist/esm/hooks/useShapes/line/index.d.ts +0 -15
- package/dist/esm/hooks/useShapes/line/index.js +0 -38
- package/dist/esm/hooks/useShapes/pie/index.d.ts +0 -12
- package/dist/esm/hooks/useShapes/pie/index.js +0 -20
- package/dist/esm/hooks/useShapes/radar/index.d.ts +0 -12
- package/dist/esm/hooks/useShapes/radar/index.js +0 -19
- package/dist/esm/hooks/useShapes/sankey/index.d.ts +0 -12
- package/dist/esm/hooks/useShapes/sankey/index.js +0 -18
- package/dist/esm/hooks/useShapes/scatter/index.d.ts +0 -13
- package/dist/esm/hooks/useShapes/scatter/index.js +0 -22
- package/dist/esm/hooks/useShapes/treemap/index.d.ts +0 -12
- package/dist/esm/hooks/useShapes/treemap/index.js +0 -18
- package/dist/esm/hooks/useShapes/waterfall/index.d.ts +0 -14
- package/dist/esm/hooks/useShapes/waterfall/index.js +0 -31
- package/dist/esm/hooks/useShapes/x-range/index.d.ts +0 -14
- package/dist/esm/hooks/useShapes/x-range/index.js +0 -20
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { path } from 'd3-path';
|
|
2
|
-
import { calculateNumericProperty, getFormattedValue, getLabelsSize, getTextSizeFn, } from '../../utils';
|
|
2
|
+
import { calculateNumericProperty, getFormattedValue, getLabelsSize, getTextSizeFn, isPointDataLabelEnabled, } from '../../utils';
|
|
3
3
|
function getLineConnectorPaths(args) {
|
|
4
4
|
const { points } = args;
|
|
5
5
|
const leftPath = path();
|
|
@@ -19,7 +19,7 @@ function getAreaConnectorPath(args) {
|
|
|
19
19
|
return p;
|
|
20
20
|
}
|
|
21
21
|
export async function prepareFunnelData(args) {
|
|
22
|
-
var _a, _b, _c, _d
|
|
22
|
+
var _a, _b, _c, _d;
|
|
23
23
|
const { series, boundsWidth, boundsHeight } = args;
|
|
24
24
|
const items = [];
|
|
25
25
|
const svgLabels = [];
|
|
@@ -33,75 +33,59 @@ export async function prepareFunnelData(args) {
|
|
|
33
33
|
})) !== null && _b !== void 0 ? _b : 0;
|
|
34
34
|
const itemHeight = (boundsHeight - connectorHeight * (series.length - 1)) / series.length;
|
|
35
35
|
const getTextSize = getTextSizeFn({ style: series[0].dataLabels.style });
|
|
36
|
-
const getSegmentY = (index) =>
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
let
|
|
40
|
-
|
|
36
|
+
const getSegmentY = (index) => index * (itemHeight + connectorHeight);
|
|
37
|
+
// measure labels and accumulate max outside-label widths per side.
|
|
38
|
+
let rawLeftOffset = 0;
|
|
39
|
+
let rawRightOffset = 0;
|
|
40
|
+
const labelInfos = [];
|
|
41
41
|
for (let index = 0; index < series.length; index++) {
|
|
42
42
|
const s = series[index];
|
|
43
|
-
if (s.
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
:
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
case 'center': {
|
|
70
|
-
x = boundsWidth / 2 - width / 2;
|
|
71
|
-
break;
|
|
72
|
-
}
|
|
73
|
-
}
|
|
74
|
-
const y = getSegmentY(index) + itemHeight / 2 - height / 2 + hangingOffset;
|
|
75
|
-
if (s.dataLabels.html) {
|
|
76
|
-
htmlLabels.push({
|
|
77
|
-
x,
|
|
78
|
-
y,
|
|
79
|
-
content: labelContent,
|
|
80
|
-
size: { width, height },
|
|
81
|
-
style: s.dataLabels.style,
|
|
82
|
-
});
|
|
43
|
+
if (!isPointDataLabelEnabled({ data: s.data, series: s })) {
|
|
44
|
+
labelInfos.push(null);
|
|
45
|
+
continue;
|
|
46
|
+
}
|
|
47
|
+
const d = s.data;
|
|
48
|
+
const labelContent = (_c = d.label) !== null && _c !== void 0 ? _c : getFormattedValue({ value: d.value, format: s.dataLabels.format });
|
|
49
|
+
const { width, height, hangingOffset } = s.dataLabels.html
|
|
50
|
+
? await getLabelsSize({
|
|
51
|
+
labels: [labelContent],
|
|
52
|
+
style: s.dataLabels.style,
|
|
53
|
+
html: true,
|
|
54
|
+
}).then((size) => ({
|
|
55
|
+
width: size.maxWidth,
|
|
56
|
+
height: size.maxHeight,
|
|
57
|
+
hangingOffset: 0,
|
|
58
|
+
}))
|
|
59
|
+
: await getTextSize(labelContent);
|
|
60
|
+
labelInfos.push({ text: labelContent, width, height, hangingOffset, series: s });
|
|
61
|
+
const { inside, align, padding } = s.dataLabels;
|
|
62
|
+
if (!inside) {
|
|
63
|
+
// Minimum offset so this label stays within the plot boundary.
|
|
64
|
+
// Accounts for the fact that narrower segments are already indented from the edge.
|
|
65
|
+
const ratio = s.data.value / maxValue;
|
|
66
|
+
const minOffset = (2 * (width + padding) - boundsWidth * (1 - ratio)) / (1 + ratio);
|
|
67
|
+
if (align === 'left') {
|
|
68
|
+
rawLeftOffset = Math.max(rawLeftOffset, minOffset);
|
|
83
69
|
}
|
|
84
|
-
else {
|
|
85
|
-
|
|
86
|
-
x,
|
|
87
|
-
y,
|
|
88
|
-
text: labelContent,
|
|
89
|
-
style: s.dataLabels.style,
|
|
90
|
-
size: { width, height, hangingOffset },
|
|
91
|
-
textAnchor: 'start',
|
|
92
|
-
series: s,
|
|
93
|
-
});
|
|
70
|
+
else if (align === 'right') {
|
|
71
|
+
rawRightOffset = Math.max(rawRightOffset, minOffset);
|
|
94
72
|
}
|
|
95
73
|
}
|
|
96
74
|
}
|
|
75
|
+
// reserveSpace=true → inset only the labelled side so labels don't overlap segments.
|
|
76
|
+
// reserveSpace=false → no inset; labels overlap segments.
|
|
77
|
+
const { reserveSpace } = series[0].dataLabels;
|
|
78
|
+
const segmentLeftOffset = reserveSpace ? rawLeftOffset : 0;
|
|
79
|
+
const segmentRightOffset = reserveSpace ? rawRightOffset : 0;
|
|
80
|
+
// compute shapes and label positions in a single pass.
|
|
81
|
+
// centerX is constant across all segments — hoist it out of the loop.
|
|
97
82
|
const segmentMaxWidth = boundsWidth - segmentLeftOffset - segmentRightOffset;
|
|
98
|
-
const isTrapezoid =
|
|
83
|
+
const isTrapezoid = series[0].shape === 'trapezoid';
|
|
84
|
+
const centerX = segmentLeftOffset + segmentMaxWidth / 2;
|
|
99
85
|
const getItemWidth = (index) => (segmentMaxWidth * series[index].data.value) / maxValue;
|
|
100
86
|
for (let index = 0; index < series.length; index++) {
|
|
101
87
|
const s = series[index];
|
|
102
|
-
const d = s.data;
|
|
103
88
|
const itemWidth = getItemWidth(index);
|
|
104
|
-
const centerX = segmentLeftOffset + segmentMaxWidth / 2;
|
|
105
89
|
const segmentY = getSegmentY(index);
|
|
106
90
|
const isLastSegment = index === series.length - 1;
|
|
107
91
|
const bottomWidth = isTrapezoid && !isLastSegment ? getItemWidth(index + 1) : itemWidth;
|
|
@@ -111,7 +95,7 @@ export async function prepareFunnelData(args) {
|
|
|
111
95
|
[centerX + bottomWidth / 2, segmentY + itemHeight],
|
|
112
96
|
[centerX - bottomWidth / 2, segmentY + itemHeight],
|
|
113
97
|
];
|
|
114
|
-
const
|
|
98
|
+
const item = {
|
|
115
99
|
x: centerX - itemWidth / 2,
|
|
116
100
|
y: segmentY,
|
|
117
101
|
width: itemWidth,
|
|
@@ -119,22 +103,22 @@ export async function prepareFunnelData(args) {
|
|
|
119
103
|
points,
|
|
120
104
|
color: s.color,
|
|
121
105
|
series: s,
|
|
122
|
-
data:
|
|
106
|
+
data: s.data,
|
|
123
107
|
borderColor: '',
|
|
124
108
|
borderWidth: 0,
|
|
125
109
|
cursor: s.cursor,
|
|
126
110
|
};
|
|
127
|
-
items.push(
|
|
111
|
+
items.push(item);
|
|
128
112
|
const prevSeries = series[index - 1];
|
|
129
113
|
const prevItem = items[index - 1];
|
|
130
|
-
if (prevSeries && prevItem && ((
|
|
114
|
+
if (prevSeries && prevItem && ((_d = prevSeries.connectors) === null || _d === void 0 ? void 0 : _d.enabled)) {
|
|
131
115
|
// Use the actual bottom corners of the previous segment (points[3]/[2]) so that
|
|
132
116
|
// trapezoid segments (whose bottom edge differs from the top edge) are handled correctly.
|
|
133
117
|
const connectorPoints = [
|
|
134
118
|
prevItem.points[3],
|
|
135
119
|
prevItem.points[2],
|
|
136
|
-
|
|
137
|
-
|
|
120
|
+
item.points[1],
|
|
121
|
+
item.points[0],
|
|
138
122
|
];
|
|
139
123
|
connectors.push({
|
|
140
124
|
linePath: getLineConnectorPaths({ points: connectorPoints }),
|
|
@@ -147,13 +131,82 @@ export async function prepareFunnelData(args) {
|
|
|
147
131
|
dashStyle: prevSeries.connectors.lineDashStyle,
|
|
148
132
|
});
|
|
149
133
|
}
|
|
134
|
+
const info = labelInfos[index];
|
|
135
|
+
if (!info)
|
|
136
|
+
continue;
|
|
137
|
+
const { text, width, height, hangingOffset } = info;
|
|
138
|
+
const { anchor, inside, padding } = s.dataLabels;
|
|
139
|
+
const y = segmentY + itemHeight / 2 - height / 2 + hangingOffset;
|
|
140
|
+
let x;
|
|
141
|
+
if (inside) {
|
|
142
|
+
switch (s.dataLabels.align) {
|
|
143
|
+
case 'left':
|
|
144
|
+
x = item.x + padding;
|
|
145
|
+
break;
|
|
146
|
+
case 'right':
|
|
147
|
+
x = item.x + item.width - width - padding;
|
|
148
|
+
break;
|
|
149
|
+
default:
|
|
150
|
+
x = item.x + item.width / 2 - width / 2;
|
|
151
|
+
break;
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
else {
|
|
155
|
+
switch (s.dataLabels.align) {
|
|
156
|
+
case 'left': {
|
|
157
|
+
const edge = 0;
|
|
158
|
+
if (anchor === 'plot') {
|
|
159
|
+
x = edge;
|
|
160
|
+
}
|
|
161
|
+
else {
|
|
162
|
+
x = Math.max(edge, item.x - width - padding);
|
|
163
|
+
}
|
|
164
|
+
break;
|
|
165
|
+
}
|
|
166
|
+
case 'right': {
|
|
167
|
+
const edge = boundsWidth - width;
|
|
168
|
+
if (anchor === 'plot') {
|
|
169
|
+
x = edge;
|
|
170
|
+
}
|
|
171
|
+
else {
|
|
172
|
+
x = Math.min(edge, item.x + item.width + padding);
|
|
173
|
+
}
|
|
174
|
+
break;
|
|
175
|
+
}
|
|
176
|
+
default:
|
|
177
|
+
x = boundsWidth / 2 - width / 2;
|
|
178
|
+
break;
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
if (s.dataLabels.html) {
|
|
182
|
+
htmlLabels.push({
|
|
183
|
+
x,
|
|
184
|
+
y,
|
|
185
|
+
content: text,
|
|
186
|
+
size: { width, height },
|
|
187
|
+
style: s.dataLabels.style,
|
|
188
|
+
});
|
|
189
|
+
}
|
|
190
|
+
else {
|
|
191
|
+
svgLabels.push({
|
|
192
|
+
x,
|
|
193
|
+
y,
|
|
194
|
+
text,
|
|
195
|
+
style: s.dataLabels.style,
|
|
196
|
+
size: { width, height, hangingOffset },
|
|
197
|
+
textAnchor: 'start',
|
|
198
|
+
series: s,
|
|
199
|
+
});
|
|
200
|
+
}
|
|
150
201
|
}
|
|
151
|
-
|
|
202
|
+
return {
|
|
152
203
|
type: 'funnel',
|
|
153
204
|
items,
|
|
154
205
|
svgLabels,
|
|
155
206
|
htmlLabels,
|
|
156
207
|
connectors,
|
|
208
|
+
markers: [],
|
|
209
|
+
getHoverMarkers: () => [],
|
|
210
|
+
annotations: [],
|
|
157
211
|
};
|
|
158
|
-
return data;
|
|
159
212
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { getDomainDataXBySeries, getDomainDataYBySeries, getFormattedValue, getLabelsSize, getTextSizeFn, getTextWithElipsis, isBandScale, } from '../../utils';
|
|
1
|
+
import { getDomainDataXBySeries, getDomainDataYBySeries, getFormattedValue, getLabelsSize, getTextSizeFn, getTextWithElipsis, isBandScale, isPointDataLabelEnabled, shouldPrepareSeriesDataLabels, } from '../../utils';
|
|
2
2
|
import { getBandSize } from '../../utils/band-size';
|
|
3
3
|
export async function prepareHeatmapData({ series, xAxis, xScale, yAxis, yScale, }) {
|
|
4
4
|
var _a, _b, _c, _d, _e;
|
|
@@ -44,10 +44,13 @@ export async function prepareHeatmapData({ series, xAxis, xScale, yAxis, yScale,
|
|
|
44
44
|
}, []);
|
|
45
45
|
const svgDataLabels = [];
|
|
46
46
|
const htmlDataLabels = [];
|
|
47
|
-
if (series
|
|
47
|
+
if (shouldPrepareSeriesDataLabels(series)) {
|
|
48
48
|
if (series.dataLabels.html) {
|
|
49
49
|
for (let i = 0; i < heatmapItems.length; i++) {
|
|
50
50
|
const item = heatmapItems[i];
|
|
51
|
+
if (!isPointDataLabelEnabled({ data: item.data, series })) {
|
|
52
|
+
continue;
|
|
53
|
+
}
|
|
51
54
|
const labelContent = (_c = item.data.label) !== null && _c !== void 0 ? _c : getFormattedValue({ value: item.data.value, format: series.dataLabels.format });
|
|
52
55
|
if (labelContent) {
|
|
53
56
|
const dataLabelsStyle = Object.assign(Object.assign({}, series.dataLabels.style), { maxWidth: `${item.width}px`, maxHeight: `${item.height}px`, overflow: 'hidden' });
|
|
@@ -71,6 +74,9 @@ export async function prepareHeatmapData({ series, xAxis, xScale, yAxis, yScale,
|
|
|
71
74
|
const getTextSize = getTextSizeFn({ style: series.dataLabels.style });
|
|
72
75
|
for (let i = 0; i < heatmapItems.length; i++) {
|
|
73
76
|
const item = heatmapItems[i];
|
|
77
|
+
if (!isPointDataLabelEnabled({ data: item.data, series })) {
|
|
78
|
+
continue;
|
|
79
|
+
}
|
|
74
80
|
const labelContent = (_e = item.data.label) !== null && _e !== void 0 ? _e : getFormattedValue({ value: item.data.value, format: series.dataLabels.format });
|
|
75
81
|
if (labelContent) {
|
|
76
82
|
const size = await getTextSize(labelContent);
|
|
@@ -97,6 +103,9 @@ export async function prepareHeatmapData({ series, xAxis, xScale, yAxis, yScale,
|
|
|
97
103
|
htmlLabels: htmlDataLabels,
|
|
98
104
|
items: heatmapItems,
|
|
99
105
|
labels: svgDataLabels,
|
|
106
|
+
markers: [],
|
|
107
|
+
getHoverMarkers: () => [],
|
|
108
|
+
annotations: [],
|
|
100
109
|
};
|
|
101
110
|
return preparedData;
|
|
102
111
|
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { prepareAnnotation } from '../../series/prepare-annotation';
|
|
2
2
|
import { filterOverlappingLabels, preparePointDataLabels } from '../../utils';
|
|
3
|
+
import { buildHoverMarkerGetter } from '../marker';
|
|
3
4
|
import { getXValue, getYValue, markHiddenPointsOutOfYRange } from '../utils';
|
|
4
5
|
export const prepareLineData = async (args) => {
|
|
5
6
|
var _a, _b, _c, _d, _e, _f;
|
|
@@ -58,44 +59,53 @@ export const prepareLineData = async (args) => {
|
|
|
58
59
|
svgLabels = filterOverlappingLabels(svgLabels, otherLayers.map((l) => l.svgLabels).flat());
|
|
59
60
|
htmlElements = filterOverlappingLabels(htmlElements, otherLayers.map((l) => l.htmlLabels).flat());
|
|
60
61
|
}
|
|
61
|
-
|
|
62
|
+
markHiddenPointsOutOfYRange({
|
|
63
|
+
points,
|
|
64
|
+
yScale: seriesYScale,
|
|
65
|
+
yAxisTop,
|
|
66
|
+
axisMin: seriesYAxis.min,
|
|
67
|
+
axisMax: seriesYAxis.max,
|
|
68
|
+
getDataY: (p) => p.data.y,
|
|
69
|
+
});
|
|
70
|
+
const normalState = s.marker.states.normal;
|
|
62
71
|
const hasPerPointNormalMarkers = s.data.some((d) => { var _a, _b, _c; return (_c = (_b = (_a = d.marker) === null || _a === void 0 ? void 0 : _a.states) === null || _b === void 0 ? void 0 : _b.normal) === null || _c === void 0 ? void 0 : _c.enabled; });
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
var _a, _b, _c, _d;
|
|
66
|
-
if (p.y === null || p.x === null) {
|
|
72
|
+
const markers = s.marker.states.normal.enabled || hasPerPointNormalMarkers
|
|
73
|
+
? points.reduce((result, p) => {
|
|
74
|
+
var _a, _b, _c, _d, _e;
|
|
75
|
+
if (p.y === null || p.x === null || p.hiddenInLine) {
|
|
67
76
|
return result;
|
|
68
77
|
}
|
|
69
78
|
const pointNormalEnabled = (_d = (_c = (_b = (_a = p.data.marker) === null || _a === void 0 ? void 0 : _a.states) === null || _b === void 0 ? void 0 : _b.normal) === null || _c === void 0 ? void 0 : _c.enabled) !== null && _d !== void 0 ? _d : false;
|
|
70
79
|
if (s.marker.states.normal.enabled || pointNormalEnabled) {
|
|
71
80
|
result.push({
|
|
72
|
-
|
|
81
|
+
cx: p.x,
|
|
82
|
+
cy: p.y,
|
|
83
|
+
radius: normalState.radius,
|
|
84
|
+
symbolType: normalState.symbol,
|
|
85
|
+
fill: (_e = p.color) !== null && _e !== void 0 ? _e : s.color,
|
|
86
|
+
stroke: normalState.borderColor,
|
|
87
|
+
strokeWidth: normalState.borderWidth,
|
|
88
|
+
opacity: 1,
|
|
73
89
|
active: true,
|
|
74
|
-
hovered: false,
|
|
75
90
|
clipped: isOutsideBounds(p.x, p.y),
|
|
91
|
+
series: { id: s.id },
|
|
92
|
+
data: p.data,
|
|
76
93
|
});
|
|
77
94
|
}
|
|
78
95
|
return result;
|
|
79
|
-
}, [])
|
|
80
|
-
|
|
96
|
+
}, [])
|
|
97
|
+
: [];
|
|
81
98
|
const annotations = points.reduce((result, p) => {
|
|
82
99
|
if (p.annotation && p.x !== null && p.y !== null) {
|
|
83
100
|
result.push({ annotation: p.annotation, x: p.x, y: p.y });
|
|
84
101
|
}
|
|
85
102
|
return result;
|
|
86
103
|
}, []);
|
|
87
|
-
markHiddenPointsOutOfYRange({
|
|
88
|
-
points,
|
|
89
|
-
yScale: seriesYScale,
|
|
90
|
-
yAxisTop,
|
|
91
|
-
axisMin: seriesYAxis.min,
|
|
92
|
-
axisMax: seriesYAxis.max,
|
|
93
|
-
getDataY: (p) => p.data.y,
|
|
94
|
-
});
|
|
95
104
|
const result = {
|
|
96
105
|
annotations,
|
|
97
106
|
points,
|
|
98
107
|
markers,
|
|
108
|
+
getHoverMarkers: buildHoverMarkerGetter(points, s),
|
|
99
109
|
svgLabels: svgLabels,
|
|
100
110
|
series: s,
|
|
101
111
|
hovered: false,
|
|
@@ -3,9 +3,4 @@ import type { PreparedSeriesOptions } from '../../series/types';
|
|
|
3
3
|
import type { PreparedLineData } from './types';
|
|
4
4
|
export declare function renderLine(elements: {
|
|
5
5
|
plot: SVGGElement;
|
|
6
|
-
markers: SVGGElement;
|
|
7
|
-
hoverMarkers: SVGGElement;
|
|
8
|
-
annotations: SVGGElement;
|
|
9
|
-
boundsWidth: number;
|
|
10
|
-
boundsHeight: number;
|
|
11
6
|
}, preparedData: PreparedLineData[], seriesOptions: PreparedSeriesOptions, dispatcher?: Dispatch<object>): () => void;
|
|
@@ -4,17 +4,12 @@ import { line as lineGenerator } from 'd3-shape';
|
|
|
4
4
|
import get from 'lodash/get';
|
|
5
5
|
import { block } from '../../../utils';
|
|
6
6
|
import { getLineDashArray } from '../../utils';
|
|
7
|
-
import { renderAnnotations } from '../annotation';
|
|
8
7
|
import { renderDataLabels } from '../data-labels';
|
|
9
|
-
import { getMarkerHaloVisibility, getMarkerVisibility, renderMarker, selectMarkerHalo, selectMarkerSymbol, setMarker, } from '../marker';
|
|
10
8
|
import { setActiveState } from '../utils';
|
|
11
9
|
const b = block('line');
|
|
12
10
|
export function renderLine(elements, preparedData, seriesOptions, dispatcher) {
|
|
13
11
|
var _a, _b;
|
|
14
12
|
const plotSvgElement = select(elements.plot);
|
|
15
|
-
const markersSvgElement = select(elements.markers);
|
|
16
|
-
const hoverMarkersSvgElement = select(elements.hoverMarkers);
|
|
17
|
-
const annotationsSvgElement = select(elements.annotations);
|
|
18
13
|
const hoverOptions = get(seriesOptions, 'line.states.hover');
|
|
19
14
|
const inactiveOptions = get(seriesOptions, 'line.states.inactive');
|
|
20
15
|
const line = lineGenerator()
|
|
@@ -22,7 +17,6 @@ export function renderLine(elements, preparedData, seriesOptions, dispatcher) {
|
|
|
22
17
|
.x((d) => d.x)
|
|
23
18
|
.y((d) => d.y);
|
|
24
19
|
plotSvgElement.selectAll('*').remove();
|
|
25
|
-
markersSvgElement.selectAll('*').remove();
|
|
26
20
|
const lineSelection = plotSvgElement
|
|
27
21
|
.selectAll('path')
|
|
28
22
|
.data(preparedData)
|
|
@@ -44,23 +38,10 @@ export function renderLine(elements, preparedData, seriesOptions, dispatcher) {
|
|
|
44
38
|
data: dataLabels,
|
|
45
39
|
className: b('label'),
|
|
46
40
|
});
|
|
47
|
-
const markers = preparedData.reduce((acc, d) => acc.concat(d.markers), []);
|
|
48
|
-
const markerSelection = markersSvgElement
|
|
49
|
-
.selectAll('marker')
|
|
50
|
-
.data(markers)
|
|
51
|
-
.join('g')
|
|
52
|
-
.call(renderMarker);
|
|
53
|
-
renderAnnotations({
|
|
54
|
-
anchors: preparedData.flatMap((d) => d.annotations),
|
|
55
|
-
container: annotationsSvgElement,
|
|
56
|
-
plotHeight: elements.boundsHeight,
|
|
57
|
-
plotWidth: elements.boundsWidth,
|
|
58
|
-
});
|
|
59
41
|
const hoverEnabled = hoverOptions === null || hoverOptions === void 0 ? void 0 : hoverOptions.enabled;
|
|
60
42
|
const inactiveEnabled = inactiveOptions === null || inactiveOptions === void 0 ? void 0 : inactiveOptions.enabled;
|
|
61
43
|
function handleShapeHover(data) {
|
|
62
44
|
const selected = (data === null || data === void 0 ? void 0 : data.filter((d) => d.series.type === 'line')) || [];
|
|
63
|
-
const selectedDataItems = selected.map((d) => d.data);
|
|
64
45
|
const selectedSeriesIds = selected.map((d) => { var _a; return (_a = d.series) === null || _a === void 0 ? void 0 : _a.id; });
|
|
65
46
|
lineSelection.datum((d, index, list) => {
|
|
66
47
|
const elementSelection = select(list[index]);
|
|
@@ -96,62 +77,6 @@ export function renderLine(elements, preparedData, seriesOptions, dispatcher) {
|
|
|
96
77
|
datum: d,
|
|
97
78
|
});
|
|
98
79
|
});
|
|
99
|
-
markerSelection.datum((d, index, list) => {
|
|
100
|
-
const elementSelection = select(list[index]);
|
|
101
|
-
const hovered = Boolean(hoverEnabled && selectedDataItems.includes(d.point.data));
|
|
102
|
-
if (d.hovered !== hovered) {
|
|
103
|
-
d.hovered = hovered;
|
|
104
|
-
elementSelection.attr('visibility', getMarkerVisibility(d));
|
|
105
|
-
selectMarkerHalo(elementSelection).attr('visibility', getMarkerHaloVisibility);
|
|
106
|
-
selectMarkerSymbol(elementSelection).call(setMarker, hovered ? 'hover' : 'normal');
|
|
107
|
-
}
|
|
108
|
-
if (d.point.series.marker.states.normal.enabled) {
|
|
109
|
-
const isActive = Boolean(!inactiveEnabled ||
|
|
110
|
-
!selectedSeriesIds.length ||
|
|
111
|
-
selectedSeriesIds.includes(d.point.series.id));
|
|
112
|
-
setActiveState({
|
|
113
|
-
element: list[index],
|
|
114
|
-
state: inactiveOptions,
|
|
115
|
-
active: isActive,
|
|
116
|
-
datum: d,
|
|
117
|
-
});
|
|
118
|
-
}
|
|
119
|
-
return d;
|
|
120
|
-
});
|
|
121
|
-
hoverMarkersSvgElement.selectAll('*').remove();
|
|
122
|
-
if (hoverEnabled && selected.length > 0) {
|
|
123
|
-
const hoverOnlyMarkers = [];
|
|
124
|
-
for (const chunk of selected) {
|
|
125
|
-
const seriesData = preparedData.find((pd) => pd.id === chunk.series.id);
|
|
126
|
-
if (!seriesData) {
|
|
127
|
-
continue;
|
|
128
|
-
}
|
|
129
|
-
const { series } = seriesData;
|
|
130
|
-
if (series.marker.states.normal.enabled || !series.marker.states.hover.enabled) {
|
|
131
|
-
continue;
|
|
132
|
-
}
|
|
133
|
-
const point = seriesData.points.find((p) => p.data === chunk.data);
|
|
134
|
-
if (!point || point.x === null || point.y === null) {
|
|
135
|
-
continue;
|
|
136
|
-
}
|
|
137
|
-
hoverOnlyMarkers.push({
|
|
138
|
-
point: point,
|
|
139
|
-
active: true,
|
|
140
|
-
hovered: true,
|
|
141
|
-
clipped: false,
|
|
142
|
-
});
|
|
143
|
-
}
|
|
144
|
-
if (hoverOnlyMarkers.length > 0) {
|
|
145
|
-
hoverMarkersSvgElement
|
|
146
|
-
.selectAll('g')
|
|
147
|
-
.data(hoverOnlyMarkers)
|
|
148
|
-
.join('g')
|
|
149
|
-
.call(renderMarker)
|
|
150
|
-
.each((_d, i, nodes) => {
|
|
151
|
-
selectMarkerSymbol(select(nodes[i])).call(setMarker, 'hover');
|
|
152
|
-
});
|
|
153
|
-
}
|
|
154
|
-
}
|
|
155
80
|
}
|
|
156
81
|
const eventName = `hover-shape.line-${(_b = (_a = preparedData[0]) === null || _a === void 0 ? void 0 : _a.id) !== null && _b !== void 0 ? _b : 'unknown'}`;
|
|
157
82
|
dispatcher === null || dispatcher === void 0 ? void 0 : dispatcher.on(eventName, handleShapeHover);
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { LabelData, LineSeriesData, LineSeriesLineBaseStyle } from '../../../types';
|
|
2
2
|
import type { DashStyle, LineCap, LineJoin } from '../../constants';
|
|
3
3
|
import type { AnnotationAnchor, PreparedAnnotation, PreparedLineSeries } from '../../series/types';
|
|
4
|
-
import type { SeriesShapeData } from '../types';
|
|
4
|
+
import type { MarkerItem, SeriesShapeData } from '../types';
|
|
5
5
|
export type PointData = {
|
|
6
6
|
annotation?: PreparedAnnotation;
|
|
7
7
|
color?: string;
|
|
@@ -15,17 +15,11 @@ export type MarkerPointData = PointData & {
|
|
|
15
15
|
y: number;
|
|
16
16
|
x: number;
|
|
17
17
|
};
|
|
18
|
-
export type MarkerData = {
|
|
19
|
-
point: MarkerPointData;
|
|
20
|
-
active: boolean;
|
|
21
|
-
hovered: boolean;
|
|
22
|
-
clipped: boolean;
|
|
23
|
-
};
|
|
24
18
|
export type PreparedLineData = {
|
|
25
19
|
annotations: AnnotationAnchor[];
|
|
26
20
|
id: string;
|
|
27
21
|
points: PointData[];
|
|
28
|
-
markers:
|
|
22
|
+
markers: MarkerItem[];
|
|
29
23
|
series: PreparedLineSeries;
|
|
30
24
|
hovered: boolean;
|
|
31
25
|
active: boolean;
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { BaseType, Selection } from 'd3-selection';
|
|
2
2
|
import { SymbolType } from '../constants';
|
|
3
|
+
import type { MarkerItem } from './types';
|
|
3
4
|
export interface BaseMarkerData {
|
|
4
5
|
point: {
|
|
5
6
|
x: number;
|
|
@@ -43,3 +44,32 @@ export declare function setMarker<T extends BaseType, D extends BaseMarkerData>(
|
|
|
43
44
|
export declare function getMarkerSymbol(type: `${SymbolType}` | undefined, radius: number): string | null;
|
|
44
45
|
export declare function selectMarkerHalo<T>(parentSelection: Selection<BaseType, T, null, undefined>): Selection<BaseType, T, null, undefined>;
|
|
45
46
|
export declare function selectMarkerSymbol<T>(parentSelection: Selection<BaseType, T, null, undefined>): Selection<BaseType, T, null, undefined>;
|
|
47
|
+
export declare function renderMarkers(container: Selection<SVGGElement, unknown, null, undefined>, markers: MarkerItem[]): void;
|
|
48
|
+
export declare function renderHoverMarkers(container: Selection<SVGGElement, unknown, null, undefined>, hoverMarkers: MarkerItem[]): void;
|
|
49
|
+
interface HoverMarkerPoint {
|
|
50
|
+
data: unknown;
|
|
51
|
+
x: number | null;
|
|
52
|
+
y: number | null;
|
|
53
|
+
hiddenInLine?: boolean;
|
|
54
|
+
color?: string;
|
|
55
|
+
}
|
|
56
|
+
interface HoverMarkerSeries {
|
|
57
|
+
id: string;
|
|
58
|
+
color: string;
|
|
59
|
+
marker: {
|
|
60
|
+
states: {
|
|
61
|
+
normal: {
|
|
62
|
+
enabled: boolean;
|
|
63
|
+
symbol: `${SymbolType}`;
|
|
64
|
+
};
|
|
65
|
+
hover: {
|
|
66
|
+
enabled: boolean;
|
|
67
|
+
radius: number;
|
|
68
|
+
borderColor: string;
|
|
69
|
+
borderWidth: number;
|
|
70
|
+
};
|
|
71
|
+
};
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
export declare function buildHoverMarkerGetter(points: HoverMarkerPoint[], series: HoverMarkerSeries): (hoveredData: unknown[]) => MarkerItem[];
|
|
75
|
+
export {};
|
|
@@ -80,3 +80,71 @@ export function selectMarkerHalo(parentSelection) {
|
|
|
80
80
|
export function selectMarkerSymbol(parentSelection) {
|
|
81
81
|
return parentSelection.select(`.${symbolClassName}`);
|
|
82
82
|
}
|
|
83
|
+
export function renderMarkers(container, markers) {
|
|
84
|
+
container.selectAll('*').remove();
|
|
85
|
+
const selection = container
|
|
86
|
+
.selectAll('g')
|
|
87
|
+
.data(markers)
|
|
88
|
+
.join('g')
|
|
89
|
+
.attr('class', b('wrapper'))
|
|
90
|
+
.attr('transform', (d) => `translate(${d.cx},${d.cy})`);
|
|
91
|
+
selection
|
|
92
|
+
.append('path')
|
|
93
|
+
.attr('class', b('symbol'))
|
|
94
|
+
.attr('d', (d) => d.clipped ? null : getMarkerSymbol(d.symbolType, d.radius + d.strokeWidth))
|
|
95
|
+
.attr('fill', (d) => d.fill)
|
|
96
|
+
.attr('stroke', (d) => d.stroke)
|
|
97
|
+
.attr('stroke-width', (d) => d.strokeWidth);
|
|
98
|
+
}
|
|
99
|
+
export function renderHoverMarkers(container, hoverMarkers) {
|
|
100
|
+
container.selectAll('*').remove();
|
|
101
|
+
if (hoverMarkers.length === 0)
|
|
102
|
+
return;
|
|
103
|
+
container
|
|
104
|
+
.selectAll('g')
|
|
105
|
+
.data(hoverMarkers)
|
|
106
|
+
.join('g')
|
|
107
|
+
.attr('class', b('wrapper'))
|
|
108
|
+
.attr('transform', (d) => `translate(${d.cx},${d.cy})`)
|
|
109
|
+
.append('path')
|
|
110
|
+
.attr('class', b('symbol'))
|
|
111
|
+
.attr('d', (d) => getMarkerSymbol(d.symbolType, d.radius + d.strokeWidth))
|
|
112
|
+
.attr('fill', (d) => d.fill)
|
|
113
|
+
.attr('stroke', (d) => d.stroke)
|
|
114
|
+
.attr('stroke-width', (d) => d.strokeWidth);
|
|
115
|
+
}
|
|
116
|
+
export function buildHoverMarkerGetter(points, series) {
|
|
117
|
+
const { normal: normalState, hover: hoverState } = series.marker.states;
|
|
118
|
+
if (normalState.enabled || !hoverState.enabled)
|
|
119
|
+
return () => [];
|
|
120
|
+
const pointByData = new Map();
|
|
121
|
+
for (const p of points) {
|
|
122
|
+
if (p.x !== null && p.y !== null && !p.hiddenInLine) {
|
|
123
|
+
pointByData.set(p.data, p);
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
return (hoveredData) => {
|
|
127
|
+
var _a;
|
|
128
|
+
const items = [];
|
|
129
|
+
for (const rawData of hoveredData) {
|
|
130
|
+
const point = pointByData.get(rawData);
|
|
131
|
+
if (!point || point.x === null || point.y === null)
|
|
132
|
+
continue;
|
|
133
|
+
items.push({
|
|
134
|
+
cx: point.x,
|
|
135
|
+
cy: point.y,
|
|
136
|
+
radius: hoverState.radius,
|
|
137
|
+
symbolType: normalState.symbol,
|
|
138
|
+
fill: (_a = point.color) !== null && _a !== void 0 ? _a : series.color,
|
|
139
|
+
stroke: hoverState.borderColor,
|
|
140
|
+
strokeWidth: hoverState.borderWidth,
|
|
141
|
+
opacity: 1,
|
|
142
|
+
active: true,
|
|
143
|
+
clipped: false,
|
|
144
|
+
series: { id: series.id },
|
|
145
|
+
data: rawData,
|
|
146
|
+
});
|
|
147
|
+
}
|
|
148
|
+
return items;
|
|
149
|
+
};
|
|
150
|
+
}
|