@gravity-ui/chartkit 5.14.1 → 5.16.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (67) hide show
  1. package/build/plugins/d3/renderer/components/Chart.js +5 -0
  2. package/build/plugins/d3/renderer/components/Legend.js +129 -66
  3. package/build/plugins/d3/renderer/components/styles.css +16 -0
  4. package/build/plugins/d3/renderer/constants/defaults/legend.d.ts +12 -4
  5. package/build/plugins/d3/renderer/constants/defaults/legend.js +4 -0
  6. package/build/plugins/d3/renderer/hooks/useSeries/prepare-area.js +1 -0
  7. package/build/plugins/d3/renderer/hooks/useSeries/prepare-bar-x.js +1 -0
  8. package/build/plugins/d3/renderer/hooks/useSeries/prepare-bar-y.js +8 -6
  9. package/build/plugins/d3/renderer/hooks/useSeries/prepare-legend.js +58 -11
  10. package/build/plugins/d3/renderer/hooks/useSeries/prepare-line.js +1 -0
  11. package/build/plugins/d3/renderer/hooks/useSeries/prepare-pie.js +1 -0
  12. package/build/plugins/d3/renderer/hooks/useSeries/prepare-treemap.js +1 -0
  13. package/build/plugins/d3/renderer/hooks/useSeries/prepare-waterfall.js +1 -0
  14. package/build/plugins/d3/renderer/hooks/useSeries/types.d.ts +24 -1
  15. package/build/plugins/d3/renderer/hooks/useShapes/HtmlLayer.d.ts +8 -0
  16. package/build/plugins/d3/renderer/hooks/useShapes/HtmlLayer.js +22 -0
  17. package/build/plugins/d3/renderer/hooks/useShapes/area/index.d.ts +1 -0
  18. package/build/plugins/d3/renderer/hooks/useShapes/area/index.js +5 -2
  19. package/build/plugins/d3/renderer/hooks/useShapes/area/prepare-data.js +18 -3
  20. package/build/plugins/d3/renderer/hooks/useShapes/area/types.d.ts +2 -1
  21. package/build/plugins/d3/renderer/hooks/useShapes/bar-x/index.d.ts +1 -0
  22. package/build/plugins/d3/renderer/hooks/useShapes/bar-x/index.js +5 -2
  23. package/build/plugins/d3/renderer/hooks/useShapes/bar-x/prepare-data.js +21 -4
  24. package/build/plugins/d3/renderer/hooks/useShapes/bar-x/types.d.ts +2 -1
  25. package/build/plugins/d3/renderer/hooks/useShapes/bar-y/index.d.ts +1 -0
  26. package/build/plugins/d3/renderer/hooks/useShapes/bar-y/index.js +18 -23
  27. package/build/plugins/d3/renderer/hooks/useShapes/bar-y/prepare-data.js +44 -3
  28. package/build/plugins/d3/renderer/hooks/useShapes/bar-y/types.d.ts +3 -0
  29. package/build/plugins/d3/renderer/hooks/useShapes/index.d.ts +1 -0
  30. package/build/plugins/d3/renderer/hooks/useShapes/index.js +9 -9
  31. package/build/plugins/d3/renderer/hooks/useShapes/line/index.d.ts +1 -0
  32. package/build/plugins/d3/renderer/hooks/useShapes/line/index.js +5 -2
  33. package/build/plugins/d3/renderer/hooks/useShapes/line/prepare-data.js +17 -1
  34. package/build/plugins/d3/renderer/hooks/useShapes/line/types.d.ts +2 -1
  35. package/build/plugins/d3/renderer/hooks/useShapes/pie/index.d.ts +1 -0
  36. package/build/plugins/d3/renderer/hooks/useShapes/pie/index.js +10 -14
  37. package/build/plugins/d3/renderer/hooks/useShapes/pie/prepare-data.js +30 -12
  38. package/build/plugins/d3/renderer/hooks/useShapes/pie/types.d.ts +7 -5
  39. package/build/plugins/d3/renderer/hooks/useShapes/scatter/index.d.ts +1 -0
  40. package/build/plugins/d3/renderer/hooks/useShapes/scatter/index.js +5 -2
  41. package/build/plugins/d3/renderer/hooks/useShapes/scatter/prepare-data.js +1 -0
  42. package/build/plugins/d3/renderer/hooks/useShapes/scatter/types.d.ts +2 -0
  43. package/build/plugins/d3/renderer/hooks/useShapes/treemap/index.d.ts +1 -0
  44. package/build/plugins/d3/renderer/hooks/useShapes/treemap/index.js +5 -2
  45. package/build/plugins/d3/renderer/hooks/useShapes/treemap/prepare-data.js +1 -1
  46. package/build/plugins/d3/renderer/hooks/useShapes/treemap/types.d.ts +2 -0
  47. package/build/plugins/d3/renderer/hooks/useShapes/waterfall/index.d.ts +1 -0
  48. package/build/plugins/d3/renderer/hooks/useShapes/waterfall/index.js +5 -2
  49. package/build/plugins/d3/renderer/hooks/useShapes/waterfall/prepare-data.js +1 -0
  50. package/build/plugins/d3/renderer/hooks/useShapes/waterfall/types.d.ts +2 -1
  51. package/build/plugins/d3/renderer/types/index.d.ts +8 -0
  52. package/build/plugins/d3/renderer/utils/axis-generators/bottom.d.ts +5 -4
  53. package/build/plugins/d3/renderer/utils/axis-generators/bottom.js +11 -7
  54. package/build/plugins/d3/renderer/utils/axis.d.ts +1 -1
  55. package/build/plugins/d3/renderer/utils/axis.js +1 -1
  56. package/build/plugins/d3/renderer/utils/color.d.ts +10 -0
  57. package/build/plugins/d3/renderer/utils/color.js +43 -0
  58. package/build/plugins/d3/renderer/utils/index.d.ts +2 -0
  59. package/build/plugins/d3/renderer/utils/index.js +2 -0
  60. package/build/plugins/d3/renderer/utils/legend.d.ts +8 -0
  61. package/build/plugins/d3/renderer/utils/legend.js +23 -0
  62. package/build/plugins/d3/renderer/utils/text.d.ts +2 -1
  63. package/build/plugins/d3/renderer/utils/text.js +32 -10
  64. package/build/types/widget-data/bar-x.d.ts +1 -1
  65. package/build/types/widget-data/base.d.ts +7 -0
  66. package/build/types/widget-data/legend.d.ts +24 -0
  67. package/package.json +2 -2
