@mui/x-charts-pro 8.5.0 → 8.5.2
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.
- package/BarChartPro/BarChartPro.d.ts +3 -2
- package/BarChartPro/BarChartPro.js +1 -1
- package/CHANGELOG.md +204 -0
- package/ChartContainerPro/ChartProApi.d.ts +2 -0
- package/ChartDataProviderPro/ChartDataProviderPro.js +1 -1
- package/ChartZoomSlider/internals/ChartAxisZoomSliderActiveTrack.d.ts +0 -2
- package/ChartZoomSlider/internals/ChartAxisZoomSliderActiveTrack.js +42 -9
- package/ChartZoomSlider/internals/ChartAxisZoomSliderTrack.js +0 -22
- package/ChartsToolbarPro/ChartsToolbarPro.d.ts +2 -4
- package/ChartsToolbarPro/ChartsToolbarPro.js +7 -13
- package/ChartsToolbarPro/{ChartsToolbarZoomInButton.d.ts → ChartsToolbarZoomInTrigger.d.ts} +6 -5
- package/ChartsToolbarPro/{ChartsToolbarZoomInButton.js → ChartsToolbarZoomInTrigger.js} +7 -6
- package/ChartsToolbarPro/{ChartsToolbarZoomOutButton.d.ts → ChartsToolbarZoomOutTrigger.d.ts} +6 -5
- package/ChartsToolbarPro/{ChartsToolbarZoomOutButton.js → ChartsToolbarZoomOutTrigger.js} +7 -6
- package/ChartsToolbarPro/Toolbar.types.d.ts +15 -0
- package/ChartsToolbarPro/Toolbar.types.js +5 -0
- package/ChartsToolbarPro/index.d.ts +2 -2
- package/ChartsToolbarPro/index.js +8 -8
- package/FunnelChart/FunnelChart.js +4 -11
- package/FunnelChart/FunnelChart.plugins.d.ts +3 -2
- package/FunnelChart/FunnelChart.plugins.js +2 -1
- package/FunnelChart/FunnelPlot.d.ts +0 -5
- package/FunnelChart/FunnelPlot.js +40 -50
- package/FunnelChart/FunnelSection.d.ts +1 -1
- package/FunnelChart/FunnelSectionLabel.d.ts +21 -0
- package/FunnelChart/FunnelSectionLabel.js +52 -0
- package/FunnelChart/categoryAxis.types.d.ts +2 -1
- package/FunnelChart/curves/bump.d.ts +9 -5
- package/FunnelChart/curves/bump.js +72 -43
- package/FunnelChart/curves/curve.types.d.ts +6 -1
- package/FunnelChart/curves/getFunnelCurve.js +3 -0
- package/FunnelChart/curves/linear.d.ts +10 -2
- package/FunnelChart/curves/linear.js +97 -17
- package/FunnelChart/curves/pyramid.js +10 -14
- package/FunnelChart/curves/step-pyramid.js +4 -6
- package/FunnelChart/curves/step.js +1 -15
- package/FunnelChart/funnel.types.d.ts +1 -0
- package/FunnelChart/funnelAxisPlugin/computeAxisValue.d.ts +25 -0
- package/FunnelChart/funnelAxisPlugin/computeAxisValue.js +124 -0
- package/FunnelChart/funnelAxisPlugin/useChartFunnelAxis.d.ts +3 -0
- package/FunnelChart/funnelAxisPlugin/useChartFunnelAxis.js +173 -0
- package/FunnelChart/funnelAxisPlugin/useChartFunnelAxis.types.d.ts +27 -0
- package/FunnelChart/funnelAxisPlugin/useChartFunnelAxis.types.js +5 -0
- package/FunnelChart/funnelAxisPlugin/useChartFunnelAxisRendering.selectors.d.ts +1482 -0
- package/FunnelChart/funnelAxisPlugin/useChartFunnelAxisRendering.selectors.js +27 -0
- package/FunnelChart/funnelPlotSlots.types.d.ts +11 -0
- package/FunnelChart/funnelSectionClasses.d.ts +2 -0
- package/FunnelChart/funnelSectionClasses.js +17 -4
- package/FunnelChart/index.d.ts +3 -1
- package/FunnelChart/index.js +18 -2
- package/FunnelChart/labelUtils.d.ts +3 -2
- package/FunnelChart/labelUtils.js +15 -15
- package/FunnelChart/positionGetter.d.ts +1 -0
- package/FunnelChart/positionGetter.js +5 -0
- package/FunnelChart/useFunnelChartProps.js +1 -3
- package/Heatmap/Heatmap.d.ts +8 -3
- package/Heatmap/Heatmap.js +10 -2
- package/Heatmap/HeatmapTooltip/HeatmapTooltipAxesValue.d.ts +1 -1
- package/LineChartPro/LineChartPro.d.ts +3 -2
- package/LineChartPro/LineChartPro.js +1 -1
- package/PieChartPro/PieChartPro.d.ts +22 -0
- package/PieChartPro/PieChartPro.js +204 -0
- package/PieChartPro/PieChartPro.plugins.d.ts +4 -0
- package/PieChartPro/PieChartPro.plugins.js +9 -0
- package/PieChartPro/index.d.ts +1 -0
- package/PieChartPro/index.js +16 -0
- package/RadarChartPro/RadarChartPro.d.ts +17 -2
- package/RadarChartPro/RadarChartPro.js +1 -1
- package/ScatterChartPro/ScatterChartPro.d.ts +3 -2
- package/ScatterChartPro/ScatterChartPro.js +1 -1
- package/esm/BarChartPro/BarChartPro.d.ts +3 -2
- package/esm/BarChartPro/BarChartPro.js +1 -1
- package/esm/ChartContainerPro/ChartProApi.d.ts +2 -0
- package/esm/ChartDataProviderPro/ChartDataProviderPro.js +1 -1
- package/esm/ChartZoomSlider/internals/ChartAxisZoomSliderActiveTrack.d.ts +0 -2
- package/esm/ChartZoomSlider/internals/ChartAxisZoomSliderActiveTrack.js +43 -10
- package/esm/ChartZoomSlider/internals/ChartAxisZoomSliderTrack.js +0 -22
- package/esm/ChartsToolbarPro/ChartsToolbarPro.d.ts +2 -4
- package/esm/ChartsToolbarPro/ChartsToolbarPro.js +8 -14
- package/esm/ChartsToolbarPro/{ChartsToolbarZoomInButton.d.ts → ChartsToolbarZoomInTrigger.d.ts} +6 -5
- package/esm/ChartsToolbarPro/{ChartsToolbarZoomInButton.js → ChartsToolbarZoomInTrigger.js} +8 -7
- package/esm/ChartsToolbarPro/{ChartsToolbarZoomOutButton.d.ts → ChartsToolbarZoomOutTrigger.d.ts} +6 -5
- package/esm/ChartsToolbarPro/{ChartsToolbarZoomOutButton.js → ChartsToolbarZoomOutTrigger.js} +8 -7
- package/esm/ChartsToolbarPro/Toolbar.types.d.ts +15 -0
- package/esm/ChartsToolbarPro/Toolbar.types.js +1 -0
- package/esm/ChartsToolbarPro/index.d.ts +2 -2
- package/esm/ChartsToolbarPro/index.js +2 -2
- package/esm/FunnelChart/FunnelChart.js +4 -11
- package/esm/FunnelChart/FunnelChart.plugins.d.ts +3 -2
- package/esm/FunnelChart/FunnelChart.plugins.js +3 -2
- package/esm/FunnelChart/FunnelPlot.d.ts +0 -5
- package/esm/FunnelChart/FunnelPlot.js +41 -51
- package/esm/FunnelChart/FunnelSection.d.ts +1 -1
- package/esm/FunnelChart/FunnelSectionLabel.d.ts +21 -0
- package/esm/FunnelChart/FunnelSectionLabel.js +46 -0
- package/esm/FunnelChart/categoryAxis.types.d.ts +2 -1
- package/esm/FunnelChart/curves/bump.d.ts +9 -5
- package/esm/FunnelChart/curves/bump.js +72 -43
- package/esm/FunnelChart/curves/curve.types.d.ts +6 -1
- package/esm/FunnelChart/curves/getFunnelCurve.js +3 -0
- package/esm/FunnelChart/curves/linear.d.ts +10 -2
- package/esm/FunnelChart/curves/linear.js +97 -17
- package/esm/FunnelChart/curves/pyramid.js +10 -14
- package/esm/FunnelChart/curves/step-pyramid.js +4 -6
- package/esm/FunnelChart/curves/step.js +1 -15
- package/esm/FunnelChart/funnel.types.d.ts +1 -0
- package/esm/FunnelChart/funnelAxisPlugin/computeAxisValue.d.ts +25 -0
- package/esm/FunnelChart/funnelAxisPlugin/computeAxisValue.js +114 -0
- package/esm/FunnelChart/funnelAxisPlugin/useChartFunnelAxis.d.ts +3 -0
- package/esm/FunnelChart/funnelAxisPlugin/useChartFunnelAxis.js +165 -0
- package/esm/FunnelChart/funnelAxisPlugin/useChartFunnelAxis.types.d.ts +27 -0
- package/esm/FunnelChart/funnelAxisPlugin/useChartFunnelAxis.types.js +1 -0
- package/esm/FunnelChart/funnelAxisPlugin/useChartFunnelAxisRendering.selectors.d.ts +1482 -0
- package/esm/FunnelChart/funnelAxisPlugin/useChartFunnelAxisRendering.selectors.js +20 -0
- package/esm/FunnelChart/funnelPlotSlots.types.d.ts +11 -0
- package/esm/FunnelChart/funnelSectionClasses.d.ts +2 -0
- package/esm/FunnelChart/funnelSectionClasses.js +15 -3
- package/esm/FunnelChart/index.d.ts +3 -1
- package/esm/FunnelChart/index.js +3 -1
- package/esm/FunnelChart/labelUtils.d.ts +3 -2
- package/esm/FunnelChart/labelUtils.js +15 -15
- package/esm/FunnelChart/positionGetter.d.ts +1 -0
- package/esm/FunnelChart/positionGetter.js +1 -0
- package/esm/FunnelChart/useFunnelChartProps.js +1 -3
- package/esm/Heatmap/Heatmap.d.ts +8 -3
- package/esm/Heatmap/Heatmap.js +10 -2
- package/esm/Heatmap/HeatmapTooltip/HeatmapTooltipAxesValue.d.ts +1 -1
- package/esm/LineChartPro/LineChartPro.d.ts +3 -2
- package/esm/LineChartPro/LineChartPro.js +1 -1
- package/esm/PieChartPro/PieChartPro.d.ts +22 -0
- package/esm/PieChartPro/PieChartPro.js +197 -0
- package/esm/PieChartPro/PieChartPro.plugins.d.ts +4 -0
- package/esm/PieChartPro/PieChartPro.plugins.js +3 -0
- package/esm/PieChartPro/index.d.ts +1 -0
- package/esm/PieChartPro/index.js +1 -0
- package/esm/RadarChartPro/RadarChartPro.d.ts +17 -2
- package/esm/RadarChartPro/RadarChartPro.js +1 -1
- package/esm/ScatterChartPro/ScatterChartPro.d.ts +3 -2
- package/esm/ScatterChartPro/ScatterChartPro.js +1 -1
- package/esm/index.d.ts +1 -0
- package/esm/index.js +2 -1
- package/index.d.ts +1 -0
- package/index.js +12 -1
- package/package.json +7 -7
|
@@ -97,7 +97,7 @@ export class Pyramid {
|
|
|
97
97
|
return;
|
|
98
98
|
}
|
|
99
99
|
|
|
100
|
-
//
|
|
100
|
+
// Replace funnel points by pyramids ones.
|
|
101
101
|
this.points = this.points.map((point, index) => {
|
|
102
102
|
if (this.isHorizontal) {
|
|
103
103
|
const slopeEnd = {
|
|
@@ -109,10 +109,9 @@ export class Pyramid {
|
|
|
109
109
|
y: this.max.y
|
|
110
110
|
};
|
|
111
111
|
const yGetter = lerpY(slopeStart.x, slopeStart.y, slopeEnd.x, slopeEnd.y);
|
|
112
|
-
const xGap = point.x + (index === 0 || index === 3 ? this.gap : -this.gap);
|
|
113
112
|
return {
|
|
114
|
-
x:
|
|
115
|
-
y: yGetter(
|
|
113
|
+
x: point.x,
|
|
114
|
+
y: yGetter(point.x)
|
|
116
115
|
};
|
|
117
116
|
}
|
|
118
117
|
const slopeEnd = {
|
|
@@ -124,10 +123,9 @@ export class Pyramid {
|
|
|
124
123
|
y: this.min.y
|
|
125
124
|
} : this.min;
|
|
126
125
|
const xGetter = lerpX(slopeStart.x, slopeStart.y, slopeEnd.x, slopeEnd.y);
|
|
127
|
-
const yGap = point.y + (index === 0 || index === 3 ? this.gap : -this.gap);
|
|
128
126
|
return {
|
|
129
|
-
x: xGetter(
|
|
130
|
-
y:
|
|
127
|
+
x: xGetter(point.y),
|
|
128
|
+
y: point.y
|
|
131
129
|
};
|
|
132
130
|
});
|
|
133
131
|
|
|
@@ -135,13 +133,11 @@ export class Pyramid {
|
|
|
135
133
|
// Else the algorithm will break.
|
|
136
134
|
const isLastSection = this.position === this.sections - 1;
|
|
137
135
|
const isFirstSection = this.position === 0;
|
|
138
|
-
if (this.
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
this.points = [this.points[0], this.points[1], this.points[3]];
|
|
144
|
-
}
|
|
136
|
+
if (isFirstSection && this.isIncreasing) {
|
|
137
|
+
this.points = [this.points[0], this.points[1], this.points[2]];
|
|
138
|
+
}
|
|
139
|
+
if (isLastSection && !this.isIncreasing) {
|
|
140
|
+
this.points = [this.points[0], this.points[1], this.points[3]];
|
|
145
141
|
}
|
|
146
142
|
borderRadiusPolygon(this.context, this.points, this.getBorderRadius());
|
|
147
143
|
}
|
|
@@ -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 =
|
|
40
|
+
this.gap = gap ?? 0;
|
|
41
41
|
this.position = position ?? 0;
|
|
42
42
|
this.sections = sections ?? 1;
|
|
43
43
|
this.borderRadius = borderRadius ?? 0;
|
|
@@ -151,25 +151,23 @@ export class StepPyramid {
|
|
|
151
151
|
return;
|
|
152
152
|
}
|
|
153
153
|
|
|
154
|
-
//
|
|
154
|
+
// Replace funnel points by pyramids ones.
|
|
155
155
|
this.points = this.points.map((point, index) => {
|
|
156
156
|
const slopeStart = this.slopeStart(index);
|
|
157
157
|
const slopeEnd = this.slopeEnd(index);
|
|
158
158
|
if (this.isHorizontal) {
|
|
159
159
|
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
160
|
const xInitial = this.initialX(index);
|
|
162
161
|
return {
|
|
163
|
-
x:
|
|
162
|
+
x: point.x,
|
|
164
163
|
y: yGetter(xInitial)
|
|
165
164
|
};
|
|
166
165
|
}
|
|
167
166
|
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
167
|
const yInitial = this.initialY(index);
|
|
170
168
|
return {
|
|
171
169
|
x: xGetter(yInitial),
|
|
172
|
-
y:
|
|
170
|
+
y: point.y
|
|
173
171
|
};
|
|
174
172
|
});
|
|
175
173
|
borderRadiusPolygon(this.context, this.points, this.getBorderRadius());
|
|
@@ -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 =
|
|
35
|
+
this.gap = gap ?? 0;
|
|
36
36
|
this.position = position ?? 0;
|
|
37
37
|
this.sections = sections ?? 1;
|
|
38
38
|
this.borderRadius = borderRadius ?? 0;
|
|
@@ -81,20 +81,6 @@ export class Step {
|
|
|
81
81
|
y: index === 1 || index === 2 ? max(allY) : min(allY)
|
|
82
82
|
};
|
|
83
83
|
});
|
|
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
|
-
};
|
|
97
|
-
});
|
|
98
84
|
borderRadiusPolygon(this.context, this.points, this.getBorderRadius());
|
|
99
85
|
}
|
|
100
86
|
}
|
|
@@ -47,6 +47,7 @@ export interface FunnelSeriesType extends Omit<CommonSeriesType<FunnelValueType>
|
|
|
47
47
|
*
|
|
48
48
|
* - `bump`: A curve that creates a smooth transition between points, with a bump in the middle.
|
|
49
49
|
* - `linear`: A straight line between points.
|
|
50
|
+
* - `linear-sharp`: A straight line between points, the smaller end of the funnel is a triangle.
|
|
50
51
|
* - `step`: A step line that creates a staircase effect.
|
|
51
52
|
* - `pyramid`: A pyramid shape that connects the points.
|
|
52
53
|
* - `step-pyramid`: A step line that creates a staircase effect, with a pyramid shape.
|
|
@@ -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,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 @@
|
|
|
1
|
+
export {};
|