@gravity-ui/charts 1.43.0 → 1.43.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.
Files changed (55) hide show
  1. package/dist/cjs/components/ChartInner/index.js +3 -3
  2. package/dist/cjs/components/ChartInner/useChartInnerHandlers.d.ts +3 -3
  3. package/dist/cjs/components/ChartInner/useChartInnerHandlers.js +10 -12
  4. package/dist/cjs/components/ChartInner/useChartInnerProps.js +8 -4
  5. package/dist/cjs/components/ChartInner/utils/title.d.ts +3 -2
  6. package/dist/cjs/components/ChartInner/utils/title.js +19 -14
  7. package/dist/cjs/components/Title/index.d.ts +1 -3
  8. package/dist/cjs/components/Title/index.js +2 -2
  9. package/dist/cjs/core/constants/index.d.ts +0 -1
  10. package/dist/cjs/core/constants/index.js +0 -1
  11. package/dist/cjs/core/utils/labels.d.ts +1 -1
  12. package/dist/cjs/core/utils/labels.js +3 -2
  13. package/dist/cjs/hooks/useSeries/index.js +8 -2
  14. package/dist/cjs/hooks/useShapes/area/index.js +2 -2
  15. package/dist/cjs/hooks/useShapes/area/prepare-data.js +4 -4
  16. package/dist/cjs/hooks/useShapes/area/types.d.ts +2 -2
  17. package/dist/cjs/hooks/useShapes/bar-x/index.js +2 -2
  18. package/dist/cjs/hooks/useShapes/bar-x/prepare-data.js +15 -12
  19. package/dist/cjs/hooks/useShapes/bar-x/types.d.ts +2 -2
  20. package/dist/cjs/hooks/useShapes/index.js +18 -5
  21. package/dist/cjs/hooks/useShapes/line/index.js +7 -16
  22. package/dist/cjs/hooks/useShapes/line/prepare-data.d.ts +2 -0
  23. package/dist/cjs/hooks/useShapes/line/prepare-data.js +11 -7
  24. package/dist/cjs/hooks/useShapes/line/types.d.ts +2 -2
  25. package/dist/cjs/types/chart-ui.d.ts +4 -0
  26. package/dist/esm/components/ChartInner/index.js +3 -3
  27. package/dist/esm/components/ChartInner/useChartInnerHandlers.d.ts +3 -3
  28. package/dist/esm/components/ChartInner/useChartInnerHandlers.js +10 -12
  29. package/dist/esm/components/ChartInner/useChartInnerProps.js +8 -4
  30. package/dist/esm/components/ChartInner/utils/title.d.ts +3 -2
  31. package/dist/esm/components/ChartInner/utils/title.js +19 -14
  32. package/dist/esm/components/Title/index.d.ts +1 -3
  33. package/dist/esm/components/Title/index.js +2 -2
  34. package/dist/esm/core/constants/index.d.ts +0 -1
  35. package/dist/esm/core/constants/index.js +0 -1
  36. package/dist/esm/core/utils/labels.d.ts +1 -1
  37. package/dist/esm/core/utils/labels.js +3 -2
  38. package/dist/esm/hooks/useSeries/index.js +8 -2
  39. package/dist/esm/hooks/useShapes/area/index.js +2 -2
  40. package/dist/esm/hooks/useShapes/area/prepare-data.js +4 -4
  41. package/dist/esm/hooks/useShapes/area/types.d.ts +2 -2
  42. package/dist/esm/hooks/useShapes/bar-x/index.js +2 -2
  43. package/dist/esm/hooks/useShapes/bar-x/prepare-data.js +15 -12
  44. package/dist/esm/hooks/useShapes/bar-x/types.d.ts +2 -2
  45. package/dist/esm/hooks/useShapes/index.js +18 -5
  46. package/dist/esm/hooks/useShapes/line/index.js +7 -16
  47. package/dist/esm/hooks/useShapes/line/prepare-data.d.ts +2 -0
  48. package/dist/esm/hooks/useShapes/line/prepare-data.js +11 -7
  49. package/dist/esm/hooks/useShapes/line/types.d.ts +2 -2
  50. package/dist/esm/types/chart-ui.d.ts +4 -0
  51. package/package.json +1 -1
  52. package/dist/cjs/core/constants/misc.d.ts +0 -1
  53. package/dist/cjs/core/constants/misc.js +0 -7
  54. package/dist/esm/core/constants/misc.d.ts +0 -1
  55. package/dist/esm/core/constants/misc.js +0 -7
@@ -25,8 +25,8 @@ export type PreparedLineData = {
25
25
  series: PreparedLineSeries;
26
26
  hovered: boolean;
27
27
  active: boolean;
28
- labels: LabelData[];
29
- htmlElements: HtmlItem[];
28
+ svgLabels: LabelData[];
29
+ htmlLabels: HtmlItem[];
30
30
  color: string;
31
31
  dashStyle: DashStyle;
32
32
  linecap: LineCap;
@@ -25,6 +25,10 @@ export interface HtmlItem {
25
25
  };
26
26
  style?: BaseTextStyle & React.CSSProperties;
27
27
  }