@@ -4,7 +4,7 @@ import { getXValue, getYValue } from '../utils';
4
4
  function getLabelData(point, series, xMax) {
5
5
  const text = String(point.data.label || point.data.y);
6
6
  const style = series.dataLabels.style;
7
- const size = getLabelsSize({ labels: [text], style });
7
+ const size = getLabelsSize({ labels: [text], style, html: series.dataLabels.html });
8
8
  const labelData = {
9
9
  text,
10
10
  x: point.x,
@@ -22,7 +22,7 @@ function getLabelData(point, series, xMax) {
22
22
  else {
23
23
  const right = left + labelData.size.width;
24
24
  if (right > xMax) {
25
- labelData.x = labelData.x - xMax - right;
25
+ labelData.x = labelData.x - (right - xMax);
26
26
  }
27
27
  }
28
28
  return labelData;
@@ -97,8 +97,22 @@ export const prepareAreaData = (args) => {
97
97
  return pointsAcc;
98
98
  }, []);
99
99
  let labels = [];
100
+ const htmlElements = [];
100
101
  if (s.dataLabels.enabled) {
101
- labels = points.map((p) => getLabelData(p, s, xMax));
102
+ const labelItems = points.map((p) => getLabelData(p, s, xMax));
103
+ if (s.dataLabels.html) {
104
+ const htmlLabels = labelItems.map((l) => {
105
+ return {
106
+ x: l.x - l.size.width / 2,
107
+ y: l.y,
108
+ content: l.text,
109
+ };
110
+ });
111
+ htmlElements.push(...htmlLabels);
112
+ }
113
+ else {
114
+ labels = labelItems;
115
+ }
102
116
  }
103
117
  let markers = [];
104
118
  if (s.marker.states.normal.enabled || s.marker.states.hover.enabled) {
@@ -119,6 +133,7 @@ export const prepareAreaData = (args) => {
119
133
  hovered: false,
120
134
  active: true,
121
135
  id: s.id,
136
+ htmlElements,
122
137
  });
123
138
  return acc;
124
139
  }, []);
@@ -1,5 +1,5 @@
1
1
  import { AreaSeriesData } from '../../../../../../types';
2
- import { LabelData } from '../../../types';
2
+ import { HtmlItem, LabelData } from '../../../types';
3
3
  import { PreparedAreaSeries } from '../../useSeries/types';
