@gravity-ui/charts 1.10.2 → 1.11.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 (91) hide show
  1. package/dist/cjs/components/Axis/AxisY.js +3 -0
  2. package/dist/cjs/components/ChartInner/index.js +8 -3
  3. package/dist/cjs/components/ChartInner/useChartInnerHandlers.d.ts +2 -1
  4. package/dist/cjs/components/ChartInner/useChartInnerHandlers.js +1 -5
  5. package/dist/cjs/components/ChartInner/useChartInnerProps.d.ts +2 -0
  6. package/dist/cjs/components/ChartInner/useChartInnerProps.js +11 -3
  7. package/dist/cjs/components/ChartInner/utils.d.ts +1 -1
  8. package/dist/cjs/components/ChartInner/utils.js +3 -3
  9. package/dist/cjs/components/Legend/index.js +4 -1
  10. package/dist/cjs/hooks/hooks-utils/zoom.d.ts +1 -1
  11. package/dist/cjs/hooks/hooks-utils/zoom.js +2 -2
  12. package/dist/cjs/hooks/useAxisScales/index.js +49 -18
  13. package/dist/cjs/hooks/useChartOptions/x-axis.js +3 -14
  14. package/dist/cjs/hooks/useChartOptions/y-axis.js +5 -24
  15. package/dist/cjs/hooks/useSeries/prepare-area.js +2 -1
  16. package/dist/cjs/hooks/useSeries/prepare-legend.js +2 -2
  17. package/dist/cjs/hooks/useShapes/area/index.d.ts +1 -0
  18. package/dist/cjs/hooks/useShapes/area/index.js +13 -9
  19. package/dist/cjs/hooks/useShapes/area/prepare-data.d.ts +1 -0
  20. package/dist/cjs/hooks/useShapes/area/prepare-data.js +4 -3
  21. package/dist/cjs/hooks/useShapes/area/types.d.ts +1 -0
  22. package/dist/cjs/hooks/useShapes/bar-x/index.d.ts +1 -0
  23. package/dist/cjs/hooks/useShapes/bar-x/index.js +2 -2
  24. package/dist/cjs/hooks/useShapes/bar-y/index.d.ts +1 -0
  25. package/dist/cjs/hooks/useShapes/bar-y/index.js +2 -2
  26. package/dist/cjs/hooks/useShapes/index.d.ts +2 -0
  27. package/dist/cjs/hooks/useShapes/index.js +146 -137
  28. package/dist/cjs/hooks/useShapes/line/index.d.ts +1 -0
  29. package/dist/cjs/hooks/useShapes/line/index.js +16 -12
  30. package/dist/cjs/hooks/useShapes/line/prepare-data.d.ts +1 -0
  31. package/dist/cjs/hooks/useShapes/line/prepare-data.js +2 -1
  32. package/dist/cjs/hooks/useShapes/line/types.d.ts +1 -0
  33. package/dist/cjs/hooks/useShapes/marker.js +6 -0
  34. package/dist/cjs/hooks/useShapes/scatter/prepare-data.d.ts +1 -0
  35. package/dist/cjs/hooks/useShapes/scatter/prepare-data.js +6 -3
  36. package/dist/cjs/hooks/useShapes/scatter/types.d.ts +1 -0
  37. package/dist/cjs/hooks/useShapes/waterfall/index.d.ts +1 -0
  38. package/dist/cjs/hooks/useShapes/waterfall/index.js +2 -2
  39. package/dist/cjs/hooks/useZoom/index.js +1 -1
  40. package/dist/cjs/hooks/useZoom/utils.d.ts +1 -1
  41. package/dist/cjs/hooks/useZoom/utils.js +3 -3
  42. package/dist/cjs/types/chart/axis.d.ts +4 -5
  43. package/dist/cjs/utils/chart/axis-generators/bottom.js +3 -1
  44. package/dist/cjs/utils/chart/index.d.ts +2 -0
  45. package/dist/cjs/utils/chart/index.js +31 -0
  46. package/dist/esm/components/Axis/AxisY.js +3 -0
  47. package/dist/esm/components/ChartInner/index.js +8 -3
  48. package/dist/esm/components/ChartInner/useChartInnerHandlers.d.ts +2 -1
  49. package/dist/esm/components/ChartInner/useChartInnerHandlers.js +1 -5
  50. package/dist/esm/components/ChartInner/useChartInnerProps.d.ts +2 -0
  51. package/dist/esm/components/ChartInner/useChartInnerProps.js +11 -3
  52. package/dist/esm/components/ChartInner/utils.d.ts +1 -1
  53. package/dist/esm/components/ChartInner/utils.js +3 -3
  54. package/dist/esm/components/Legend/index.js +4 -1
  55. package/dist/esm/hooks/hooks-utils/zoom.d.ts +1 -1
  56. package/dist/esm/hooks/hooks-utils/zoom.js +2 -2
  57. package/dist/esm/hooks/useAxisScales/index.js +49 -18
  58. package/dist/esm/hooks/useChartOptions/x-axis.js +3 -14
  59. package/dist/esm/hooks/useChartOptions/y-axis.js +5 -24
  60. package/dist/esm/hooks/useSeries/prepare-area.js +2 -1
  61. package/dist/esm/hooks/useSeries/prepare-legend.js +2 -2
  62. package/dist/esm/hooks/useShapes/area/index.d.ts +1 -0
  63. package/dist/esm/hooks/useShapes/area/index.js +13 -9
  64. package/dist/esm/hooks/useShapes/area/prepare-data.d.ts +1 -0
  65. package/dist/esm/hooks/useShapes/area/prepare-data.js +4 -3
  66. package/dist/esm/hooks/useShapes/area/types.d.ts +1 -0
  67. package/dist/esm/hooks/useShapes/bar-x/index.d.ts +1 -0
  68. package/dist/esm/hooks/useShapes/bar-x/index.js +2 -2
  69. package/dist/esm/hooks/useShapes/bar-y/index.d.ts +1 -0
  70. package/dist/esm/hooks/useShapes/bar-y/index.js +2 -2
  71. package/dist/esm/hooks/useShapes/index.d.ts +2 -0
  72. package/dist/esm/hooks/useShapes/index.js +146 -137
  73. package/dist/esm/hooks/useShapes/line/index.d.ts +1 -0
  74. package/dist/esm/hooks/useShapes/line/index.js +16 -12
  75. package/dist/esm/hooks/useShapes/line/prepare-data.d.ts +1 -0
  76. package/dist/esm/hooks/useShapes/line/prepare-data.js +2 -1
  77. package/dist/esm/hooks/useShapes/line/types.d.ts +1 -0
  78. package/dist/esm/hooks/useShapes/marker.js +6 -0
  79. package/dist/esm/hooks/useShapes/scatter/prepare-data.d.ts +1 -0
  80. package/dist/esm/hooks/useShapes/scatter/prepare-data.js +6 -3
  81. package/dist/esm/hooks/useShapes/scatter/types.d.ts +1 -0
  82. package/dist/esm/hooks/useShapes/waterfall/index.d.ts +1 -0
  83. package/dist/esm/hooks/useShapes/waterfall/index.js +2 -2
  84. package/dist/esm/hooks/useZoom/index.js +1 -1
  85. package/dist/esm/hooks/useZoom/utils.d.ts +1 -1
  86. package/dist/esm/hooks/useZoom/utils.js +3 -3
  87. package/dist/esm/types/chart/axis.d.ts +4 -5
  88. package/dist/esm/utils/chart/axis-generators/bottom.js +3 -1
  89. package/dist/esm/utils/chart/index.d.ts +2 -0
  90. package/dist/esm/utils/chart/index.js +31 -0
  91. package/package.json +1 -1
