@mui/x-charts-pro 8.1.0 → 8.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/BarChartPro/BarChartPro.js +2 -1
- package/CHANGELOG.md +126 -7
- package/ChartContainerPro/useChartContainerProProps.d.ts +1 -1
- package/ChartDataProviderPro/ChartDataProviderPro.js +1 -1
- package/ChartDataProviderPro/useChartDataProviderProProps.d.ts +2 -2
- package/FunnelChart/FunnelChart.js +7 -1
- package/FunnelChart/FunnelPlot.d.ts +5 -0
- package/FunnelChart/FunnelPlot.js +13 -16
- package/FunnelChart/curves/bump.d.ts +24 -0
- package/FunnelChart/curves/bump.js +82 -0
- package/FunnelChart/curves/curve.types.d.ts +8 -0
- package/FunnelChart/curves/curve.types.js +5 -0
- package/FunnelChart/curves/funnelStep.d.ts +25 -0
- package/FunnelChart/{funnelStepCurve.js → curves/funnelStep.js} +32 -19
- package/FunnelChart/curves/getFunnelCurve.d.ts +3 -0
- package/FunnelChart/curves/getFunnelCurve.js +22 -0
- package/FunnelChart/curves/index.d.ts +2 -0
- package/FunnelChart/curves/index.js +27 -0
- package/FunnelChart/curves/linear.d.ts +24 -0
- package/FunnelChart/curves/linear.js +113 -0
- package/FunnelChart/funnel.types.d.ts +2 -2
- package/FunnelChart/funnelPlotSlots.types.d.ts +1 -1
- package/FunnelChart/funnelSectionClasses.d.ts +1 -1
- package/FunnelChart/index.d.ts +3 -2
- package/FunnelChart/useFunnelChartProps.d.ts +1 -1
- package/FunnelChart/useFunnelChartProps.js +7 -4
- package/Heatmap/Heatmap.js +1 -1
- package/LineChartPro/LineChartPro.js +2 -1
- package/ScatterChartPro/ScatterChartPro.js +2 -1
- package/esm/BarChartPro/BarChartPro.js +2 -1
- package/esm/ChartContainerPro/useChartContainerProProps.d.ts +1 -1
- package/esm/ChartDataProviderPro/ChartDataProviderPro.js +1 -1
- package/esm/ChartDataProviderPro/useChartDataProviderProProps.d.ts +2 -2
- package/esm/FunnelChart/FunnelChart.js +7 -1
- package/esm/FunnelChart/FunnelPlot.d.ts +5 -0
- package/esm/FunnelChart/FunnelPlot.js +14 -17
- package/esm/FunnelChart/curves/bump.d.ts +24 -0
- package/esm/FunnelChart/curves/bump.js +75 -0
- package/esm/FunnelChart/curves/curve.types.d.ts +8 -0
- package/esm/FunnelChart/curves/curve.types.js +1 -0
- package/esm/FunnelChart/curves/funnelStep.d.ts +25 -0
- package/esm/FunnelChart/{funnelStepCurve.js → curves/funnelStep.js} +32 -19
- package/esm/FunnelChart/curves/getFunnelCurve.d.ts +3 -0
- package/esm/FunnelChart/curves/getFunnelCurve.js +15 -0
- package/esm/FunnelChart/curves/index.d.ts +2 -0
- package/esm/FunnelChart/curves/index.js +2 -0
- package/esm/FunnelChart/curves/linear.d.ts +24 -0
- package/esm/FunnelChart/curves/linear.js +106 -0
- package/esm/FunnelChart/funnel.types.d.ts +2 -2
- package/esm/FunnelChart/funnelPlotSlots.types.d.ts +1 -1
- package/esm/FunnelChart/funnelSectionClasses.d.ts +1 -1
- package/esm/FunnelChart/index.d.ts +3 -2
- package/esm/FunnelChart/useFunnelChartProps.d.ts +1 -1
- package/esm/FunnelChart/useFunnelChartProps.js +7 -4
- package/esm/Heatmap/Heatmap.js +1 -1
- package/esm/LineChartPro/LineChartPro.js +2 -1
- package/esm/ScatterChartPro/ScatterChartPro.js +2 -1
- package/esm/index.js +1 -1
- package/esm/internals/plugins/useChartProExport/common.d.ts +1 -0
- package/esm/internals/plugins/useChartProExport/common.js +8 -0
- package/esm/internals/plugins/useChartProExport/exportImage.d.ts +3 -0
- package/esm/internals/plugins/useChartProExport/exportImage.js +85 -0
- package/esm/internals/plugins/useChartProExport/print.js +6 -50
- package/esm/internals/plugins/useChartProExport/useChartProExport.js +22 -2
- package/esm/internals/plugins/useChartProExport/useChartProExport.types.d.ts +32 -0
- package/esm/internals/plugins/useChartProZoom/useChartProZoom.js +1 -1
- package/esm/internals/plugins/useChartProZoom/useChartProZoom.selectors.d.ts +25 -25
- package/esm/themeAugmentation/components.d.ts +0 -4
- package/esm/themeAugmentation/components.js +1 -0
- package/esm/themeAugmentation/index.d.ts +3 -3
- package/esm/themeAugmentation/overrides.d.ts +0 -3
- package/esm/themeAugmentation/overrides.js +2 -0
- package/esm/themeAugmentation/props.d.ts +0 -6
- package/esm/themeAugmentation/props.js +2 -0
- package/index.js +1 -1
- package/internals/plugins/useChartProExport/common.d.ts +1 -0
- package/internals/plugins/useChartProExport/common.js +14 -0
- package/internals/plugins/useChartProExport/exportImage.d.ts +3 -0
- package/internals/plugins/useChartProExport/exportImage.js +95 -0
- package/internals/plugins/useChartProExport/print.js +6 -50
- package/internals/plugins/useChartProExport/useChartProExport.js +22 -2
- package/internals/plugins/useChartProExport/useChartProExport.types.d.ts +32 -0
- package/internals/plugins/useChartProZoom/useChartProZoom.js +1 -1
- package/internals/plugins/useChartProZoom/useChartProZoom.selectors.d.ts +25 -25
- package/package.json +7 -4
- package/themeAugmentation/components.d.ts +0 -4
- package/themeAugmentation/components.js +5 -0
- package/themeAugmentation/index.d.ts +3 -3
- package/themeAugmentation/overrides.d.ts +0 -3
- package/themeAugmentation/overrides.js +5 -0
- package/themeAugmentation/props.d.ts +0 -6
- package/themeAugmentation/props.js +5 -0
- package/FunnelChart/funnelStepCurve.d.ts +0 -4
- package/esm/FunnelChart/funnelStepCurve.d.ts +0 -4
|
@@ -2,19 +2,23 @@
|
|
|
2
2
|
* This is a custom "step" curve generator for the funnel chart.
|
|
3
3
|
* It is used to draw the funnel using "rectangles" without having to rework the rendering logic.
|
|
4
4
|
*
|
|
5
|
+
* It takes into account the gap between the points and draws a smooth curve between them.
|
|
6
|
+
*
|
|
5
7
|
* It is based on the d3-shape step curve generator.
|
|
6
8
|
* https://github.com/d3/d3-shape/blob/a82254af78f08799c71d7ab25df557c4872a3c51/src/curve/step.js
|
|
7
9
|
*/
|
|
8
|
-
class FunnelStep {
|
|
9
|
-
constructor(context, isHorizontal) {
|
|
10
|
+
export class FunnelStep {
|
|
11
|
+
constructor(context, isHorizontal, gap = 0) {
|
|
10
12
|
this.context = void 0;
|
|
11
13
|
this.line = NaN;
|
|
12
14
|
this.x = NaN;
|
|
13
15
|
this.y = NaN;
|
|
14
16
|
this.currentPoint = 0;
|
|
15
17
|
this.isHorizontal = false;
|
|
18
|
+
this.gap = 0;
|
|
16
19
|
this.context = context;
|
|
17
20
|
this.isHorizontal = isHorizontal;
|
|
21
|
+
this.gap = gap / 2;
|
|
18
22
|
}
|
|
19
23
|
areaStart() {
|
|
20
24
|
this.line = 0;
|
|
@@ -41,27 +45,36 @@ class FunnelStep {
|
|
|
41
45
|
point(x, y) {
|
|
42
46
|
x = +x;
|
|
43
47
|
y = +y;
|
|
48
|
+
|
|
49
|
+
// 0 is the top-left corner.
|
|
50
|
+
if (this.isHorizontal) {
|
|
51
|
+
if (this.currentPoint === 0) {
|
|
52
|
+
this.context.moveTo(x + this.gap, y);
|
|
53
|
+
} else if (this.currentPoint === 1 || this.currentPoint === 2) {
|
|
54
|
+
this.context.lineTo(x - this.gap, this.y);
|
|
55
|
+
this.context.lineTo(x - this.gap, y);
|
|
56
|
+
} else {
|
|
57
|
+
this.context.lineTo(this.x - this.gap, y);
|
|
58
|
+
this.context.lineTo(x + this.gap, y);
|
|
59
|
+
}
|
|
60
|
+
this.currentPoint += 1;
|
|
61
|
+
this.x = x;
|
|
62
|
+
this.y = y;
|
|
63
|
+
return;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
// 0 is the top-right corner.
|
|
44
67
|
if (this.currentPoint === 0) {
|
|
45
|
-
this.context.moveTo(x, y);
|
|
46
|
-
} else if (this.
|
|
47
|
-
this.context.lineTo(x, this.y);
|
|
48
|
-
this.context.lineTo(x, y);
|
|
49
|
-
} else if (this.currentPoint === 3 && !this.isHorizontal) {
|
|
50
|
-
this.context.lineTo(x, this.y);
|
|
51
|
-
this.context.lineTo(x, y);
|
|
68
|
+
this.context.moveTo(x, y + this.gap);
|
|
69
|
+
} else if (this.currentPoint === 3) {
|
|
70
|
+
this.context.lineTo(x, this.y - this.gap);
|
|
71
|
+
this.context.lineTo(x, y + this.gap);
|
|
52
72
|
} else {
|
|
53
|
-
this.context.lineTo(this.x, y);
|
|
54
|
-
this.context.lineTo(x, y);
|
|
73
|
+
this.context.lineTo(this.x, y - this.gap);
|
|
74
|
+
this.context.lineTo(x, y - this.gap);
|
|
55
75
|
}
|
|
56
76
|
this.currentPoint += 1;
|
|
57
77
|
this.x = x;
|
|
58
78
|
this.y = y;
|
|
59
79
|
}
|
|
60
|
-
}
|
|
61
|
-
const funnelHorizontalStepCurve = context => {
|
|
62
|
-
return new FunnelStep(context, true);
|
|
63
|
-
};
|
|
64
|
-
const funnelVerticalStepCurve = context => {
|
|
65
|
-
return new FunnelStep(context, false);
|
|
66
|
-
};
|
|
67
|
-
export { funnelHorizontalStepCurve, funnelVerticalStepCurve };
|
|
80
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { FunnelStep } from "./funnelStep.js";
|
|
2
|
+
import { Linear } from "./linear.js";
|
|
3
|
+
import { Bump } from "./bump.js";
|
|
4
|
+
const curveConstructor = curve => {
|
|
5
|
+
if (curve === 'step') {
|
|
6
|
+
return FunnelStep;
|
|
7
|
+
}
|
|
8
|
+
if (curve === 'bump') {
|
|
9
|
+
return Bump;
|
|
10
|
+
}
|
|
11
|
+
return Linear;
|
|
12
|
+
};
|
|
13
|
+
export const getFunnelCurve = (curve, isHorizontal, gap = 0) => {
|
|
14
|
+
return context => new (curveConstructor(curve))(context, isHorizontal, gap);
|
|
15
|
+
};
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { CurveGenerator } from '@mui/x-charts-vendor/d3-shape';
|
|
2
|
+
/**
|
|
3
|
+
* This is a custom "linear" curve generator.
|
|
4
|
+
*
|
|
5
|
+
* It takes into account the gap between the points and draws a smooth curve between them.
|
|
6
|
+
*
|
|
7
|
+
* It is based on the d3-shape linear curve generator.
|
|
8
|
+
* https://github.com/d3/d3-shape/blob/a82254af78f08799c71d7ab25df557c4872a3c51/src/curve/linear.js
|
|
9
|
+
*/
|
|
10
|
+
export declare class Linear implements CurveGenerator {
|
|
11
|
+
private context;
|
|
12
|
+
private line;
|
|
13
|
+
private x;
|
|
14
|
+
private y;
|
|
15
|
+
private currentPoint;
|
|
16
|
+
private isHorizontal;
|
|
17
|
+
private gap;
|
|
18
|
+
constructor(context: CanvasRenderingContext2D, isHorizontal: boolean, gap?: number);
|
|
19
|
+
areaStart(): void;
|
|
20
|
+
areaEnd(): void;
|
|
21
|
+
lineStart(): void;
|
|
22
|
+
lineEnd(): void;
|
|
23
|
+
point(x: number, y: number): void;
|
|
24
|
+
}
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
// From point1 to point2, get the x value from y
|
|
2
|
+
const xFromY = (x1, y1, x2, y2) => y => {
|
|
3
|
+
if (y1 === y2) {
|
|
4
|
+
return x1;
|
|
5
|
+
}
|
|
6
|
+
const result = (x2 - x1) * (y - y1) / (y2 - y1) + x1;
|
|
7
|
+
return Number.isNaN(result) ? 0 : result;
|
|
8
|
+
};
|
|
9
|
+
|
|
10
|
+
// From point1 to point2, get the y value from x
|
|
11
|
+
const yFromX = (x1, y1, x2, y2) => x => {
|
|
12
|
+
if (x1 === x2) {
|
|
13
|
+
return y1;
|
|
14
|
+
}
|
|
15
|
+
const result = (y2 - y1) * (x - x1) / (x2 - x1) + y1;
|
|
16
|
+
return Number.isNaN(result) ? 0 : result;
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* This is a custom "linear" curve generator.
|
|
21
|
+
*
|
|
22
|
+
* It takes into account the gap between the points and draws a smooth curve between them.
|
|
23
|
+
*
|
|
24
|
+
* It is based on the d3-shape linear curve generator.
|
|
25
|
+
* https://github.com/d3/d3-shape/blob/a82254af78f08799c71d7ab25df557c4872a3c51/src/curve/linear.js
|
|
26
|
+
*/
|
|
27
|
+
export class Linear {
|
|
28
|
+
constructor(context, isHorizontal, gap = 0) {
|
|
29
|
+
this.context = void 0;
|
|
30
|
+
this.line = NaN;
|
|
31
|
+
this.x = NaN;
|
|
32
|
+
this.y = NaN;
|
|
33
|
+
this.currentPoint = 0;
|
|
34
|
+
this.isHorizontal = false;
|
|
35
|
+
this.gap = 0;
|
|
36
|
+
this.context = context;
|
|
37
|
+
this.isHorizontal = isHorizontal;
|
|
38
|
+
this.gap = gap / 2;
|
|
39
|
+
}
|
|
40
|
+
areaStart() {
|
|
41
|
+
this.line = 0;
|
|
42
|
+
}
|
|
43
|
+
areaEnd() {
|
|
44
|
+
this.line = NaN;
|
|
45
|
+
}
|
|
46
|
+
lineStart() {
|
|
47
|
+
this.currentPoint = 0;
|
|
48
|
+
}
|
|
49
|
+
lineEnd() {
|
|
50
|
+
if (this.line || this.line !== 0 && this.currentPoint === 1) {
|
|
51
|
+
this.context.closePath();
|
|
52
|
+
}
|
|
53
|
+
this.line = 1 - this.line;
|
|
54
|
+
}
|
|
55
|
+
point(x, y) {
|
|
56
|
+
x = +x;
|
|
57
|
+
y = +y;
|
|
58
|
+
|
|
59
|
+
// We draw the lines only at currentPoint 1 & 3 because we need
|
|
60
|
+
// The data of a pair of points to draw the lines.
|
|
61
|
+
// Hence currentPoint 1 draws a line from point 0 to point 1 and point 1 to point 2.
|
|
62
|
+
// currentPoint 3 draws a line from point 2 to point 3 and point 3 to point 0.
|
|
63
|
+
|
|
64
|
+
if (this.isHorizontal) {
|
|
65
|
+
const yGetter = yFromX(this.x, this.y, x, y);
|
|
66
|
+
let xGap = 0;
|
|
67
|
+
|
|
68
|
+
// 0 is the top-left corner.
|
|
69
|
+
if (this.currentPoint === 1) {
|
|
70
|
+
xGap = this.x + this.gap;
|
|
71
|
+
this.context.moveTo(xGap, yGetter(xGap));
|
|
72
|
+
this.context.lineTo(xGap, yGetter(xGap));
|
|
73
|
+
xGap = x - this.gap;
|
|
74
|
+
this.context.lineTo(xGap, yGetter(xGap));
|
|
75
|
+
} else if (this.currentPoint === 3) {
|
|
76
|
+
xGap = this.x - this.gap;
|
|
77
|
+
this.context.lineTo(xGap, yGetter(xGap));
|
|
78
|
+
xGap = x + this.gap;
|
|
79
|
+
this.context.lineTo(xGap, yGetter(xGap));
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
if (!this.isHorizontal) {
|
|
83
|
+
const xGetter = xFromY(this.x, this.y, x, y);
|
|
84
|
+
let yGap = 0;
|
|
85
|
+
|
|
86
|
+
// 0 is the top-right corner.
|
|
87
|
+
if (this.currentPoint === 1) {
|
|
88
|
+
yGap = this.y + this.gap;
|
|
89
|
+
this.context.moveTo(xGetter(yGap), yGap);
|
|
90
|
+
this.context.lineTo(xGetter(yGap), yGap);
|
|
91
|
+
yGap = y - this.gap;
|
|
92
|
+
this.context.lineTo(xGetter(yGap), yGap);
|
|
93
|
+
} else if (this.currentPoint === 3) {
|
|
94
|
+
yGap = this.y - this.gap;
|
|
95
|
+
this.context.lineTo(xGetter(yGap), yGap);
|
|
96
|
+
yGap = y + this.gap;
|
|
97
|
+
this.context.lineTo(xGetter(yGap), yGap);
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
// Increment the values
|
|
102
|
+
this.currentPoint += 1;
|
|
103
|
+
this.x = x;
|
|
104
|
+
this.y = y;
|
|
105
|
+
}
|
|
106
|
+
}
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { ChartsLabelMarkProps } from '@mui/x-charts/ChartsLabel';
|
|
2
2
|
import { CommonSeriesType, CartesianSeriesType, CommonDefaultizedProps, SeriesId } from '@mui/x-charts/internals';
|
|
3
|
-
import {
|
|
3
|
+
import { Position } from '@mui/x-charts/models';
|
|
4
4
|
import { DefaultizedProps, MakeRequired } from '@mui/x-internals/types';
|
|
5
|
+
import { FunnelCurveType } from "./curves/index.js";
|
|
5
6
|
export type FunnelItemId = string | number;
|
|
6
|
-
export type FunnelCurveType = Extract<CurveType, 'linear' | 'step'> | 'bump';
|
|
7
7
|
export type FunnelValueType = {
|
|
8
8
|
/**
|
|
9
9
|
* A unique identifier of the funnel section.
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
export { FunnelChart as Unstable_FunnelChart } from "./FunnelChart.js";
|
|
2
|
-
export type { FunnelChartProps } from
|
|
2
|
+
export type { FunnelChartProps } from "./FunnelChart.js";
|
|
3
3
|
export * from "./FunnelPlot.js";
|
|
4
4
|
export * from "./funnel.types.js";
|
|
5
5
|
export * from "./categoryAxis.types.js";
|
|
6
6
|
export * from "./funnelSlots.types.js";
|
|
7
|
+
export type { FunnelCurveType } from "./curves/index.js";
|
|
7
8
|
export { funnelSectionClasses } from "./funnelSectionClasses.js";
|
|
8
|
-
export type { FunnelSectionClasses } from
|
|
9
|
+
export type { FunnelSectionClasses } from "./funnelSectionClasses.js";
|
|
@@ -5,7 +5,7 @@ import { ChartsClipPathProps } from '@mui/x-charts/ChartsClipPath';
|
|
|
5
5
|
import { ChartsWrapperProps } from '@mui/x-charts/internals';
|
|
6
6
|
import { ChartsAxisHighlightProps } from '@mui/x-charts/ChartsAxisHighlight';
|
|
7
7
|
import { FunnelPlotProps } from "./FunnelPlot.js";
|
|
8
|
-
import type { FunnelChartProps } from
|
|
8
|
+
import type { FunnelChartProps } from "./FunnelChart.js";
|
|
9
9
|
import { ChartContainerProProps } from "../ChartContainerPro/index.js";
|
|
10
10
|
/**
|
|
11
11
|
* A helper function that extracts FunnelChartProps from the input props
|
|
@@ -2,11 +2,12 @@
|
|
|
2
2
|
|
|
3
3
|
import _objectWithoutPropertiesLoose from "@babel/runtime/helpers/esm/objectWithoutPropertiesLoose";
|
|
4
4
|
import _extends from "@babel/runtime/helpers/esm/extends";
|
|
5
|
-
const _excluded = ["categoryAxis", "series", "width", "height", "margin", "colors", "sx", "children", "slots", "slotProps", "skipAnimation", "loading", "onItemClick", "highlightedItem", "onHighlightChange", "className", "hideLegend", "axisHighlight", "apiRef"];
|
|
5
|
+
const _excluded = ["categoryAxis", "series", "width", "height", "margin", "colors", "sx", "children", "slots", "slotProps", "skipAnimation", "loading", "onItemClick", "highlightedItem", "onHighlightChange", "className", "hideLegend", "axisHighlight", "apiRef", "gap"];
|
|
6
6
|
import { DEFAULT_MARGINS, DEFAULT_X_AXIS_KEY, DEFAULT_Y_AXIS_KEY } from '@mui/x-charts/constants';
|
|
7
7
|
import useId from '@mui/utils/useId';
|
|
8
8
|
import { defaultizeMargin } from '@mui/x-charts/internals';
|
|
9
9
|
import { warnOnce } from '@mui/x-internals/warning';
|
|
10
|
+
import { strawberrySkyPalette } from '@mui/x-charts/colorPalettes';
|
|
10
11
|
function getCategoryAxisConfig(categoryAxis, series, isHorizontal, direction) {
|
|
11
12
|
const maxSeriesLength = Math.max(...series.map(s => (s.data ?? []).length), 0);
|
|
12
13
|
const maxSeriesValue = Array.from({
|
|
@@ -14,7 +15,7 @@ function getCategoryAxisConfig(categoryAxis, series, isHorizontal, direction) {
|
|
|
14
15
|
}, (_, index) => series.reduce((a, s) => a + (s.data?.[index]?.value ?? 0), 0));
|
|
15
16
|
if (process.env.NODE_ENV !== 'production') {
|
|
16
17
|
if ((categoryAxis?.position === 'left' || categoryAxis?.position === 'right') && isHorizontal || (categoryAxis?.position === 'top' || categoryAxis?.position === 'bottom') && !isHorizontal) {
|
|
17
|
-
warnOnce([`MUI X: the categoryAxis position is set to '${categoryAxis.position}' but the series layout is ${isHorizontal ? 'horizontal' : 'vertical'}.`, `Ensure that the categoryAxis position is set to '${isHorizontal ? 'top' : 'left'}' or '${isHorizontal ? 'bottom' : 'right'}' for ${isHorizontal ? 'horizontal' : 'vertical'} layout.\n`], 'warning');
|
|
18
|
+
warnOnce([`MUI X Charts: the categoryAxis position is set to '${categoryAxis.position}' but the series layout is ${isHorizontal ? 'horizontal' : 'vertical'}.`, `Ensure that the categoryAxis position is set to '${isHorizontal ? 'top' : 'left'}' or '${isHorizontal ? 'bottom' : 'right'}' for ${isHorizontal ? 'horizontal' : 'vertical'} layout.\n`], 'warning');
|
|
18
19
|
}
|
|
19
20
|
}
|
|
20
21
|
const side = isHorizontal ? 'bottom' : 'left';
|
|
@@ -84,7 +85,8 @@ export const useFunnelChartProps = props => {
|
|
|
84
85
|
onHighlightChange,
|
|
85
86
|
className,
|
|
86
87
|
axisHighlight,
|
|
87
|
-
apiRef
|
|
88
|
+
apiRef,
|
|
89
|
+
gap
|
|
88
90
|
} = props,
|
|
89
91
|
rest = _objectWithoutPropertiesLoose(props, _excluded);
|
|
90
92
|
const margin = defaultizeMargin(marginProps, DEFAULT_MARGINS);
|
|
@@ -107,7 +109,7 @@ export const useFunnelChartProps = props => {
|
|
|
107
109
|
width,
|
|
108
110
|
height,
|
|
109
111
|
margin,
|
|
110
|
-
colors,
|
|
112
|
+
colors: colors ?? strawberrySkyPalette,
|
|
111
113
|
xAxis: [xAxis],
|
|
112
114
|
yAxis: [yAxis],
|
|
113
115
|
sx,
|
|
@@ -117,6 +119,7 @@ export const useFunnelChartProps = props => {
|
|
|
117
119
|
apiRef
|
|
118
120
|
});
|
|
119
121
|
const funnelPlotProps = {
|
|
122
|
+
gap,
|
|
120
123
|
onItemClick,
|
|
121
124
|
slots,
|
|
122
125
|
slotProps
|
package/esm/Heatmap/Heatmap.js
CHANGED
|
@@ -187,7 +187,7 @@ process.env.NODE_ENV !== "production" ? Heatmap.propTypes = {
|
|
|
187
187
|
* The function called for onClick events.
|
|
188
188
|
* The second argument contains information about all line/bar elements at the current mouse position.
|
|
189
189
|
* @param {MouseEvent} event The mouse event recorded on the `<svg/>` element.
|
|
190
|
-
* @param {null |
|
|
190
|
+
* @param {null | ChartsAxisData} data The data about the clicked axis and items associated with it.
|
|
191
191
|
*/
|
|
192
192
|
onAxisClick: PropTypes.func,
|
|
193
193
|
/**
|
|
@@ -89,6 +89,7 @@ process.env.NODE_ENV !== "production" ? LineChartPro.propTypes = {
|
|
|
89
89
|
// ----------------------------------------------------------------------
|
|
90
90
|
apiRef: PropTypes.shape({
|
|
91
91
|
current: PropTypes.shape({
|
|
92
|
+
exportAsImage: PropTypes.func.isRequired,
|
|
92
93
|
exportAsPrint: PropTypes.func.isRequired,
|
|
93
94
|
setZoomData: PropTypes.func.isRequired
|
|
94
95
|
})
|
|
@@ -190,7 +191,7 @@ process.env.NODE_ENV !== "production" ? LineChartPro.propTypes = {
|
|
|
190
191
|
* The function called for onClick events.
|
|
191
192
|
* The second argument contains information about all line/bar elements at the current mouse position.
|
|
192
193
|
* @param {MouseEvent} event The mouse event recorded on the `<svg/>` element.
|
|
193
|
-
* @param {null |
|
|
194
|
+
* @param {null | ChartsAxisData} data The data about the clicked axis and items associated with it.
|
|
194
195
|
*/
|
|
195
196
|
onAxisClick: PropTypes.func,
|
|
196
197
|
/**
|
|
@@ -83,6 +83,7 @@ process.env.NODE_ENV !== "production" ? ScatterChartPro.propTypes = {
|
|
|
83
83
|
// ----------------------------------------------------------------------
|
|
84
84
|
apiRef: PropTypes.shape({
|
|
85
85
|
current: PropTypes.shape({
|
|
86
|
+
exportAsImage: PropTypes.func.isRequired,
|
|
86
87
|
exportAsPrint: PropTypes.func.isRequired,
|
|
87
88
|
setZoomData: PropTypes.func.isRequired
|
|
88
89
|
})
|
|
@@ -181,7 +182,7 @@ process.env.NODE_ENV !== "production" ? ScatterChartPro.propTypes = {
|
|
|
181
182
|
* The function called for onClick events.
|
|
182
183
|
* The second argument contains information about all line/bar elements at the current mouse position.
|
|
183
184
|
* @param {MouseEvent} event The mouse event recorded on the `<svg/>` element.
|
|
184
|
-
* @param {null |
|
|
185
|
+
* @param {null | ChartsAxisData} data The data about the clicked axis and items associated with it.
|
|
185
186
|
*/
|
|
186
187
|
onAxisClick: PropTypes.func,
|
|
187
188
|
/**
|
package/esm/index.js
CHANGED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function createExportIframe(title?: string): HTMLIFrameElement;
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export function createExportIframe(title) {
|
|
2
|
+
const iframeEl = document.createElement('iframe');
|
|
3
|
+
iframeEl.style.position = 'absolute';
|
|
4
|
+
iframeEl.style.width = '0px';
|
|
5
|
+
iframeEl.style.height = '0px';
|
|
6
|
+
iframeEl.title = title || document.title;
|
|
7
|
+
return iframeEl;
|
|
8
|
+
}
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import { ChartImageExportOptions } from "./useChartProExport.types.js";
|
|
2
|
+
export declare const getDrawDocument: () => Promise<typeof import("rasterizehtml").drawDocument>;
|
|
3
|
+
export declare function exportImage(element: HTMLElement | SVGElement, params?: ChartImageExportOptions): Promise<void>;
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import ownerDocument from '@mui/utils/ownerDocument';
|
|
2
|
+
import { loadStyleSheets } from '@mui/x-internals/export';
|
|
3
|
+
import { createExportIframe } from "./common.js";
|
|
4
|
+
export const getDrawDocument = async () => {
|
|
5
|
+
try {
|
|
6
|
+
const module = await import('rasterizehtml');
|
|
7
|
+
return module.drawDocument;
|
|
8
|
+
} catch (error) {
|
|
9
|
+
throw new Error(`MUI X Charts: Failed to import 'rasterizehtml' module. This dependency is mandatory when exporting a chart as an image. Make sure you have it installed as a dependency.`, {
|
|
10
|
+
cause: error
|
|
11
|
+
});
|
|
12
|
+
}
|
|
13
|
+
};
|
|
14
|
+
export async function exportImage(element, params) {
|
|
15
|
+
const {
|
|
16
|
+
fileName,
|
|
17
|
+
type = 'image/png',
|
|
18
|
+
quality = 0.9
|
|
19
|
+
} = params ?? {};
|
|
20
|
+
const drawDocumentPromise = getDrawDocument();
|
|
21
|
+
const {
|
|
22
|
+
width,
|
|
23
|
+
height
|
|
24
|
+
} = element.getBoundingClientRect();
|
|
25
|
+
const doc = ownerDocument(element);
|
|
26
|
+
const canvas = document.createElement('canvas');
|
|
27
|
+
const ratio = window.devicePixelRatio || 1;
|
|
28
|
+
canvas.width = width * ratio;
|
|
29
|
+
canvas.height = height * ratio;
|
|
30
|
+
canvas.style.width = `${width}px`;
|
|
31
|
+
canvas.style.height = `${height}px`;
|
|
32
|
+
const iframe = createExportIframe(fileName);
|
|
33
|
+
let resolve;
|
|
34
|
+
const iframeLoadPromise = new Promise(res => {
|
|
35
|
+
resolve = res;
|
|
36
|
+
});
|
|
37
|
+
iframe.onload = async () => {
|
|
38
|
+
const exportDoc = iframe.contentDocument;
|
|
39
|
+
const elementClone = element.cloneNode(true);
|
|
40
|
+
const container = document.createElement('div');
|
|
41
|
+
container.appendChild(elementClone);
|
|
42
|
+
exportDoc.body.innerHTML = container.innerHTML;
|
|
43
|
+
exportDoc.body.style.margin = '0px';
|
|
44
|
+
const rootCandidate = element.getRootNode();
|
|
45
|
+
const root = rootCandidate.constructor.name === 'ShadowRoot' ? rootCandidate : doc;
|
|
46
|
+
await Promise.all(loadStyleSheets(exportDoc, root));
|
|
47
|
+
resolve();
|
|
48
|
+
};
|
|
49
|
+
doc.body.appendChild(iframe);
|
|
50
|
+
const [drawDocument] = await Promise.all([drawDocumentPromise, iframeLoadPromise]);
|
|
51
|
+
try {
|
|
52
|
+
await drawDocument(iframe.contentDocument, canvas, {
|
|
53
|
+
// Handle retina displays: https://github.com/cburgmer/rasterizeHTML.js/blob/262b3404d1c469ce4a7750a2976dec09b8ae2d6c/examples/retina.html#L71
|
|
54
|
+
zoom: ratio
|
|
55
|
+
});
|
|
56
|
+
} finally {
|
|
57
|
+
doc.body.removeChild(iframe);
|
|
58
|
+
}
|
|
59
|
+
let resolveBlobPromise;
|
|
60
|
+
const blobPromise = new Promise(res => {
|
|
61
|
+
resolveBlobPromise = res;
|
|
62
|
+
});
|
|
63
|
+
canvas.toBlob(blob => resolveBlobPromise(blob), type, quality);
|
|
64
|
+
let blob;
|
|
65
|
+
try {
|
|
66
|
+
blob = await blobPromise;
|
|
67
|
+
} catch (error) {
|
|
68
|
+
throw new Error('MUI X Charts: Failed to create blob from canvas.', {
|
|
69
|
+
cause: error
|
|
70
|
+
});
|
|
71
|
+
}
|
|
72
|
+
if (!blob) {
|
|
73
|
+
throw new Error('MUI X Charts: Failed to create blob from canvas.');
|
|
74
|
+
return;
|
|
75
|
+
}
|
|
76
|
+
const url = URL.createObjectURL(blob);
|
|
77
|
+
triggerDownload(url, fileName || document.title);
|
|
78
|
+
URL.revokeObjectURL(url);
|
|
79
|
+
}
|
|
80
|
+
function triggerDownload(url, name) {
|
|
81
|
+
const a = document.createElement('a');
|
|
82
|
+
a.href = url;
|
|
83
|
+
a.download = name;
|
|
84
|
+
a.click();
|
|
85
|
+
}
|
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
import ownerDocument from '@mui/utils/ownerDocument';
|
|
2
|
+
import { loadStyleSheets } from '@mui/x-internals/export';
|
|
3
|
+
import { createExportIframe } from "./common.js";
|
|
2
4
|
export function printChart(element, {
|
|
3
5
|
fileName
|
|
4
6
|
} = {}) {
|
|
5
|
-
const printWindow =
|
|
7
|
+
const printWindow = createExportIframe(fileName);
|
|
6
8
|
const doc = ownerDocument(element);
|
|
7
9
|
printWindow.onload = async () => {
|
|
8
10
|
const printDoc = printWindow.contentDocument;
|
|
@@ -10,7 +12,9 @@ export function printChart(element, {
|
|
|
10
12
|
const container = document.createElement('div');
|
|
11
13
|
container.appendChild(elementClone);
|
|
12
14
|
printDoc.body.innerHTML = container.innerHTML;
|
|
13
|
-
|
|
15
|
+
const rootCandidate = element.getRootNode();
|
|
16
|
+
const root = rootCandidate.constructor.name === 'ShadowRoot' ? rootCandidate : doc;
|
|
17
|
+
await Promise.all(loadStyleSheets(printDoc, root));
|
|
14
18
|
printWindow.contentWindow.print();
|
|
15
19
|
const mediaQueryList = printWindow.contentWindow.matchMedia('print');
|
|
16
20
|
mediaQueryList.addEventListener('change', mql => {
|
|
@@ -21,52 +25,4 @@ export function printChart(element, {
|
|
|
21
25
|
});
|
|
22
26
|
};
|
|
23
27
|
doc.body.appendChild(printWindow);
|
|
24
|
-
}
|
|
25
|
-
function buildPrintWindow(title) {
|
|
26
|
-
const iframeEl = document.createElement('iframe');
|
|
27
|
-
iframeEl.style.position = 'absolute';
|
|
28
|
-
iframeEl.style.width = '0px';
|
|
29
|
-
iframeEl.style.height = '0px';
|
|
30
|
-
iframeEl.title = title || document.title;
|
|
31
|
-
return iframeEl;
|
|
32
|
-
}
|
|
33
|
-
function loadStyleSheets(printDoc, element) {
|
|
34
|
-
const stylesheetLoadPromises = [];
|
|
35
|
-
const doc = ownerDocument(element);
|
|
36
|
-
const rootCandidate = element.getRootNode();
|
|
37
|
-
const root = rootCandidate.constructor.name === 'ShadowRoot' ? rootCandidate : doc;
|
|
38
|
-
const headStyleElements = root.querySelectorAll("style, link[rel='stylesheet']");
|
|
39
|
-
for (let i = 0; i < headStyleElements.length; i += 1) {
|
|
40
|
-
const node = headStyleElements[i];
|
|
41
|
-
if (node.tagName === 'STYLE') {
|
|
42
|
-
const newHeadStyleElements = printDoc.createElement(node.tagName);
|
|
43
|
-
const sheet = node.sheet;
|
|
44
|
-
if (sheet) {
|
|
45
|
-
let styleCSS = '';
|
|
46
|
-
// NOTE: for-of is not supported by IE
|
|
47
|
-
for (let j = 0; j < sheet.cssRules.length; j += 1) {
|
|
48
|
-
if (typeof sheet.cssRules[j].cssText === 'string') {
|
|
49
|
-
styleCSS += `${sheet.cssRules[j].cssText}\r\n`;
|
|
50
|
-
}
|
|
51
|
-
}
|
|
52
|
-
newHeadStyleElements.appendChild(printDoc.createTextNode(styleCSS));
|
|
53
|
-
printDoc.head.appendChild(newHeadStyleElements);
|
|
54
|
-
}
|
|
55
|
-
} else if (node.getAttribute('href')) {
|
|
56
|
-
// If `href` tag is empty, avoid loading these links
|
|
57
|
-
|
|
58
|
-
const newHeadStyleElements = printDoc.createElement(node.tagName);
|
|
59
|
-
for (let j = 0; j < node.attributes.length; j += 1) {
|
|
60
|
-
const attr = node.attributes[j];
|
|
61
|
-
if (attr) {
|
|
62
|
-
newHeadStyleElements.setAttribute(attr.nodeName, attr.nodeValue || '');
|
|
63
|
-
}
|
|
64
|
-
}
|
|
65
|
-
stylesheetLoadPromises.push(new Promise(resolve => {
|
|
66
|
-
newHeadStyleElements.addEventListener('load', () => resolve());
|
|
67
|
-
}));
|
|
68
|
-
printDoc.head.appendChild(newHeadStyleElements);
|
|
69
|
-
}
|
|
70
|
-
}
|
|
71
|
-
return Promise.all(stylesheetLoadPromises);
|
|
72
28
|
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import _extends from "@babel/runtime/helpers/esm/extends";
|
|
2
2
|
import { printChart } from "./print.js";
|
|
3
|
+
import { exportImage } from "./exportImage.js";
|
|
3
4
|
function waitForAnimationFrame() {
|
|
4
5
|
let resolve;
|
|
5
6
|
const promise = new Promise(res => {
|
|
@@ -22,6 +23,23 @@ export const useChartProExport = ({
|
|
|
22
23
|
// Wait for animation frame to ensure the animation finished
|
|
23
24
|
await waitForAnimationFrame();
|
|
24
25
|
printChart(chartRoot, options);
|
|
26
|
+
} catch (error) {
|
|
27
|
+
console.error('MUI X Charts: Error exporting chart as print:', error);
|
|
28
|
+
} finally {
|
|
29
|
+
enableAnimation();
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
};
|
|
33
|
+
const exportAsImage = async options => {
|
|
34
|
+
const chartRoot = chartRootRef.current;
|
|
35
|
+
if (chartRoot) {
|
|
36
|
+
const enableAnimation = instance.disableAnimation();
|
|
37
|
+
try {
|
|
38
|
+
// Wait for animation frame to ensure the animation finished
|
|
39
|
+
await waitForAnimationFrame();
|
|
40
|
+
await exportImage(chartRoot, options);
|
|
41
|
+
} catch (error) {
|
|
42
|
+
console.error('MUI X Charts: Error exporting chart as image:', error);
|
|
25
43
|
} finally {
|
|
26
44
|
enableAnimation();
|
|
27
45
|
}
|
|
@@ -29,10 +47,12 @@ export const useChartProExport = ({
|
|
|
29
47
|
};
|
|
30
48
|
return {
|
|
31
49
|
publicAPI: {
|
|
32
|
-
exportAsPrint
|
|
50
|
+
exportAsPrint,
|
|
51
|
+
exportAsImage
|
|
33
52
|
},
|
|
34
53
|
instance: {
|
|
35
|
-
exportAsPrint
|
|
54
|
+
exportAsPrint,
|
|
55
|
+
exportAsImage
|
|
36
56
|
}
|
|
37
57
|
};
|
|
38
58
|
};
|
|
@@ -16,6 +16,30 @@ export interface ChartPrintExportOptions {
|
|
|
16
16
|
*/
|
|
17
17
|
fileName?: string;
|
|
18
18
|
}
|
|
19
|
+
/**
|
|
20
|
+
* The options to apply on the image export.
|
|
21
|
+
* @demos
|
|
22
|
+
* - [Image export](/x/react-charts/export/#export-as-image)
|
|
23
|
+
*/
|
|
24
|
+
export interface ChartImageExportOptions {
|
|
25
|
+
/**
|
|
26
|
+
* The value to be used as the print window title.
|
|
27
|
+
* @default The title of the page.
|
|
28
|
+
*/
|
|
29
|
+
fileName?: string;
|
|
30
|
+
/**
|
|
31
|
+
* The format of the image to be exported.
|
|
32
|
+
* Browsers are required to support 'image/png'. Some browsers also support 'image/jpeg' and 'image/webp'.
|
|
33
|
+
* @default 'image/png'
|
|
34
|
+
*/
|
|
35
|
+
type?: 'image/png' | string;
|
|
36
|
+
/**
|
|
37
|
+
* The quality of the image to be exported between 0 and 1. This is only applicable for lossy formats, such as
|
|
38
|
+
* 'image/jpeg' and 'image/webp'. 'image/png' does not support this option.
|
|
39
|
+
* @default 0.9
|
|
40
|
+
*/
|
|
41
|
+
quality?: number;
|
|
42
|
+
}
|
|
19
43
|
export interface UseChartProExportPublicApi {
|
|
20
44
|
/**
|
|
21
45
|
* Opens the browser's print dialog, which can be used to print the chart or export it as PDF.
|
|
@@ -23,6 +47,14 @@ export interface UseChartProExportPublicApi {
|
|
|
23
47
|
* @returns {void}
|
|
24
48
|
*/
|
|
25
49
|
exportAsPrint: (options?: ChartPrintExportOptions) => void;
|
|
50
|
+
/**
|
|
51
|
+
* Exports the chart as an image.
|
|
52
|
+
* If the provided `type` is not supported by the browser, it will default to `image/png`.
|
|
53
|
+
*
|
|
54
|
+
* @param {ChartPrintExportOptions} options Options to customize the print export.
|
|
55
|
+
* @returns {void}
|
|
56
|
+
*/
|
|
57
|
+
exportAsImage: (options?: ChartImageExportOptions) => void;
|
|
26
58
|
}
|
|
27
59
|
export interface UseChartProExportInstance extends UseChartProExportPublicApi {}
|
|
28
60
|
export type UseChartProExportSignature = ChartPluginSignature<{
|