4
4
  export type PointData = {
5
5
  y0: number;
@@ -24,4 +24,5 @@ export type PreparedAreaData = {
24
24
  hovered: boolean;
25
25
  active: boolean;
26
26
  labels: LabelData[];
27
+ htmlElements: HtmlItem[];
27
28
  };
@@ -8,5 +8,6 @@ type Args = {
8
8
  dispatcher: Dispatch<object>;
9
9
  preparedData: PreparedBarXData[];
10
10
  seriesOptions: PreparedSeriesOptions;
11
+ htmlLayout: HTMLElement | null;
11
12
  };
12
13
  export declare const BarXSeriesShapes: (args: Args) => React.JSX.Element;
@@ -3,11 +3,12 @@ import { color, select } from 'd3';
3
3
  import get from 'lodash/get';
4
4
  import { block } from '../../../../../../utils/cn';
5
5
  import { filterOverlappingLabels } from '../../../utils';
6
+ import { HtmlLayer } from '../HtmlLayer';
6
7
  export { prepareBarXData } from './prepare-data';
7
8
  export * from './types';
8
9
  const b = block('d3-bar-x');
9
10
  export const BarXSeriesShapes = (args) => {
10
- const { dispatcher, preparedData, seriesOptions } = args;
11
+ const { dispatcher, preparedData, seriesOptions, htmlLayout } = args;
11
12
  const ref = React.useRef(null);
12
13
  React.useEffect(() => {
13
14
  var _a;
@@ -89,5 +90,7 @@ export const BarXSeriesShapes = (args) => {
89
90
  dispatcher.on('hover-shape.bar-x', null);
90
91
  };
91
92
  }, [dispatcher, preparedData, seriesOptions]);
92
- return React.createElement("g", { ref: ref, className: b() });
93
+ return (React.createElement(React.Fragment, null,
94
+ React.createElement("g", { ref: ref, className: b() }),
95
+ React.createElement(HtmlLayer, { preparedData: preparedData, htmlLayout: htmlLayout })));
93
96
  };
@@ -8,15 +8,21 @@ function getLabelData(d) {
8
8
  }
9
9
  const text = String(d.data.label || d.data.y);
10
10
  const style = d.series.dataLabels.style;
11
- const { maxHeight: height, maxWidth: width } = getLabelsSize({ labels: [text], style });
11
+ const html = d.series.dataLabels.html;
12
+ const { maxHeight: height, maxWidth: width } = getLabelsSize({
13
+ labels: [text],
14
+ style,
15
+ html,
16
+ });
12
17
  let y = Math.max(height, d.y - d.series.dataLabels.padding);
13
18
  if (d.series.dataLabels.inside) {
14
19
  y = d.y + d.height / 2;
15
20
  }
21
+ const x = d.x + d.width / 2;
16
22
  return {
17
23
  text,
18
- x: d.x + d.width / 2,
19
- y,
24
+ x: html ? x - width / 2 : x,
25
+ y: html ? y - height : y,
20
26
  style,
21
27
  size: { width, height },
22
28
  textAnchor: 'middle',
@@ -122,8 +128,19 @@ export const prepareBarXData = (args) => {
122
128
  opacity: get(yValue.data, 'opacity', null),
123
129
  data: yValue.data,
124
130
  series: yValue.series,
131
+ htmlElements: [],
125
132
  };
126
- barData.label = getLabelData(barData);
133
+ const label = getLabelData(barData);
134
+ if (yValue.series.dataLabels.html && label) {
135
+ barData.htmlElements.push({
136
+ x: label.x,
137
+ y: label.y,
138
+ content: label.text,
139
+ });
140
+ }
141
+ else {
142
+ barData.label = getLabelData(barData);
143
+ }
127
144
  stackItems.push(barData);
128
145
  stackHeight += height + 1;
129
146
  });
@@ -1,5 +1,5 @@
1
1
  import { TooltipDataChunkBarX } from '../../../../../../types';
2
- import { LabelData } from '../../../types';
2
+ import { HtmlItem, LabelData } from '../../../types';
3
3
  import { PreparedBarXSeries } from '../../useSeries/types';
