@gravity-ui/charts 1.43.1 → 1.45.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/utils/zoom.js +3 -1
- package/dist/cjs/components/Tooltip/DefaultTooltipContent/index.js +31 -6
- package/dist/cjs/components/Tooltip/DefaultTooltipContent/utils.js +4 -5
- package/dist/cjs/core/constants/chart-types.d.ts +1 -0
- package/dist/cjs/core/constants/chart-types.js +1 -0
- package/dist/cjs/core/constants/defaults/annotation.d.ts +12 -0
- package/dist/cjs/core/constants/defaults/annotation.js +12 -0
- package/dist/cjs/core/constants/defaults/index.d.ts +1 -0
- package/dist/cjs/core/constants/defaults/index.js +1 -0
- package/dist/cjs/core/constants/defaults/series-options.d.ts +5 -1
- package/dist/cjs/core/constants/defaults/series-options.js +13 -0
- package/dist/cjs/core/i18n/keysets/en.json +2 -1
- package/dist/cjs/core/i18n/keysets/ru.json +2 -1
- package/dist/cjs/core/series/constants.d.ts +1 -1
- package/dist/cjs/core/series/constants.js +1 -1
- package/dist/cjs/core/series/prepare-annotation.d.ts +12 -0
- package/dist/cjs/core/series/prepare-annotation.js +31 -0
- package/dist/cjs/core/series/prepare-legend.js +2 -2
- package/dist/cjs/core/series/prepare-x-range.d.ts +11 -0
- package/dist/cjs/core/series/prepare-x-range.js +41 -0
- package/dist/cjs/core/series/prepareSeries.js +9 -0
- package/dist/cjs/core/series/types.d.ts +34 -2
- package/dist/cjs/core/types/chart/annotation.d.ts +45 -0
- package/dist/cjs/core/types/chart/annotation.js +1 -0
- package/dist/cjs/core/types/chart/area.d.ts +10 -1
- package/dist/cjs/core/types/chart/bar-x.d.ts +6 -0
- package/dist/cjs/core/types/chart/line.d.ts +8 -0
- package/dist/cjs/core/types/chart/marker.d.ts +6 -4
- package/dist/cjs/core/types/chart/series.d.ts +36 -2
- package/dist/cjs/core/types/chart/tooltip.d.ts +7 -1
- package/dist/cjs/core/types/chart/x-range.d.ts +59 -0
- package/dist/cjs/core/types/chart/x-range.js +1 -0
- package/dist/cjs/core/types/chart/zoom.d.ts +1 -1
- package/dist/cjs/core/types/index.d.ts +2 -0
- package/dist/cjs/core/types/index.js +2 -0
- package/dist/cjs/core/utils/axis/x-axis.js +9 -1
- package/dist/cjs/core/utils/color.js +6 -0
- package/dist/cjs/core/utils/common.js +10 -0
- package/dist/cjs/core/utils/get-closest-data.js +19 -0
- package/dist/cjs/core/utils/text.d.ts +8 -0
- package/dist/cjs/core/utils/text.js +9 -1
- package/dist/cjs/core/validation/index.js +13 -0
- package/dist/cjs/core/zoom/zoom.js +24 -7
- package/dist/cjs/hooks/useShapes/annotation/index.d.ts +14 -0
- package/dist/cjs/hooks/useShapes/annotation/index.js +200 -0
- package/dist/cjs/hooks/useShapes/area/index.d.ts +2 -0
- package/dist/cjs/hooks/useShapes/area/index.js +21 -2
- package/dist/cjs/hooks/useShapes/area/prepare-data.d.ts +2 -1
- package/dist/cjs/hooks/useShapes/area/prepare-data.js +45 -26
- package/dist/cjs/hooks/useShapes/area/types.d.ts +4 -0
- package/dist/cjs/hooks/useShapes/bar-x/index.d.ts +2 -0
- package/dist/cjs/hooks/useShapes/bar-x/index.js +30 -2
- package/dist/cjs/hooks/useShapes/bar-x/prepare-data.js +32 -11
- package/dist/cjs/hooks/useShapes/bar-x/types.d.ts +2 -0
- package/dist/cjs/hooks/useShapes/index.d.ts +2 -1
- package/dist/cjs/hooks/useShapes/index.js +22 -3
- package/dist/cjs/hooks/useShapes/line/index.d.ts +2 -0
- package/dist/cjs/hooks/useShapes/line/index.js +21 -7
- package/dist/cjs/hooks/useShapes/line/prepare-data.d.ts +2 -1
- package/dist/cjs/hooks/useShapes/line/prepare-data.js +28 -10
- package/dist/cjs/hooks/useShapes/line/types.d.ts +4 -0
- package/dist/cjs/hooks/useShapes/x-range/index.d.ts +14 -0
- package/dist/cjs/hooks/useShapes/x-range/index.js +115 -0
- package/dist/cjs/hooks/useShapes/x-range/prepare-data.d.ts +15 -0
- package/dist/cjs/hooks/useShapes/x-range/prepare-data.js +147 -0
- package/dist/cjs/hooks/useShapes/x-range/types.d.ts +12 -0
- package/dist/cjs/hooks/useShapes/x-range/types.js +1 -0
- package/dist/esm/components/ChartInner/utils/zoom.js +3 -1
- package/dist/esm/components/Tooltip/DefaultTooltipContent/index.js +31 -6
- package/dist/esm/components/Tooltip/DefaultTooltipContent/utils.js +4 -5
- package/dist/esm/core/constants/chart-types.d.ts +1 -0
- package/dist/esm/core/constants/chart-types.js +1 -0
- package/dist/esm/core/constants/defaults/annotation.d.ts +12 -0
- package/dist/esm/core/constants/defaults/annotation.js +12 -0
- package/dist/esm/core/constants/defaults/index.d.ts +1 -0
- package/dist/esm/core/constants/defaults/index.js +1 -0
- package/dist/esm/core/constants/defaults/series-options.d.ts +5 -1
- package/dist/esm/core/constants/defaults/series-options.js +13 -0
- package/dist/esm/core/i18n/keysets/en.json +2 -1
- package/dist/esm/core/i18n/keysets/ru.json +2 -1
- package/dist/esm/core/series/constants.d.ts +1 -1
- package/dist/esm/core/series/constants.js +1 -1
- package/dist/esm/core/series/prepare-annotation.d.ts +12 -0
- package/dist/esm/core/series/prepare-annotation.js +31 -0
- package/dist/esm/core/series/prepare-legend.js +2 -2
- package/dist/esm/core/series/prepare-x-range.d.ts +11 -0
- package/dist/esm/core/series/prepare-x-range.js +41 -0
- package/dist/esm/core/series/prepareSeries.js +9 -0
- package/dist/esm/core/series/types.d.ts +34 -2
- package/dist/esm/core/types/chart/annotation.d.ts +45 -0
- package/dist/esm/core/types/chart/annotation.js +1 -0
- package/dist/esm/core/types/chart/area.d.ts +10 -1
- package/dist/esm/core/types/chart/bar-x.d.ts +6 -0
- package/dist/esm/core/types/chart/line.d.ts +8 -0
- package/dist/esm/core/types/chart/marker.d.ts +6 -4
- package/dist/esm/core/types/chart/series.d.ts +36 -2
- package/dist/esm/core/types/chart/tooltip.d.ts +7 -1
- package/dist/esm/core/types/chart/x-range.d.ts +59 -0
- package/dist/esm/core/types/chart/x-range.js +1 -0
- package/dist/esm/core/types/chart/zoom.d.ts +1 -1
- package/dist/esm/core/types/index.d.ts +2 -0
- package/dist/esm/core/types/index.js +2 -0
- package/dist/esm/core/utils/axis/x-axis.js +9 -1
- package/dist/esm/core/utils/color.js +6 -0
- package/dist/esm/core/utils/common.js +10 -0
- package/dist/esm/core/utils/get-closest-data.js +19 -0
- package/dist/esm/core/utils/text.d.ts +8 -0
- package/dist/esm/core/utils/text.js +9 -1
- package/dist/esm/core/validation/index.js +13 -0
- package/dist/esm/core/zoom/zoom.js +24 -7
- package/dist/esm/hooks/useShapes/annotation/index.d.ts +14 -0
- package/dist/esm/hooks/useShapes/annotation/index.js +200 -0
- package/dist/esm/hooks/useShapes/area/index.d.ts +2 -0
- package/dist/esm/hooks/useShapes/area/index.js +21 -2
- package/dist/esm/hooks/useShapes/area/prepare-data.d.ts +2 -1
- package/dist/esm/hooks/useShapes/area/prepare-data.js +45 -26
- package/dist/esm/hooks/useShapes/area/types.d.ts +4 -0
- package/dist/esm/hooks/useShapes/bar-x/index.d.ts +2 -0
- package/dist/esm/hooks/useShapes/bar-x/index.js +30 -2
- package/dist/esm/hooks/useShapes/bar-x/prepare-data.js +32 -11
- package/dist/esm/hooks/useShapes/bar-x/types.d.ts +2 -0
- package/dist/esm/hooks/useShapes/index.d.ts +2 -1
- package/dist/esm/hooks/useShapes/index.js +22 -3
- package/dist/esm/hooks/useShapes/line/index.d.ts +2 -0
- package/dist/esm/hooks/useShapes/line/index.js +21 -7
- package/dist/esm/hooks/useShapes/line/prepare-data.d.ts +2 -1
- package/dist/esm/hooks/useShapes/line/prepare-data.js +28 -10
- package/dist/esm/hooks/useShapes/line/types.d.ts +4 -0
- package/dist/esm/hooks/useShapes/x-range/index.d.ts +14 -0
- package/dist/esm/hooks/useShapes/x-range/index.js +115 -0
- package/dist/esm/hooks/useShapes/x-range/prepare-data.d.ts +15 -0
- package/dist/esm/hooks/useShapes/x-range/prepare-data.js +147 -0
- package/dist/esm/hooks/useShapes/x-range/types.d.ts +12 -0
- package/dist/esm/hooks/useShapes/x-range/types.js +1 -0
- package/package.json +2 -2
|
@@ -6,15 +6,17 @@ import get from 'lodash/get';
|
|
|
6
6
|
import { filterOverlappingLabels } from '../../../core/utils';
|
|
7
7
|
import { block } from '../../../utils';
|
|
8
8
|
import { HtmlLayer } from '../HtmlLayer';
|
|
9
|
+
import { renderAnnotations } from '../annotation';
|
|
9
10
|
import { getMarkerHaloVisibility, getMarkerVisibility, renderMarker, selectMarkerHalo, selectMarkerSymbol, setMarker, } from '../marker';
|
|
10
11
|
import { setActiveState } from '../utils';
|
|
11
12
|
const b = block('area');
|
|
12
13
|
export const AreaSeriesShapes = (args) => {
|
|
13
|
-
const { dispatcher, preparedData, seriesOptions, htmlLayout, clipPathId } = args;
|
|
14
|
+
const { boundsHeight, boundsWidth, dispatcher, preparedData, seriesOptions, htmlLayout, clipPathId, } = args;
|
|
14
15
|
const hoveredDataRef = React.useRef(null);
|
|
15
16
|
const plotRef = React.useRef(null);
|
|
16
17
|
const markersRef = React.useRef(null);
|
|
17
18
|
const hoverMarkersRef = React.useRef(null);
|
|
19
|
+
const annotationsRef = React.useRef(null);
|
|
18
20
|
const allowOverlapDataLabels = React.useMemo(() => {
|
|
19
21
|
return preparedData.some((d) => d === null || d === void 0 ? void 0 : d.series.dataLabels.allowOverlap);
|
|
20
22
|
}, [preparedData]);
|
|
@@ -83,6 +85,15 @@ export const AreaSeriesShapes = (args) => {
|
|
|
83
85
|
.data(markers)
|
|
84
86
|
.join('g')
|
|
85
87
|
.call(renderMarker);
|
|
88
|
+
if (annotationsRef.current) {
|
|
89
|
+
const anchors = preparedData.flatMap((d) => d.annotations);
|
|
90
|
+
renderAnnotations({
|
|
91
|
+
anchors,
|
|
92
|
+
container: select(annotationsRef.current),
|
|
93
|
+
plotHeight: boundsHeight,
|
|
94
|
+
plotWidth: boundsWidth,
|
|
95
|
+
});
|
|
96
|
+
}
|
|
86
97
|
const hoverEnabled = hoverOptions === null || hoverOptions === void 0 ? void 0 : hoverOptions.enabled;
|
|
87
98
|
const inactiveEnabled = inactiveOptions === null || inactiveOptions === void 0 ? void 0 : inactiveOptions.enabled;
|
|
88
99
|
function handleShapeHover(data) {
|
|
@@ -189,7 +200,14 @@ export const AreaSeriesShapes = (args) => {
|
|
|
189
200
|
return () => {
|
|
190
201
|
dispatcher === null || dispatcher === void 0 ? void 0 : dispatcher.on('hover-shape.area', null);
|
|
191
202
|
};
|
|
192
|
-
}, [
|
|
203
|
+
}, [
|
|
204
|
+
allowOverlapDataLabels,
|
|
205
|
+
boundsHeight,
|
|
206
|
+
boundsWidth,
|
|
207
|
+
dispatcher,
|
|
208
|
+
preparedData,
|
|
209
|
+
seriesOptions,
|
|
210
|
+
]);
|
|
193
211
|
const htmlLayerData = React.useMemo(() => {
|
|
194
212
|
const items = preparedData.map((d) => d === null || d === void 0 ? void 0 : d.htmlLabels).flat();
|
|
195
213
|
if (allowOverlapDataLabels) {
|
|
@@ -201,5 +219,6 @@ export const AreaSeriesShapes = (args) => {
|
|
|
201
219
|
React.createElement("g", { ref: plotRef, className: b(), clipPath: `url(#${clipPathId})` }),
|
|
202
220
|
React.createElement("g", { ref: markersRef }),
|
|
203
221
|
React.createElement("g", { ref: hoverMarkersRef }),
|
|
222
|
+
React.createElement("g", { ref: annotationsRef }),
|
|
204
223
|
React.createElement(HtmlLayer, { preparedData: htmlLayerData, htmlLayout: htmlLayout })));
|
|
205
224
|
};
|
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
import type { PreparedSplit } from '../../../core/layout/split-types';
|
|
2
2
|
import type { ChartScale } from '../../../core/scales/types';
|
|
3
3
|
import type { PreparedXAxis, PreparedYAxis } from '../../useAxis/types';
|
|
4
|
-
import type { PreparedAreaSeries } from '../../useSeries/types';
|
|
4
|
+
import type { PreparedAreaSeries, PreparedSeriesOptions } from '../../useSeries/types';
|
|
5
5
|
import type { PreparedAreaData } from './types';
|
|
6
6
|
export declare const prepareAreaData: (args: {
|
|
7
7
|
series: PreparedAreaSeries[];
|
|
8
|
+
seriesOptions?: PreparedSeriesOptions;
|
|
8
9
|
xAxis: PreparedXAxis;
|
|
9
10
|
xScale: ChartScale;
|
|
10
11
|
yAxis: PreparedYAxis[];
|
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
import { group, min } from 'd3-array';
|
|
1
|
+
import { group, min, sort } from 'd3-array';
|
|
2
2
|
import isNil from 'lodash/isNil';
|
|
3
3
|
import round from 'lodash/round';
|
|
4
|
+
import { prepareAnnotation } from '../../../core/series/prepare-annotation';
|
|
4
5
|
import { getDataCategoryValue, getLabelsSize, getTextSizeFn } from '../../../core/utils';
|
|
5
6
|
import { getFormattedValue } from '../../../core/utils/format';
|
|
6
7
|
import { getXValue, getYValue } from '../utils';
|
|
@@ -27,7 +28,7 @@ function getXValues(series, xAxis, xScale) {
|
|
|
27
28
|
return acc;
|
|
28
29
|
}, []);
|
|
29
30
|
}
|
|
30
|
-
return Array.from(xValues);
|
|
31
|
+
return sort(Array.from(xValues), (d) => d[1]);
|
|
31
32
|
}
|
|
32
33
|
async function prepareDataLabels({ series, points, xMax, yAxisTop, isOutsideBounds, }) {
|
|
33
34
|
var _a;
|
|
@@ -76,8 +77,8 @@ async function prepareDataLabels({ series, points, xMax, yAxisTop, isOutsideBoun
|
|
|
76
77
|
return { svgLabels, htmlLabels };
|
|
77
78
|
}
|
|
78
79
|
export const prepareAreaData = async (args) => {
|
|
79
|
-
var _a, _b, _c, _d;
|
|
80
|
-
const { series, xAxis, xScale, yAxis, yScale, split, isOutsideBounds, isRangeSlider } = args;
|
|
80
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p;
|
|
81
|
+
const { series, seriesOptions, xAxis, xScale, yAxis, yScale, split, isOutsideBounds, isRangeSlider, } = args;
|
|
81
82
|
const [_xMin, xRangeMax] = xScale.range();
|
|
82
83
|
const xMax = xRangeMax;
|
|
83
84
|
const result = [];
|
|
@@ -165,15 +166,25 @@ export const prepareAreaData = async (args) => {
|
|
|
165
166
|
: d.x);
|
|
166
167
|
return m.set(key, d);
|
|
167
168
|
}, new Map());
|
|
168
|
-
const
|
|
169
|
-
|
|
170
|
-
|
|
169
|
+
const annotationOpts = (_d = seriesOptions === null || seriesOptions === void 0 ? void 0 : seriesOptions.area) === null || _d === void 0 ? void 0 : _d.annotation;
|
|
170
|
+
const points = [];
|
|
171
|
+
for (let xIdx = 0; xIdx < xValues.length; xIdx++) {
|
|
172
|
+
const [x, xValue] = xValues[xIdx];
|
|
173
|
+
const rawData = seriesData.get(x);
|
|
174
|
+
const d = rawData !== null && rawData !== void 0 ? rawData : {
|
|
171
175
|
x,
|
|
172
176
|
y: 0,
|
|
173
177
|
};
|
|
174
|
-
let yDataValue = (
|
|
175
|
-
|
|
176
|
-
|
|
178
|
+
let yDataValue = (_e = d.y) !== null && _e !== void 0 ? _e : null;
|
|
179
|
+
const pointAnnotation = d.annotation && !isRangeSlider
|
|
180
|
+
? await prepareAnnotation({
|
|
181
|
+
annotation: d.annotation,
|
|
182
|
+
optionsLabel: annotationOpts === null || annotationOpts === void 0 ? void 0 : annotationOpts.label,
|
|
183
|
+
optionsPopup: annotationOpts === null || annotationOpts === void 0 ? void 0 : annotationOpts.popup,
|
|
184
|
+
})
|
|
185
|
+
: undefined;
|
|
186
|
+
if (s.nullMode === 'connect' && (yDataValue === null || !rawData)) {
|
|
187
|
+
continue;
|
|
177
188
|
}
|
|
178
189
|
if (yDataValue && isPercentStacking) {
|
|
179
190
|
yDataValue = Number(yDataValue) * ratio[x];
|
|
@@ -187,21 +198,23 @@ export const prepareAreaData = async (args) => {
|
|
|
187
198
|
});
|
|
188
199
|
if (typeof yDataValue === 'number' && yValue !== null) {
|
|
189
200
|
yValue = round(yValue, 2);
|
|
190
|
-
const prevPoint = seriesData.get((
|
|
191
|
-
const nextPoint = seriesData.get((
|
|
201
|
+
const prevPoint = seriesData.get((_f = xValues[xIdx - 1]) === null || _f === void 0 ? void 0 : _f[0]);
|
|
202
|
+
const nextPoint = seriesData.get((_g = xValues[xIdx + 1]) === null || _g === void 0 ? void 0 : _g[0]);
|
|
192
203
|
const currentPointStackHeight = Math.abs(yMin - yValue);
|
|
193
204
|
if (yDataValue >= 0) {
|
|
194
205
|
const positiveStackHeights = positiveStackValues.get(x);
|
|
195
|
-
let prevSectionStackHeight = (
|
|
196
|
-
let nextSectionStackHeight = (
|
|
206
|
+
let prevSectionStackHeight = (_h = positiveStackHeights === null || positiveStackHeights === void 0 ? void 0 : positiveStackHeights.prev) !== null && _h !== void 0 ? _h : 0;
|
|
207
|
+
let nextSectionStackHeight = (_j = positiveStackHeights === null || positiveStackHeights === void 0 ? void 0 : positiveStackHeights.next) !== null && _j !== void 0 ? _j : 0;
|
|
197
208
|
const point = {
|
|
198
209
|
y0: yAxisTop + yMin - prevSectionStackHeight,
|
|
199
210
|
x: xValue,
|
|
200
211
|
y: yAxisTop + yValue - prevSectionStackHeight,
|
|
212
|
+
color: (_l = (_k = d.marker) === null || _k === void 0 ? void 0 : _k.color) !== null && _l !== void 0 ? _l : d.color,
|
|
201
213
|
data: d,
|
|
202
214
|
series: s,
|
|
215
|
+
annotation: pointAnnotation,
|
|
203
216
|
};
|
|
204
|
-
|
|
217
|
+
points.push(point);
|
|
205
218
|
if (prevSectionStackHeight !== nextSectionStackHeight) {
|
|
206
219
|
const point2 = {
|
|
207
220
|
y0: yAxisTop + yMin - nextSectionStackHeight,
|
|
@@ -210,7 +223,7 @@ export const prepareAreaData = async (args) => {
|
|
|
210
223
|
data: d,
|
|
211
224
|
series: s,
|
|
212
225
|
};
|
|
213
|
-
|
|
226
|
+
points.push(point2);
|
|
214
227
|
if (isPercentStacking) {
|
|
215
228
|
const newYValue = yAxisTop +
|
|
216
229
|
yValue -
|
|
@@ -219,11 +232,11 @@ export const prepareAreaData = async (args) => {
|
|
|
219
232
|
point2.y = newYValue;
|
|
220
233
|
}
|
|
221
234
|
}
|
|
222
|
-
if ((prevPoint === null || prevPoint === void 0 ? void 0 : prevPoint.y) !== null) {
|
|
235
|
+
if ((prevPoint === null || prevPoint === void 0 ? void 0 : prevPoint.y) !== null || s.nullMode === 'zero') {
|
|
223
236
|
prevSectionStackHeight =
|
|
224
237
|
prevSectionStackHeight + currentPointStackHeight;
|
|
225
238
|
}
|
|
226
|
-
if ((nextPoint === null || nextPoint === void 0 ? void 0 : nextPoint.y) !== null) {
|
|
239
|
+
if ((nextPoint === null || nextPoint === void 0 ? void 0 : nextPoint.y) !== null || s.nullMode === 'zero') {
|
|
227
240
|
nextSectionStackHeight =
|
|
228
241
|
nextSectionStackHeight + currentPointStackHeight;
|
|
229
242
|
}
|
|
@@ -234,9 +247,9 @@ export const prepareAreaData = async (args) => {
|
|
|
234
247
|
}
|
|
235
248
|
else {
|
|
236
249
|
const negativeStackHeights = negativeStackValues.get(x);
|
|
237
|
-
let prevSectionStackHeight = (
|
|
238
|
-
let nextSectionStackHeight = (
|
|
239
|
-
|
|
250
|
+
let prevSectionStackHeight = (_m = negativeStackHeights === null || negativeStackHeights === void 0 ? void 0 : negativeStackHeights.prev) !== null && _m !== void 0 ? _m : 0;
|
|
251
|
+
let nextSectionStackHeight = (_o = negativeStackHeights === null || negativeStackHeights === void 0 ? void 0 : negativeStackHeights.next) !== null && _o !== void 0 ? _o : 0;
|
|
252
|
+
points.push({
|
|
240
253
|
y0: yAxisTop + yMin + prevSectionStackHeight,
|
|
241
254
|
x: xValue,
|
|
242
255
|
y: yAxisTop + yValue + prevSectionStackHeight,
|
|
@@ -244,7 +257,7 @@ export const prepareAreaData = async (args) => {
|
|
|
244
257
|
series: s,
|
|
245
258
|
});
|
|
246
259
|
if (prevSectionStackHeight !== nextSectionStackHeight) {
|
|
247
|
-
|
|
260
|
+
points.push({
|
|
248
261
|
y0: yAxisTop + yMin + nextSectionStackHeight,
|
|
249
262
|
x: xValue,
|
|
250
263
|
y: yAxisTop + yValue + nextSectionStackHeight,
|
|
@@ -267,7 +280,7 @@ export const prepareAreaData = async (args) => {
|
|
|
267
280
|
}
|
|
268
281
|
}
|
|
269
282
|
else {
|
|
270
|
-
|
|
283
|
+
points.push({
|
|
271
284
|
y0: yAxisTop + yMin,
|
|
272
285
|
x: xValue,
|
|
273
286
|
y: null,
|
|
@@ -275,8 +288,7 @@ export const prepareAreaData = async (args) => {
|
|
|
275
288
|
series: s,
|
|
276
289
|
});
|
|
277
290
|
}
|
|
278
|
-
|
|
279
|
-
}, []);
|
|
291
|
+
}
|
|
280
292
|
let markers = [];
|
|
281
293
|
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; });
|
|
282
294
|
if (s.marker.states.normal.enabled || hasPerPointNormalMarkers) {
|
|
@@ -297,7 +309,14 @@ export const prepareAreaData = async (args) => {
|
|
|
297
309
|
return markersAcc;
|
|
298
310
|
}, []);
|
|
299
311
|
}
|
|
312
|
+
const annotations = points.reduce((result, p) => {
|
|
313
|
+
if (p.annotation && p.y !== null) {
|
|
314
|
+
result.push({ annotation: p.annotation, x: p.x, y: p.y });
|
|
315
|
+
}
|
|
316
|
+
return result;
|
|
317
|
+
}, []);
|
|
300
318
|
seriesStackData.push({
|
|
319
|
+
annotations,
|
|
301
320
|
points,
|
|
302
321
|
markers,
|
|
303
322
|
svgLabels: [],
|
|
@@ -314,7 +333,7 @@ export const prepareAreaData = async (args) => {
|
|
|
314
333
|
for (let itemIndex = 0; itemIndex < seriesStackData.length; itemIndex++) {
|
|
315
334
|
const item = seriesStackData[itemIndex];
|
|
316
335
|
const currentYAxis = yAxis[item.series.yAxis];
|
|
317
|
-
const itemYAxisTop = ((
|
|
336
|
+
const itemYAxisTop = ((_p = split.plots[currentYAxis.plotIndex]) === null || _p === void 0 ? void 0 : _p.top) || 0;
|
|
318
337
|
if (item.series.dataLabels.enabled && !isRangeSlider) {
|
|
319
338
|
const labelsData = await prepareDataLabels({
|
|
320
339
|
series: item.series,
|
|
@@ -1,11 +1,14 @@
|
|
|
1
|
+
import type { PreparedAnnotation } from '../../../core/series/types';
|
|
1
2
|
import type { AreaSeriesData, HtmlItem, LabelData } from '../../../types';
|
|
2
3
|
import type { PreparedAreaSeries } from '../../useSeries/types';
|
|
4
|
+
import type { AnnotationAnchor } from '../annotation';
|
|
3
5
|
export type PointData = {
|
|
4
6
|
y0: number;
|
|
5
7
|
x: number;
|
|
6
8
|
y: number | null;
|
|
7
9
|
data: AreaSeriesData;
|
|
8
10
|
series: PreparedAreaSeries;
|
|
11
|
+
annotation?: PreparedAnnotation;
|
|
9
12
|
color?: string;
|
|
10
13
|
};
|
|
11
14
|
export type MarkerPointData = PointData & {
|
|
@@ -18,6 +21,7 @@ export type MarkerData = {
|
|
|
18
21
|
clipped: boolean;
|
|
19
22
|
};
|
|
20
23
|
export type PreparedAreaData = {
|
|
24
|
+
annotations: AnnotationAnchor[];
|
|
21
25
|
id: string;
|
|
22
26
|
points: PointData[];
|
|
23
27
|
markers: MarkerData[];
|
|
@@ -5,6 +5,8 @@ import type { PreparedBarXData } from './types';
|
|
|
5
5
|
export { prepareBarXData } from './prepare-data';
|
|
6
6
|
export * from './types';
|
|
7
7
|
type Args = {
|
|
8
|
+
boundsHeight: number;
|
|
9
|
+
boundsWidth: number;
|
|
8
10
|
clipPathId: string;
|
|
9
11
|
htmlLayout: HTMLElement | null;
|
|
10
12
|
preparedData: PreparedBarXData[];
|
|
@@ -5,14 +5,16 @@ import get from 'lodash/get';
|
|
|
5
5
|
import { filterOverlappingLabels } from '../../../core/utils';
|
|
6
6
|
import { block } from '../../../utils';
|
|
7
7
|
import { HtmlLayer } from '../HtmlLayer';
|
|
8
|
+
import { renderAnnotations } from '../annotation';
|
|
8
9
|
import { getRectPath } from '../utils';
|
|
9
10
|
export { prepareBarXData } from './prepare-data';
|
|
10
11
|
export * from './types';
|
|
11
12
|
const b = block('bar-x');
|
|
12
13
|
export const BarXSeriesShapes = (args) => {
|
|
13
|
-
const { dispatcher, preparedData, seriesOptions, htmlLayout, clipPathId } = args;
|
|
14
|
+
const { boundsHeight, boundsWidth, dispatcher, preparedData, seriesOptions, htmlLayout, clipPathId, } = args;
|
|
14
15
|
const hoveredDataRef = React.useRef(null);
|
|
15
16
|
const ref = React.useRef(null);
|
|
17
|
+
const annotationsRef = React.useRef(null);
|
|
16
18
|
const allowOverlapDataLabels = React.useMemo(() => {
|
|
17
19
|
return preparedData.some((d) => d === null || d === void 0 ? void 0 : d.series.dataLabels.allowOverlap);
|
|
18
20
|
}, [preparedData]);
|
|
@@ -65,6 +67,24 @@ export const BarXSeriesShapes = (args) => {
|
|
|
65
67
|
.style('font-size', (d) => d.style.fontSize)
|
|
66
68
|
.style('font-weight', (d) => d.style.fontWeight || null)
|
|
67
69
|
.style('fill', (d) => d.style.fontColor || null);
|
|
70
|
+
if (annotationsRef.current) {
|
|
71
|
+
const anchors = [];
|
|
72
|
+
for (const d of preparedData) {
|
|
73
|
+
if (d.annotation) {
|
|
74
|
+
anchors.push({
|
|
75
|
+
annotation: d.annotation,
|
|
76
|
+
x: d.x + d.width / 2,
|
|
77
|
+
y: d.y,
|
|
78
|
+
});
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
renderAnnotations({
|
|
82
|
+
anchors,
|
|
83
|
+
container: select(annotationsRef.current),
|
|
84
|
+
plotHeight: boundsHeight,
|
|
85
|
+
plotWidth: boundsWidth,
|
|
86
|
+
});
|
|
87
|
+
}
|
|
68
88
|
function handleShapeHover(data) {
|
|
69
89
|
hoveredDataRef.current = data;
|
|
70
90
|
const hoverEnabled = hoverOptions === null || hoverOptions === void 0 ? void 0 : hoverOptions.enabled;
|
|
@@ -112,7 +132,14 @@ export const BarXSeriesShapes = (args) => {
|
|
|
112
132
|
return () => {
|
|
113
133
|
dispatcher === null || dispatcher === void 0 ? void 0 : dispatcher.on('hover-shape.bar-x', null);
|
|
114
134
|
};
|
|
115
|
-
}, [
|
|
135
|
+
}, [
|
|
136
|
+
allowOverlapDataLabels,
|
|
137
|
+
boundsHeight,
|
|
138
|
+
boundsWidth,
|
|
139
|
+
dispatcher,
|
|
140
|
+
preparedData,
|
|
141
|
+
seriesOptions,
|
|
142
|
+
]);
|
|
116
143
|
const htmlLayerData = React.useMemo(() => {
|
|
117
144
|
const items = preparedData.map((d) => d === null || d === void 0 ? void 0 : d.htmlLabels).flat();
|
|
118
145
|
if (allowOverlapDataLabels) {
|
|
@@ -122,5 +149,6 @@ export const BarXSeriesShapes = (args) => {
|
|
|
122
149
|
}, [allowOverlapDataLabels, preparedData]);
|
|
123
150
|
return (React.createElement(React.Fragment, null,
|
|
124
151
|
React.createElement("g", { ref: ref, className: b(), clipPath: `url(#${clipPathId})` }),
|
|
152
|
+
React.createElement("g", { ref: annotationsRef }),
|
|
125
153
|
React.createElement(HtmlLayer, { preparedData: htmlLayerData, htmlLayout: htmlLayout })));
|
|
126
154
|
};
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { ascending, descending, max, min, reverse, sort } from 'd3-array';
|
|
2
2
|
import get from 'lodash/get';
|
|
3
|
+
import { prepareAnnotation } from '../../../core/series/prepare-annotation';
|
|
3
4
|
import { getDataCategoryValue, getLabelsSize } from '../../../core/utils';
|
|
4
5
|
import { getFormattedValue } from '../../../core/utils/format';
|
|
5
6
|
import { MIN_BAR_GAP, MIN_BAR_GROUP_GAP, MIN_BAR_WIDTH } from '../../constants';
|
|
@@ -35,7 +36,7 @@ async function getLabelData(d, xMax) {
|
|
|
35
36
|
};
|
|
36
37
|
}
|
|
37
38
|
export const prepareBarXData = async (args) => {
|
|
38
|
-
var _a, _b, _c, _d, _e, _f;
|
|
39
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k;
|
|
39
40
|
const { series, seriesOptions, xAxis, xScale, yAxis, yScale, boundsHeight: plotHeight, split, isRangeSlider, } = args;
|
|
40
41
|
const stackGap = seriesOptions['bar-x'].stackGap;
|
|
41
42
|
const categories = (_a = xAxis === null || xAxis === void 0 ? void 0 : xAxis.categories) !== null && _a !== void 0 ? _a : [];
|
|
@@ -110,8 +111,8 @@ export const prepareBarXData = async (args) => {
|
|
|
110
111
|
const currentGroupWidth = rectWidth * stacks.length + rectGap * (stacks.length - 1);
|
|
111
112
|
for (let groupItemIndex = 0; groupItemIndex < stacks.length; groupItemIndex++) {
|
|
112
113
|
const yValues = stacks[groupItemIndex];
|
|
113
|
-
let
|
|
114
|
-
let
|
|
114
|
+
let positiveStackSum = 0;
|
|
115
|
+
let negativeStackSum = 0;
|
|
115
116
|
const stackItems = [];
|
|
116
117
|
let sortedData = yValues;
|
|
117
118
|
if (sortKey) {
|
|
@@ -144,7 +145,6 @@ export const prepareBarXData = async (args) => {
|
|
|
144
145
|
}
|
|
145
146
|
const x = xCenter - currentGroupWidth / 2 + (rectWidth + rectGap) * groupItemIndex;
|
|
146
147
|
const yDataValue = ((_d = yValue.data.y) !== null && _d !== void 0 ? _d : 0);
|
|
147
|
-
const y = seriesYScale(yDataValue);
|
|
148
148
|
let base = 0;
|
|
149
149
|
if (seriesYAxis.type === 'logarithmic') {
|
|
150
150
|
const domainData = seriesYScale.domain();
|
|
@@ -155,7 +155,22 @@ export const prepareBarXData = async (args) => {
|
|
|
155
155
|
base = seriesYScale(0);
|
|
156
156
|
}
|
|
157
157
|
const isLastStackItem = yValueIndex === sortedData.length - 1;
|
|
158
|
-
|
|
158
|
+
let height;
|
|
159
|
+
let barPositionY;
|
|
160
|
+
if (yDataValue > 0) {
|
|
161
|
+
const newSum = positiveStackSum + yDataValue;
|
|
162
|
+
const topPixel = seriesYScale(newSum);
|
|
163
|
+
const bottomPixel = positiveStackSum === 0 ? base : seriesYScale(positiveStackSum);
|
|
164
|
+
height = Math.abs(bottomPixel - topPixel);
|
|
165
|
+
barPositionY = yAxisTop + topPixel;
|
|
166
|
+
}
|
|
167
|
+
else {
|
|
168
|
+
const newSum = negativeStackSum + yDataValue;
|
|
169
|
+
const bottomPixel = negativeStackSum === 0 ? base : seriesYScale(negativeStackSum);
|
|
170
|
+
const topPixel = seriesYScale(newSum);
|
|
171
|
+
height = Math.abs(bottomPixel - topPixel);
|
|
172
|
+
barPositionY = yAxisTop + bottomPixel;
|
|
173
|
+
}
|
|
159
174
|
let shapeHeight = height - (stackItems.length ? stackGap : 0);
|
|
160
175
|
if (shapeHeight < 0) {
|
|
161
176
|
shapeHeight = height;
|
|
@@ -164,10 +179,15 @@ export const prepareBarXData = async (args) => {
|
|
|
164
179
|
continue;
|
|
165
180
|
}
|
|
166
181
|
const barData = {
|
|
182
|
+
annotation: yValue.data.annotation && !isRangeSlider
|
|
183
|
+
? await prepareAnnotation({
|
|
184
|
+
annotation: yValue.data.annotation,
|
|
185
|
+
optionsLabel: (_g = (_f = seriesOptions['bar-x']) === null || _f === void 0 ? void 0 : _f.annotation) === null || _g === void 0 ? void 0 : _g.label,
|
|
186
|
+
optionsPopup: (_j = (_h = seriesOptions['bar-x']) === null || _h === void 0 ? void 0 : _h.annotation) === null || _j === void 0 ? void 0 : _j.popup,
|
|
187
|
+
})
|
|
188
|
+
: undefined,
|
|
167
189
|
x,
|
|
168
|
-
y:
|
|
169
|
-
? yAxisTop + y - positiveStackHeight
|
|
170
|
-
: yAxisTop + base + negativeStackHeight,
|
|
190
|
+
y: barPositionY,
|
|
171
191
|
width: rectWidth,
|
|
172
192
|
height: shapeHeight,
|
|
173
193
|
_height: height,
|
|
@@ -180,14 +200,15 @@ export const prepareBarXData = async (args) => {
|
|
|
180
200
|
};
|
|
181
201
|
stackItems.push(barData);
|
|
182
202
|
if (yDataValue > 0) {
|
|
183
|
-
|
|
203
|
+
positiveStackSum += yDataValue;
|
|
184
204
|
}
|
|
185
205
|
else {
|
|
186
|
-
|
|
206
|
+
negativeStackSum += yDataValue;
|
|
187
207
|
}
|
|
188
208
|
}
|
|
189
209
|
if (series.some((s) => s.stacking === 'percent')) {
|
|
190
210
|
let acc = 0;
|
|
211
|
+
const positiveStackHeight = stackItems.reduce((sum, item) => sum + item._height, 0);
|
|
191
212
|
const ratio = plotHeight / positiveStackHeight;
|
|
192
213
|
stackItems.forEach((item) => {
|
|
193
214
|
item.height = item._height * ratio;
|
|
@@ -207,7 +228,7 @@ export const prepareBarXData = async (args) => {
|
|
|
207
228
|
barData.x >= xMax ||
|
|
208
229
|
barData.y + barData.height <= 0 ||
|
|
209
230
|
barData.y >= plotHeight;
|
|
210
|
-
const isZeroValue = ((
|
|
231
|
+
const isZeroValue = ((_k = barData.data.y) !== null && _k !== void 0 ? _k : 0) === 0;
|
|
211
232
|
if (barData.series.dataLabels.enabled &&
|
|
212
233
|
!isRangeSlider &&
|
|
213
234
|
(!isBarOutsideBounds || isZeroValue)) {
|
|
@@ -1,6 +1,8 @@
|
|
|
1
|
+
import type { PreparedAnnotation } from '../../../core/series/types';
|
|
1
2
|
import type { HtmlItem, LabelData, TooltipDataChunkBarX } from '../../../types';
|
|
2
3
|
import type { PreparedBarXSeries } from '../../useSeries/types';
|
|
3
4
|
export type PreparedBarXData = Omit<TooltipDataChunkBarX, 'series'> & {
|
|
5
|
+
annotation?: PreparedAnnotation;
|
|
4
6
|
x: number;
|
|
5
7
|
y: number;
|
|
6
8
|
width: number;
|
|
@@ -19,8 +19,9 @@ import type { PreparedScatterData } from './scatter/types';
|
|
|
19
19
|
export type { PreparedBarXData } from './bar-x';
|
|
20
20
|
export type { PreparedScatterData } from './scatter/types';
|
|
21
21
|
import type { PreparedWaterfallData } from './waterfall';
|
|
22
|
+
import type { PreparedXRangeData } from './x-range';
|
|
22
23
|
import './styles.css';
|
|
23
|
-
export type ShapeData = PreparedBarXData | PreparedBarYData | PreparedScatterData | PreparedLineData | PreparedPieData | PreparedAreaData | PreparedWaterfallData | PreparedSankeyData | PreparedRadarData | PreparedHeatmapData | PreparedFunnelData;
|
|
24
|
+
export type ShapeData = PreparedBarXData | PreparedBarYData | PreparedScatterData | PreparedLineData | PreparedPieData | PreparedAreaData | PreparedWaterfallData | PreparedSankeyData | PreparedRadarData | PreparedHeatmapData | PreparedFunnelData | PreparedXRangeData;
|
|
24
25
|
export type ClipPathBySeriesType = Partial<Record<SeriesType, boolean>>;
|
|
25
26
|
type Args = {
|
|
26
27
|
boundsWidth: number;
|
|
@@ -22,6 +22,7 @@ import { TreemapSeriesShape } from './treemap';
|
|
|
22
22
|
import { prepareTreemapData } from './treemap/prepare-data';
|
|
23
23
|
import { getSeriesClipPathId } from './utils';
|
|
24
24
|
import { WaterfallSeriesShapes, prepareWaterfallData } from './waterfall';
|
|
25
|
+
import { XRangeSeriesShapes, prepareXRangeData } from './x-range';
|
|
25
26
|
import './styles.css';
|
|
26
27
|
function IS_OUTSIDE_BOUNDS() {
|
|
27
28
|
return false;
|
|
@@ -61,7 +62,7 @@ export async function getShapes(args) {
|
|
|
61
62
|
split,
|
|
62
63
|
isRangeSlider,
|
|
63
64
|
});
|
|
64
|
-
shapes[index] = (React.createElement(BarXSeriesShapes, { key: SERIES_TYPE.BarX, dispatcher: dispatcher, seriesOptions: seriesOptions, preparedData: preparedData, htmlLayout: htmlLayout, clipPathId: clipPathId }));
|
|
65
|
+
shapes[index] = (React.createElement(BarXSeriesShapes, { key: SERIES_TYPE.BarX, boundsHeight: boundsHeight, boundsWidth: boundsWidth, dispatcher: dispatcher, seriesOptions: seriesOptions, preparedData: preparedData, htmlLayout: htmlLayout, clipPathId: clipPathId }));
|
|
65
66
|
shapesData.splice(index, 0, ...preparedData);
|
|
66
67
|
layers.push(...preparedData);
|
|
67
68
|
}
|
|
@@ -103,6 +104,7 @@ export async function getShapes(args) {
|
|
|
103
104
|
if (xAxis && xScale && (yScale === null || yScale === void 0 ? void 0 : yScale.length)) {
|
|
104
105
|
const preparedData = await prepareLineData({
|
|
105
106
|
series: chartSeries,
|
|
107
|
+
seriesOptions,
|
|
106
108
|
xAxis,
|
|
107
109
|
xScale,
|
|
108
110
|
yAxis,
|
|
@@ -117,7 +119,7 @@ export async function getShapes(args) {
|
|
|
117
119
|
yAxis,
|
|
118
120
|
zoomState,
|
|
119
121
|
});
|
|
120
|
-
shapes[index] = (React.createElement(LineSeriesShapes, { key: groupId, dispatcher: dispatcher, seriesOptions: seriesOptions, preparedData: preparedData, htmlLayout: htmlLayout, clipPathId: resultClipPathId }));
|
|
122
|
+
shapes[index] = (React.createElement(LineSeriesShapes, { key: groupId, boundsHeight: boundsHeight, boundsWidth: boundsWidth, dispatcher: dispatcher, seriesOptions: seriesOptions, preparedData: preparedData, htmlLayout: htmlLayout, clipPathId: resultClipPathId }));
|
|
121
123
|
shapesData.splice(index, 0, ...preparedData);
|
|
122
124
|
layers.push(...preparedData);
|
|
123
125
|
}
|
|
@@ -127,6 +129,7 @@ export async function getShapes(args) {
|
|
|
127
129
|
if (xAxis && xScale && (yScale === null || yScale === void 0 ? void 0 : yScale.length)) {
|
|
128
130
|
const preparedData = await prepareAreaData({
|
|
129
131
|
series: chartSeries,
|
|
132
|
+
seriesOptions,
|
|
130
133
|
xAxis,
|
|
131
134
|
xScale,
|
|
132
135
|
yAxis,
|
|
@@ -135,7 +138,7 @@ export async function getShapes(args) {
|
|
|
135
138
|
isOutsideBounds,
|
|
136
139
|
isRangeSlider,
|
|
137
140
|
});
|
|
138
|
-
shapes[index] = (React.createElement(AreaSeriesShapes, { key: SERIES_TYPE.Area, dispatcher: dispatcher, seriesOptions: seriesOptions, preparedData: preparedData, htmlLayout: htmlLayout, clipPathId: clipPathId }));
|
|
141
|
+
shapes[index] = (React.createElement(AreaSeriesShapes, { key: SERIES_TYPE.Area, boundsHeight: boundsHeight, boundsWidth: boundsWidth, dispatcher: dispatcher, seriesOptions: seriesOptions, preparedData: preparedData, htmlLayout: htmlLayout, clipPathId: clipPathId }));
|
|
139
142
|
shapesData.splice(index, 0, ...preparedData);
|
|
140
143
|
layers.push(...preparedData);
|
|
141
144
|
}
|
|
@@ -224,6 +227,22 @@ export async function getShapes(args) {
|
|
|
224
227
|
shapesData.splice(index, 0, preparedData);
|
|
225
228
|
break;
|
|
226
229
|
}
|
|
230
|
+
case SERIES_TYPE.XRange: {
|
|
231
|
+
if (xAxis && xScale && (yScale === null || yScale === void 0 ? void 0 : yScale.length)) {
|
|
232
|
+
const preparedData = await prepareXRangeData({
|
|
233
|
+
series: chartSeries,
|
|
234
|
+
xAxis,
|
|
235
|
+
xScale,
|
|
236
|
+
yAxis,
|
|
237
|
+
yScale,
|
|
238
|
+
boundsWidth,
|
|
239
|
+
isRangeSlider,
|
|
240
|
+
});
|
|
241
|
+
shapes[index] = (React.createElement(XRangeSeriesShapes, { key: SERIES_TYPE.XRange, dispatcher: dispatcher, preparedData: preparedData, seriesOptions: seriesOptions, htmlLayout: htmlLayout, clipPathId: clipPathId }));
|
|
242
|
+
shapesData.splice(index, 0, ...preparedData);
|
|
243
|
+
}
|
|
244
|
+
break;
|
|
245
|
+
}
|
|
227
246
|
default: {
|
|
228
247
|
throw new ChartError({
|
|
229
248
|
message: `The display method is not defined for a series with type "${seriesType}"`,
|
|
@@ -3,6 +3,8 @@ import type { Dispatch } from 'd3-dispatch';
|
|
|
3
3
|
import type { PreparedSeriesOptions } from '../../useSeries/types';
|
|
4
4
|
import type { PreparedLineData } from './types';
|
|
5
5
|
type Args = {
|
|
6
|
+
boundsHeight: number;
|
|
7
|
+
boundsWidth: number;
|
|
6
8
|
clipPathId: string;
|
|
7
9
|
htmlLayout: HTMLElement | null;
|
|
8
10
|
preparedData: PreparedLineData[];
|
|
@@ -6,16 +6,19 @@ import get from 'lodash/get';
|
|
|
6
6
|
import { getLineDashArray } from '../../../core/utils';
|
|
7
7
|
import { block } from '../../../utils';
|
|
8
8
|
import { HtmlLayer } from '../HtmlLayer';
|
|
9
|
+
import { renderAnnotations } from '../annotation';
|
|
9
10
|
import { getMarkerHaloVisibility, getMarkerVisibility, renderMarker, selectMarkerHalo, selectMarkerSymbol, setMarker, } from '../marker';
|
|
10
11
|
import { setActiveState } from '../utils';
|
|
11
12
|
const b = block('line');
|
|
12
13
|
export const LineSeriesShapes = (args) => {
|
|
13
|
-
const { dispatcher, preparedData, seriesOptions, htmlLayout, clipPathId } = args;
|
|
14
|
+
const { boundsHeight, boundsWidth, dispatcher, preparedData, seriesOptions, htmlLayout, clipPathId, } = args;
|
|
14
15
|
const hoveredDataRef = React.useRef(null);
|
|
15
16
|
const plotRef = React.useRef(null);
|
|
16
17
|
const markersRef = React.useRef(null);
|
|
17
18
|
const hoverMarkersRef = React.useRef(null);
|
|
19
|
+
const annotationsRef = React.useRef(null);
|
|
18
20
|
React.useEffect(() => {
|
|
21
|
+
var _a, _b;
|
|
19
22
|
if (!plotRef.current || !markersRef.current) {
|
|
20
23
|
return () => { };
|
|
21
24
|
}
|
|
@@ -64,13 +67,22 @@ export const LineSeriesShapes = (args) => {
|
|
|
64
67
|
.data(markers)
|
|
65
68
|
.join('g')
|
|
66
69
|
.call(renderMarker);
|
|
70
|
+
if (annotationsRef.current) {
|
|
71
|
+
const anchors = preparedData.flatMap((d) => d.annotations);
|
|
72
|
+
renderAnnotations({
|
|
73
|
+
anchors,
|
|
74
|
+
container: select(annotationsRef.current),
|
|
75
|
+
plotHeight: boundsHeight,
|
|
76
|
+
plotWidth: boundsWidth,
|
|
77
|
+
});
|
|
78
|
+
}
|
|
67
79
|
const hoverEnabled = hoverOptions === null || hoverOptions === void 0 ? void 0 : hoverOptions.enabled;
|
|
68
80
|
const inactiveEnabled = inactiveOptions === null || inactiveOptions === void 0 ? void 0 : inactiveOptions.enabled;
|
|
69
81
|
function handleShapeHover(data) {
|
|
70
82
|
hoveredDataRef.current = data;
|
|
71
83
|
const selected = (data === null || data === void 0 ? void 0 : data.filter((d) => d.series.type === 'line')) || [];
|
|
72
|
-
const selectedDataItems = selected.map((d) => d.data);
|
|
73
84
|
const selectedSeriesIds = selected.map((d) => { var _a; return (_a = d.series) === null || _a === void 0 ? void 0 : _a.id; });
|
|
85
|
+
const closestChunk = selected.find((d) => d.closest);
|
|
74
86
|
lineSelection.datum((d, index, list) => {
|
|
75
87
|
const elementSelection = select(list[index]);
|
|
76
88
|
const hovered = Boolean(hoverEnabled && selectedSeriesIds.includes(d.id));
|
|
@@ -106,7 +118,7 @@ export const LineSeriesShapes = (args) => {
|
|
|
106
118
|
});
|
|
107
119
|
markerSelection.datum((d, index, list) => {
|
|
108
120
|
const elementSelection = select(list[index]);
|
|
109
|
-
const hovered = Boolean(hoverEnabled &&
|
|
121
|
+
const hovered = Boolean(hoverEnabled && d.point.data === (closestChunk === null || closestChunk === void 0 ? void 0 : closestChunk.data));
|
|
110
122
|
if (d.hovered !== hovered) {
|
|
111
123
|
d.hovered = hovered;
|
|
112
124
|
elementSelection.attr('visibility', getMarkerVisibility(d));
|
|
@@ -129,7 +141,7 @@ export const LineSeriesShapes = (args) => {
|
|
|
129
141
|
hoverMarkersSvgElement.selectAll('*').remove();
|
|
130
142
|
if (hoverEnabled && selected.length > 0) {
|
|
131
143
|
const hoverOnlyMarkers = [];
|
|
132
|
-
for (const chunk of selected) {
|
|
144
|
+
for (const chunk of selected.filter((c) => c.closest)) {
|
|
133
145
|
const seriesData = preparedData.find((pd) => pd.id === chunk.series.id);
|
|
134
146
|
if (!seriesData) {
|
|
135
147
|
continue;
|
|
@@ -165,11 +177,12 @@ export const LineSeriesShapes = (args) => {
|
|
|
165
177
|
if (hoveredDataRef.current !== null) {
|
|
166
178
|
handleShapeHover(hoveredDataRef.current);
|
|
167
179
|
}
|
|
168
|
-
|
|
180
|
+
const eventName = `hover-shape.line-${(_b = (_a = preparedData[0]) === null || _a === void 0 ? void 0 : _a.id) !== null && _b !== void 0 ? _b : 'unknown'}`;
|
|
181
|
+
dispatcher === null || dispatcher === void 0 ? void 0 : dispatcher.on(eventName, handleShapeHover);
|
|
169
182
|
return () => {
|
|
170
|
-
dispatcher === null || dispatcher === void 0 ? void 0 : dispatcher.on(
|
|
183
|
+
dispatcher === null || dispatcher === void 0 ? void 0 : dispatcher.on(eventName, null);
|
|
171
184
|
};
|
|
172
|
-
}, [dispatcher, preparedData, seriesOptions]);
|
|
185
|
+
}, [boundsHeight, boundsWidth, dispatcher, preparedData, seriesOptions]);
|
|
173
186
|
const htmlLayerData = React.useMemo(() => {
|
|
174
187
|
const items = preparedData.map((d) => d === null || d === void 0 ? void 0 : d.htmlLabels).flat();
|
|
175
188
|
return { htmlElements: items };
|
|
@@ -178,5 +191,6 @@ export const LineSeriesShapes = (args) => {
|
|
|
178
191
|
React.createElement("g", { ref: plotRef, className: b(), clipPath: `url(#${clipPathId})` }),
|
|
179
192
|
React.createElement("g", { ref: markersRef }),
|
|
180
193
|
React.createElement("g", { ref: hoverMarkersRef }),
|
|
194
|
+
React.createElement("g", { ref: annotationsRef }),
|
|
181
195
|
React.createElement(HtmlLayer, { preparedData: htmlLayerData, htmlLayout: htmlLayout })));
|
|
182
196
|
};
|