28
+ export interface ShapeDataWithLabels {
29
+ svgLabels: LabelData[];
30
+ htmlLabels: HtmlItem[];
31
+ }
28
32
  export interface ShapeDataWithHtmlItems {
29
33
  htmlElements: HtmlItem[];
30
34
  }
@@ -71,7 +71,7 @@ export const ChartInner = (props) => {
71
71
  value: allPreparedSeries,
72
72
  delay: DEBOUNCED_VALUE_DELAY,
73
73
  });
74
- const { handleChartClick, handleMouseLeave, throttledHandleMouseMove, throttledHandleTouchMove } = useChartInnerHandlers({
74
+ const { handleChartClick, handlePointerLeave, throttledHandlePointerMove, throttledHandleTouchMove, } = useChartInnerHandlers({
75
75
  boundsHeight,
76
76
  boundsOffsetLeft,
77
77
  boundsOffsetTop,
@@ -256,7 +256,7 @@ export const ChartInner = (props) => {
256
256
  React.createElement("rect", { x: 0, y: 0, width: boundsWidth, height: boundsHeight })),
257
257
  React.createElement("clipPath", { id: getClipPathIdByBounds({ clipPathId, bounds: 'horizontal' }) },
258
258
  React.createElement("rect", { x: 0, y: -boundsHeight, width: boundsWidth, height: boundsHeight * 3 }))),
259
- preparedTitle && React.createElement(Title, Object.assign({}, preparedTitle, { chartWidth: width })),
259
+ preparedTitle && React.createElement(Title, Object.assign({}, preparedTitle)),
260
260
  React.createElement("g", { transform: `translate(0, ${boundsOffsetTop})` }, preparedSplit === null || preparedSplit === void 0 ? void 0 : preparedSplit.plots.map((plot, index) => {
261
261
  return React.createElement(PlotTitle, { key: `plot-${index}`, title: plot.title });
262
262
  })),
@@ -283,7 +283,7 @@ export const ChartInner = (props) => {
283
283
  React.createElement("svg", { ref: svgRef, width: width, height: height,
284
284
  // We use onPointerMove here because onMouseMove works incorrectly when the zoom setting is enabled:
285
285
  // when starting to select an area, the tooltip remains in the position where the selection began
286
- onPointerMove: throttledHandleMouseMove, onMouseLeave: handleMouseLeave, onTouchStart: throttledHandleTouchMove, onTouchMove: throttledHandleTouchMove, onClick: handleChartClick }, initialized ? chartContent : null),
286
+ onPointerMove: throttledHandlePointerMove, onPointerLeave: handlePointerLeave, onTouchStart: throttledHandleTouchMove, onTouchMove: throttledHandleTouchMove, onClick: handleChartClick }, initialized ? chartContent : null),
287
287
  React.createElement("div", { className: b('html-layer'), ref: setHtmlLayout, style: {
288
288
  '--g-html-layout-transform': `translate(${boundsOffsetLeft}px, ${boundsOffsetTop}px)`,
289
289
  } }),
@@ -23,8 +23,8 @@ type Props = {
23
23
  };
24
24
  export declare function useChartInnerHandlers(props: Props): {
25
25
  handleChartClick: (event: React.MouseEvent<SVGSVGElement>) => void;
26
- handleMouseLeave: React.MouseEventHandler<SVGSVGElement>;
27
- throttledHandleMouseMove: import("lodash").DebouncedFuncLeading<React.MouseEventHandler<SVGSVGElement>> | undefined;
28
- throttledHandleTouchMove: import("lodash").DebouncedFuncLeading<React.TouchEventHandler<SVGSVGElement>> | undefined;
26
+ handlePointerLeave: React.PointerEventHandler<SVGSVGElement>;
27
+ throttledHandlePointerMove: import("lodash").DebouncedFuncLeading<React.PointerEventHandler<SVGSVGElement>>;
28
+ throttledHandleTouchMove: import("lodash").DebouncedFuncLeading<React.TouchEventHandler<SVGSVGElement>>;
29
29
  };
30
30
  export {};
@@ -2,7 +2,6 @@ import React from 'react';
2
2
  import { pointer } from 'd3-selection';
3
3
  import get from 'lodash/get';
4
4
  import throttle from 'lodash/throttle';
5
- import { IS_TOUCH_ENABLED } from '../../core/constants';
6
5
  import { EventType } from '../../core/utils';
7
6
  import { getClosestPoints } from '../../core/utils/get-closest-data';
8
7
  import { getHoveredPlots } from '../../core/utils/get-hovered-plots';
@@ -47,18 +46,19 @@ export function useChartInnerHandlers(props) {
47
46
  hoveredPlotBands: plotBands,
48
47
  }, event);
49
48
  };