4
4
  export type PreparedBarXData = Omit<TooltipDataChunkBarX, 'series'> & {
5
5
  x: number;
@@ -9,4 +9,5 @@ export type PreparedBarXData = Omit<TooltipDataChunkBarX, 'series'> & {
9
9
  opacity: number | null;
10
10
  series: PreparedBarXSeries;
11
11
  label?: LabelData;
12
+ htmlElements: HtmlItem[];
12
13
  };
@@ -7,5 +7,6 @@ type Args = {
7
7
  dispatcher: Dispatch<object>;
8
8
  preparedData: PreparedBarYData[];
9
9
  seriesOptions: PreparedSeriesOptions;
10
+ htmlLayout: HTMLElement | null;
10
11
  };
11
12
  export declare const BarYSeriesShapes: (args: Args) => React.JSX.Element;
@@ -2,11 +2,11 @@ import React from 'react';
2
2
  import { color, select } from 'd3';
3
3
  import get from 'lodash/get';
4
4
  import { block } from '../../../../../../utils/cn';
5
+ import { HtmlLayer } from '../HtmlLayer';
5
6
  export { prepareBarYData } from './prepare-data';
6
- const DEFAULT_LABEL_PADDING = 7;
7
7
  const b = block('d3-bar-y');
8
8
  export const BarYSeriesShapes = (args) => {
9
- const { dispatcher, preparedData, seriesOptions } = args;
9
+ const { dispatcher, preparedData, seriesOptions, htmlLayout } = args;
10
10
  const ref = React.useRef(null);
11
11
  React.useEffect(() => {
12
12
  if (!ref.current) {
@@ -26,31 +26,24 @@ export const BarYSeriesShapes = (args) => {
26
26
  .attr('fill', (d) => d.color)
27
27
  .attr('opacity', (d) => d.data.opacity || null)
28
28
  .attr('cursor', (d) => d.series.cursor);
29
- const dataLabels = preparedData.filter((d) => d.series.dataLabels.enabled);
29
+ const dataLabels = preparedData.reduce((acc, d) => {
30
+ if (d.label) {
31
+ acc.push(d.label);
32
+ }
33
+ return acc;
34
+ }, []);
30
35
  const labelSelection = svgElement
31
36
  .selectAll('text')
32
37
  .data(dataLabels)
33
38
  .join('text')
34
- .text((d) => String(d.data.label || d.data.x))
39
+ .text((d) => d.text)
35
40
  .attr('class', b('label'))
36
- .attr('x', (d) => {
37
- if (d.series.dataLabels.inside) {
38
- return d.x + d.width / 2;
39
- }
40
- return d.x + d.width + DEFAULT_LABEL_PADDING;
41
- })
42
- .attr('y', (d) => {
43
- return d.y + d.height / 2 + d.series.dataLabels.maxHeight / 2;
44
- })
45
- .attr('text-anchor', (d) => {
46
- if (d.series.dataLabels.inside) {
47
- return 'middle';
48
- }
49
- return 'right';
50
- })
51
- .style('font-size', (d) => d.series.dataLabels.style.fontSize)
52
- .style('font-weight', (d) => d.series.dataLabels.style.fontWeight || null)
53
- .style('fill', (d) => d.series.dataLabels.style.fontColor || null);
41
+ .attr('x', (d) => d.x)
42
+ .attr('y', (d) => d.y)
43
+ .attr('text-anchor', (d) => d.textAnchor)
44
+ .style('font-size', (d) => d.style.fontSize)
45
+ .style('font-weight', (d) => d.style.fontWeight || null)
46
+ .style('fill', (d) => d.style.fontColor || null);
54
47
  const hoverOptions = get(seriesOptions, 'bar-y.states.hover');
55
48
  const inactiveOptions = get(seriesOptions, 'bar-y.states.inactive');
56
49
  dispatcher.on('hover-shape.bar-y', (data) => {
@@ -85,5 +78,7 @@ export const BarYSeriesShapes = (args) => {
85
78
  dispatcher.on('hover-shape.bar-y', null);
86
79
  };
87
80
  }, [dispatcher, preparedData, seriesOptions]);
88
- return React.createElement("g", { ref: ref, className: b() });
81
+ return (React.createElement(React.Fragment, null,
82
+ React.createElement("g", { ref: ref, className: b() }),
83
+ React.createElement(HtmlLayer, { preparedData: preparedData, htmlLayout: htmlLayout })));
89
84
  };
@@ -1,7 +1,8 @@
1
1
  import { ascending, descending, max, sort } from 'd3';
2
2
  import get from 'lodash/get';
3
- import { getDataCategoryValue } from '../../../utils';
3
+ import { getDataCategoryValue, getLabelsSize } from '../../../utils';
4
4
  import { MIN_BAR_GAP, MIN_BAR_GROUP_GAP, MIN_BAR_WIDTH } from '../constants';
5
+ const DEFAULT_LABEL_PADDING = 7;
5
6
  function groupByYValue(series, yAxis) {
6
7
  const data = {};
7
8
  series.forEach((s) => {
@@ -47,6 +48,41 @@ function getBandWidth(series, yAxis, yScale) {
47
48
  }
48
49
  return bandWidth;
49
50
  }
51
+ function setLabel(prepared) {
52
+ const dataLabels = prepared.series.dataLabels;
53
+ if (!dataLabels.enabled) {
54
+ return;
55
+ }
56
+ const data = prepared.data;
57
+ const content = String(data.label || data.x);
58
+ const { maxHeight: height, maxWidth: width } = getLabelsSize({
59
+ labels: [content],
60
+ style: dataLabels.style,
61
+ html: dataLabels.html,
62
+ });
63
+ const x = dataLabels.inside
64
+ ? prepared.x + prepared.width / 2
65
+ : prepared.x + prepared.width + DEFAULT_LABEL_PADDING;
66
+ const y = prepared.y + prepared.height / 2;
67
+ if (dataLabels.html) {
68
+ prepared.htmlElements.push({
69
+ x,
70
+ y: y - height / 2,
71
+ content,
72
+ });
73
+ }
74
+ else {
75
+ prepared.label = {
76
+ x,
77
+ y: y + height / 2,
78
+ text: content,
79
+ textAnchor: dataLabels.inside ? 'middle' : 'right',
80
+ style: dataLabels.style,
81
+ series: prepared.series,
82
+ size: { width, height },
83
+ };
84
+ }
85
+ }
50
86
  export const prepareBarYData = (args) => {
51
87
  const { series, seriesOptions, yAxis, xScale, yScale: [yScale], } = args;
52
88
  const xLinearScale = xScale;
@@ -100,7 +136,7 @@ export const prepareBarYData = (args) => {
100
136
  const y = center - currentBarHeight / 2 + (barHeight + rectGap) * groupItemIndex;
101
137
  const xValue = Number(data.x);
102
138
  const width = xValue > 0 ? xLinearScale(xValue) - base : base - xLinearScale(xValue);
103
- stackItems.push({
139
+ const item = {
104
140
  x: xValue > 0 ? stackSum : stackSum - width,
105
141
  y,
106
142
  width,
@@ -109,7 +145,9 @@ export const prepareBarYData = (args) => {
109
145
  opacity: get(data, 'opacity', null),
110
146
  data,
111
147
  series: s,
112
- });
148
+ htmlElements: [],
149
+ };
150
+ stackItems.push(item);
113
151
  stackSum += width + 1;
114
152
  });
115
153
  if (series.some((s) => s.stacking === 'percent')) {
@@ -124,5 +162,8 @@ export const prepareBarYData = (args) => {
124
162
  result.push(...stackItems);
125
163
  });
126
164
  });
165
+ result.forEach((d) => {
166
+ setLabel(d);
167
+ });
127
168
  return result;
128
169
  };
@@ -1,4 +1,5 @@
1
1
  import { TooltipDataChunkBarX } from '../../../../../../types';
2
+ import { HtmlItem, LabelData } from '../../../types';
2
3
  import { PreparedBarYSeries } from '../../useSeries/types';
3
4
  export type PreparedBarYData = Omit<TooltipDataChunkBarX, 'series'> & {
4
5
  x: number;
@@ -8,4 +9,6 @@ export type PreparedBarYData = Omit<TooltipDataChunkBarX, 'series'> & {
8
9
  color: string;
9
10
  opacity: number | null;
10
11
  series: PreparedBarYSeries;
12
+ label?: LabelData;
13
+ htmlElements: HtmlItem[];
11
14
  };
@@ -25,6 +25,7 @@ type Args = {
25
25
  xScale?: ChartScale;
26
26
  yScale?: ChartScale[];
27
27
  split: PreparedSplit;
28
+ htmlLayout: HTMLElement | null;
28
29
  };
29
30
  export declare const useShapes: (args: Args) => {
30
31
  shapes: React.ReactElement<any, string | React.JSXElementConstructor<any>>[];
@@ -15,7 +15,7 @@ import { prepareTreemapData } from './treemap/prepare-data';
15
15
  import { WaterfallSeriesShapes, prepareWaterfallData } from './waterfall';
16
16
  import './styles.css';
17
17
  export const useShapes = (args) => {
18
- const { boundsWidth, boundsHeight, dispatcher, series, seriesOptions, xAxis, xScale, yAxis, yScale, split, } = args;
18
+ const { boundsWidth, boundsHeight, dispatcher, series, seriesOptions, xAxis, xScale, yAxis, yScale, split, htmlLayout, } = args;
19
19
  const shapesComponents = React.useMemo(() => {
20
20
  const visibleSeries = getOnlyVisibleSeries(series);
21
21
  const groupedSeries = group(visibleSeries, (item) => item.type);
@@ -34,7 +34,7 @@ export const useShapes = (args) => {
34
34
  yScale,
35
35
  boundsHeight,
36
36
  });
37
- acc.push(React.createElement(BarXSeriesShapes, { key: "bar-x", dispatcher: dispatcher, seriesOptions: seriesOptions, preparedData: preparedData }));
37
+ acc.push(React.createElement(BarXSeriesShapes, { key: "bar-x", dispatcher: dispatcher, seriesOptions: seriesOptions, preparedData: preparedData, htmlLayout: htmlLayout }));
38
38
  shapesData.push(...preparedData);
39
39
  }
40
40
  break;
@@ -49,7 +49,7 @@ export const useShapes = (args) => {
49
49
  yAxis,
50
50
  yScale,
51
51
  });
52
- acc.push(React.createElement(BarYSeriesShapes, { key: "bar-y", dispatcher: dispatcher, seriesOptions: seriesOptions, preparedData: preparedData }));
52
+ acc.push(React.createElement(BarYSeriesShapes, { key: "bar-y", dispatcher: dispatcher, seriesOptions: seriesOptions, preparedData: preparedData, htmlLayout: htmlLayout }));
53
53
  shapesData.push(...preparedData);
54
54
  }
55
55
  break;
@@ -64,7 +64,7 @@ export const useShapes = (args) => {
64
64
  yAxis,
65
65
  yScale,
66
66
  });
67
- acc.push(React.createElement(WaterfallSeriesShapes, { key: "waterfall", dispatcher: dispatcher, seriesOptions: seriesOptions, preparedData: preparedData }));
67
+ acc.push(React.createElement(WaterfallSeriesShapes, { key: "waterfall", dispatcher: dispatcher, seriesOptions: seriesOptions, preparedData: preparedData, htmlLayout: htmlLayout }));
68
68
  shapesData.push(...preparedData);
69
69
  }
70
70
  break;
@@ -79,7 +79,7 @@ export const useShapes = (args) => {
79
79
  yScale,
80
80
  split,
81
81
  });
82
- acc.push(React.createElement(LineSeriesShapes, { key: "line", dispatcher: dispatcher, seriesOptions: seriesOptions, preparedData: preparedData }));
82
+ acc.push(React.createElement(LineSeriesShapes, { key: "line", dispatcher: dispatcher, seriesOptions: seriesOptions, preparedData: preparedData, htmlLayout: htmlLayout }));
83
83
  shapesData.push(...preparedData);
84
84
  }
85
85
  break;
@@ -94,7 +94,7 @@ export const useShapes = (args) => {
94
94
  yScale,
95
95
  boundsHeight,
96
96
  });
97
- acc.push(React.createElement(AreaSeriesShapes, { key: "area", dispatcher: dispatcher, seriesOptions: seriesOptions, preparedData: preparedData }));
97
+ acc.push(React.createElement(AreaSeriesShapes, { key: "area", dispatcher: dispatcher, seriesOptions: seriesOptions, preparedData: preparedData, htmlLayout: htmlLayout }));
98
98
  shapesData.push(...preparedData);
99
99
  }