@@ -7,7 +7,7 @@ import { getRectPath } from '../utils';
7
7
  export { prepareBarYData } from './prepare-data';
8
8
  const b = block('bar-y');
9
9
  export const BarYSeriesShapes = (args) => {
10
- const { dispatcher, preparedData, seriesOptions, htmlLayout } = args;
10
+ const { dispatcher, preparedData, seriesOptions, htmlLayout, clipPathId } = args;
11
11
  const hoveredDataRef = React.useRef(null);
12
12
  const ref = React.useRef(null);
13
13
  React.useEffect(() => {
@@ -99,6 +99,6 @@ export const BarYSeriesShapes = (args) => {
99
99
  };
100
100
  }, [dispatcher, preparedData, seriesOptions]);
101
101
  return (React.createElement(React.Fragment, null,
102
- React.createElement("g", { ref: ref, className: b() }),
102
+ React.createElement("g", { ref: ref, className: b(), clipPath: `url(#${clipPathId})` }),
103
103
  React.createElement(HtmlLayer, { preparedData: preparedData, htmlLayout: htmlLayout })));
104
104
  };
@@ -28,6 +28,8 @@ type Args = {
28
28
  yScale?: ChartScale[];
29
29
  split: PreparedSplit;
30
30
  htmlLayout: HTMLElement | null;
31
+ clipPathId: string;
32
+ isOutsideBounds: (x: number, y: number) => boolean;
31
33
  };
