@mui/x-charts-pro 8.5.1 → 8.5.3

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 (98) hide show
  1. package/BarChartPro/BarChartPro.d.ts +3 -2
  2. package/CHANGELOG.md +187 -10
  3. package/ChartDataProviderPro/ChartDataProviderPro.js +1 -1
  4. package/ChartZoomSlider/internals/ChartAxisZoomSlider.js +1 -1
  5. package/ChartZoomSlider/internals/ChartAxisZoomSliderActiveTrack.js +22 -32
  6. package/ChartZoomSlider/internals/ChartAxisZoomSliderTrack.js +1 -8
  7. package/ChartZoomSlider/internals/zoom-utils.d.ts +3 -1
  8. package/ChartZoomSlider/internals/zoom-utils.js +19 -8
  9. package/ChartsToolbarPro/ChartsToolbarPro.d.ts +2 -1
  10. package/ChartsToolbarPro/Toolbar.types.d.ts +15 -0
  11. package/ChartsToolbarPro/Toolbar.types.js +5 -0
  12. package/FunnelChart/FunnelChart.js +4 -11
  13. package/FunnelChart/FunnelChart.plugins.d.ts +3 -2
  14. package/FunnelChart/FunnelChart.plugins.js +2 -1
  15. package/FunnelChart/FunnelPlot.d.ts +0 -5
  16. package/FunnelChart/FunnelPlot.js +85 -67
  17. package/FunnelChart/FunnelSection.js +2 -0
  18. package/FunnelChart/categoryAxis.types.d.ts +2 -1
  19. package/FunnelChart/curves/bump.d.ts +3 -5
  20. package/FunnelChart/curves/bump.js +13 -13
  21. package/FunnelChart/curves/curve.types.d.ts +14 -1
  22. package/FunnelChart/curves/getFunnelCurve.d.ts +7 -2
  23. package/FunnelChart/curves/linear.d.ts +4 -4
  24. package/FunnelChart/curves/linear.js +42 -34
  25. package/FunnelChart/curves/pyramid.d.ts +3 -3
  26. package/FunnelChart/curves/pyramid.js +25 -24
  27. package/FunnelChart/curves/step-pyramid.d.ts +5 -5
  28. package/FunnelChart/curves/step-pyramid.js +24 -24
  29. package/FunnelChart/curves/step.d.ts +3 -3
  30. package/FunnelChart/curves/step.js +14 -26
  31. package/FunnelChart/funnelAxisPlugin/computeAxisValue.d.ts +25 -0
  32. package/FunnelChart/funnelAxisPlugin/computeAxisValue.js +124 -0
  33. package/FunnelChart/funnelAxisPlugin/useChartFunnelAxis.d.ts +3 -0
  34. package/FunnelChart/funnelAxisPlugin/useChartFunnelAxis.js +173 -0
  35. package/FunnelChart/funnelAxisPlugin/useChartFunnelAxis.types.d.ts +27 -0
  36. package/FunnelChart/funnelAxisPlugin/useChartFunnelAxis.types.js +5 -0
  37. package/FunnelChart/funnelAxisPlugin/useChartFunnelAxisRendering.selectors.d.ts +56 -0
  38. package/FunnelChart/funnelAxisPlugin/useChartFunnelAxisRendering.selectors.js +27 -0
  39. package/FunnelChart/labelUtils.d.ts +4 -11
  40. package/FunnelChart/labelUtils.js +43 -44
  41. package/FunnelChart/useFunnelChartProps.js +1 -3
  42. package/Heatmap/Heatmap.d.ts +3 -3
  43. package/LineChartPro/LineChartPro.d.ts +3 -2
  44. package/PieChartPro/PieChartPro.d.ts +3 -2
  45. package/RadarChartPro/RadarChartPro.d.ts +17 -2
  46. package/ScatterChartPro/ScatterChartPro.d.ts +3 -2
  47. package/esm/BarChartPro/BarChartPro.d.ts +3 -2
  48. package/esm/ChartDataProviderPro/ChartDataProviderPro.js +1 -1
  49. package/esm/ChartZoomSlider/internals/ChartAxisZoomSlider.js +1 -1
  50. package/esm/ChartZoomSlider/internals/ChartAxisZoomSliderActiveTrack.js +23 -33
  51. package/esm/ChartZoomSlider/internals/ChartAxisZoomSliderTrack.js +1 -8
  52. package/esm/ChartZoomSlider/internals/zoom-utils.d.ts +3 -1
  53. package/esm/ChartZoomSlider/internals/zoom-utils.js +19 -9
  54. package/esm/ChartsToolbarPro/ChartsToolbarPro.d.ts +2 -1
  55. package/esm/ChartsToolbarPro/Toolbar.types.d.ts +15 -0
  56. package/esm/ChartsToolbarPro/Toolbar.types.js +1 -0
  57. package/esm/FunnelChart/FunnelChart.js +4 -11
  58. package/esm/FunnelChart/FunnelChart.plugins.d.ts +3 -2
  59. package/esm/FunnelChart/FunnelChart.plugins.js +3 -2
  60. package/esm/FunnelChart/FunnelPlot.d.ts +0 -5
  61. package/esm/FunnelChart/FunnelPlot.js +86 -68
  62. package/esm/FunnelChart/FunnelSection.js +2 -0
  63. package/esm/FunnelChart/categoryAxis.types.d.ts +2 -1
  64. package/esm/FunnelChart/curves/bump.d.ts +3 -5
  65. package/esm/FunnelChart/curves/bump.js +13 -13
  66. package/esm/FunnelChart/curves/curve.types.d.ts +14 -1
  67. package/esm/FunnelChart/curves/getFunnelCurve.d.ts +7 -2
  68. package/esm/FunnelChart/curves/linear.d.ts +4 -4
  69. package/esm/FunnelChart/curves/linear.js +42 -34
  70. package/esm/FunnelChart/curves/pyramid.d.ts +3 -3
  71. package/esm/FunnelChart/curves/pyramid.js +25 -24
  72. package/esm/FunnelChart/curves/step-pyramid.d.ts +5 -5
  73. package/esm/FunnelChart/curves/step-pyramid.js +24 -24
  74. package/esm/FunnelChart/curves/step.d.ts +3 -3
  75. package/esm/FunnelChart/curves/step.js +14 -26
  76. package/esm/FunnelChart/funnelAxisPlugin/computeAxisValue.d.ts +25 -0
  77. package/esm/FunnelChart/funnelAxisPlugin/computeAxisValue.js +114 -0
  78. package/esm/FunnelChart/funnelAxisPlugin/useChartFunnelAxis.d.ts +3 -0
  79. package/esm/FunnelChart/funnelAxisPlugin/useChartFunnelAxis.js +165 -0
  80. package/esm/FunnelChart/funnelAxisPlugin/useChartFunnelAxis.types.d.ts +27 -0
  81. package/esm/FunnelChart/funnelAxisPlugin/useChartFunnelAxis.types.js +1 -0
  82. package/esm/FunnelChart/funnelAxisPlugin/useChartFunnelAxisRendering.selectors.d.ts +56 -0
  83. package/esm/FunnelChart/funnelAxisPlugin/useChartFunnelAxisRendering.selectors.js +20 -0
  84. package/esm/FunnelChart/labelUtils.d.ts +4 -11
  85. package/esm/FunnelChart/labelUtils.js +43 -44
  86. package/esm/FunnelChart/useFunnelChartProps.js +1 -3
  87. package/esm/Heatmap/Heatmap.d.ts +3 -3
  88. package/esm/LineChartPro/LineChartPro.d.ts +3 -2
  89. package/esm/PieChartPro/PieChartPro.d.ts +3 -2
  90. package/esm/RadarChartPro/RadarChartPro.d.ts +17 -2
  91. package/esm/ScatterChartPro/ScatterChartPro.d.ts +3 -2
  92. package/esm/index.js +1 -1
  93. package/esm/internals/plugins/useChartProZoom/useChartProZoom.selectors.d.ts +16 -595
  94. package/esm/internals/plugins/useChartProZoom/useChartProZoom.selectors.js +2 -2
  95. package/index.js +1 -1
  96. package/internals/plugins/useChartProZoom/useChartProZoom.selectors.d.ts +16 -595
  97. package/internals/plugins/useChartProZoom/useChartProZoom.selectors.js +2 -2
  98. package/package.json +6 -6