100
100
  break;
@@ -108,7 +108,7 @@ export const useShapes = (args) => {
108
108
  yAxis,
109
109
  yScale,
110
110
  });
111
- acc.push(React.createElement(ScatterSeriesShape, { key: "scatter", dispatcher: dispatcher, preparedData: preparedData, seriesOptions: seriesOptions }));
111
+ acc.push(React.createElement(ScatterSeriesShape, { key: "scatter", dispatcher: dispatcher, preparedData: preparedData, seriesOptions: seriesOptions, htmlLayout: htmlLayout }));
112
112
  shapesData.push(...preparedData);
113
113
  }
114
114
  break;
@@ -119,7 +119,7 @@ export const useShapes = (args) => {
119
119
  boundsWidth,
120
120
  boundsHeight,
121
121
  });
122
- acc.push(React.createElement(PieSeriesShapes, { key: "pie", dispatcher: dispatcher, preparedData: preparedData, seriesOptions: seriesOptions }));
122
+ acc.push(React.createElement(PieSeriesShapes, { key: "pie", dispatcher: dispatcher, preparedData: preparedData, seriesOptions: seriesOptions, htmlLayout: htmlLayout }));
123
123
  shapesData.push(...preparedData);
124
124
  break;
125
125
  }
@@ -131,7 +131,7 @@ export const useShapes = (args) => {
131
131
  width: boundsWidth,
132
132
  height: boundsHeight,
133
133
  });