32
34
  export declare const useShapes: (args: Args) => {
33
35
  shapes: React.ReactElement<any, string | React.JSXElementConstructor<any>>[];
@@ -20,160 +20,170 @@ import { prepareTreemapData } from './treemap/prepare-data';
20
20
  import { WaterfallSeriesShapes, prepareWaterfallData } from './waterfall';
21
21
  import './styles.css';
22
22
  export const useShapes = (args) => {
23
- const { boundsWidth, boundsHeight, dispatcher, series, seriesOptions, xAxis, xScale, yAxis, yScale, split, htmlLayout, } = args;
23
+ const { boundsWidth, boundsHeight, dispatcher, series, seriesOptions, xAxis, xScale, yAxis, yScale, split, htmlLayout, clipPathId, isOutsideBounds, } = args;
24
24
  const [shapesElemens, setShapesElements] = React.useState([]);
25
25
  const [shapesElemensData, setShapesElemensData] = React.useState([]);
26
- const setShapes = React.useCallback(async () => {
27
- const visibleSeries = getOnlyVisibleSeries(series);
28
- const groupedSeries = group(visibleSeries, (item) => item.type);
29
- const shapesData = [];
30
- const shapes = [];
31
- await Promise.all(
32
- // eslint-disable-next-line complexity
33
- Array.from(groupedSeries).map(async (item) => {
34
- const [seriesType, chartSeries] = item;
35
- switch (seriesType) {
36
- case 'bar-x': {
37
- if (xAxis && xScale && yScale) {
38
- const preparedData = await prepareBarXData({
39
- series: chartSeries,
40
- seriesOptions,
41
- xAxis,
42
- xScale,
43
- yAxis,
44
- yScale,
45
- boundsHeight,
46
- });
47
- shapes.push(React.createElement(BarXSeriesShapes, { key: "bar-x", dispatcher: dispatcher, seriesOptions: seriesOptions, preparedData: preparedData, htmlLayout: htmlLayout }));
48
- shapesData.push(...preparedData);
26
+ const countedRef = React.useRef(0);
27
+ React.useEffect(() => {
28
+ countedRef.current++;
29
+ (async () => {
30
+ const currentRun = countedRef.current;
31
+ const visibleSeries = getOnlyVisibleSeries(series);
32
+ const groupedSeries = group(visibleSeries, (item) => item.type);
33
+ const shapesData = [];
34
+ const shapes = [];
35
+ await Promise.all(
36
+ // eslint-disable-next-line complexity
37
+ Array.from(groupedSeries).map(async (item) => {
38
+ const [seriesType, chartSeries] = item;
39
+ switch (seriesType) {
40
+ case 'bar-x': {
41
+ if (xAxis && xScale && (yScale === null || yScale === void 0 ? void 0 : yScale.length)) {
42
+ const preparedData = await prepareBarXData({
43
+ series: chartSeries,
44
+ seriesOptions,
45
+ xAxis,
46
+ xScale,
47
+ yAxis,
48
+ yScale,
49
+ boundsHeight,
50
+ });
51
+ shapes.push(React.createElement(BarXSeriesShapes, { key: "bar-x", dispatcher: dispatcher, seriesOptions: seriesOptions, preparedData: preparedData, htmlLayout: htmlLayout, clipPathId: clipPathId }));
52
+ shapesData.push(...preparedData);
53
+ }
54
+ break;
49
55
  }
50
- break;
51
- }
52
- case 'bar-y': {
53
- if (xAxis && xScale && yScale) {
54
- const preparedData = await prepareBarYData({
56
+ case 'bar-y': {
57
+ if (xAxis && xScale && (yScale === null || yScale === void 0 ? void 0 : yScale.length)) {
58
+ const preparedData = await prepareBarYData({
59
+ series: chartSeries,
60
+ seriesOptions,
61
+ xAxis,
62
+ xScale,
63
+ yAxis,
64
+ yScale,
65
+ });
66
+ shapes.push(React.createElement(BarYSeriesShapes, { key: "bar-y", dispatcher: dispatcher, seriesOptions: seriesOptions, preparedData: preparedData, htmlLayout: htmlLayout, clipPathId: clipPathId }));
67
+ shapesData.push(...preparedData);
68
+ }
69
+ break;
70
+ }
71
+ case 'waterfall': {
72
+ if (xAxis && xScale && (yScale === null || yScale === void 0 ? void 0 : yScale.length)) {
73
+ const preparedData = await prepareWaterfallData({
74
+ series: chartSeries,
75
+ seriesOptions,
76
+ xAxis,
77
+ xScale,
78
+ yAxis,
79
+ yScale,
80
+ });
81
+ shapes.push(React.createElement(WaterfallSeriesShapes, { key: "waterfall", dispatcher: dispatcher, seriesOptions: seriesOptions, preparedData: preparedData, htmlLayout: htmlLayout, clipPathId: clipPathId }));
82
+ shapesData.push(...preparedData);
83
+ }
84
+ break;
85
+ }
86
+ case 'line': {
87
+ if (xAxis && xScale && (yScale === null || yScale === void 0 ? void 0 : yScale.length)) {
88
+ const preparedData = await prepareLineData({
89
+ series: chartSeries,
90
+ xAxis,
91
+ xScale,
92
+ yAxis,
93
+ yScale,
94
+ split,
95
+ isOutsideBounds,
96
+ });
97
+ shapes.push(React.createElement(LineSeriesShapes, { key: "line", dispatcher: dispatcher, seriesOptions: seriesOptions, preparedData: preparedData, htmlLayout: htmlLayout, clipPathId: clipPathId }));
98
+ shapesData.push(...preparedData);
99
+ }
100
+ break;
101
+ }
102
+ case 'area': {
103
+ if (xAxis && xScale && (yScale === null || yScale === void 0 ? void 0 : yScale.length)) {
104
+ const preparedData = await prepareAreaData({
105
+ series: chartSeries,
106
+ xAxis,
107
+ xScale,
108
+ yAxis,
109
+ yScale,
110
+ boundsHeight,
111
+ isOutsideBounds,
112
+ });
113
+ shapes.push(React.createElement(AreaSeriesShapes, { key: "area", dispatcher: dispatcher, seriesOptions: seriesOptions, preparedData: preparedData, htmlLayout: htmlLayout, clipPathId: clipPathId }));
114
+ shapesData.push(...preparedData);
115
+ }
116
+ break;
117
+ }
118
+ case 'scatter': {
119
+ if (xAxis && xScale && (yScale === null || yScale === void 0 ? void 0 : yScale.length)) {
120
+ const preparedData = prepareScatterData({
121
+ series: chartSeries,
122
+ xAxis,
123
+ xScale,
124
+ yAxis,
125
+ yScale,
126
+ isOutsideBounds,
127
+ });
128
+ shapes.push(React.createElement(ScatterSeriesShape, { key: "scatter", dispatcher: dispatcher, preparedData: preparedData, seriesOptions: seriesOptions, htmlLayout: htmlLayout }));
129
+ shapesData.push(...preparedData);
130
+ }
131
+ break;
132
+ }
133
+ case 'pie': {
134
+ const preparedData = await preparePieData({
55
135
  series: chartSeries,
56
- seriesOptions,
57
- xAxis,
58
- xScale,
59
- yAxis,
60
- yScale,
136
+ boundsWidth,
137
+ boundsHeight,
61
138
  });
62
- shapes.push(React.createElement(BarYSeriesShapes, { key: "bar-y", dispatcher: dispatcher, seriesOptions: seriesOptions, preparedData: preparedData, htmlLayout: htmlLayout }));
139
+ shapes.push(React.createElement(PieSeriesShapes, { key: "pie", dispatcher: dispatcher, preparedData: preparedData, seriesOptions: seriesOptions, htmlLayout: htmlLayout }));
63
140
  shapesData.push(...preparedData);
141
+ break;
64
142
  }
65
- break;
66
- }
67
- case 'waterfall': {
68
- if (xAxis && xScale && yScale) {
69
- const preparedData = await prepareWaterfallData({
70
- series: chartSeries,
71
- seriesOptions,
72
- xAxis,
73
- xScale,
74
- yAxis,
75
- yScale,
143
+ case 'treemap': {
144
+ const preparedData = await prepareTreemapData({
145
+ // We should have exactly one series with "treemap" type
146
+ // Otherwise data validation should emit an error
147
+ series: chartSeries[0],
148
+ width: boundsWidth,
149
+ height: boundsHeight,
76
150
  });
77
- shapes.push(React.createElement(WaterfallSeriesShapes, { key: "waterfall", dispatcher: dispatcher, seriesOptions: seriesOptions, preparedData: preparedData, htmlLayout: htmlLayout }));
78
- shapesData.push(...preparedData);
151
+ shapes.push(React.createElement(TreemapSeriesShape, { key: "treemap", dispatcher: dispatcher, preparedData: preparedData, seriesOptions: seriesOptions, htmlLayout: htmlLayout }));
152
+ shapesData.push(preparedData);
153
+ break;
79
154
  }
80
- break;
81
- }
82
- case 'line': {
83
- if (xAxis && xScale && yScale) {
84
- const preparedData = await prepareLineData({
85
- series: chartSeries,
86
- xAxis,
87
- xScale,
88
- yAxis,
89
- yScale,
90
- split,
155
+ case 'sankey': {
156
+ const preparedData = prepareSankeyData({
157
+ series: chartSeries[0],
158
+ width: boundsWidth,
159
+ height: boundsHeight,
91
160
  });
92
- shapes.push(React.createElement(LineSeriesShapes, { key: "line", dispatcher: dispatcher, seriesOptions: seriesOptions, preparedData: preparedData, htmlLayout: htmlLayout }));
93
- shapesData.push(...preparedData);
161
+ shapes.push(React.createElement(SankeySeriesShape, { key: "sankey", dispatcher: dispatcher, preparedData: preparedData, seriesOptions: seriesOptions, htmlLayout: htmlLayout }));
162
+ shapesData.push(preparedData);
163
+ break;
94
164
  }
95
- break;
96
- }
97
- case 'area': {
98
- if (xAxis && xScale && yScale) {
99
- const preparedData = await prepareAreaData({
165
+ case 'radar': {
166
+ const preparedData = await prepareRadarData({
100
167
  series: chartSeries,
101
- xAxis,
102
- xScale,
103
- yAxis,
104
- yScale,
168
+ boundsWidth,
105
169
  boundsHeight,
106
170
  });
107
- shapes.push(React.createElement(AreaSeriesShapes, { key: "area", dispatcher: dispatcher, seriesOptions: seriesOptions, preparedData: preparedData, htmlLayout: htmlLayout }));
171
+ shapes.push(React.createElement(RadarSeriesShapes, { key: "radar", dispatcher: dispatcher, series: preparedData, seriesOptions: seriesOptions, htmlLayout: htmlLayout }));
108
172
  shapesData.push(...preparedData);
173
+ break;
109
174
  }
110
- break;
111
- }
112
- case 'scatter': {
113
- if (xAxis && xScale && yScale) {
114
- const preparedData = prepareScatterData({
115
- series: chartSeries,
116
- xAxis,
117
- xScale,
118
- yAxis,
119
- yScale,
175
+ default: {
176
+ throw new ChartError({
177
+ message: `The display method is not defined for a series with type "${seriesType}"`,
120
178
  });
121
- shapes.push(React.createElement(ScatterSeriesShape, { key: "scatter", dispatcher: dispatcher, preparedData: preparedData, seriesOptions: seriesOptions, htmlLayout: htmlLayout }));
122
- shapesData.push(...preparedData);
123
179
  }
124
- break;
125
- }
126
- case 'pie': {
127
- const preparedData = await preparePieData({
128
- series: chartSeries,
129
- boundsWidth,
130
- boundsHeight,
131
- });
132
- shapes.push(React.createElement(PieSeriesShapes, { key: "pie", dispatcher: dispatcher, preparedData: preparedData, seriesOptions: seriesOptions, htmlLayout: htmlLayout }));
133
- shapesData.push(...preparedData);
134
- break;
135
- }
136
- case 'treemap': {
137
- const preparedData = await prepareTreemapData({
138
- // We should have exactly one series with "treemap" type
139
- // Otherwise data validation should emit an error
140
- series: chartSeries[0],
141
- width: boundsWidth,
142
- height: boundsHeight,
143
- });
144
- shapes.push(React.createElement(TreemapSeriesShape, { key: "treemap", dispatcher: dispatcher, preparedData: preparedData, seriesOptions: seriesOptions, htmlLayout: htmlLayout }));
145
- shapesData.push(preparedData);
146
- break;
147
- }
148
- case 'sankey': {
149
- const preparedData = prepareSankeyData({
150
- series: chartSeries[0],
151
- width: boundsWidth,
152
- height: boundsHeight,
153
- });
154
- shapes.push(React.createElement(SankeySeriesShape, { key: "sankey", dispatcher: dispatcher, preparedData: preparedData, seriesOptions: seriesOptions, htmlLayout: htmlLayout }));
155
- shapesData.push(preparedData);
156
- break;
157
- }
158
- case 'radar': {
159
- const preparedData = await prepareRadarData({
160
- series: chartSeries,
161
- boundsWidth,
162
- boundsHeight,
163
- });
164
- shapes.push(React.createElement(RadarSeriesShapes, { key: "radar", dispatcher: dispatcher, series: preparedData, seriesOptions: seriesOptions, htmlLayout: htmlLayout }));
165
- shapesData.push(...preparedData);
166
- break;
167
- }
168
- default: {
169
- throw new ChartError({
170
- message: `The display method is not defined for a series with type "${seriesType}"`,
171
- });
172
180
  }
181
+ }));
182
+ if (countedRef.current === currentRun) {
183
+ setShapesElements(shapes);
184
+ setShapesElemensData(shapesData);
173
185
  }
174
- }));
175
- setShapesElements(shapes);
176
- setShapesElemensData(shapesData);
186
+ })();
177
187
  }, [
178
188
  boundsHeight,
179
189
  boundsWidth,
@@ -186,9 +196,8 @@ export const useShapes = (args) => {
186
196
  xScale,
187
197
  yAxis,
188
198
  yScale,
199
+ clipPathId,
200
+ isOutsideBounds,
189
201
  ]);
190
- React.useEffect(() => {
191
- setShapes();
192
- }, [setShapes]);
193
202
  return { shapes: shapesElemens, shapesData: shapesElemensData };
194
203
  };
@@ -7,6 +7,7 @@ type Args = {
7
7
  preparedData: PreparedLineData[];
8
8
  seriesOptions: PreparedSeriesOptions;
9
9
  htmlLayout: HTMLElement | null;
10
+ clipPathId: string;
10
11
  };
11
12
  export declare const LineSeriesShapes: (args: Args) => React.JSX.Element;
12
13
  export {};
@@ -7,22 +7,25 @@ import { getMarkerHaloVisibility, getMarkerVisibility, renderMarker, selectMarke
7
7
  import { setActiveState } from '../utils';
8
8
  const b = block('line');
9
9
  export const LineSeriesShapes = (args) => {
10
- const { dispatcher, preparedData, seriesOptions, htmlLayout } = args;
10
+ const { dispatcher, preparedData, seriesOptions, htmlLayout, clipPathId } = args;
11
11
  const hoveredDataRef = React.useRef(null);
12
- const ref = React.useRef(null);
12
+ const plotRef = React.useRef(null);
13
+ const markersRef = React.useRef(null);
13
14
  React.useEffect(() => {
14
15
  var _a;
15
- if (!ref.current) {
16
+ if (!plotRef.current || !markersRef.current) {
16
17
  return () => { };
17
18
  }
18
- const svgElement = select(ref.current);
19
+ const plotSvgElement = select(plotRef.current);
20
+ const markersSvgElement = select(markersRef.current);
19
21
  const hoverOptions = get(seriesOptions, 'line.states.hover');
20
22
  const inactiveOptions = get(seriesOptions, 'line.states.inactive');
21
23
  const line = lineGenerator()
22
24
  .x((d) => d.x)
23
25
  .y((d) => d.y);
24
- svgElement.selectAll('*').remove();
25
- const lineSelection = svgElement
26
+ plotSvgElement.selectAll('*').remove();
27
+ markersSvgElement.selectAll('*').remove();
28
+ const lineSelection = plotSvgElement
26
29
  .selectAll('path')
27
30
  .data(preparedData)
28
31
  .join('path')
@@ -41,7 +44,7 @@ export const LineSeriesShapes = (args) => {
41
44
  if (!((_a = preparedData[0]) === null || _a === void 0 ? void 0 : _a.series.dataLabels.allowOverlap)) {
42
45
  dataLabels = filterOverlappingLabels(dataLabels);
43
46
  }
44
- const labelsSelection = svgElement
47
+ const labelsSelection = plotSvgElement
45
48
  .selectAll('text')
46
49
  .data(dataLabels)
47
50
  .join('text')
@@ -54,7 +57,7 @@ export const LineSeriesShapes = (args) => {
54
57
  .style('font-weight', (d) => d.style.fontWeight || null)
55
58
  .style('fill', (d) => d.style.fontColor || null);
56
59
  const markers = preparedData.reduce((acc, d) => acc.concat(d.markers), []);
57
- const markerSelection = svgElement
60
+ const markerSelection = markersSvgElement
58
61
  .selectAll('marker')
59
62
  .data(markers)
60
63
  .join('g')
@@ -71,10 +74,10 @@ export const LineSeriesShapes = (args) => {
71
74
  const hovered = Boolean(hoverEnabled && selectedSeriesIds.includes(d.id));
72
75
  if (d.hovered !== hovered) {
73
76
  d.hovered = hovered;
74
- elementSelection.attr('stroke', (d) => {
77
+ elementSelection.attr('stroke', (dSelection) => {
75
78
  var _a;
76
- const initialColor = d.color || '';
77
- if (d.hovered) {
79
+ const initialColor = dSelection.color || '';
80
+ if (dSelection.hovered) {
78
81
  return (((_a = color(initialColor)) === null || _a === void 0 ? void 0 : _a.brighter(hoverOptions === null || hoverOptions === void 0 ? void 0 : hoverOptions.brightness).toString()) || initialColor);
79
82
  }
80
83
  return initialColor;
@@ -131,6 +134,7 @@ export const LineSeriesShapes = (args) => {
131
134
  };
132
135
  }, [dispatcher, preparedData, seriesOptions]);
133
136
  return (React.createElement(React.Fragment, null,
134
- React.createElement("g", { ref: ref, className: b() }),
137
+ React.createElement("g", { ref: plotRef, className: b(), clipPath: `url(#${clipPathId})` }),
138
+ React.createElement("g", { ref: markersRef }),
135
139
  React.createElement(HtmlLayer, { preparedData: preparedData, htmlLayout: htmlLayout })));
136
140
  };
@@ -10,4 +10,5 @@ export declare const prepareLineData: (args: {
10
10
  yAxis: PreparedAxis[];
11
11
  yScale: ChartScale[];
12
12
  split: PreparedSplit;
13
+ isOutsideBounds: (x: number, y: number) => boolean;
13
14
  }) => Promise<PreparedLineData[]>;
@@ -40,7 +40,7 @@ async function getHtmlLabel(point, series, xMax) {
40
40
  }
41
41
  export const prepareLineData = async (args) => {
42
42
  var _a;
43
- const { series, xAxis, yAxis, xScale, yScale, split } = args;
43
+ const { series, xAxis, yAxis, xScale, yScale, split, isOutsideBounds } = args;
44
44
  const [_xMin, xRangeMax] = xScale.range();
45
45
  const xMax = xRangeMax / (1 - xAxis.maxPadding);
46
46
  const acc = [];
@@ -74,6 +74,7 @@ export const prepareLineData = async (args) => {
74
74
  point: p,
75
75
  active: true,
76
76
  hovered: false,
77
+ clipped: isOutsideBounds(p.x, p.y),
77
78
  }));
78
79
  }
79
80
  const result = {
@@ -12,6 +12,7 @@ export type MarkerData = {
12
12
  point: PointData;
13
13
  active: boolean;
14
14
  hovered: boolean;
15
+ clipped: boolean;
15
16
  };
16
17
  export type PreparedLineData = {
17
18
  id: string;
@@ -16,6 +16,9 @@ export function renderMarker(selection) {
16
16
  .append('path')
17
17
  .attr('class', haloClassName)
18
18
  .attr('d', (d) => {
19
+ if ('clipped' in d && d.clipped) {
20
+ return null;
21
+ }
19
22
  const series = d.point.series;
20
23
  const type = series.marker.states.normal.symbol;
21
24
  const radius = get(d.point.data, 'radius', series.marker.states.hover.radius);
@@ -53,6 +56,9 @@ export function getMarkerHaloVisibility(d) {
53
56
  export function setMarker(selection, state) {
54
57
  selection
55
58
  .attr('d', (d) => {
59
+ if ('clipped' in d && d.clipped) {
60
+ return null;
61
+ }
56
62
  const series = d.point.series;
57
63
  const type = series.marker.states.normal.symbol;
58
64
  const radius = get(d.point.data, 'radius', series.marker.states[state].radius);
@@ -8,4 +8,5 @@ export declare const prepareScatterData: (args: {
8
8
  xScale: ChartScale;
9
9
  yAxis: PreparedAxis[];
10
10
  yScale: ChartScale[];
11
+ isOutsideBounds: (x: number, y: number) => boolean;
11
12
  }) => PreparedScatterData[];
@@ -4,7 +4,7 @@ const getFilteredLinearScatterData = (data) => {
4
4
  return data.filter((d) => typeof d.x === 'number' && typeof d.y === 'number');
5
5
  };
6
6
  export const prepareScatterData = (args) => {
7
- const { series, xAxis, xScale, yAxis, yScale } = args;
7
+ const { series, xAxis, xScale, yAxis, yScale, isOutsideBounds } = args;
8
8
  return series.reduce((acc, s) => {
9
9
  const yAxisIndex = get(s, 'yAxis', 0);
10
10
  const seriesYAxis = yAxis[yAxisIndex];
@@ -14,18 +14,21 @@ export const prepareScatterData = (args) => {
14
14
  : getFilteredLinearScatterData(s.data);
15
15
  filteredData.forEach((d) => {
16
16
  var _a;
17
+ const x = getXValue({ point: d, xAxis, xScale });
18
+ const y = getYValue({ point: d, yAxis: seriesYAxis, yScale: seriesYScale });
17
19
  acc.push({
18
20
  point: {
19
21
  data: d,
20
22
  series: s,
21
- x: getXValue({ point: d, xAxis, xScale }),
22
- y: getYValue({ point: d, yAxis: seriesYAxis, yScale: seriesYScale }),
23
+ x,
24
+ y,
23
25
  opacity: get(d, 'opacity', null),
24
26
  color: (_a = d.color) !== null && _a !== void 0 ? _a : s.color,
25
27
  },
26
28
  hovered: false,
27
29
  active: true,
28
30
  htmlElements: [],
31
+ clipped: isOutsideBounds(x, y),
29
32
  });
30
33
  });
31
34
  return acc;
@@ -13,6 +13,7 @@ export type MarkerData = {
13
13
  active: boolean;
14
14
  hovered: boolean;
15
15
  htmlElements: HtmlItem[];
16
+ clipped: boolean;
16
17
  };
17
18
  export type PreparedScatterData = MarkerData;
18
19
  export {};
@@ -9,5 +9,6 @@ type Args = {
9
9
  preparedData: PreparedWaterfallData[];
10
10
  seriesOptions: PreparedSeriesOptions;
11
11
  htmlLayout: HTMLElement | null;
12
+ clipPathId: string;
12
13
  };
13
14
  export declare const WaterfallSeriesShapes: (args: Args) => React.JSX.Element;
@@ -8,7 +8,7 @@ export { prepareWaterfallData } from './prepare-data';
8
8
  export * from './types';
9
9
  const b = block('waterfall');
10
10
  export const WaterfallSeriesShapes = (args) => {
11
- const { dispatcher, preparedData, seriesOptions, htmlLayout } = args;
11
+ const { dispatcher, preparedData, seriesOptions, htmlLayout, clipPathId } = args;
12
12
  const hoveredDataRef = React.useRef(null);
13
13
  const ref = React.useRef(null);
14
14
  const connectorSelector = `.${b('connector')}`;
@@ -127,6 +127,6 @@ export const WaterfallSeriesShapes = (args) => {
127
127
  };
128
128
  }, [dispatcher, preparedData, seriesOptions]);
129
129
  return (React.createElement(React.Fragment, null,
130
- React.createElement("g", { ref: ref, className: b() }),
130
+ React.createElement("g", { ref: ref, className: b(), clipPath: `url(#${clipPathId})` }),
131
131
  React.createElement(HtmlLayer, { preparedData: preparedData, htmlLayout: htmlLayout })));
132
132
  };
@@ -35,7 +35,7 @@ export function useZoom(props) {
35
35
  selection,
36
36
  xAxis,
37
37
  xScale,
38
- yAxises: yAxis,
38
+ yAxes: yAxis,
39
39
  yScales: yScale,
40
40
  zoomType: preparedZoom.type,
41
41
  });
@@ -6,7 +6,7 @@ export declare function selectionToZoomBounds(args: {
6
6
  selection: BrushSelection;
7
7
  xAxis: PreparedAxis;
8
8
  xScale: ChartScale;
9
- yAxises: PreparedAxis[];
9
+ yAxes: PreparedAxis[];
10
10
  yScales: ChartScale[];
11
11
  zoomType: PreparedZoom['type'];
12
12
  }): Partial<ZoomState>;
@@ -1,5 +1,5 @@
1
1
  export function selectionToZoomBounds(args) {
2
- const { selection, xAxis, xScale, yAxises, yScales, zoomType } = args;
2
+ const { selection, xAxis, xScale, yAxes, yScales, zoomType } = args;
3
3
  const zoomState = {};
4
4
  switch (zoomType) {
5
5
  case 'x': {
@@ -9,7 +9,7 @@ export function selectionToZoomBounds(args) {
9
9
  }
10
10
  case 'y': {
11
11
  const [y1, y0] = selection;
12
- yAxises.forEach((yAxis, index) => {
12
+ yAxes.forEach((yAxis, index) => {
13
13
  if (!Array.isArray(zoomState.y)) {
14
14
  zoomState.y = [];
15
15
  }
@@ -25,7 +25,7 @@ export function selectionToZoomBounds(args) {
25
25
  const [x0, y0] = selection[0];
26
26
  const [x1, y1] = selection[1];
27
27
  zoomState.x = selectionXToZoomBounds({ xAxis, xScale, selection: [x0, x1] });
28
- yAxises.forEach((yAxis, index) => {
28
+ yAxes.forEach((yAxis, index) => {
29
29
  if (!Array.isArray(zoomState.y)) {
30
30
  zoomState.y = [];
31
31
  }
@@ -53,6 +53,8 @@ export interface ChartAxis {
53
53
  };
54
54
  /** The minimum value of the axis. If undefined the min value is automatically calculate. */
55
55
  min?: number;
56
+ /** The maximum value of the axis. If undefined the max value is automatically calculate. */
57
+ max?: number;
56
58
  /** The grid lines settings. */
57
59
  grid?: {
58
60
  /** Enable or disable the grid lines.
@@ -130,11 +132,8 @@ export interface AxisCrosshair extends Omit<AxisPlotLine, 'value'> {
130
132
  enabled?: boolean;
131
133
  }
132
134
  export interface ChartYAxis extends ChartAxis {
133
- /** Axis location.
134
- * Possible values - 'left' and 'right'.
135
- * */
135
+ /** Axis location. */
136
136
  position?: 'left' | 'right';
137
- /** Property for splitting charts. Determines which area the axis is located in.
138
- * */
137
+ /** Property for splitting charts. Determines which area the axis is located in. */
139
138
  plotIndex?: number;
140
139
  }
@@ -106,6 +106,7 @@ export async function axisBottom(args) {
106
106
  .remove();
107
107
  // add an ellipsis to the labels that go beyond the boundaries of the chart
108
108
  labels.each(function (_d, i, nodes) {
109
+ var _a;
109
110
  if (i === 0) {
110
111
  const currentElement = this;
111
112
  const text = select(currentElement);
@@ -113,7 +114,8 @@ export async function axisBottom(args) {
113
114
  const nextElement = nodes[i + 1];
114
115
  const nextElementPosition = nextElement === null || nextElement === void 0 ? void 0 : nextElement.getBoundingClientRect();
115
116
  if (currentElementPosition.left < leftmostLimit) {
116
- const remainSpace = nextElementPosition.left -
117
+ const rightmostPossiblePoint = (_a = nextElementPosition === null || nextElementPosition === void 0 ? void 0 : nextElementPosition.left) !== null && _a !== void 0 ? _a : right;
118
+ const remainSpace = rightmostPossiblePoint -
117
119
  currentElementPosition.right +
118
120
  x -
119
121
  labelsMargin;