@gravity-ui/chartkit 5.3.3 → 5.5.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 (52) hide show
  1. package/build/constants/widget-data.d.ts +1 -0
  2. package/build/constants/widget-data.js +1 -0
  3. package/build/plugins/d3/renderer/components/Chart.js +28 -8
  4. package/build/plugins/d3/renderer/components/Tooltip/DefaultContent.js +70 -40
  5. package/build/plugins/d3/renderer/components/Tooltip/index.d.ts +2 -5
  6. package/build/plugins/d3/renderer/components/Tooltip/index.js +4 -3
  7. package/build/plugins/d3/renderer/components/styles.css +14 -0
  8. package/build/plugins/d3/renderer/constants/defaults/series-options.d.ts +7 -1
  9. package/build/plugins/d3/renderer/constants/defaults/series-options.js +14 -0
  10. package/build/plugins/d3/renderer/hooks/useChartOptions/y-axis.js +13 -3
  11. package/build/plugins/d3/renderer/hooks/useSeries/prepare-waterfall.d.ts +10 -0
  12. package/build/plugins/d3/renderer/hooks/useSeries/prepare-waterfall.js +36 -0
  13. package/build/plugins/d3/renderer/hooks/useSeries/prepareSeries.js +8 -0
  14. package/build/plugins/d3/renderer/hooks/useSeries/types.d.ts +14 -2
  15. package/build/plugins/d3/renderer/hooks/useShapes/area/index.js +13 -10
  16. package/build/plugins/d3/renderer/hooks/useShapes/index.d.ts +2 -2
  17. package/build/plugins/d3/renderer/hooks/useShapes/index.js +23 -5
  18. package/build/plugins/d3/renderer/hooks/useShapes/line/index.js +13 -10
  19. package/build/plugins/d3/renderer/hooks/useShapes/pie/index.d.ts +0 -1
  20. package/build/plugins/d3/renderer/hooks/useShapes/pie/index.js +6 -23
  21. package/build/plugins/d3/renderer/hooks/useShapes/scatter/index.d.ts +0 -1
  22. package/build/plugins/d3/renderer/hooks/useShapes/scatter/index.js +4 -24
  23. package/build/plugins/d3/renderer/hooks/useShapes/styles.css +4 -0
  24. package/build/plugins/d3/renderer/hooks/useShapes/treemap/index.d.ts +0 -1
  25. package/build/plugins/d3/renderer/hooks/useShapes/treemap/index.js +6 -13
  26. package/build/plugins/d3/renderer/hooks/useShapes/waterfall/index.d.ts +12 -0
  27. package/build/plugins/d3/renderer/hooks/useShapes/waterfall/index.js +125 -0
  28. package/build/plugins/d3/renderer/hooks/useShapes/waterfall/prepare-data.d.ts +12 -0
  29. package/build/plugins/d3/renderer/hooks/useShapes/waterfall/prepare-data.js +132 -0
  30. package/build/plugins/d3/renderer/hooks/useShapes/waterfall/types.d.ts +14 -0
  31. package/build/plugins/d3/renderer/hooks/useShapes/waterfall/types.js +1 -0
  32. package/build/plugins/d3/renderer/utils/get-closest-data.d.ts +15 -0
  33. package/build/plugins/d3/renderer/utils/get-closest-data.js +167 -0
  34. package/build/plugins/d3/renderer/utils/index.d.ts +1 -5
  35. package/build/plugins/d3/renderer/utils/index.js +11 -7
  36. package/build/plugins/d3/renderer/utils/series/index.d.ts +1 -0
  37. package/build/plugins/d3/renderer/utils/series/index.js +1 -0
  38. package/build/plugins/d3/renderer/utils/series/waterfall.d.ts +4 -0
  39. package/build/plugins/d3/renderer/utils/series/waterfall.js +25 -0
  40. package/build/plugins/highcharts/renderer/components/HighchartsComponent.d.ts +1 -1
  41. package/build/plugins/highcharts/renderer/helpers/config/config.d.ts +1 -1
  42. package/build/plugins/highcharts/renderer/helpers/config/config.js +2 -6
  43. package/build/plugins/highcharts/renderer/helpers/graph.d.ts +1 -1
  44. package/build/types/widget-data/index.d.ts +1 -0
  45. package/build/types/widget-data/index.js +1 -0
  46. package/build/types/widget-data/series.d.ts +21 -2
  47. package/build/types/widget-data/tooltip.d.ts +8 -1
  48. package/build/types/widget-data/waterfall.d.ts +39 -0
  49. package/build/types/widget-data/waterfall.js +1 -0
  50. package/package.json +1 -1
  51. package/build/plugins/d3/renderer/components/Tooltip/TooltipTriggerArea.d.ts +0 -12
  52. package/build/plugins/d3/renderer/components/Tooltip/TooltipTriggerArea.js +0 -153