134
- acc.push(React.createElement(TreemapSeriesShape, { key: "treemap", dispatcher: dispatcher, preparedData: preparedData, seriesOptions: seriesOptions }));
134
+ acc.push(React.createElement(TreemapSeriesShape, { key: "treemap", dispatcher: dispatcher, preparedData: preparedData, seriesOptions: seriesOptions, htmlLayout: htmlLayout }));
135
135
  shapesData.push(preparedData);
136
136
  }
137
137
  }
@@ -6,6 +6,7 @@ type Args = {
6
6
  dispatcher: Dispatch<object>;
7
7
  preparedData: PreparedLineData[];
8
8
  seriesOptions: PreparedSeriesOptions;
9
+ htmlLayout: HTMLElement | null;
9
10
  };
10
11
  export declare const LineSeriesShapes: (args: Args) => React.JSX.Element;
11
12
  export {};
@@ -3,11 +3,12 @@ import { color, line as lineGenerator, select } from 'd3';
3
3
  import get from 'lodash/get';
4
4
  import { block } from '../../../../../../utils/cn';
5
5
  import { filterOverlappingLabels } from '../../../utils';
6
+ import { HtmlLayer } from '../HtmlLayer';
6
7
  import { getMarkerHaloVisibility, getMarkerVisibility, renderMarker, selectMarkerHalo, selectMarkerSymbol, setMarker, } from '../marker';
