@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
@@ -6,6 +6,7 @@ export declare const SeriesType: {
6
6
  readonly Pie: "pie";
7
7
  readonly Scatter: "scatter";
8
8
  readonly Treemap: "treemap";
9
+ readonly Waterfall: "waterfall";
9
10
  };
10
11
  export declare enum DashStyle {
11
12
  Dash = "Dash",
@@ -6,6 +6,7 @@ export const SeriesType = {
6
6
  Pie: 'pie',
7
7
  Scatter: 'scatter',
8
8
  Treemap: 'treemap',
9
+ Waterfall: 'waterfall',
9
10
  };
10
11
  export var DashStyle;
11
12
  (function (DashStyle) {
@@ -1,17 +1,21 @@
1
1
  import React from 'react';
2
+ import { pointer } from 'd3';
3
+ import throttle from 'lodash/throttle';
2
4
  import { block } from '../../../../utils/cn';
3
5
  import { getD3Dispatcher } from '../d3-dispatcher';
4
- import { useAxisScales, useChartDimensions, useChartOptions, useSeries, useShapes, useTooltip, } from '../hooks';
6
+ import { useAxisScales, useChartDimensions, useChartOptions, useSeries, useShapes } from '../hooks';
5
7
  import { getWidthOccupiedByYAxis } from '../hooks/useChartDimensions/utils';
6
8
  import { getPreparedXAxis } from '../hooks/useChartOptions/x-axis';
7
9
  import { getPreparedYAxis } from '../hooks/useChartOptions/y-axis';
10
+ import { getClosestPoints } from '../utils/get-closest-data';
8
11
  import { AxisX } from './AxisX';
9
12
  import { AxisY } from './AxisY';
10
13
  import { Legend } from './Legend';
11
14
  import { Title } from './Title';
12
- import { Tooltip, TooltipTriggerArea } from './Tooltip';
15
+ import { Tooltip } from './Tooltip';
13
16
  import './styles.css';
14
17
  const b = block('d3');
18
+ const THROTTLE_DELAY = 50;
15
19
  export const Chart = (props) => {
16
20
  var _a, _b;
17
21
  const { width, height, data } = props;
@@ -48,7 +52,6 @@ export const Chart = (props) => {
48
52
  xAxis,
49
53
  yAxis,
50
54
  });
51
- const { hovered, pointerPosition } = useTooltip({ dispatcher, tooltip });
52
55
  const { shapes, shapesData } = useShapes({
53
56
  boundsWidth,
54
57
  boundsHeight,
@@ -59,7 +62,6 @@ export const Chart = (props) => {
59
62
  xScale,
60
63
  yAxis,
61
64
  yScale,
62
- svgContainer: svgRef.current,
63
65
  });
64
66
  const clickHandler = (_b = (_a = data.chart) === null || _a === void 0 ? void 0 : _a.events) === null || _b === void 0 ? void 0 : _b.click;
65
67
  React.useEffect(() => {
@@ -72,16 +74,34 @@ export const Chart = (props) => {
72
74
  }, [dispatcher, clickHandler]);
73
75
  const boundsOffsetTop = chart.margin.top;
74
76
  const boundsOffsetLeft = chart.margin.left + getWidthOccupiedByYAxis({ preparedAxis: yAxis });
77
+ const handleMouseMove = (event) => {
78
+ const [pointerX, pointerY] = pointer(event, svgRef.current);
79
+ const x = pointerX - boundsOffsetLeft;
80
+ const y = pointerY - boundsOffsetTop;
81
+ if (x < 0 || x > boundsWidth || y < 0 || y > boundsHeight) {
82
+ dispatcher.call('hover-shape', {}, undefined);
83
+ return;
84
+ }
85
+ const closest = getClosestPoints({
86
+ position: [x, y],
87
+ shapesData,
88
+ });
89
+ dispatcher.call('hover-shape', event.target, closest, [pointerX, pointerY]);
90
+ };
91
+ const throttledHandleMouseMove = throttle(handleMouseMove, THROTTLE_DELAY);
92
+ const handleMouseLeave = () => {
93
+ throttledHandleMouseMove.cancel();
94
+ dispatcher.call('hover-shape', {}, undefined);
95
+ };
75
96
  return (React.createElement(React.Fragment, null,
76
- React.createElement("svg", { ref: svgRef, className: b(), width: width, height: height },
97
+ React.createElement("svg", { ref: svgRef, className: b(), width: width, height: height, onMouseMove: throttledHandleMouseMove, onMouseLeave: handleMouseLeave },
77
98
  title && React.createElement(Title, Object.assign({}, title, { chartWidth: width })),
78
99
  React.createElement("g", { width: boundsWidth, height: boundsHeight, transform: `translate(${[boundsOffsetLeft, boundsOffsetTop].join(',')})` },
79
100
  xScale && yScale && (React.createElement(React.Fragment, null,
80
101
  React.createElement(AxisY, { axises: yAxis, width: boundsWidth, height: boundsHeight, scale: yScale }),
81
102
  React.createElement("g", { transform: `translate(0, ${boundsHeight})` },
82
103
  React.createElement(AxisX, { axis: xAxis, width: boundsWidth, height: boundsHeight, scale: xScale })))),
83
- shapes,
84
- (tooltip === null || tooltip === void 0 ? void 0 : tooltip.enabled) && Boolean(shapesData.length) && (React.createElement(TooltipTriggerArea, { boundsWidth: boundsWidth, boundsHeight: boundsHeight, dispatcher: dispatcher, shapesData: shapesData, svgContainer: svgRef.current }))),
104
+ shapes),
85
105
  preparedLegend.enabled && (React.createElement(Legend, { chartSeries: preparedSeries, boundsWidth: boundsWidth, legend: preparedLegend, items: legendItems, config: legendConfig, onItemClick: handleLegendItemClick }))),
86
- React.createElement(Tooltip, { dispatcher: dispatcher, tooltip: tooltip, svgContainer: svgRef.current, xAxis: xAxis, yAxis: yAxis[0], hovered: hovered, pointerPosition: pointerPosition })));
106
+ React.createElement(Tooltip, { dispatcher: dispatcher, tooltip: tooltip, svgContainer: svgRef.current, xAxis: xAxis, yAxis: yAxis[0] })));
87
107
  };
@@ -1,8 +1,10 @@
1
1
  import React from 'react';
2
2
  import { dateTime } from '@gravity-ui/date-utils';
3
3
  import get from 'lodash/get';
4
+ import { block } from '../../../../../utils/cn';
4
5
  import { formatNumber } from '../../../../shared';
5
- import { getDataCategoryValue } from '../../utils';
6
+ import { getDataCategoryValue, getWaterfallPointSubtotal } from '../../utils';
7
+ const b = block('d3-tooltip');
6
8
  const DEFAULT_DATE_FORMAT = 'DD.MM.YY';
7
9
  const getRowData = (fieldName, axis, data) => {
8
10
  switch (axis.type) {
@@ -26,47 +28,75 @@ const getRowData = (fieldName, axis, data) => {
26
28
  };
27
29
  const getXRowData = (xAxis, data) => getRowData('x', xAxis, data);
28
30
  const getYRowData = (yAxis, data) => getRowData('y', yAxis, data);
31
+ const getMeasureValue = (data, xAxis, yAxis) => {
32
+ var _a, _b;
33
+ if (data.every((item) => ['pie', 'treemap', 'waterfall'].includes(item.series.type))) {
34
+ return null;
35
+ }
36
+ if (data.some((item) => item.series.type === 'bar-y')) {
37
+ return getYRowData(yAxis, (_a = data[0]) === null || _a === void 0 ? void 0 : _a.data);
38
+ }
39
+ return getXRowData(xAxis, (_b = data[0]) === null || _b === void 0 ? void 0 : _b.data);
40
+ };
29
41
  export const DefaultContent = ({ hovered, xAxis, yAxis }) => {
30
- return (React.createElement(React.Fragment, null, hovered.map(({ data, series }, i) => {
31
- const id = get(series, 'id', i);
32
- switch (series.type) {
33
- case 'scatter':
34
- case 'line':
35
- case 'area':
36
- case 'bar-x': {
37
- const xRow = getXRowData(xAxis, data);
38
- const yRow = getYRowData(yAxis, data);
39
- return (React.createElement("div", { key: id },
40
- React.createElement("div", null, xRow),
41
- React.createElement("div", null,
42
- React.createElement("span", null,
43
- React.createElement("b", null, series.name),
42
+ const measureValue = getMeasureValue(hovered, xAxis, yAxis);
43
+ return (React.createElement(React.Fragment, null,
44
+ measureValue && React.createElement("div", null, measureValue),
45
+ hovered.map(({ data, series, closest }, i) => {
46
+ const id = `${get(series, 'id')}_${i}`;
47
+ const color = get(series, 'color');
48
+ switch (series.type) {
49
+ case 'scatter':
50
+ case 'line':
51
+ case 'area':
52
+ case 'bar-x': {
53
+ const value = (React.createElement(React.Fragment, null,
54
+ series.name,
55
+ ": ",
56
+ getYRowData(yAxis, data)));
57
+ return (React.createElement("div", { key: id, className: b('content-row') },
58
+ React.createElement("div", { className: b('color'), style: { backgroundColor: color } }),
59
+ React.createElement("div", null, closest ? React.createElement("b", null, value) : React.createElement("span", null, value))));
60
+ }
61
+ case 'waterfall': {
62
+ const isTotal = get(data, 'total', false);
63
+ const subTotal = getWaterfallPointSubtotal(data, series);
64
+ return (React.createElement("div", { key: `${id}_${get(data, 'x')}` },
65
+ !isTotal && (React.createElement(React.Fragment, null,
66
+ React.createElement("div", { key: id, className: b('content-row') },
67
+ React.createElement("b", null, getXRowData(xAxis, data))),
68
+ React.createElement("div", { className: b('content-row') },
69
+ React.createElement("span", null,
70
+ series.name,
71
+ "\u00A0"),
72
+ React.createElement("span", null, getYRowData(yAxis, data))))),
73
+ React.createElement("div", { key: id, className: b('content-row') },
74
+ isTotal ? 'Total' : 'Subtotal',
44
75
  ": ",
45
- yRow))));
46
- }
47
- case 'bar-y': {
48
- const xRow = getXRowData(xAxis, data);
49
- const yRow = getYRowData(yAxis, data);
50
- return (React.createElement("div", { key: id },
51
- React.createElement("div", null, yRow),
52
- React.createElement("div", null,
76
+ subTotal)));
77
+ }
78
+ case 'bar-y': {
79
+ const value = (React.createElement(React.Fragment, null,
80
+ series.name,
81
+ ": ",
82
+ getXRowData(xAxis, data)));
83
+ return (React.createElement("div", { key: id, className: b('content-row') },
84
+ React.createElement("div", { className: b('color'), style: { backgroundColor: color } }),
85
+ React.createElement("div", null, closest ? React.createElement("b", null, value) : React.createElement("span", null, value))));
86
+ }
87
+ case 'pie':
88
+ case 'treemap': {
89
+ const seriesData = data;
90
+ return (React.createElement("div", { key: id, className: b('content-row') },
91
+ React.createElement("div", { className: b('color'), style: { backgroundColor: color } }),
53
92
  React.createElement("span", null,
54
- React.createElement("b", null, series.name),
55
- ": ",
56
- xRow))));
57
- }
58
- case 'pie':
59
- case 'treemap': {
60
- const pieSeriesData = data;
61
- return (React.createElement("div", { key: id },
62
- React.createElement("span", null,
63
- pieSeriesData.name || pieSeriesData.id,
64
- "\u00A0"),
65
- React.createElement("span", null, pieSeriesData.value)));
93
+ seriesData.name || seriesData.id,
94
+ "\u00A0"),
95
+ React.createElement("span", null, seriesData.value)));
96
+ }
97
+ default: {
98
+ return null;
99
+ }
66
100
  }
67
- default: {
68
- return null;
69
- }
70
- }
71
- })));
101
+ })));
72
102
  };
@@ -1,15 +1,12 @@
1
1
  import React from 'react';
2
2
  import type { Dispatch } from 'd3';
3
- import type { TooltipDataChunk } from '../../../../../types/widget-data';
4
- import type { PointerPosition, PreparedAxis, PreparedTooltip } from '../../hooks';
5
- export * from './TooltipTriggerArea';
3
+ import type { PreparedAxis, PreparedTooltip } from '../../hooks';
6
4
  type TooltipProps = {
7
5
  dispatcher: Dispatch<object>;
8
6
  tooltip: PreparedTooltip;
9
7
  svgContainer: SVGSVGElement | null;
10
8
  xAxis: PreparedAxis;
11
9
  yAxis: PreparedAxis;
12
- hovered?: TooltipDataChunk[];
13
- pointerPosition?: PointerPosition;
14
10
  };
15
11
  export declare const Tooltip: (props: TooltipProps) => React.JSX.Element | null;
12
+ export {};
@@ -2,11 +2,12 @@ import React from 'react';
2
2
  import { Popup, useVirtualElementRef } from '@gravity-ui/uikit';
3
3
  import isNil from 'lodash/isNil';
4
4
  import { block } from '../../../../../utils/cn';
5
+ import { useTooltip } from '../../hooks';
5
6
  import { DefaultContent } from './DefaultContent';
6
- export * from './TooltipTriggerArea';
7
7
  const b = block('d3-tooltip');
8
8
  export const Tooltip = (props) => {
9
- const { tooltip, xAxis, yAxis, hovered, svgContainer, pointerPosition } = props;
9
+ const { tooltip, xAxis, yAxis, svgContainer, dispatcher } = props;
10
+ const { hovered, pointerPosition } = useTooltip({ dispatcher, tooltip });
10
11
  const containerRect = (svgContainer === null || svgContainer === void 0 ? void 0 : svgContainer.getBoundingClientRect()) || { left: 0, top: 0 };
11
12
  const left = ((pointerPosition === null || pointerPosition === void 0 ? void 0 : pointerPosition[0]) || 0) + containerRect.left;
12
13
  const top = ((pointerPosition === null || pointerPosition === void 0 ? void 0 : pointerPosition[1]) || 0) + containerRect.top;
@@ -22,6 +23,6 @@ export const Tooltip = (props) => {
22
23
  React.useEffect(() => {
23
24
  window.dispatchEvent(new CustomEvent('scroll'));
24
25
  }, [left, top]);
25
- return hovered ? (React.createElement(Popup, { className: b(), open: true, anchorRef: anchorRef, offset: [0, 20], placement: ['right', 'left', 'top', 'bottom'], modifiers: [{ name: 'preventOverflow', options: { padding: 10, altAxis: true } }] },
26
+ return (hovered === null || hovered === void 0 ? void 0 : hovered.length) ? (React.createElement(Popup, { className: b(), open: true, anchorRef: anchorRef, offset: [0, 20], placement: ['right', 'left', 'top', 'bottom'], modifiers: [{ name: 'preventOverflow', options: { padding: 10, altAxis: true } }] },
26
27
  React.createElement("div", { className: b('content') }, content))) : null;
27
28
  };
@@ -97,4 +97,18 @@
97
97
  border-radius: 3px;
98
98
  box-shadow: 0 2px 12px var(--g-color-sfx-shadow);
99
99
  text-wrap: nowrap;
100
+ }
101
+
102
+ .chartkit-d3-tooltip__content-row {
103
+ display: flex;
104
+ align-items: center;
105
+ }
106
+
107
+ .chartkit-d3-tooltip__color {
108
+ height: 8px;
109
+ width: 16px;
110
+ display: inline-block;
111
+ margin-right: 8px;
112
+ border-radius: 2px;
113
+ background-color: #dddddd;
100
114
  }
@@ -13,6 +13,12 @@ type DefaultBarYSeriesOptions = Partial<ChartKitWidgetSeriesOptions['bar-x']> &
13
13
  groupPadding: number;
14
14
  };
15
15
  };
16
- export type SeriesOptionsDefaults = Partial<ChartKitWidgetSeriesOptions> & DefaultBarXSeriesOptions & DefaultBarYSeriesOptions;
16
+ type DefaultWaterfallSeriesOptions = Partial<ChartKitWidgetSeriesOptions['waterfall']> & {
17
+ waterfall: {
18
+ barMaxWidth: number;
19
+ barPadding: number;
20
+ };
21
+ };
22
+ export type SeriesOptionsDefaults = Partial<ChartKitWidgetSeriesOptions> & DefaultBarXSeriesOptions & DefaultBarYSeriesOptions & DefaultWaterfallSeriesOptions;
17
23
  export declare const seriesOptionsDefaults: SeriesOptionsDefaults;
18
24
  export {};
@@ -89,4 +89,18 @@ export const seriesOptionsDefaults = {
89
89
  },
90
90
  },
91
91
  },
92
+ waterfall: {
93
+ barMaxWidth: 50,
94
+ barPadding: 0.1,
95
+ states: {
96
+ hover: {
97
+ enabled: true,
98
+ brightness: 0.3,
99
+ },
100
+ inactive: {
101
+ enabled: false,
102
+ opacity: 0.5,
103
+ },
104
+ },
105
+ },
92
106
  };
@@ -1,6 +1,6 @@
1
1
  import get from 'lodash/get';
2
2
  import { DEFAULT_AXIS_LABEL_FONT_SIZE, axisLabelsDefaults, yAxisTitleDefaults, } from '../../constants';
3
- import { formatAxisTickLabel, getClosestPointsRange, getHorisontalSvgTextHeight, getLabelsSize, getScaleTicks, } from '../../utils';
3
+ import { formatAxisTickLabel, getClosestPointsRange, getHorisontalSvgTextHeight, getLabelsSize, getScaleTicks, getWaterfallPointSubtotal, } from '../../utils';
4
4
  import { createYScale } from '../useAxisScales';
5
5
  const getAxisLabelMaxWidth = (args) => {
6
6
  const { axis, series } = args;
@@ -24,9 +24,19 @@ const getAxisLabelMaxWidth = (args) => {
24
24
  };
25
25
  function getAxisMin(axis, series) {
26
26
  const min = axis === null || axis === void 0 ? void 0 : axis.min;
27
- const seriesWithVolume = ['bar-x', 'area'];
27
+ const seriesWithVolume = ['bar-x', 'area', 'waterfall'];
28
28
  if (typeof min === 'undefined' && (series === null || series === void 0 ? void 0 : series.some((s) => seriesWithVolume.includes(s.type)))) {
29
- return 0;
29
+ return series.reduce((minValue, s) => {
30
+ switch (s.type) {
31
+ case 'waterfall': {
32
+ const minSubTotal = s.data.reduce((res, d) => Math.min(res, getWaterfallPointSubtotal(d, s) || 0), 0);
33
+ return Math.min(minValue, minSubTotal);
34
+ }
35
+ default: {
36
+ return minValue;
37
+ }
38
+ }
39
+ }, 0);
30
40
  }
31
41
  return min;
32
42
  }
@@ -0,0 +1,10 @@
1
+ import type { ScaleOrdinal } from 'd3';
2
+ import type { WaterfallSeries } from '../../../../../types';
3
+ import type { PreparedLegend, PreparedSeries } from './types';
4
+ type PrepareWaterfallSeriesArgs = {
5
+ colorScale: ScaleOrdinal<string, string>;
6
+ series: WaterfallSeries[];
7
+ legend: PreparedLegend;
8
+ };
9
+ export declare function prepareWaterfallSeries(args: PrepareWaterfallSeriesArgs): PreparedSeries[];
10
+ export {};
@@ -0,0 +1,36 @@
1
+ import get from 'lodash/get';
2
+ import { getRandomCKId } from '../../../../../utils';
3
+ import { DEFAULT_PALETTE } from '../../constants';
4
+ import { DEFAULT_DATALABELS_PADDING, DEFAULT_DATALABELS_STYLE } from './constants';
5
+ import { prepareLegendSymbol } from './utils';
6
+ export function prepareWaterfallSeries(args) {
7
+ const { colorScale, series: seriesList, legend } = args;
8
+ const [, negativeColor, positiveColor] = DEFAULT_PALETTE;
9
+ return seriesList.map((series) => {
10
+ var _a, _b, _c;
11
+ const name = series.name || '';
12
+ const color = series.color || colorScale(name);
13
+ const prepared = {
14
+ type: series.type,
15
+ color,
16
+ positiveColor: positiveColor,
17
+ negativeColor: negativeColor,
18
+ name,
19
+ id: getRandomCKId(),
20
+ visible: get(series, 'visible', true),
21
+ legend: {
22
+ enabled: get(series, 'legend.enabled', legend.enabled),
23
+ symbol: prepareLegendSymbol(series),
24
+ },
25
+ data: series.data,
26
+ dataLabels: {
27
+ enabled: ((_a = series.dataLabels) === null || _a === void 0 ? void 0 : _a.enabled) || false,
28
+ style: Object.assign({}, DEFAULT_DATALABELS_STYLE, (_b = series.dataLabels) === null || _b === void 0 ? void 0 : _b.style),
29
+ allowOverlap: ((_c = series.dataLabels) === null || _c === void 0 ? void 0 : _c.allowOverlap) || false,
30
+ padding: get(series, 'dataLabels.padding', DEFAULT_DATALABELS_PADDING),
31
+ },
32
+ cursor: get(series, 'cursor', null),
33
+ };
34
+ return prepared;
35
+ }, []);
36
+ }
@@ -6,6 +6,7 @@ import { prepareLineSeries } from './prepare-line';
6
6
  import { preparePieSeries } from './prepare-pie';
7
7
  import { prepareScatterSeries } from './prepare-scatter';
8
8
  import { prepareTreemap } from './prepare-treemap';
9
+ import { prepareWaterfallSeries } from './prepare-waterfall';
9
10
  export function prepareSeries(args) {
10
11
  const { type, series, seriesOptions, legend, colorScale } = args;
11
12
  switch (type) {
@@ -48,6 +49,13 @@ export function prepareSeries(args) {
48
49
  colorScale,
49
50
  });
50
51
  }
52
+ case 'waterfall': {
53
+ return prepareWaterfallSeries({
54
+ series: series,
55
+ legend,
56
+ colorScale,
57
+ });
58
+ }
51
59
  default: {
52
60
  throw new ChartKitError({
53
61
  message: `Series type "${type}" does not support data preparation for series that do not support the presence of axes`,
@@ -1,5 +1,5 @@
1
1
  import { DashStyle, LayoutAlgorithm, LineCap, SymbolType } from '../../../../../constants';
2
- import { AreaSeries, AreaSeriesData, BarXSeries, BarXSeriesData, BarYSeries, BarYSeriesData, BaseTextStyle, ChartKitWidgetLegend, ConnectorCurve, ConnectorShape, LineSeries, LineSeriesData, PathLegendSymbolOptions, PieSeries, PieSeriesData, RectLegendSymbolOptions, ScatterSeries, ScatterSeriesData, SymbolLegendSymbolOptions, TreemapSeries, TreemapSeriesData } from '../../../../../types';
2
+ import type { AreaSeries, AreaSeriesData, BarXSeries, BarXSeriesData, BarYSeries, BarYSeriesData, BaseTextStyle, ChartKitWidgetLegend, ConnectorCurve, ConnectorShape, LineSeries, LineSeriesData, PathLegendSymbolOptions, PieSeries, PieSeriesData, RectLegendSymbolOptions, ScatterSeries, ScatterSeriesData, SymbolLegendSymbolOptions, TreemapSeries, TreemapSeriesData, WaterfallSeries, WaterfallSeriesData } from '../../../../../types';
3
3
  import type { SeriesOptionsDefaults } from '../../constants';
4
4
  export type RectLegendSymbol = {
5
5
  shape: 'rect';
@@ -208,7 +208,19 @@ export type PreparedTreemapSeries = {
208
208
  };
209
209
  layoutAlgorithm: `${LayoutAlgorithm}`;
210
210
  } & BasePreparedSeries & Omit<TreemapSeries, keyof BasePreparedSeries>;
211
- export type PreparedSeries = PreparedScatterSeries | PreparedBarXSeries | PreparedBarYSeries | PreparedPieSeries | PreparedLineSeries | PreparedAreaSeries | PreparedTreemapSeries;
211
+ export type PreparedWaterfallSeries = {
212
+ type: WaterfallSeries['type'];
213
+ data: WaterfallSeriesData[];
214
+ dataLabels: {
215
+ enabled: boolean;
216
+ style: BaseTextStyle;
217
+ allowOverlap: boolean;
218
+ padding: number;
219
+ };
220
+ positiveColor: string;
221
+ negativeColor: string;
222
+ } & BasePreparedSeries;
223
+ export type PreparedSeries = PreparedScatterSeries | PreparedBarXSeries | PreparedBarYSeries | PreparedPieSeries | PreparedLineSeries | PreparedAreaSeries | PreparedTreemapSeries | PreparedWaterfallSeries;
212
224
  export type PreparedSeriesOptions = SeriesOptionsDefaults;
213
225
  export type StackedSeries = BarXSeries | AreaSeries | BarYSeries;
214
226
  export {};
@@ -73,14 +73,13 @@ export const AreaSeriesShapes = (args) => {
73
73
  const hoverEnabled = hoverOptions === null || hoverOptions === void 0 ? void 0 : hoverOptions.enabled;
74
74
  const inactiveEnabled = inactiveOptions === null || inactiveOptions === void 0 ? void 0 : inactiveOptions.enabled;
75
75
  dispatcher.on('hover-shape.area', (data) => {
76
- var _a;
77
- const selected = data === null || data === void 0 ? void 0 : data.find((d) => d.series.type === 'area');
78
- const selectedDataItem = selected === null || selected === void 0 ? void 0 : selected.data;
79
- const selectedSeriesId = (_a = selected === null || selected === void 0 ? void 0 : selected.series) === null || _a === void 0 ? void 0 : _a.id;
76
+ const selected = (data === null || data === void 0 ? void 0 : data.filter((d) => d.series.type === 'area')) || [];
77
+ const selectedDataItems = selected.map((d) => d.data);
78
+ const selectedSeriesIds = selected.map((d) => { var _a; return (_a = d.series) === null || _a === void 0 ? void 0 : _a.id; });
80
79
  shapeSelection.datum((d, index, list) => {
81
80
  var _a;
82
81
  const elementSelection = select(list[index]);
83
- const hovered = Boolean(hoverEnabled && d.id === selectedSeriesId);
82
+ const hovered = Boolean(hoverEnabled && selectedSeriesIds.includes(d.id));
84
83
  if (d.hovered !== hovered) {
85
84
  d.hovered = hovered;
86
85
  let strokeColor = d.color || '';
@@ -95,7 +94,9 @@ export const AreaSeriesShapes = (args) => {
95
94
  return setActiveState({
96
95
  element: list[index],
97
96
  state: inactiveOptions,
98
- active: Boolean(!inactiveEnabled || !selectedSeriesId || selectedSeriesId === d.id),
97
+ active: Boolean(!inactiveEnabled ||
98
+ !selectedSeriesIds.length ||
99
+ selectedSeriesIds.includes(d.id)),
99
100
  datum: d,
100
101
  });
101
102
  });
@@ -103,13 +104,15 @@ export const AreaSeriesShapes = (args) => {
103
104
  return setActiveState({
104
105
  element: list[index],
105
106
  state: inactiveOptions,
106
- active: Boolean(!inactiveEnabled || !selectedSeriesId || selectedSeriesId === d.series.id),
107
+ active: Boolean(!inactiveEnabled ||
108
+ !selectedSeriesIds.length ||
109
+ selectedSeriesIds.includes(d.series.id)),
107
110
  datum: d,
108
111
  });
109
112
  });
110
113
  markerSelection.datum((d, index, list) => {
111
114
  const elementSelection = select(list[index]);
112
- const hovered = Boolean(hoverEnabled && d.point.data === selectedDataItem);
115
+ const hovered = Boolean(hoverEnabled && selectedDataItems.includes(d.point.data));
113
116
  if (d.hovered !== hovered) {
114
117
  d.hovered = hovered;
115
118
  elementSelection.attr('visibility', getMarkerVisibility(d));
@@ -118,8 +121,8 @@ export const AreaSeriesShapes = (args) => {
118
121
  }
119
122
  if (d.point.series.marker.states.normal.enabled) {
120
123
  const isActive = Boolean(!inactiveEnabled ||
121
- !selectedSeriesId ||
122
- selectedSeriesId === d.point.series.id);
124
+ !selectedSeriesIds.length ||
125
+ selectedSeriesIds.includes(d.point.series.id));
123
126
  setActiveState({
124
127
  element: list[index],
125
128
  state: inactiveOptions,
@@ -11,8 +11,9 @@ import type { PreparedPieData } from './pie/types';
11
11
  import type { PreparedScatterData } from './scatter/types';
12
12
  export type { PreparedBarXData } from './bar-x';
13
13
  export type { PreparedScatterData } from './scatter/types';
14
+ import { PreparedWaterfallData } from './waterfall';
14
15
  import './styles.css';
15
- export type ShapeData = PreparedBarXData | PreparedBarYData | PreparedScatterData | PreparedLineData | PreparedPieData | PreparedAreaData;
16
+ export type ShapeData = PreparedBarXData | PreparedBarYData | PreparedScatterData | PreparedLineData | PreparedPieData | PreparedAreaData | PreparedWaterfallData;
16
17
  type Args = {
17
18
  boundsWidth: number;
18
19
  boundsHeight: number;
@@ -21,7 +22,6 @@ type Args = {
21
22
  seriesOptions: PreparedSeriesOptions;
22
23
  xAxis: PreparedAxis;
23
24
  yAxis: PreparedAxis[];
24
- svgContainer: SVGSVGElement | null;
25
25
  xScale?: ChartScale;
26
26
  yScale?: ChartScale;
27
27
  };
@@ -12,9 +12,10 @@ import { preparePieData } from './pie/prepare-data';
12
12
  import { ScatterSeriesShape, prepareScatterData } from './scatter';
13
13
  import { TreemapSeriesShape } from './treemap';
14
14
  import { prepareTreemapData } from './treemap/prepare-data';
15
+ import { WaterfallSeriesShapes, prepareWaterfallData } from './waterfall';
15
16
  import './styles.css';
16
17
  export const useShapes = (args) => {
17
- const { boundsWidth, boundsHeight, dispatcher, series, seriesOptions, xAxis, xScale, yAxis, yScale, svgContainer, } = args;
18
+ const { boundsWidth, boundsHeight, dispatcher, series, seriesOptions, xAxis, xScale, yAxis, yScale, } = args;
18
19
  const shapesComponents = React.useMemo(() => {
19
20
  const visibleSeries = getOnlyVisibleSeries(series);
20
21
  const groupedSeries = group(visibleSeries, (item) => item.type);
@@ -52,6 +53,21 @@ export const useShapes = (args) => {
52
53
  }
53
54
  break;
54
55
  }
56
+ case 'waterfall': {
57
+ if (xScale && yScale) {
58
+ const preparedData = prepareWaterfallData({
59
+ series: chartSeries,
60
+ seriesOptions,
61
+ xAxis,
62
+ xScale,
63
+ yAxis,
64
+ yScale,
65
+ });
66
+ acc.push(React.createElement(WaterfallSeriesShapes, { key: "waterfall", dispatcher: dispatcher, seriesOptions: seriesOptions, preparedData: preparedData }));
67
+ shapesData.push(...preparedData);
68
+ }
69
+ break;
70
+ }
55
71
  case 'line': {
56
72
  if (xScale && yScale) {
57
73
  const preparedData = prepareLineData({
@@ -89,7 +105,8 @@ export const useShapes = (args) => {
89
105
  yAxis: yAxis[0],
90
106
  yScale,
91
107
  });
92
- acc.push(React.createElement(ScatterSeriesShape, { key: "scatter", dispatcher: dispatcher, preparedData: preparedData, seriesOptions: seriesOptions, svgContainer: svgContainer }));
108
+ acc.push(React.createElement(ScatterSeriesShape, { key: "scatter", dispatcher: dispatcher, preparedData: preparedData, seriesOptions: seriesOptions }));
109
+ shapesData.push(...preparedData);
93
110
  }
94
111
  break;
95
112
  }
@@ -99,7 +116,8 @@ export const useShapes = (args) => {
99
116
  boundsWidth,
100
117
  boundsHeight,
101
118
  });
102
- acc.push(React.createElement(PieSeriesShapes, { key: "pie", dispatcher: dispatcher, preparedData: preparedData, seriesOptions: seriesOptions, svgContainer: svgContainer }));
119
+ acc.push(React.createElement(PieSeriesShapes, { key: "pie", dispatcher: dispatcher, preparedData: preparedData, seriesOptions: seriesOptions }));
120
+ shapesData.push(...preparedData);
103
121
  break;
104
122
  }
105
123
  case 'treemap': {
@@ -110,7 +128,8 @@ export const useShapes = (args) => {
110
128
  width: boundsWidth,
111
129
  height: boundsHeight,
112
130
  });
113
- acc.push(React.createElement(TreemapSeriesShape, { key: "treemap", dispatcher: dispatcher, preparedData: preparedData, seriesOptions: seriesOptions, svgContainer: svgContainer }));
131
+ acc.push(React.createElement(TreemapSeriesShape, { key: "treemap", dispatcher: dispatcher, preparedData: preparedData, seriesOptions: seriesOptions }));
132
+ shapesData.push(preparedData);
114
133
  }
115
134
  }
116
135
  return acc;
@@ -126,7 +145,6 @@ export const useShapes = (args) => {
126
145
  xScale,
127
146
  yAxis,
128
147
  yScale,
129
- svgContainer,
130
148
  ]);
131
149
  return { shapes: shapesComponents.shapes, shapesData: shapesComponents.shapesData };
132
150
  };