@@ -37,7 +37,7 @@ export class StepPyramid {
37
37
  this.points = [];
38
38
  this.context = context;
39
39
  this.isHorizontal = isHorizontal ?? false;
40
- this.gap = (gap ?? 0) / 2;
40
+ this.gap = gap ?? 0;
41
41
  this.position = position ?? 0;
42
42
  this.sections = sections ?? 1;
43
43
  this.borderRadius = borderRadius ?? 0;
@@ -130,48 +130,48 @@ export class StepPyramid {
130
130
  y: this.max.y
131
131
  };
132
132
  }
133
- initialX(index) {
133
+ initialX(index, points) {
134
134
  if (this.isIncreasing) {
135
- return index === 0 || index === 1 ? this.points.at(1).x : this.points.at(2).x;
135
+ return index === 0 || index === 1 ? points.at(1).x : points.at(2).x;
136
136
  }
137
- return index === 0 || index === 1 ? this.points.at(0).x : this.points.at(3).x;
137
+ return index === 0 || index === 1 ? points.at(0).x : points.at(3).x;
138
138
  }
139
- initialY(index) {
139
+ initialY(index, points) {
140
140
  if (this.isIncreasing) {
141
- return index === 0 || index === 1 ? this.points.at(1).y : this.points.at(2).y;
141
+ return index === 0 || index === 1 ? points.at(1).y : points.at(2).y;
142
142
  }
143
- return index === 0 || index === 1 ? this.points.at(0).y : this.points.at(3).y;
143
+ return index === 0 || index === 1 ? points.at(0).y : points.at(3).y;
144
144
  }
145
- point(xIn, yIn) {
146
- this.points.push({
147
- x: xIn,
148
- y: yIn
149
- });
150
- if (this.points.length < 4) {
151
- return;
152
- }
153
-
154
- // Add gaps where they are needed.
155
- this.points = this.points.map((point, index) => {
145
+ processPoints(points) {
146
+ // Replace funnel points by pyramids ones.
147
+ const processedPoints = points.map((point, index) => {
156
148
  const slopeStart = this.slopeStart(index);
157
149
  const slopeEnd = this.slopeEnd(index);
158
150
  if (this.isHorizontal) {
159
151
  const yGetter = lerpY(slopeStart.x, slopeStart.y, slopeEnd.x, slopeEnd.y);
160
- const xGap = point.x + (index === 0 || index === 3 ? this.gap : -this.gap);
161
- const xInitial = this.initialX(index);
152
+ const xInitial = this.initialX(index, points);
162
153
  return {
163
- x: xGap,
154
+ x: point.x,
164
155
  y: yGetter(xInitial)
165
156
  };
166
157
  }
167
158
  const xGetter = lerpX(slopeStart.x, slopeStart.y, slopeEnd.x, slopeEnd.y);
168
- const yGap = point.y + (index === 0 || index === 3 ? this.gap : -this.gap);
169
- const yInitial = this.initialY(index);
159
+ const yInitial = this.initialY(index, points);
170
160
  return {
171
161
  x: xGetter(yInitial),
172
- y: yGap
162
+ y: point.y
173
163
  };
174
164
  });
165
+ return processedPoints;
166
+ }
167
+ point(xIn, yIn) {
168
+ this.points.push({
169
+ x: xIn,
170
+ y: yIn
171
+ });
172
+ if (this.points.length < 4) {
173
+ return;
174
+ }
175
175
  borderRadiusPolygon(this.context, this.points, this.getBorderRadius());
176
176
  }
177
177
  }
@@ -1,5 +1,4 @@
1
- import { CurveGenerator } from '@mui/x-charts-vendor/d3-shape';
2
- import { CurveOptions } from "./curve.types.js";
1
+ import { FunnelCurveGenerator, CurveOptions, Point } from "./curve.types.js";
3
2
  /**
4
3
  * This is a custom "step" curve generator.
5
4
  * It is used to draw "rectangles" from 4 points without having to rework the rendering logic,
@@ -10,7 +9,7 @@ import { CurveOptions } from "./curve.types.js";
10
9
  * The implementation is based on the d3-shape step curve generator.
11
10
  * https://github.com/d3/d3-shape/blob/a82254af78f08799c71d7ab25df557c4872a3c51/src/curve/step.js
12
11
  */
13
- export declare class Step implements CurveGenerator {
12
+ export declare class Step implements FunnelCurveGenerator {
14
13
  private context;
15
14
  private isHorizontal;
16
15
  private isIncreasing;
@@ -32,5 +31,6 @@ export declare class Step implements CurveGenerator {
32
31
  lineStart(): void;
33
32
  lineEnd(): void;
34
33
  protected getBorderRadius(): number | number[];
34
+ processPoints(points: Point[]): Point[];
35
35
  point(xIn: number, yIn: number): void;
36
36
  }
@@ -32,7 +32,7 @@ export class Step {
32
32
  this.points = [];
33
33
  this.context = context;
34
34
  this.isHorizontal = isHorizontal ?? false;
35
- this.gap = (gap ?? 0) / 2;
35
+ this.gap = gap ?? 0;
36
36
  this.position = position ?? 0;
37
37
  this.sections = sections ?? 1;
38
38
  this.borderRadius = borderRadius ?? 0;
@@ -57,19 +57,11 @@ export class Step {
57
57
  }
58
58
  return [this.borderRadius, this.borderRadius];
59
59
  }
60
- point(xIn, yIn) {
61
- this.points.push({
62
- x: xIn,
63
- y: yIn
64
- });
65
- if (this.points.length < 4) {
66
- return;
67
- }
68
-
60
+ processPoints(points) {
69
61
  // Ensure we have rectangles instead of trapezoids.
70
- this.points = this.points.map((_, index) => {
71
- const allX = this.points.map(p => p.x);
72
- const allY = this.points.map(p => p.y);
62
+ const processedPoints = points.map((_, index) => {
63
+ const allX = points.map(p => p.x);
64
+ const allY = points.map(p => p.y);
73
65
  if (this.isHorizontal) {
74
66
  return {
75
67
  x: index === 1 || index === 2 ? max(allX) : min(allX),
@@ -81,20 +73,16 @@ export class Step {
81
73
  y: index === 1 || index === 2 ? max(allY) : min(allY)
82
74
  };
83
75
  });
84
-
85
- // Add gaps where they are needed.
86
- this.points = this.points.map((point, index) => {
87
- if (this.isHorizontal) {
88
- return {
89
- x: point.x + (index === 0 || index === 3 ? this.gap : -this.gap),
90
- y: point.y
91
- };
92
- }
93
- return {
94
- x: point.x,
95
- y: point.y + (index === 0 || index === 3 ? this.gap : -this.gap)
96
- };
76
+ return processedPoints;
77
+ }
78
+ point(xIn, yIn) {
79
+ this.points.push({
80
+ x: xIn,
81
+ y: yIn
97
82
  });
83
+ if (this.points.length < 4) {
84
+ return;
85
+ }
98
86
  borderRadiusPolygon(this.context, this.points, this.getBorderRadius());
99
87
  }
100
88
  }
@@ -0,0 +1,25 @@
1
+ import { ChartsAxisProps } from '@mui/x-charts/ChartsAxis';
2
+ import { ChartDrawingArea } from '@mui/x-charts/hooks';
3
+ import { ComputedAxisConfig, ChartSeriesType, ProcessedSeries, ChartSeriesConfig, DefaultedYAxis, DefaultedXAxis } from '@mui/x-charts/internals';
4
+ import { ChartsXAxisProps, ChartsYAxisProps } from '@mui/x-charts/models';
5
+ export declare const xRangeGetter: (drawingArea: ChartDrawingArea, reverse?: boolean, removedSpace?: number) => [number, number];
6
+ export declare const yRangeGetter: (drawingArea: ChartDrawingArea, reverse?: boolean, removedSpace?: number) => [number, number];
7
+ export type ComputeResult<T extends ChartsAxisProps> = {
8
+ axis: ComputedAxisConfig<T>;
9
+ axisIds: string[];
10
+ };
11
+ type ComputeCommonParams<T extends ChartSeriesType = 'funnel'> = {
12
+ drawingArea: ChartDrawingArea;
13
+ formattedSeries: ProcessedSeries<T>;
14
+ seriesConfig: ChartSeriesConfig<T>;
15
+ gap: number;
16
+ };
17
+ export declare function computeAxisValue(options: ComputeCommonParams<'funnel'> & {
18
+ axis?: DefaultedYAxis[];
19
+ axisDirection: 'y';
20
+ }): ComputeResult<ChartsYAxisProps>;
21
+ export declare function computeAxisValue(options: ComputeCommonParams<'funnel'> & {
22
+ axis?: DefaultedXAxis[];
23
+ axisDirection: 'x';
24
+ }): ComputeResult<ChartsXAxisProps>;
25
+ export {};
@@ -0,0 +1,114 @@
1
+ import _extends from "@babel/runtime/helpers/esm/extends";
2
+ import { scaleBand } from '@mui/x-charts-vendor/d3-scale';
3
+ import { getAxisExtremum, isBandScaleConfig, getScale, getColorScale, getOrdinalColorScale, getTickNumber, scaleTickNumberByRange, getCartesianAxisTriggerTooltip, isDateData, createDateFormatter } from '@mui/x-charts/internals';
4
+ export const xRangeGetter = (drawingArea, reverse, removedSpace = 0) => {
5
+ const range = [drawingArea.left, drawingArea.left + drawingArea.width - removedSpace];
6
+ return reverse ? [range[1], range[0]] : [range[0], range[1]];
7
+ };
8
+ export const yRangeGetter = (drawingArea, reverse, removedSpace = 0) => {
9
+ const range = [drawingArea.top + drawingArea.height - removedSpace, drawingArea.top];
10
+ return reverse ? [range[1], range[0]] : [range[0], range[1]];
11
+ };
12
+ function getRange(drawingArea, axisDirection, axis, removedSpace = 0) {
13
+ return axisDirection === 'x' ? xRangeGetter(drawingArea, axis.reverse, removedSpace) : yRangeGetter(drawingArea, axis.reverse, removedSpace);
14
+ }
15
+ export function computeAxisValue({
16
+ drawingArea,
17
+ formattedSeries,
18
+ axis: allAxis,
19
+ seriesConfig,
20
+ axisDirection,
21
+ gap
22
+ }) {
23
+ if (allAxis === undefined) {
24
+ return {
25
+ axis: {},
26
+ axisIds: []
27
+ };
28
+ }
29
+ const axisIdsTriggeringTooltip = getCartesianAxisTriggerTooltip(axisDirection, seriesConfig, formattedSeries, allAxis[0].id);
30
+ const completeAxis = {};
31
+ allAxis.forEach((eachAxis, axisIndex) => {
32
+ const axis = eachAxis;
33
+ let range = getRange(drawingArea, axisDirection, axis);
34
+ const [minData, maxData] = getAxisExtremum(axis, axisDirection, seriesConfig, axisIndex, formattedSeries);
35
+ const triggerTooltip = !axis.ignoreTooltip && axisIdsTriggeringTooltip.has(axis.id);
36
+ const data = axis.data ?? [];
37
+ if (isBandScaleConfig(axis)) {
38
+ // Reverse range because ordinal scales are presented from top to bottom on y-axis
39
+ const scaleRange = axisDirection === 'y' ? [range[1], range[0]] : range;
40
+ const rangeSpace = Math.abs(range[1] - range[0]);
41
+ const N = axis.data.length;
42
+ const bandWidth = (rangeSpace - gap * (N - 1)) / N;
43
+ const step = bandWidth + gap;
44
+ completeAxis[axis.id] = _extends({
45
+ offset: 0,
46
+ height: 0,
47
+ categoryGapRatio: 0,
48
+ barGapRatio: 0,
49
+ triggerTooltip
50
+ }, axis, {
51
+ data,
52
+ scale: scaleBand(axis.data, scaleRange).paddingInner(gap / step).paddingOuter(0),
53
+ tickNumber: axis.data.length,
54
+ colorScale: axis.colorMap && (axis.colorMap.type === 'ordinal' ? getOrdinalColorScale(_extends({
55
+ values: axis.data
56
+ }, axis.colorMap)) : getColorScale(axis.colorMap))
57
+ });
58
+ if (isDateData(axis.data)) {
59
+ const dateFormatter = createDateFormatter(axis, scaleRange);
60
+ completeAxis[axis.id].valueFormatter = axis.valueFormatter ?? dateFormatter;
61
+ }
62
+ }
63
+ if (axis.scaleType === 'band') {
64
+ return;
65
+ }
66
+ if (axis.scaleType === 'point') {
67
+ throw new Error('Point scale is not supported in FunnelChart. Please use band scale instead.');
68
+ }
69
+ const isHorizontal = Object.values(formattedSeries.funnel?.series ?? {}).some(s => s.layout === 'horizontal');
70
+ if (isHorizontal ? axisDirection === 'x' : axisDirection === 'y') {
71
+ // For linear scale replacing the band scale, we remove the space needed for gap from the scale range.
72
+ const itemNumber = formattedSeries.funnel?.series[formattedSeries.funnel.seriesOrder[0]].data.length ?? 0;
73
+ const spaceToRemove = gap * (itemNumber - 1);
74
+ range = getRange(drawingArea, axisDirection, axis, spaceToRemove);
75
+ }
76
+ const scaleType = axis.scaleType ?? 'linear';
77
+ const domainLimit = axis.domainLimit ?? 'nice';
78
+ const axisExtremums = [axis.min ?? minData, axis.max ?? maxData];
79
+ if (typeof domainLimit === 'function') {
80
+ const {
81
+ min,
82
+ max
83
+ } = domainLimit(minData, maxData);
84
+ axisExtremums[0] = min;
85
+ axisExtremums[1] = max;
86
+ }
87
+ const rawTickNumber = getTickNumber(_extends({}, axis, {
88
+ range,
89
+ domain: axisExtremums
90
+ }));
91
+ const tickNumber = scaleTickNumberByRange(rawTickNumber, range);
92
+ const scale = getScale(scaleType, axisExtremums, range);
93
+ const finalScale = domainLimit === 'nice' ? scale.nice(rawTickNumber) : scale;
94
+ const [minDomain, maxDomain] = finalScale.domain();
95
+ const domain = [axis.min ?? minDomain, axis.max ?? maxDomain];
96
+ completeAxis[axis.id] = _extends({
97
+ offset: 0,
98
+ height: 0,
99
+ triggerTooltip
100
+ }, axis, {
101
+ data,
102
+ scaleType: scaleType,
103
+ scale: finalScale.domain(domain),
104
+ tickNumber,
105
+ colorScale: axis.colorMap && getColorScale(axis.colorMap)
106
+ });
107
+ });
108
+ return {
109
+ axis: completeAxis,
110
+ axisIds: allAxis.map(({
111
+ id
112
+ }) => id)
113
+ };
114
+ }
@@ -0,0 +1,3 @@
1
+ import { ChartPlugin } from '@mui/x-charts/internals';
2
+ import { UseChartFunnelAxisSignature } from "./useChartFunnelAxis.types.js";
3
+ export declare const useChartFunnelAxis: ChartPlugin<UseChartFunnelAxisSignature>;
@@ -0,0 +1,165 @@
1
+ 'use client';
2
+
3
+ import _extends from "@babel/runtime/helpers/esm/extends";
4
+ import * as React from 'react';
5
+ import { warnOnce } from '@mui/x-internals/warning';
6
+ import { getSVGPoint, getCartesianAxisIndex, selectorChartDrawingArea, selectorChartSeriesProcessed, selectorChartsInteractionIsInitialized, useSelector, defaultizeXAxis, defaultizeYAxis } from '@mui/x-charts/internals';
7
+ import { selectorChartXAxis, selectorChartYAxis } from "./useChartFunnelAxisRendering.selectors.js";
8
+ export const useChartFunnelAxis = ({
9
+ params,
10
+ store,
11
+ seriesConfig,
12
+ svgRef,
13
+ instance
14
+ }) => {
15
+ const {
16
+ xAxis,
17
+ yAxis,
18
+ dataset,
19
+ gap
20
+ } = params;
21
+ if (process.env.NODE_ENV !== 'production') {
22
+ const ids = [...(xAxis ?? []), ...(yAxis ?? [])].filter(axis => axis.id).map(axis => axis.id);
23
+ const duplicates = new Set(ids.filter((id, index) => ids.indexOf(id) !== index));
24
+ if (duplicates.size > 0) {
25
+ warnOnce([`MUI X Charts: The following axis ids are duplicated: ${Array.from(duplicates).join(', ')}.`, `Please make sure that each axis has a unique id.`].join('\n'), 'error');
26
+ }
27
+ }
28
+ const drawingArea = useSelector(store, selectorChartDrawingArea);
29
+ const isInteractionEnabled = useSelector(store, selectorChartsInteractionIsInitialized);
30
+ const isFirstRender = React.useRef(true);
31
+ React.useEffect(() => {
32
+ if (isFirstRender.current) {
33
+ isFirstRender.current = false;
34
+ return;
35
+ }
36
+ store.update(prev => _extends({}, prev, {
37
+ funnel: {
38
+ gap: gap ?? 0
39
+ },
40
+ cartesianAxis: _extends({}, prev.cartesianAxis, {
41
+ x: defaultizeXAxis(xAxis, dataset),
42
+ y: defaultizeYAxis(yAxis, dataset)
43
+ })
44
+ }));
45
+ }, [seriesConfig, drawingArea, xAxis, yAxis, dataset, store, gap]);
46
+ React.useEffect(() => {
47
+ const element = svgRef.current;
48
+ if (!isInteractionEnabled || element === null || params.disableAxisListener) {
49
+ return () => {};
50
+ }
51
+ const handleOut = () => {
52
+ instance.cleanInteraction?.();
53
+ };
54
+ const handleMove = event => {
55
+ const target = 'targetTouches' in event ? event.targetTouches[0] : event;
56
+ const svgPoint = getSVGPoint(element, target);
57
+ if (!instance.isPointInside(svgPoint.x, svgPoint.y, event.target)) {
58
+ instance.cleanInteraction?.();
59
+ return;
60
+ }
61
+ instance.setPointerCoordinate?.(svgPoint);
62
+ };
63
+ const handleDown = event => {
64
+ const target = event.currentTarget;
65
+ if (!target) {
66
+ return;
67
+ }
68
+ if ('hasPointerCapture' in target && target.hasPointerCapture(event.pointerId)) {
69
+ target.releasePointerCapture(event.pointerId);
70
+ }
71
+ };
72
+ element.addEventListener('pointerdown', handleDown);
73
+ element.addEventListener('pointermove', handleMove);
74
+ element.addEventListener('pointercancel', handleOut);
75
+ element.addEventListener('pointerleave', handleOut);
76
+ return () => {
77
+ element.removeEventListener('pointerdown', handleDown);
78
+ element.removeEventListener('pointermove', handleMove);
79
+ element.removeEventListener('pointercancel', handleOut);
80
+ element.removeEventListener('pointerleave', handleOut);
81
+ };
82
+ }, [svgRef, instance, params.disableAxisListener, isInteractionEnabled]);
83
+ React.useEffect(() => {
84
+ const element = svgRef.current;
85
+ const onAxisClick = params.onAxisClick;
86
+ if (element === null || !onAxisClick) {
87
+ return () => {};
88
+ }
89
+ const handleMouseClick = event => {
90
+ event.preventDefault();
91
+ const {
92
+ axis: xAxisWithScale,
93
+ axisIds: xAxisIds
94
+ } = selectorChartXAxis(store.value);
95
+ const {
96
+ axis: yAxisWithScale,
97
+ axisIds: yAxisIds
98
+ } = selectorChartYAxis(store.value);
99
+ const processedSeries = selectorChartSeriesProcessed(store.value);
100
+ const usedXAxis = xAxisIds[0];
101
+ const usedYAxis = yAxisIds[0];
102
+ let dataIndex = null;
103
+ let isXAxis = false;
104
+ const svgPoint = getSVGPoint(element, event);
105
+ const xIndex = getCartesianAxisIndex(xAxisWithScale[usedXAxis], svgPoint.x);
106
+ isXAxis = xIndex !== -1;
107
+ dataIndex = isXAxis ? xIndex : getCartesianAxisIndex(yAxisWithScale[usedYAxis], svgPoint.y);
108
+ const USED_AXIS_ID = isXAxis ? xAxisIds[0] : yAxisIds[0];
109
+ if (dataIndex == null || dataIndex === -1) {
110
+ return;
111
+ }
112
+
113
+ // The .data exist because otherwise the dataIndex would be null or -1.
114
+ const axisValue = (isXAxis ? xAxisWithScale : yAxisWithScale)[USED_AXIS_ID].data[dataIndex];
115
+ const seriesValues = {};
116
+ processedSeries.funnel?.seriesOrder.forEach(seriesId => {
117
+ const seriesItem = processedSeries.funnel.series[seriesId];
118
+ const providedXAxisId = seriesItem.xAxisId;
119
+ const providedYAxisId = seriesItem.yAxisId;
120
+ const axisKey = isXAxis ? providedXAxisId : providedYAxisId;
121
+ if (axisKey === undefined || axisKey === USED_AXIS_ID) {
122
+ seriesValues[seriesId] = seriesItem.data[dataIndex].value;
123
+ }
124
+ });
125
+ onAxisClick(event, {
126
+ dataIndex,
127
+ axisValue,
128
+ seriesValues
129
+ });
130
+ };
131
+ element.addEventListener('click', handleMouseClick);
132
+ return () => {
133
+ element.removeEventListener('click', handleMouseClick);
134
+ };
135
+ }, [params.onAxisClick, svgRef, store]);
136
+ return {};
137
+ };
138
+ useChartFunnelAxis.params = {
139
+ xAxis: true,
140
+ yAxis: true,
141
+ gap: true,
142
+ dataset: true,
143
+ onAxisClick: true,
144
+ disableAxisListener: true
145
+ };
146
+ useChartFunnelAxis.getDefaultizedParams = ({
147
+ params
148
+ }) => {
149
+ return _extends({}, params, {
150
+ gap: params.gap ?? 0,
151
+ defaultizedXAxis: defaultizeXAxis(params.xAxis, params.dataset),
152
+ defaultizedYAxis: defaultizeYAxis(params.yAxis, params.dataset)
153
+ });
154
+ };
155
+ useChartFunnelAxis.getInitialState = params => {
156
+ return {
157
+ funnel: {
158
+ gap: params.gap ?? 0
159
+ },
160
+ cartesianAxis: {
161
+ x: params.defaultizedXAxis,
162
+ y: params.defaultizedYAxis
163
+ }
164
+ };
165
+ };
@@ -0,0 +1,27 @@
1
+ import { ChartPluginSignature, UseChartCartesianAxisDefaultizedParameters, UseChartCartesianAxisParameters, UseChartCartesianAxisState, UseChartInteractionSignature, UseChartSeriesSignature, ChartsAxisData } from '@mui/x-charts/internals';
2
+ export type UseChartFunnelAxisSignature = ChartPluginSignature<{
3
+ params: Omit<UseChartCartesianAxisParameters, 'onAxisClick'> & {
4
+ /**
5
+ * The gap, in pixels, between funnel sections.
6
+ * @default 0
7
+ */
8
+ gap?: number;
9
+ /**
10
+ * The function called for onClick events.
11
+ * The second argument contains information about all funnel elements at the current position.
12
+ * @param {MouseEvent} event The mouse event recorded on the `<svg/>` element.
13
+ * @param {null | ChartsAxisData} data The data about the clicked axis and items associated with it.
14
+ */
15
+ onAxisClick?: (event: MouseEvent, data: null | ChartsAxisData) => void;
16
+ };
17
+ defaultizedParams: UseChartCartesianAxisDefaultizedParameters & {
18
+ gap: number;
19
+ };
20
+ state: Pick<UseChartCartesianAxisState, 'cartesianAxis'> & {
21
+ funnel: {
22
+ gap: number;
23
+ };
24
+ };
25
+ dependencies: [UseChartSeriesSignature<'funnel'>];
26
+ optionalDependencies: [UseChartInteractionSignature];
27
+ }>;
@@ -0,0 +1,56 @@
1
+ import { ChartState } from '@mui/x-charts/internals';
2
+ import { UseChartFunnelAxisSignature } from "./useChartFunnelAxis.types.js";
3
+ export declare const selectorFunnel: (state: ChartState<[], [UseChartFunnelAxisSignature]>) => {
4
+ gap: number;
5
+ } | undefined;
6
+ export declare const selectorFunnelGap: import("reselect").Selector<import("@mui/x-charts/internals/plugins/corePlugins/useChartId/useChartId.types").UseChartIdState & import("@mui/x-charts/internals/plugins/corePlugins/useChartDimensions/useChartDimensions.types").UseChartDimensionsState & import("@mui/x-charts/internals/plugins/corePlugins/useChartSeries/useChartSeries.types").UseChartSeriesState<keyof import("@mui/x-charts/internals").ChartsSeriesConfig> & import("@mui/x-charts/internals/plugins/corePlugins/useChartAnimation/useChartAnimation.types").UseChartAnimationState & Partial<Pick<import("@mui/x-charts/internals").UseChartCartesianAxisState, "cartesianAxis"> & {
7
+ funnel: {
8
+ gap: number;
9
+ };
10
+ }> & {
11
+ cacheKey: import("@mui/x-charts/internals").ChartStateCacheKey;
12
+ } & {
13
+ cacheKey: import("@mui/x-charts/internals").ChartStateCacheKey;
14
+ }, number, []>;
15
+ export declare const selectorChartXAxis: import("reselect").Selector<import("@mui/x-charts/internals/plugins/corePlugins/useChartId/useChartId.types").UseChartIdState & import("@mui/x-charts/internals/plugins/corePlugins/useChartDimensions/useChartDimensions.types").UseChartDimensionsState & import("@mui/x-charts/internals/plugins/corePlugins/useChartSeries/useChartSeries.types").UseChartSeriesState<keyof import("@mui/x-charts/internals").ChartsSeriesConfig> & import("@mui/x-charts/internals/plugins/corePlugins/useChartAnimation/useChartAnimation.types").UseChartAnimationState & Partial<import("@mui/x-charts/internals").UseChartCartesianAxisState> & {
16
+ cacheKey: import("@mui/x-charts/internals").ChartStateCacheKey;
17
+ } & Partial<{}> & {
18
+ cacheKey: import("@mui/x-charts/internals").ChartStateCacheKey;
19
+ } & {
20
+ cacheKey: import("@mui/x-charts/internals").ChartStateCacheKey;
21
+ } & {
22
+ cacheKey: import("@mui/x-charts/internals").ChartStateCacheKey;
23
+ } & {
24
+ cacheKey: import("@mui/x-charts/internals").ChartStateCacheKey;
25
+ } & {
26
+ cacheKey: import("@mui/x-charts/internals").ChartStateCacheKey;
27
+ } & {
28
+ cacheKey: import("@mui/x-charts/internals").ChartStateCacheKey;
29
+ } & Partial<Pick<import("@mui/x-charts/internals").UseChartCartesianAxisState, "cartesianAxis"> & {
30
+ funnel: {
31
+ gap: number;
32
+ };
33
+ }> & {
34
+ cacheKey: import("@mui/x-charts/internals").ChartStateCacheKey;
35
+ }, import("./computeAxisValue.js").ComputeResult<import("@mui/x-charts").ChartsXAxisProps>, []>;
36
+ export declare const selectorChartYAxis: import("reselect").Selector<import("@mui/x-charts/internals/plugins/corePlugins/useChartId/useChartId.types").UseChartIdState & import("@mui/x-charts/internals/plugins/corePlugins/useChartDimensions/useChartDimensions.types").UseChartDimensionsState & import("@mui/x-charts/internals/plugins/corePlugins/useChartSeries/useChartSeries.types").UseChartSeriesState<keyof import("@mui/x-charts/internals").ChartsSeriesConfig> & import("@mui/x-charts/internals/plugins/corePlugins/useChartAnimation/useChartAnimation.types").UseChartAnimationState & Partial<import("@mui/x-charts/internals").UseChartCartesianAxisState> & {
37
+ cacheKey: import("@mui/x-charts/internals").ChartStateCacheKey;
38
+ } & Partial<{}> & {
39
+ cacheKey: import("@mui/x-charts/internals").ChartStateCacheKey;
40
+ } & {
41
+ cacheKey: import("@mui/x-charts/internals").ChartStateCacheKey;
42
+ } & {
43
+ cacheKey: import("@mui/x-charts/internals").ChartStateCacheKey;
44
+ } & {
45
+ cacheKey: import("@mui/x-charts/internals").ChartStateCacheKey;
46
+ } & {
47
+ cacheKey: import("@mui/x-charts/internals").ChartStateCacheKey;
48
+ } & {
49
+ cacheKey: import("@mui/x-charts/internals").ChartStateCacheKey;
50
+ } & Partial<Pick<import("@mui/x-charts/internals").UseChartCartesianAxisState, "cartesianAxis"> & {
51
+ funnel: {
52
+ gap: number;
53
+ };
54
+ }> & {
55
+ cacheKey: import("@mui/x-charts/internals").ChartStateCacheKey;
56
+ }, import("./computeAxisValue.js").ComputeResult<import("@mui/x-charts").ChartsYAxisProps>, []>;
@@ -0,0 +1,20 @@
1
+ import { createSelector, selectorChartSeriesConfig, selectorChartSeriesProcessed, selectorChartDrawingArea, selectorChartRawXAxis, selectorChartRawYAxis } from '@mui/x-charts/internals';
2
+ import { computeAxisValue } from "./computeAxisValue.js";
3
+ export const selectorFunnel = state => state.funnel;
4
+ export const selectorFunnelGap = createSelector([selectorFunnel], funnel => funnel?.gap ?? 0);
5
+ export const selectorChartXAxis = createSelector([selectorChartRawXAxis, selectorChartDrawingArea, selectorChartSeriesProcessed, selectorChartSeriesConfig, selectorFunnelGap], (axis, drawingArea, formattedSeries, seriesConfig, gap) => computeAxisValue({
6
+ drawingArea,
7
+ formattedSeries,
8
+ axis,
9
+ seriesConfig,
10
+ axisDirection: 'x',
11
+ gap
12
+ }));
13
+ export const selectorChartYAxis = createSelector([selectorChartRawYAxis, selectorChartDrawingArea, selectorChartSeriesProcessed, selectorChartSeriesConfig, selectorFunnelGap], (axis, drawingArea, formattedSeries, seriesConfig, gap) => computeAxisValue({
14
+ drawingArea,
15
+ formattedSeries,
16
+ axis,
17
+ seriesConfig,
18
+ axisDirection: 'y',
19
+ gap
20
+ }));
@@ -1,4 +1,5 @@
1
- import { FunnelDataPoints, FunnelLabelOptions } from "./funnel.types.js";
1
+ import { FunnelLabelOptions } from "./funnel.types.js";
2
+ import { Point } from "./curves/index.js";
2
3
  /**
3
4
  * It tries to keep the label inside the bounds of the section based on the position.
4
5
  *
@@ -23,19 +24,11 @@ export declare const alignLabel: ({
23
24
  export declare const positionLabel: ({
24
25
  position,
25
26
  offset,
26
- xPosition,
27
- yPosition,
28
27
  isHorizontal,
29
- values,
30
- dataIndex,
31
- baseScaleData
28
+ values
32
29
  }: Omit<FunnelLabelOptions, "textAnchor" | "dominantBaseline"> & {
33
- xPosition: (value: number, bandIndex: number, stackOffset?: number, useBand?: boolean) => number | undefined;
34
- yPosition: (value: number, bandIndex: number, stackOffset?: number, useBand?: boolean) => number | undefined;
35
30
  isHorizontal: boolean;
36
- values: readonly FunnelDataPoints[];
37
- dataIndex: number;
38
- baseScaleData: readonly number[];
31
+ values: readonly Point[];
39
32
  }) => {
40
33
  x: number;
41
34
  y: number;