7
8
  import { getLineDashArray, setActiveState } from '../utils';
8
9
  const b = block('d3-line');
9
10
  export const LineSeriesShapes = (args) => {
10
- const { dispatcher, preparedData, seriesOptions } = args;
11
+ const { dispatcher, preparedData, seriesOptions, htmlLayout } = args;
11
12
  const ref = React.useRef(null);
12
13
  React.useEffect(() => {
13
14
  var _a;
@@ -124,5 +125,7 @@ export const LineSeriesShapes = (args) => {
124
125
  dispatcher.on('hover-shape.line', null);
125
126
  };
126
127
  }, [dispatcher, preparedData, seriesOptions]);
127
- return React.createElement("g", { ref: ref, className: b() });
128
+ return (React.createElement(React.Fragment, null,
129
+ React.createElement("g", { ref: ref, className: b() }),
130
+ React.createElement(HtmlLayer, { preparedData: preparedData, htmlLayout: htmlLayout })));
128
131
  };
@@ -26,6 +26,15 @@ function getLabelData(point, series, xMax) {
26
26
  }
27
27
  return labelData;
28
28
  }
29
+ function getHtmlLabel(point, series, xMax) {
30
+ const content = String(point.data.label || point.data.y);
31
+ const size = getLabelsSize({ labels: [content], html: true });
32
+ return {
33
+ x: Math.min(xMax - size.maxWidth, Math.max(0, point.x)),
34
+ y: Math.max(0, point.y - series.dataLabels.padding - size.maxHeight),
35
+ content,
36
+ };
37
+ }
29
38
  export const prepareLineData = (args) => {
30
39
  const { series, xAxis, yAxis, xScale, yScale, split } = args;
31
40
  const [_xMin, xRangeMax] = xScale.range();
@@ -43,9 +52,15 @@ export const prepareLineData = (args) => {
43
52
  data: d,
44
53
  series: s,
45
54
  }));
55
+ const htmlElements = [];
46
56
  let labels = [];
47
57
  if (s.dataLabels.enabled) {
48
- labels = points.map((p) => getLabelData(p, s, xMax));
58
+ if (s.dataLabels.html) {
59
+ htmlElements.push(...points.map((p) => getHtmlLabel(p, s, xMax)));
60
+ }
61
+ else {
62
+ labels = points.map((p) => getLabelData(p, s, xMax));
63
+ }
49
64
  }
50
65
  let markers = [];