50
- const handleMouseMove = (event) => {
49
+ const handlePointerMove = (event) => {
50
+ if (event.pointerType === 'touch') {
51
+ return;
52
+ }
51
53
  const [pointerX, pointerY] = pointer(event, svgContainer);
52
54
  handleMove([pointerX, pointerY], event);
53
55
  };
54
- const throttledHandleMouseMove = IS_TOUCH_ENABLED
55
- ? undefined
56
- : throttle(handleMouseMove, tooltipThrottle);
57
- const handleMouseLeave = (event) => {
56
+ const throttledHandlePointerMove = throttle(handlePointerMove, tooltipThrottle);
57
+ const handlePointerLeave = (event) => {
58
58
  if (tooltipPinned) {
59
59
  return;
60
60
  }
61
- throttledHandleMouseMove === null || throttledHandleMouseMove === void 0 ? void 0 : throttledHandleMouseMove.cancel();
61
+ throttledHandlePointerMove.cancel();
62
62
  dispatcher.call(EventType.HOVER_SHAPE, {}, undefined);
63
63
  dispatcher.call(EventType.POINTERMOVE_CHART, {}, undefined, event);
64
64
  };
@@ -67,9 +67,7 @@ export function useChartInnerHandlers(props) {
67
67
  const [pointerX, pointerY] = pointer(touch, svgContainer);
68
68
  handleMove([pointerX, pointerY], event);
69
69
  };
70
- const throttledHandleTouchMove = IS_TOUCH_ENABLED
71
- ? throttle(handleTouchMove, tooltipThrottle)
72
- : undefined;
70
+ const throttledHandleTouchMove = throttle(handleTouchMove, tooltipThrottle);
73
71
  const handleChartClick = (event) => {
74
72
  const [pointerX, pointerY] = pointer(event, svgContainer);
75
73
  const x = pointerX - boundsOffsetLeft;
@@ -116,8 +114,8 @@ export function useChartInnerHandlers(props) {
116
114
  };
117
115
  return {
118
116
  handleChartClick,
119
- handleMouseLeave,
120
- throttledHandleMouseMove,
117
+ handlePointerLeave,
118
+ throttledHandlePointerMove,
121
119
  throttledHandleTouchMove,
122
120
  };
123
121
  }
@@ -48,15 +48,19 @@ export function useChartInnerProps(props) {
48
48
  currentRunRef.current++;
49
49
  const currentRun = currentRunRef.current;
50
50
  (async function () {
51
- var _a, _b, _c;
51
+ var _a, _b, _c, _d;
52
52
  const chartDataChanged = !(previousChartData.current && isEqual(previousChartData.current, data));
53
- const preparedTitle = await getPreparedTitle({ title: data.title, chartWidth: width });
53
+ const preparedTitle = await getPreparedTitle({
54
+ title: data.title,
55
+ chartWidth: width,
56
+ chartMargin: (_a = data.chart) === null || _a === void 0 ? void 0 : _a.margin,
57
+ });
54
58
  const preparedChart = getPreparedChart({
55
59
  chart: data.chart,
56
60
  seriesData: data.series.data,
57
61
  preparedTitle,
58
62
  });
59
- const colors = (_a = data.colors) !== null && _a !== void 0 ? _a : DEFAULT_PALETTE;
63
+ const colors = (_b = data.colors) !== null && _b !== void 0 ? _b : DEFAULT_PALETTE;
60
64
  const normalizedSeriesData = getSortedSeriesData({
61
65
  seriesData: data.series.data,
62
66
  xAxis: data.xAxis,
@@ -79,7 +83,7 @@ export function useChartInnerProps(props) {
79
83
  });
80
84
  }
81
85
  else {
82
- allPreparedSeries = (_c = (_b = prevStateValue.current) === null || _b === void 0 ? void 0 : _b.allPreparedSeries) !== null && _c !== void 0 ? _c : [];
86
+ allPreparedSeries = (_d = (_c = prevStateValue.current) === null || _c === void 0 ? void 0 : _c.allPreparedSeries) !== null && _d !== void 0 ? _d : [];
83
87
  }
84
88
  const activeLegendItems = selectedLegendItems !== null && selectedLegendItems !== void 0 ? selectedLegendItems : getActiveLegendItems(allPreparedSeries);
85
89
  const visiblePreparedSeries = getVisibleSeries({
@@ -1,6 +1,7 @@
1
1
  import type { PreparedTitle } from '../../../hooks/types';
2
- import type { ChartData } from '../../../types';
3
- export declare const getPreparedTitle: ({ title, chartWidth, }: {
2
+ import type { ChartData, ChartMargin } from '../../../types';
3
+ export declare const getPreparedTitle: ({ title, chartWidth, chartMargin, }: {
4
4
  title: ChartData["title"];
5
5
  chartWidth: number;
6
+ chartMargin?: Partial<ChartMargin>;
6
7
  }) => Promise<PreparedTitle | undefined>;
@@ -2,25 +2,30 @@ import get from 'lodash/get';
2
2
  import { getTextSizeFn, getTextWithElipsis, wrapText } from '../../../core/utils';
3
3
  const DEFAULT_TITLE_FONT_SIZE = '15px';
4
4
  const DEFAULT_TITLE_MARGIN = 10;
5
- export const getPreparedTitle = async ({ title, chartWidth, }) => {
6
- var _a, _b, _c, _d, _e, _f, _g, _h;
5
+ export const getPreparedTitle = async ({ title, chartWidth, chartMargin, }) => {
6
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l;
7
+ const chartMarginTop = (_a = chartMargin === null || chartMargin === void 0 ? void 0 : chartMargin.top) !== null && _a !== void 0 ? _a : 0;
8
+ const chartMarginLeft = (_b = chartMargin === null || chartMargin === void 0 ? void 0 : chartMargin.left) !== null && _b !== void 0 ? _b : 0;
9
+ const chartMarginRight = (_c = chartMargin === null || chartMargin === void 0 ? void 0 : chartMargin.right) !== null && _c !== void 0 ? _c : 0;
7
10
  const titleText = get(title, 'text');
8
11
  const titleStyle = {
9
- fontSize: (_b = (_a = title === null || title === void 0 ? void 0 : title.style) === null || _a === void 0 ? void 0 : _a.fontSize) !== null && _b !== void 0 ? _b : DEFAULT_TITLE_FONT_SIZE,
10
- fontWeight: (_d = (_c = title === null || title === void 0 ? void 0 : title.style) === null || _c === void 0 ? void 0 : _c.fontWeight) !== null && _d !== void 0 ? _d : 'var(--g-text-subheader-font-weight)',
11
- fontColor: (_f = (_e = title === null || title === void 0 ? void 0 : title.style) === null || _e === void 0 ? void 0 : _e.fontColor) !== null && _f !== void 0 ? _f : 'var(--g-color-text-primary)',
12
+ fontSize: (_e = (_d = title === null || title === void 0 ? void 0 : title.style) === null || _d === void 0 ? void 0 : _d.fontSize) !== null && _e !== void 0 ? _e : DEFAULT_TITLE_FONT_SIZE,
13
+ fontWeight: (_g = (_f = title === null || title === void 0 ? void 0 : title.style) === null || _f === void 0 ? void 0 : _f.fontWeight) !== null && _g !== void 0 ? _g : 'var(--g-text-subheader-font-weight)',
14
+ fontColor: (_j = (_h = title === null || title === void 0 ? void 0 : title.style) === null || _h === void 0 ? void 0 : _h.fontColor) !== null && _j !== void 0 ? _j : 'var(--g-color-text-primary)',
12
15
  };
13
16
  if (!titleText) {
14
17
  return undefined;
15
18
  }
16
19
  const getTitleTextSize = getTextSizeFn({ style: titleStyle });
17
- const maxRowCount = (_g = title === null || title === void 0 ? void 0 : title.maxRowCount) !== null && _g !== void 0 ? _g : 1;
20
+ const maxRowCount = (_k = title === null || title === void 0 ? void 0 : title.maxRowCount) !== null && _k !== void 0 ? _k : 1;
18
21
  const contentRows = [];
22
+ const usableWidth = chartWidth - chartMarginLeft - chartMarginRight;
23
+ const xCenter = chartMarginLeft + usableWidth / 2;
19
24
  if (maxRowCount > 1) {
20
25
  let titleTextRows = await wrapText({
21
26
  text: titleText,
22
27
  style: titleStyle,
23
- width: chartWidth,
28
+ width: usableWidth,
24
29
  getTextSize: getTitleTextSize,
25
30
  });
26
31
  titleTextRows = titleTextRows.reduce((acc, row, index) => {
@@ -38,15 +43,15 @@ export const getPreparedTitle = async ({ title, chartWidth, }) => {
38
43
  if (i === titleTextRows.length - 1) {
39
44
  textRowContent = await getTextWithElipsis({
40
45
  text: textRowContent,
41
- maxWidth: chartWidth,
46
+ maxWidth: usableWidth,
42
47
  getTextWidth: async (s) => (await getTitleTextSize(s)).width,
43
48
  });
44
49
  }
45
50
  const textRowSize = await getTitleTextSize(textRowContent);
46
51
  contentRows.push({
47
52
  text: textRowContent,
48
- x: 0,
49
- y: textRow.y + textRowSize.hangingOffset,
53
+ x: xCenter,
54
+ y: textRow.y + textRowSize.hangingOffset + chartMarginTop,
50
55
  size: textRowSize,
51
56
  });
52
57
  }
@@ -54,14 +59,14 @@ export const getPreparedTitle = async ({ title, chartWidth, }) => {
54
59
  else {
55
60
  const truncatedText = await getTextWithElipsis({
56
61
  text: titleText,
57
- maxWidth: chartWidth,
62
+ maxWidth: usableWidth,
58
63
  getTextWidth: async (s) => (await getTitleTextSize(s)).width,
59
64
  });
60
65
  const textSize = await getTitleTextSize(truncatedText);
61
66
  contentRows.push({
62
67
  text: truncatedText,
63
- x: 0,
64
- y: textSize.hangingOffset,
68
+ x: xCenter,
69
+ y: textSize.hangingOffset + chartMarginTop,
65
70
  size: textSize,
66
71
  });
67
72
  }
@@ -71,7 +76,7 @@ export const getPreparedTitle = async ({ title, chartWidth, }) => {
71
76
  text: titleText,
72
77
  style: titleStyle,
73
78
  height: titleHeight,
74
- margin: (_h = title === null || title === void 0 ? void 0 : title.margin) !== null && _h !== void 0 ? _h : DEFAULT_TITLE_MARGIN,
79
+ margin: (_l = title === null || title === void 0 ? void 0 : title.margin) !== null && _l !== void 0 ? _l : DEFAULT_TITLE_MARGIN,
75
80
  qa: title === null || title === void 0 ? void 0 : title.qa,
76
81
  contentRows,
77
82
  };
@@ -1,7 +1,5 @@
1
1
  import React from 'react';
2
2
  import type { PreparedTitle } from '../../hooks';
3
- type Props = PreparedTitle & {
4
- chartWidth: number;
5
- };
3
+ type Props = PreparedTitle;
6
4
  export declare const Title: (props: Props) => React.JSX.Element;
7
5
  export {};
@@ -1,9 +1,9 @@
1
1
  import React from 'react';
2
2
  export const Title = (props) => {
3
- const { chartWidth, style, qa, contentRows } = props;
3
+ const { style, qa, contentRows } = props;
4
4
  return (React.createElement("text", { dominantBaseline: "hanging", textAnchor: "middle", style: {
5
5
  fill: style === null || style === void 0 ? void 0 : style.fontColor,
6
6
  fontSize: style === null || style === void 0 ? void 0 : style.fontSize,
7
7
  fontWeight: style === null || style === void 0 ? void 0 : style.fontWeight,
8
- }, "data-qa": qa }, contentRows.map((row, i) => (React.createElement("tspan", { key: i, x: chartWidth / 2, y: row.y, dominantBaseline: "hanging", dangerouslySetInnerHTML: { __html: row.text } })))));
8
+ }, "data-qa": qa }, contentRows.map((row, i) => (React.createElement("tspan", { key: i, x: row.x, y: row.y, dominantBaseline: "hanging", dangerouslySetInnerHTML: { __html: row.text } })))));
9
9
  };
@@ -4,7 +4,6 @@ export * from './datetime';
4
4
  export * from './defaults';
5
5
  export * from './layout-algorithms';
6
6
  export * from './line-styles';
7
- export * from './misc';
8
7
  export * from './palette';
9
8
  export * from './symbol-types';
10
9
  export * from './tooltip';
@@ -4,7 +4,6 @@ export * from './datetime';
4
4
  export * from './defaults';
5
5
  export * from './layout-algorithms';
6
6
  export * from './line-styles';
7
- export * from './misc';
8
7
  export * from './palette';
9
8
  export * from './symbol-types';
10
9
  export * from './tooltip';
@@ -3,7 +3,7 @@ export declare function getLeftPosition(label: LabelData): number;
3
3
  export declare function getOverlappingByX(rect1: LabelData | HtmlItem, rect2: LabelData | HtmlItem, gap?: number): number;
4
4
  export declare function getOverlappingByY(rect1: LabelData | HtmlItem, rect2: LabelData | HtmlItem, gap?: number): number;
5
5
  export declare function isLabelsOverlapping<T extends LabelData | HtmlItem>(label1: T, label2: T, padding?: number): boolean;
6
- export declare function filterOverlappingLabels<T extends LabelData | HtmlItem>(labels: T[]): T[];
6
+ export declare function filterOverlappingLabels<T extends LabelData | HtmlItem>(labels: T[], renderedSvgLabels?: T[]): T[];
7
7
  export declare function getSvgLabelConstraintedPosition(args: {
8
8
  boundsHeight: number;
9
9
  boundsWidth: number;
@@ -32,11 +32,12 @@ export function getOverlappingByY(rect1, rect2, gap = 0) {
32
32
  export function isLabelsOverlapping(label1, label2, padding = 0) {
33
33
  return Boolean(getOverlappingByX(label1, label2, padding) && getOverlappingByY(label1, label2, padding));
34
34
  }
35
- export function filterOverlappingLabels(labels) {
35
+ export function filterOverlappingLabels(labels, renderedSvgLabels) {
36
36
  const result = [];
37
37
  const sorted = sortBy(labels, (d) => d.y, (d) => ('textAnchor' in d ? getLeftPosition(d) : d.x));
38
38
  sorted.forEach((label) => {
39
- if (!result.some((l) => isLabelsOverlapping(label, l))) {
39
+ if (!(renderedSvgLabels === null || renderedSvgLabels === void 0 ? void 0 : renderedSvgLabels.some((l) => isLabelsOverlapping(label, l))) &&
40
+ !result.some((l) => isLabelsOverlapping(label, l))) {
40
41
  result.push(label);
41
42
  }
42
43
  });
@@ -13,14 +13,20 @@ export const getVisibleSeries = ({ preparedSeries, activeLegendItems, }) => {
13
13
  export const getPreparedSeries = async ({ seriesData, seriesOptions, colors, preparedLegend, }) => {
14
14
  const seriesNames = getSeriesNames(seriesData);
15
15
  const colorScale = scaleOrdinal(seriesNames, colors);
16
- const groupedSeries = group(seriesData, (item) => item.type);
16
+ const groupedSeries = group(seriesData, (item, index) => {
17
+ if (item.type === 'line') {
18
+ return `${item.type}_${index}`;
19
+ }
20
+ return item.type;
21
+ });
17
22
  const acc = [];
18
23
  if (!preparedLegend) {
19
24
  return acc;
20
25
  }
21
26
  const list = Array.from(groupedSeries);
22
27
  for (let i = 0; i < list.length; i++) {
23
- const [seriesType, seriesList] = list[i];
28
+ const [_groupId, seriesList] = list[i];
29
+ const seriesType = seriesList[0].type;
24
30
  acc.push(...(await prepareSeries({
25
31
  type: seriesType,
26
32
  series: seriesList,
@@ -60,7 +60,7 @@ export const AreaSeriesShapes = (args) => {
60
60
  .attr('fill', (d) => d.color)
61
61
  .attr('opacity', (d) => d.opacity);
62
62
  let dataLabels = preparedData.reduce((acc, d) => {
63
- return acc.concat(d.labels);
63
+ return acc.concat(d.svgLabels);
64
64
  }, []);
65
65
  if (!allowOverlapDataLabels) {
66
66
  dataLabels = filterOverlappingLabels(dataLabels);
@@ -191,7 +191,7 @@ export const AreaSeriesShapes = (args) => {
191
191
  };
192
192
  }, [allowOverlapDataLabels, dispatcher, preparedData, seriesOptions]);
193
193
  const htmlLayerData = React.useMemo(() => {
194
- const items = preparedData.map((d) => d === null || d === void 0 ? void 0 : d.htmlElements).flat();
194
+ const items = preparedData.map((d) => d === null || d === void 0 ? void 0 : d.htmlLabels).flat();
195
195
  if (allowOverlapDataLabels) {
196
196
  return { htmlElements: items };
197
197
  }
@@ -300,7 +300,7 @@ export const prepareAreaData = async (args) => {
300
300
  seriesStackData.push({
301
301
  points,
302
302
  markers,
303
- labels: [],
303
+ svgLabels: [],
304
304
  color: s.color,
305
305
  opacity: s.opacity,
306
306
  width: s.lineWidth,
@@ -308,7 +308,7 @@ export const prepareAreaData = async (args) => {
308
308
  hovered: false,
309
309
  active: true,
310
310
  id: s.id,
311
- htmlElements: [],
311
+ htmlLabels: [],
312
312
  });
313
313
  }
314
314
  for (let itemIndex = 0; itemIndex < seriesStackData.length; itemIndex++) {
@@ -323,8 +323,8 @@ export const prepareAreaData = async (args) => {
323
323
  yAxisTop: itemYAxisTop,
324
324
  isOutsideBounds,
325
325
  });
326
- item.labels.push(...labelsData.svgLabels);
327
- item.htmlElements.push(...labelsData.htmlLabels);
326
+ item.svgLabels.push(...labelsData.svgLabels);
327
+ item.htmlLabels.push(...labelsData.htmlLabels);
328
328
  }
329
329
  }
330
330
  result.push(...seriesStackData);
@@ -27,6 +27,6 @@ export type PreparedAreaData = {
27
27
  series: PreparedAreaSeries;
28
28
  hovered: boolean;
29
29
  active: boolean;
30
- labels: LabelData[];
31
- htmlElements: HtmlItem[];
30
+ svgLabels: LabelData[];
31
+ htmlLabels: HtmlItem[];
32
32
  };
@@ -49,7 +49,7 @@ export const BarXSeriesShapes = (args) => {
49
49
  .attr('fill', (d) => d.data.color || d.series.color)
50
50
  .attr('opacity', (d) => d.opacity)
51
51
  .attr('cursor', (d) => d.series.cursor);
52
- let dataLabels = preparedData.map((d) => d.label).filter(Boolean);
52
+ let dataLabels = preparedData.map((d) => d.svgLabels).flat();
53
53
  if (!allowOverlapDataLabels) {
54
54
  dataLabels = filterOverlappingLabels(dataLabels);
55
55
  }
@@ -114,7 +114,7 @@ export const BarXSeriesShapes = (args) => {
114
114
  };
115
115
  }, [allowOverlapDataLabels, dispatcher, preparedData, seriesOptions]);
116
116
  const htmlLayerData = React.useMemo(() => {
117
- const items = preparedData.map((d) => d === null || d === void 0 ? void 0 : d.htmlElements).flat();
117
+ const items = preparedData.map((d) => d === null || d === void 0 ? void 0 : d.htmlLabels).flat();
118
118
  if (allowOverlapDataLabels) {
119
119
  return { htmlElements: items };
120
120
  }
@@ -174,7 +174,8 @@ export const prepareBarXData = async (args) => {
174
174
  opacity: get(yValue.data, 'opacity', null),
175
175
  data: yValue.data,
176
176
  series: yValue.series,
177
- htmlElements: [],
177
+ htmlLabels: [],
178
+ svgLabels: [],
178
179
  isLastStackItem,
179
180
  };
180
181
  stackItems.push(barData);
@@ -211,17 +212,19 @@ export const prepareBarXData = async (args) => {
211
212
  !isRangeSlider &&
212
213
  (!isBarOutsideBounds || isZeroValue)) {
213
214
  const label = await getLabelData(barData, xMax);
214
- if (barData.series.dataLabels.html && label) {
215
- barData.htmlElements.push({
216
- x: label.x,
217
- y: label.y,
218
- content: label.text,
219
- size: label.size,
220
- style: label.style,
221
- });
222
- }
223
- else {
224
- barData.label = label;
215
+ if (label) {
216
+ if (barData.series.dataLabels.html) {
217
+ barData.htmlLabels.push({
218
+ x: label.x,
219
+ y: label.y,
220
+ content: label.text,
221
+ size: label.size,
222
+ style: label.style,
223
+ });
224
+ }
225
+ else {
226
+ barData.svgLabels.push(label);
227
+ }
225
228
  }
226
229
  }
227
230
  }
@@ -7,8 +7,8 @@ export type PreparedBarXData = Omit<TooltipDataChunkBarX, 'series'> & {
7
7
  height: number;
8
8
  opacity: number | null;
9
9
  series: PreparedBarXSeries;
10
- label?: LabelData;
11
- htmlElements: HtmlItem[];
10
+ svgLabels: LabelData[];
11
+ htmlLabels: HtmlItem[];
12
12
  isLastStackItem: boolean;
13
13
  /**
14
14
  * the utility field for storing the original height (for recalculations, etc.)
@@ -33,11 +33,20 @@ function shouldUseClipPathId(seriesType, clipPathBySeriesType) {
33
33
  export async function getShapes(args) {
34
34
  const { boundsWidth, boundsHeight, clipPathId, clipPathBySeriesType, dispatcher, htmlLayout, isOutsideBounds = IS_OUTSIDE_BOUNDS, isRangeSlider, series, seriesOptions, split, xAxis, xScale, yAxis, yScale, zoomState, } = args;
35
35
  const visibleSeries = getOnlyVisibleSeries(series);
36
- const groupedSeries = group(visibleSeries, (item) => item.type);
36
+ const groupedSeries = group(visibleSeries, (item) => {
37
+ if (item.type === 'line') {
38
+ return item.id;
39
+ }
40
+ return item.type;
41
+ });
37
42
  const shapesData = [];
38
43
  const shapes = [];
39
- await Promise.all(Array.from(groupedSeries).map(async (item, index) => {
40
- const [seriesType, chartSeries] = item;
44
+ const layers = [];
45
+ const groupedSeriesItems = Array.from(groupedSeries);
46
+ for (let index = groupedSeriesItems.length - 1; index >= 0; index--) {
47
+ const item = groupedSeriesItems[index];
48
+ const [groupId, chartSeries] = item;
49
+ const seriesType = chartSeries[0].type;
41
50
  switch (seriesType) {
42
51
  case SERIES_TYPE.BarX: {
43
52
  if (xAxis && xScale && (yScale === null || yScale === void 0 ? void 0 : yScale.length)) {
@@ -54,6 +63,7 @@ export async function getShapes(args) {
54
63
  });
55
64
  shapes[index] = (React.createElement(BarXSeriesShapes, { key: SERIES_TYPE.BarX, dispatcher: dispatcher, seriesOptions: seriesOptions, preparedData: preparedData, htmlLayout: htmlLayout, clipPathId: clipPathId }));
56
65
  shapesData.splice(index, 0, ...preparedData);
66
+ layers.push(...preparedData);
57
67
  }
58
68
  break;
59
69
  }
@@ -100,14 +110,16 @@ export async function getShapes(args) {
100
110
  split,
101
111
  isOutsideBounds,
102
112
  isRangeSlider,
113
+ otherLayers: layers,
103
114
  });
104
115
  const resultClipPathId = getSeriesClipPathId({
105
116
  clipPathId,
106
117
  yAxis,
107
118
  zoomState,
108
119
  });
109
- shapes[index] = (React.createElement(LineSeriesShapes, { key: SERIES_TYPE.Line, dispatcher: dispatcher, seriesOptions: seriesOptions, preparedData: preparedData, htmlLayout: htmlLayout, clipPathId: resultClipPathId }));
120
+ shapes[index] = (React.createElement(LineSeriesShapes, { key: groupId, dispatcher: dispatcher, seriesOptions: seriesOptions, preparedData: preparedData, htmlLayout: htmlLayout, clipPathId: resultClipPathId }));
110
121
  shapesData.splice(index, 0, ...preparedData);
122
+ layers.push(...preparedData);
111
123
  }
112
124
  break;
113
125
  }
@@ -125,6 +137,7 @@ export async function getShapes(args) {
125
137
  });
126
138
  shapes[index] = (React.createElement(AreaSeriesShapes, { key: SERIES_TYPE.Area, dispatcher: dispatcher, seriesOptions: seriesOptions, preparedData: preparedData, htmlLayout: htmlLayout, clipPathId: clipPathId }));
127
139
  shapesData.splice(index, 0, ...preparedData);
140
+ layers.push(...preparedData);
128
141
  }
129
142
  break;
130
143
  }
@@ -217,7 +230,7 @@ export async function getShapes(args) {
217
230
  });
218
231
  }
219
232
  }
220
- }));
233
+ }
221
234
  return { shapes, shapesData };
222
235
  }
223
236
  export const useShapes = (args) => {
@@ -3,7 +3,7 @@ import { color } from 'd3-color';
3
3
  import { select } from 'd3-selection';
4
4
  import { line as lineGenerator } from 'd3-shape';
5
5
  import get from 'lodash/get';
6
- import { filterOverlappingLabels, getLineDashArray } from '../../../core/utils';
6
+ import { getLineDashArray } from '../../../core/utils';
7
7
  import { block } from '../../../utils';
8
8
  import { HtmlLayer } from '../HtmlLayer';
9
9
  import { getMarkerHaloVisibility, getMarkerVisibility, renderMarker, selectMarkerHalo, selectMarkerSymbol, setMarker, } from '../marker';
@@ -15,9 +15,6 @@ export const LineSeriesShapes = (args) => {
15
15
  const plotRef = React.useRef(null);
16
16
  const markersRef = React.useRef(null);
17
17
  const hoverMarkersRef = React.useRef(null);
18
- const allowOverlapDataLabels = React.useMemo(() => {
19
- return preparedData.some((d) => d === null || d === void 0 ? void 0 : d.series.dataLabels.allowOverlap);
20
- }, [preparedData]);
21
18
  React.useEffect(() => {
22
19
  if (!plotRef.current || !markersRef.current) {
23
20
  return () => { };
@@ -46,12 +43,9 @@ export const LineSeriesShapes = (args) => {
46
43
  .attr('stroke-dasharray', (d) => getLineDashArray(d.dashStyle, d.lineWidth))
47
44
  .attr('opacity', (d) => d.opacity)
48
45
  .attr('cursor', (d) => d.series.cursor);
49
- let dataLabels = preparedData.reduce((acc, d) => {
50
- return acc.concat(d.labels);
46
+ const dataLabels = preparedData.reduce((acc, d) => {
47
+ return acc.concat(d.svgLabels);
51
48
  }, []);
52
- if (!allowOverlapDataLabels) {
53
- dataLabels = filterOverlappingLabels(dataLabels);
54
- }
55
49
  const labelsSelection = plotSvgElement
56
50
  .selectAll('text')
57
51
  .data(dataLabels)
@@ -175,14 +169,11 @@ export const LineSeriesShapes = (args) => {
175
169
  return () => {
176
170
  dispatcher === null || dispatcher === void 0 ? void 0 : dispatcher.on('hover-shape.line', null);
177
171
  };
178
- }, [allowOverlapDataLabels, dispatcher, preparedData, seriesOptions]);
172
+ }, [dispatcher, preparedData, seriesOptions]);
179
173
  const htmlLayerData = React.useMemo(() => {
180
- const items = preparedData.map((d) => d === null || d === void 0 ? void 0 : d.htmlElements).flat();
181
- if (allowOverlapDataLabels) {
182
- return { htmlElements: items };
183
- }
184
- return { htmlElements: filterOverlappingLabels(items) };
185
- }, [allowOverlapDataLabels, preparedData]);
174
+ const items = preparedData.map((d) => d === null || d === void 0 ? void 0 : d.htmlLabels).flat();
175
+ return { htmlElements: items };
176
+ }, [preparedData]);
186
177
  return (React.createElement(React.Fragment, null,
187
178
  React.createElement("g", { ref: plotRef, className: b(), clipPath: `url(#${clipPathId})` }),
188
179
  React.createElement("g", { ref: markersRef }),
@@ -1,5 +1,6 @@
1
1
  import type { PreparedSplit } from '../../../core/layout/split-types';
2
2
  import type { ChartScale } from '../../../core/scales/types';
3
+ import type { ShapeDataWithLabels } from '../../../types';
3
4
  import type { PreparedXAxis, PreparedYAxis } from '../../useAxis/types';
4
5
  import type { PreparedLineSeries } from '../../useSeries/types';
5
6
  import type { PreparedLineData } from './types';
@@ -12,4 +13,5 @@ export declare const prepareLineData: (args: {
12
13
  split: PreparedSplit;
13
14
  isOutsideBounds: (x: number, y: number) => boolean;
14
15
  isRangeSlider?: boolean;
16
+ otherLayers: ShapeDataWithLabels[];
15
17
  }) => Promise<PreparedLineData[]>;