@@ -61,13 +61,12 @@ export const LineSeriesShapes = (args) => {
61
61
  const hoverEnabled = hoverOptions === null || hoverOptions === void 0 ? void 0 : hoverOptions.enabled;
62
62
  const inactiveEnabled = inactiveOptions === null || inactiveOptions === void 0 ? void 0 : inactiveOptions.enabled;
63
63
  dispatcher.on('hover-shape.line', (data) => {
64
- var _a;
65
- const selected = data === null || data === void 0 ? void 0 : data.find((d) => d.series.type === 'line');
66
- const selectedDataItem = selected === null || selected === void 0 ? void 0 : selected.data;
67
- const selectedSeriesId = (_a = selected === null || selected === void 0 ? void 0 : selected.series) === null || _a === void 0 ? void 0 : _a.id;
64
+ const selected = (data === null || data === void 0 ? void 0 : data.filter((d) => d.series.type === 'line')) || [];
65
+ const selectedDataItems = selected.map((d) => d.data);
66
+ const selectedSeriesIds = selected.map((d) => { var _a; return (_a = d.series) === null || _a === void 0 ? void 0 : _a.id; });
68
67
  lineSelection.datum((d, index, list) => {
69
68
  const elementSelection = select(list[index]);
70
- const hovered = Boolean(hoverEnabled && d.id === selectedSeriesId);
69
+ const hovered = Boolean(hoverEnabled && selectedSeriesIds.includes(d.id));
71
70
  if (d.hovered !== hovered) {
72
71
  d.hovered = hovered;
73
72
  elementSelection.attr('stroke', (d) => {
@@ -82,7 +81,9 @@ export const LineSeriesShapes = (args) => {
82
81
  return setActiveState({
83
82
  element: list[index],
84
83
  state: inactiveOptions,
85
- active: Boolean(!inactiveEnabled || !selectedSeriesId || selectedSeriesId === d.id),
84
+ active: Boolean(!inactiveEnabled ||
85
+ !selectedSeriesIds.length ||
86
+ selectedSeriesIds.includes(d.id)),
86
87
  datum: d,
87
88
  });
88
89
  });
@@ -90,13 +91,15 @@ export const LineSeriesShapes = (args) => {
90
91
  return setActiveState({
91
92
  element: list[index],
92
93
  state: inactiveOptions,
93
- active: Boolean(!inactiveEnabled || !selectedSeriesId || selectedSeriesId === d.series.id),
94
+ active: Boolean(!inactiveEnabled ||
95
+ !selectedSeriesIds.length ||
96
+ selectedSeriesIds.includes(d.series.id)),
94
97
  datum: d,
95
98
  });
96
99
  });
97
100
  markerSelection.datum((d, index, list) => {
98
101
  const elementSelection = select(list[index]);
99
- const hovered = Boolean(hoverEnabled && d.point.data === selectedDataItem);
102
+ const hovered = Boolean(hoverEnabled && selectedDataItems.includes(d.point.data));
100
103
  if (d.hovered !== hovered) {
101
104
  d.hovered = hovered;
102
105
  elementSelection.attr('visibility', getMarkerVisibility(d));
@@ -105,8 +108,8 @@ export const LineSeriesShapes = (args) => {
105
108
  }
106
109
  if (d.point.series.marker.states.normal.enabled) {
107
110
  const isActive = Boolean(!inactiveEnabled ||
108
- !selectedSeriesId ||
109
- selectedSeriesId === d.point.series.id);
111
+ !selectedSeriesIds.length ||
112
+ selectedSeriesIds.includes(d.point.series.id));
110
113
  setActiveState({
111
114
  element: list[index],
112
115
  state: inactiveOptions,
@@ -6,7 +6,6 @@ type PreparePieSeriesArgs = {
6
6
  dispatcher: Dispatch<object>;
7
7
  preparedData: PreparedPieData[];
8
8
  seriesOptions: PreparedSeriesOptions;
9
- svgContainer: SVGSVGElement | null;
10
9
  };
11
10
  export declare function getHaloVisibility(d: PieArcDatum<SegmentData>): "" | "hidden";
12
11
  export declare function PieSeriesShapes(args: PreparePieSeriesArgs): React.JSX.Element;
@@ -1,5 +1,5 @@
1
1
  import React from 'react';
2
- import { arc, color, line as lineGenerator, pointer, select } from 'd3';
2
+ import { arc, color, line as lineGenerator, select } from 'd3';
3
3
  import get from 'lodash/get';
4
4
  import { block } from '../../../../../../utils/cn';
5
5
  import { setEllipsisForOverflowTexts } from '../../../utils';
@@ -11,7 +11,7 @@ export function getHaloVisibility(d) {
11
11
  return enabled ? '' : 'hidden';
12
12
  }
13
13
  export function PieSeriesShapes(args) {
14
- const { dispatcher, preparedData, seriesOptions, svgContainer } = args;
14
+ const { dispatcher, preparedData, seriesOptions } = args;
15
15
  const ref = React.useRef(null);
16
16
  React.useEffect(() => {
17
17
  if (!ref.current) {
@@ -127,32 +127,15 @@ export function PieSeriesShapes(args) {
127
127
  const eventName = `hover-shape.pie`;
128
128
  const hoverOptions = get(seriesOptions, 'pie.states.hover');
129
129
  const inactiveOptions = get(seriesOptions, 'pie.states.inactive');
130
- svgElement
131
- .on('mousemove', (e) => {
132
- const currentSegment = getSelectedSegment(e.target);
133
- if (currentSegment) {
134
- const data = {
135
- series: {
136
- id: currentSegment.series.id,
137
- type: 'pie',
138
- name: currentSegment.series.name,
139
- },
140
- data: currentSegment.series.data,
141
- };
142
- dispatcher.call('hover-shape', {}, [data], pointer(e, svgContainer));
143
- }
144
- })
145
- .on('mouseleave', () => {
146
- dispatcher.call('hover-shape', {}, undefined);
147
- })
148
- .on('click', (e) => {
130
+ svgElement.on('click', (e) => {
149
131
  const selectedSegment = getSelectedSegment(e.target);
150
132
  if (selectedSegment) {
151
133
  dispatcher.call('click-chart', undefined, { point: selectedSegment.series.data, series: selectedSegment.series }, e);
152
134
  }
153
135
  });
154
136
  dispatcher.on(eventName, (data) => {
155
- const selectedSeriesId = data === null || data === void 0 ? void 0 : data[0].series.id;
137
+ var _a, _b;
138
+ const selectedSeriesId = (_b = (_a = data === null || data === void 0 ? void 0 : data[0]) === null || _a === void 0 ? void 0 : _a.series) === null || _b === void 0 ? void 0 : _b.id;
156
139
  const hoverEnabled = hoverOptions === null || hoverOptions === void 0 ? void 0 : hoverOptions.enabled;
157
140
  const inactiveEnabled = inactiveOptions === null || inactiveOptions === void 0 ? void 0 : inactiveOptions.enabled;
158
141
  shapesSelection.datum((_d, index, list) => {
@@ -202,6 +185,6 @@ export function PieSeriesShapes(args) {
202
185
  return () => {
203
186
  dispatcher.on(eventName, null);
204
187
  };
205
- }, [dispatcher, preparedData, seriesOptions, svgContainer]);
188
+ }, [dispatcher, preparedData, seriesOptions]);
206
189
  return React.createElement("g", { ref: ref, className: b(), style: { zIndex: 9 } });
207
190
  }
@@ -7,6 +7,5 @@ type ScatterSeriesShapeProps = {
7
7
  dispatcher: Dispatch<object>;
8
8
  preparedData: PreparedScatterData[];
9
9
  seriesOptions: PreparedSeriesOptions;
10
- svgContainer: SVGSVGElement | null;
11
10
  };
12
11
  export declare function ScatterSeriesShape(props: ScatterSeriesShapeProps): React.JSX.Element;
@@ -1,5 +1,5 @@
1
1
  import React from 'react';
2
- import { pointer, select } from 'd3';
2
+ import { select } from 'd3';
3
3
  import get from 'lodash/get';
4
4
  import { block } from '../../../../../../utils/cn';
5
5
  import { getMarkerHaloVisibility, renderMarker, selectMarkerHalo, selectMarkerSymbol, setMarker, } from '../marker';
@@ -7,7 +7,7 @@ import { setActiveState, shapeKey } from '../utils';
7
7
  export { prepareScatterData } from './prepare-data';
8
8
  const b = block('d3-scatter');
9
9
  export function ScatterSeriesShape(props) {
10
- const { dispatcher, preparedData, seriesOptions, svgContainer } = props;
10
+ const { dispatcher, preparedData, seriesOptions } = props;
11
11
  const ref = React.useRef(null);
12
12
  React.useEffect(() => {
13
13
  if (!ref.current) {
@@ -28,27 +28,7 @@ export function ScatterSeriesShape(props) {
28
28
  const getSelectedPoint = (element) => {
29
29
  return select(element).datum();
30
30
  };
31
- svgElement
32
- .on('mousemove', (e) => {
33
- const datum = getSelectedPoint(e.target);
34
- if (!datum) {
35
- return;
36
- }
37
- const [pointerX, pointerY] = pointer(e, svgContainer);
38
- const data = {
39
- series: {
40
- id: datum.point.series.id,
41
- type: 'scatter',
42
- name: datum.point.series.name,
43
- },
44
- data: datum.point.data,
45
- };
46
- dispatcher.call('hover-shape', {}, [data], [pointerX, pointerY]);
47
- })
48
- .on('mouseleave', () => {
49
- dispatcher.call('hover-shape', {}, undefined);
50
- })
51
- .on('click', (e) => {
31
+ svgElement.on('click', (e) => {
52
32
  const datum = getSelectedPoint(e.target);
53
33
  if (datum) {
54
34
  dispatcher.call('click-chart', undefined, { point: datum.point.data, series: datum.point.series }, e);
@@ -90,6 +70,6 @@ export function ScatterSeriesShape(props) {
90
70
  return () => {
91
71
  dispatcher.on('hover-shape.scatter', null);
92
72
  };
93
- }, [dispatcher, preparedData, seriesOptions, svgContainer]);
73
+ }, [dispatcher, preparedData, seriesOptions]);
94
74
  return React.createElement("g", { ref: ref, className: b() });
95
75
  }
@@ -29,4 +29,8 @@
29
29
  alignment-baseline: text-before-edge;
30
30
  user-select: none;
31
31
  pointer-events: none;
32
+ }
33
+
34
+ .chartkit-d3-waterfall__connector {
35
+ stroke: var(--g-color-line-generic-active);
32
36
  }
@@ -6,7 +6,6 @@ type ShapeProps = {
6
6
  dispatcher: Dispatch<object>;
7
7
  preparedData: PreparedTreemapData;
8
8
  seriesOptions: PreparedSeriesOptions;
9
- svgContainer: SVGSVGElement | null;
10
9
  };
11
10
  export declare const TreemapSeriesShape: (props: ShapeProps) => React.JSX.Element;
12
11
  export {};
@@ -1,11 +1,11 @@
1
1
  import React from 'react';
2
- import { color, pointer, select } from 'd3';
2
+ import { 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
6
  const b = block('d3-treemap');
7
7
  export const TreemapSeriesShape = (props) => {
8
- const { dispatcher, preparedData, seriesOptions, svgContainer } = props;
8
+ const { dispatcher, preparedData, seriesOptions } = props;
9
9
  const ref = React.useRef(null);
10
10
  React.useEffect(() => {
11
11
  if (!ref.current) {
@@ -52,22 +52,15 @@ export const TreemapSeriesShape = (props) => {
52
52
  const eventName = `hover-shape.treemap`;
53
53
  const hoverOptions = get(seriesOptions, 'treemap.states.hover');
54
54
  const inactiveOptions = get(seriesOptions, 'treemap.states.inactive');
55
- svgElement
56
- .on('mousemove', (e) => {
57
- const datum = getSelectedPart(e.target);
58
- dispatcher.call('hover-shape', {}, [{ data: datum.data, series }], pointer(e, svgContainer));
59
- })
60
- .on('mouseleave', () => {
61
- dispatcher.call('hover-shape', {}, undefined);
62
- })
63
- .on('click', (e) => {
55
+ svgElement.on('click', (e) => {
64
56
  const datum = getSelectedPart(e.target);
65
57
  dispatcher.call('click-chart', undefined, { point: datum.data, series }, e);
66
58
  });
67
59
  dispatcher.on(eventName, (data) => {
60
+ var _a;
68
61
  const hoverEnabled = hoverOptions === null || hoverOptions === void 0 ? void 0 : hoverOptions.enabled;
69
62
  const inactiveEnabled = inactiveOptions === null || inactiveOptions === void 0 ? void 0 : inactiveOptions.enabled;
70
- const hoveredData = data === null || data === void 0 ? void 0 : data[0].data;
63
+ const hoveredData = (_a = data === null || data === void 0 ? void 0 : data[0]) === null || _a === void 0 ? void 0 : _a.data;
71
64
  rectSelection.datum((d, index, list) => {
72
65
  const currentRect = select(list[index]);
73
66
  const hovered = Boolean(hoverEnabled && hoveredData === d.data);
@@ -106,6 +99,6 @@ export const TreemapSeriesShape = (props) => {
106
99
  return () => {
107
100
  dispatcher.on(eventName, null);
108
101
  };
109
- }, [dispatcher, preparedData, seriesOptions, svgContainer]);
102
+ }, [dispatcher, preparedData, seriesOptions]);
110
103
  return React.createElement("g", { ref: ref, className: b() });
111
104
  };
@@ -0,0 +1,12 @@
1
+ import React from 'react';
2
+ import type { Dispatch } from 'd3';
3
+ import type { PreparedSeriesOptions } from '../../useSeries/types';
4
+ import type { PreparedWaterfallData } from './types';
5
+ export { prepareWaterfallData } from './prepare-data';
6
+ export * from './types';
7
+ type Args = {
8
+ dispatcher: Dispatch<object>;
9
+ preparedData: PreparedWaterfallData[];
10
+ seriesOptions: PreparedSeriesOptions;
11
+ };
12
+ export declare const WaterfallSeriesShapes: (args: Args) => React.JSX.Element;
@@ -0,0 +1,125 @@
1
+ import React from 'react';
2
+ import { color, line as lineGenerator, select } from 'd3';
3
+ import get from 'lodash/get';
4
+ import { DashStyle } from '../../../../../../constants';
5
+ import { block } from '../../../../../../utils/cn';
6
+ import { filterOverlappingLabels, getWaterfallPointColor } from '../../../utils';
7
+ import { getLineDashArray } from '../utils';
8
+ export { prepareWaterfallData } from './prepare-data';
9
+ export * from './types';
10
+ const b = block('d3-waterfall');
11
+ export const WaterfallSeriesShapes = (args) => {
12
+ const { dispatcher, preparedData, seriesOptions } = args;
13
+ const ref = React.useRef(null);
14
+ const connectorSelector = `.${b('connector')}`;
15
+ React.useEffect(() => {
16
+ var _a;
17
+ if (!ref.current) {
18
+ return () => { };
19
+ }
20
+ const svgElement = select(ref.current);
21
+ const hoverOptions = get(seriesOptions, 'waterfall.states.hover');
22
+ const inactiveOptions = get(seriesOptions, 'waterfall.states.inactive');
23
+ svgElement.selectAll('*').remove();
24
+ const rectSelection = svgElement
25
+ .selectAll('allRects')
26
+ .data(preparedData)
27
+ .join('rect')
28
+ .attr('class', b('segment'))
29
+ .attr('x', (d) => d.x)
30
+ .attr('y', (d) => d.y)
31
+ .attr('height', (d) => d.height)
32
+ .attr('width', (d) => d.width)
33
+ .attr('fill', (d) => getWaterfallPointColor(d.data, d.series))
34
+ .attr('opacity', (d) => d.opacity)
35
+ .attr('cursor', (d) => d.series.cursor);
36
+ let dataLabels = preparedData.map((d) => d.label).filter(Boolean);
37
+ if (!((_a = preparedData[0]) === null || _a === void 0 ? void 0 : _a.series.dataLabels.allowOverlap)) {
38
+ dataLabels = filterOverlappingLabels(dataLabels);
39
+ }
40
+ const labelSelection = svgElement
41
+ .selectAll('text')
42
+ .data(dataLabels)
43
+ .join('text')
44
+ .text((d) => d.text)
45
+ .attr('class', b('label'))
46
+ .attr('x', (d) => d.x)
47
+ .attr('y', (d) => d.y)
48
+ .attr('text-anchor', (d) => d.textAnchor)
49
+ .style('font-size', (d) => d.style.fontSize)
50
+ .style('font-weight', (d) => d.style.fontWeight || null)
51
+ .style('fill', (d) => d.style.fontColor || null);
52
+ // Add the connector line between bars
53
+ svgElement
54
+ .selectAll(connectorSelector)
55
+ .data(preparedData)
56
+ .join('path')
57
+ .attr('class', b('connector'))
58
+ .attr('d', (d, index) => {
59
+ const line = lineGenerator();
60
+ const prev = preparedData[index - 1];
61
+ if (!prev) {
62
+ return null;
63
+ }
64
+ const points = [];
65
+ if (Number(prev.data.y) > 0) {
66
+ points.push([prev.x, prev.y]);
67
+ }
68
+ else {
69
+ points.push([prev.x, prev.y + prev.height]);
70
+ }
71
+ if (Number(d.data.y) > 0 && !d.data.total) {
72
+ points.push([d.x + d.width, d.y + d.height]);
73
+ }
74
+ else {
75
+ points.push([d.x + d.width, d.y]);
76
+ }
77
+ return line(points);
78
+ })
79
+ .attr('stroke-width', 1)
80
+ .attr('stroke-dasharray', () => getLineDashArray(DashStyle.Dash, 1));
81
+ dispatcher.on('hover-shape.waterfall', (data) => {
82
+ const hoverEnabled = hoverOptions === null || hoverOptions === void 0 ? void 0 : hoverOptions.enabled;
83
+ const inactiveEnabled = inactiveOptions === null || inactiveOptions === void 0 ? void 0 : inactiveOptions.enabled;
84
+ if (!data) {
85
+ if (hoverEnabled) {
86
+ rectSelection.attr('fill', (d) => getWaterfallPointColor(d.data, d.series));
87
+ }
88
+ if (inactiveEnabled) {
89
+ rectSelection.attr('opacity', null);
90
+ labelSelection.attr('opacity', null);
91
+ }
92
+ return;
93
+ }
94
+ if (hoverEnabled) {
95
+ const hoveredValues = data.map((d) => d.data.x);
96
+ rectSelection.attr('fill', (d) => {
97
+ var _a;
98
+ const fillColor = getWaterfallPointColor(d.data, d.series);
99
+ if (hoveredValues.includes(d.data.x)) {
100
+ const brightness = hoverOptions === null || hoverOptions === void 0 ? void 0 : hoverOptions.brightness;
101
+ return ((_a = color(fillColor)) === null || _a === void 0 ? void 0 : _a.brighter(brightness).toString()) || fillColor;
102
+ }
103
+ return fillColor;
104
+ });
105
+ }
106
+ if (inactiveEnabled) {
107
+ const hoveredSeries = data.map((d) => d.series.id);
108
+ rectSelection.attr('opacity', (d) => {
109
+ return hoveredSeries.includes(d.series.id)
110
+ ? null
111
+ : (inactiveOptions === null || inactiveOptions === void 0 ? void 0 : inactiveOptions.opacity) || null;
112
+ });
113
+ labelSelection.attr('opacity', (d) => {
114
+ return hoveredSeries.includes(d.series.id)
115
+ ? null
116
+ : (inactiveOptions === null || inactiveOptions === void 0 ? void 0 : inactiveOptions.opacity) || null;
117
+ });
118
+ }
119
+ });
120
+ return () => {
121
+ dispatcher.on('hover-shape.waterfall', null);
122
+ };
123
+ }, [dispatcher, preparedData, seriesOptions]);
124
+ return React.createElement("g", { ref: ref, className: b() });
125
+ };
@@ -0,0 +1,12 @@
1
+ import type { ChartScale } from '../../useAxisScales';
2
+ import type { PreparedAxis } from '../../useChartOptions/types';
3
+ import type { PreparedSeriesOptions, PreparedWaterfallSeries } from '../../useSeries/types';
4
+ import type { PreparedWaterfallData } from './types';
5
+ export declare const prepareWaterfallData: (args: {
6
+ series: PreparedWaterfallSeries[];
7
+ seriesOptions: PreparedSeriesOptions;
8
+ xAxis: PreparedAxis;
9
+ xScale: ChartScale;
10
+ yAxis: PreparedAxis[];
11
+ yScale: ChartScale;
12
+ }) => PreparedWaterfallData[];
@@ -0,0 +1,132 @@
1
+ import get from 'lodash/get';
2
+ import sortBy from 'lodash/sortBy';
3
+ import { getLabelsSize } from '../../../utils';
4
+ import { MIN_BAR_GAP, MIN_BAR_WIDTH } from '../constants';
5
+ import { getXValue, getYValue } from '../utils';
6
+ function getLabelData(d, plotHeight) {
7
+ if (!d.series.dataLabels.enabled) {
8
+ return undefined;
9
+ }
10
+ const text = String(d.data.label || d.subTotal);
11
+ const style = d.series.dataLabels.style;
12
+ const { maxHeight: height, maxWidth: width } = getLabelsSize({ labels: [text], style });
13
+ let y;
14
+ if (Number(d.data.y) > 0 || d.data.total) {
15
+ y = Math.max(height, d.y - d.series.dataLabels.padding);
16
+ }
17
+ else {
18
+ y = Math.min(plotHeight - d.series.dataLabels.padding, d.y + d.height + d.series.dataLabels.padding + height);
19
+ }
20
+ return {
21
+ text,
22
+ x: d.x + d.width / 2,
23
+ y,
24
+ style,
25
+ size: { width, height },
26
+ textAnchor: 'middle',
27
+ series: d.series,
28
+ };
29
+ }
30
+ function getBandWidth(args) {
31
+ const { series, xAxis, xScale } = args;
32
+ if (xAxis.type === 'category') {
33
+ const xBandScale = xScale;
34
+ return xBandScale.bandwidth();
35
+ }
36
+ const xLinearScale = xScale;
37
+ const xValues = series.reduce((acc, s) => {
38
+ s.data.forEach((dataItem) => acc.push(Number(dataItem.x)));
39
+ return acc;
40
+ }, []);
41
+ let bandWidth = Infinity;
42
+ xValues.sort().forEach((xValue, index) => {
43
+ if (index > 0 && xValue !== xValues[index - 1]) {
44
+ const dist = xLinearScale(xValue) - xLinearScale(xValues[index - 1]);
45
+ if (dist < bandWidth) {
46
+ bandWidth = dist;
47
+ }
48
+ }
49
+ });
50
+ return bandWidth;
51
+ }
52
+ export const prepareWaterfallData = (args) => {
53
+ const { series, seriesOptions, xAxis, xScale, yAxis: [yAxis], yScale, } = args;
54
+ const yLinearScale = yScale;
55
+ const plotHeight = yLinearScale(yLinearScale.domain()[0]);
56
+ const barMaxWidth = get(seriesOptions, 'waterfall.barMaxWidth');
57
+ const barPadding = get(seriesOptions, 'waterfall.barPadding');
58
+ const flattenData = series.reduce((acc, s) => {
59
+ acc.push(...s.data.map((d) => ({ data: d, series: s })));
60
+ return acc;
61
+ }, []);
62
+ const data = sortBy(flattenData, (d) => d.data.x);
63
+ const bandWidth = getBandWidth({
64
+ series,
65
+ xAxis,
66
+ xScale,
67
+ });
68
+ const rectGap = Math.max(bandWidth * barPadding, MIN_BAR_GAP);
69
+ const rectWidth = Math.max(MIN_BAR_WIDTH, Math.min(bandWidth - rectGap, barMaxWidth));
70
+ const yZero = getYValue({
71
+ point: { y: 0 },
72
+ yScale,
73
+ yAxis,
74
+ });
75
+ let totalValue = 0;
76
+ const result = [];
77
+ data.forEach((item, _index) => {
78
+ if (typeof item.data.y !== 'number' && !item.data.total) {
79
+ return;
80
+ }
81
+ if (!item.data.total) {
82
+ totalValue += Number(item.data.y);
83
+ }
84
+ const prevPoint = result[result.length - 1];
85
+ const xCenter = getXValue({ point: item.data, xAxis, xScale });
86
+ const x = xCenter - rectWidth / 2;
87
+ const yValue = Number(item.data.total ? totalValue : item.data.y);
88
+ const height = yZero -
89
+ getYValue({
90
+ point: { y: Math.abs(yValue) },
91
+ yScale,
92
+ yAxis,
93
+ });
94
+ let y;
95
+ if (!prevPoint || item.data.total) {
96
+ y = getYValue({
97
+ point: {
98
+ y: yValue > 0 ? yValue : 0,
99
+ },
100
+ yScale,
101
+ yAxis,
102
+ });
103
+ }
104
+ else if (Number(prevPoint.data.y) < 0) {
105
+ if (Number(item.data.y) > 0) {
106
+ y = prevPoint.y + prevPoint.height - height;
107
+ }
108
+ else {
109
+ y = prevPoint.y + prevPoint.height;
110
+ }
111
+ }
112
+ else if (Number(item.data.y) < 0) {
113
+ y = prevPoint.y;
114
+ }
115
+ else {
116
+ y = prevPoint.y - height;
117
+ }
118
+ const preparedData = {
119
+ x,
120
+ y,
121
+ width: rectWidth,
122
+ height,
123
+ opacity: get(item.data, 'opacity', null),
124
+ data: item.data,
125
+ series: item.series,
126
+ subTotal: totalValue,
127
+ };
128
+ preparedData.label = getLabelData(preparedData, plotHeight);
129
+ result.push(preparedData);
130
+ });
131
+ return result;
132
+ };
@@ -0,0 +1,14 @@
1
+ import { WaterfallSeriesData } from '../../../../../../types';
2
+ import { LabelData } from '../../../types';
3
+ import { PreparedWaterfallSeries } from '../../useSeries/types';
4
+ export type PreparedWaterfallData = {
5
+ x: number;
6
+ y: number;
7
+ width: number;
8
+ height: number;
9
+ opacity: number | null;
10
+ series: PreparedWaterfallSeries;
11
+ data: WaterfallSeriesData;
12
+ label?: LabelData;
13
+ subTotal: number;
14
+ };
@@ -0,0 +1,15 @@
1
+ import type { ChartKitWidgetSeries, ChartKitWidgetSeriesData, TooltipDataChunk } from '../../../../types';
2
+ import type { ShapeData } from '../hooks';
3
+ type GetClosestPointsArgs = {
4
+ position: [number, number];
5
+ shapesData: ShapeData[];
6
+ };
7
+ export type ShapePoint = {
8
+ x: number;
9
+ y0: number;
10
+ y1: number;
11
+ data: ChartKitWidgetSeriesData;
12
+ series: ChartKitWidgetSeries;
13
+ };
14
+ export declare function getClosestPoints(args: GetClosestPointsArgs): TooltipDataChunk[];
15
+ export {};