51
66
  if (s.marker.states.normal.enabled || s.marker.states.hover.enabled) {
@@ -68,6 +83,7 @@ export const prepareLineData = (args) => {
68
83
  dashStyle: s.dashStyle,
69
84
  linecap: s.linecap,
70
85
  opacity: s.opacity,
86
+ htmlElements,
71
87
  };
72
88
  acc.push(result);
73
89
  return acc;
@@ -1,6 +1,6 @@
1
1
  import { DashStyle, LineCap } from '../../../../../../constants';
2
2
  import { LineSeriesData } from '../../../../../../types';
3
- import { LabelData } from '../../../types';
3
+ import { HtmlItem, LabelData } from '../../../types';
4
4
  import { PreparedLineSeries } from '../../useSeries/types';
5
5
  export type PointData = {
6
6
  x: number;
@@ -26,4 +26,5 @@ export type PreparedLineData = {
26
26
  dashStyle: DashStyle;
27
27
  linecap: LineCap;
28
28
  opacity: number | null;
29
+ htmlElements: HtmlItem[];
29
30
  };
@@ -6,6 +6,7 @@ type PreparePieSeriesArgs = {
6
6
  dispatcher: Dispatch<object>;
7
7
  preparedData: PreparedPieData[];
8
8
  seriesOptions: PreparedSeriesOptions;
9
+ htmlLayout: HTMLElement | null;
9
10
  };
10
11
  export declare function getHaloVisibility(d: PieArcDatum<SegmentData>): "" | "hidden";
11
12
  export declare function PieSeriesShapes(args: PreparePieSeriesArgs): React.JSX.Element;
@@ -1,17 +1,17 @@
1
1
  import React from 'react';
2
- import { arc, color, line as lineGenerator, select } from 'd3';
2
+ import { arc, color, select } from 'd3';
3
3
  import get from 'lodash/get';
4
4
  import { block } from '../../../../../../utils/cn';
5
5
  import { setEllipsisForOverflowTexts } from '../../../utils';
6
+ import { HtmlLayer } from '../HtmlLayer';
6
7
  import { setActiveState } from '../utils';
7
- import { getCurveFactory } from './utils';
8
8
  const b = block('d3-pie');
9
9
  export function getHaloVisibility(d) {
10
10
  const enabled = d.data.pie.halo.enabled && d.data.hovered;
11
11
  return enabled ? '' : 'hidden';
12
12
  }
13
13
  export function PieSeriesShapes(args) {
14
- const { dispatcher, preparedData, seriesOptions } = args;
14
+ const { dispatcher, preparedData, seriesOptions, htmlLayout } = args;
15
15
  const ref = React.useRef(null);
16
16
  React.useEffect(() => {
17
17
  if (!ref.current) {
@@ -71,6 +71,7 @@ export function PieSeriesShapes(args) {
71
71
  .attr('class', b('segment'))
72
72
  .attr('fill', (d) => d.data.color)
73
73
  .attr('opacity', (d) => d.data.opacity);
74
+ // render Labels
74
75
  shapesSelection
75
76
  .selectAll('text')
76
77
  .data((pieData) => pieData.labels)
@@ -87,19 +88,12 @@ export function PieSeriesShapes(args) {
87
88
  // Add the polyline between chart and labels
88
89
  shapesSelection
89
90
  .selectAll(connectorSelector)
90
- .data((pieData) => pieData.labels)
91
+ .data((pieData) => pieData.connectors)
91
92
  .enter()
92
93
  .append('path')
93
94
  .attr('class', b('connector'))
94
- .attr('d', (d) => {
95
- let line = lineGenerator();
96
- const curveFactory = getCurveFactory(d.segment.pie);
97
- if (curveFactory) {
98
- line = line.curve(curveFactory);
99
- }
100
- return line(d.connector.points);
101
- })
102
- .attr('stroke', (d) => d.connector.color)
95
+ .attr('d', (d) => d.path)
96
+ .attr('stroke', (d) => d.color)
103
97
  .attr('stroke-width', 1)
104
98
  .attr('stroke-linejoin', 'round')
105
99
  .attr('stroke-linecap', 'round')
@@ -172,5 +166,7 @@ export function PieSeriesShapes(args) {
172
166
  dispatcher.on(eventName, null);
173
167
  };
174
168
  }, [dispatcher, preparedData, seriesOptions]);
175
- return React.createElement("g", { ref: ref, className: b(), style: { zIndex: 9 } });
169
+ return (React.createElement(React.Fragment, null,
170
+ React.createElement("g", { ref: ref, className: b(), style: { zIndex: 9 } }),
171
+ React.createElement(HtmlLayer, { preparedData: preparedData, htmlLayout: htmlLayout })));
176
172
  }