Skip to content

[charts-pro] Allow exporting a heatmap chart #17916

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 8 commits into from
May 23, 2025

Conversation

bernardobelchior
Copy link
Member

Part of #11746.

Also updated the print example to allow selecting different chart types.

Copy link

github-actions bot commented May 20, 2025

Thanks for adding a type label to the PR! 👍

@mui-bot
Copy link

mui-bot commented May 20, 2025

Deploy preview: https://deploy-preview-17916--material-ui-x.netlify.app/

Updated pages:

Bundle size report

Total Size Change:${\tiny{\color{red}▲}}$+42B(0.00%) - Total Gzip Change:${\tiny{\color{green}▼}}$-7B(0.00%)
Files: 118 total (0 added, 0 removed, 15 changed)

Show 15 more bundle changes

@mui/x-charts-proparsed:${\tiny{\color{red}▲}}$+21B(+0.01%) gzip:${\tiny{\color{red}▲}}$+10B(+0.01%)
@mui/x-charts-pro/Heatmapparsed:${\tiny{\color{red}▲}}$+21B(+0.01%) gzip:${\tiny{\color{green}▼}}$-16B(-0.03%)
@mui/x-charts-pro/BarChartProparsed: 0B(0.00%) gzip:${\tiny{\color{green}▼}}$-2B(0.00%)
@mui/x-charts-pro/ChartContainerProparsed: 0B(0.00%) gzip:${\tiny{\color{green}▼}}$-1B(0.00%)
@mui/x-charts-pro/ChartDataProviderProparsed: 0B(0.00%) gzip:${\tiny{\color{red}▲}}$+1B(0.00%)
@mui/x-charts-pro/FunnelChartparsed: 0B(0.00%) gzip:${\tiny{\color{red}▲}}$+1B(0.00%)
@mui/x-charts-pro/ScatterChartProparsed: 0B(0.00%) gzip:${\tiny{\color{green}▼}}$-1B(0.00%)
@mui/x-data-grid-pro/DataGridProparsed: 0B(0.00%) gzip:${\tiny{\color{red}▲}}$+1B(0.00%)
@mui/x-date-pickers-pro/DateRangeCalendarparsed: 0B(0.00%) gzip:${\tiny{\color{green}▼}}$-2B(-0.01%)
@mui/x-date-pickers-pro/DateRangePickerparsed: 0B(0.00%) gzip:${\tiny{\color{red}▲}}$+1B(0.00%)
@mui/x-date-pickers-pro/DateRangePickerDayparsed: 0B(0.00%) gzip:${\tiny{\color{red}▲}}$+1B(+0.01%)
@mui/x-date-pickers-pro/DesktopDateTimeRangePickerparsed: 0B(0.00%) gzip:${\tiny{\color{green}▼}}$-1B(0.00%)
@mui/x-date-pickers-pro/MobileDateRangePickerparsed: 0B(0.00%) gzip:${\tiny{\color{red}▲}}$+1B(0.00%)
@mui/x-tree-view-proparsed: 0B(0.00%) gzip:${\tiny{\color{green}▼}}$-1B(0.00%)
@mui/x-tree-view-pro/RichTreeViewProparsed: 0B(0.00%) gzip:${\tiny{\color{red}▲}}$+1B(0.00%)

Details of bundle changes

Generated by 🚫 dangerJS against 3d939ec

@github-actions github-actions bot added the PR: out-of-date The pull request has merge conflicts and can't be merged label May 20, 2025
Copy link

This pull request has conflicts, please resolve those before we can evaluate the pull request.

@bernardobelchior bernardobelchior added type: new feature Introduces a new piece of functionality or capability. scope: charts Changes or issues related to the charts product labels May 20, 2025
Comment on lines 9 to 27
type PluginsPerSeriesType = {
heatmap: HeatmapPluginsSignatures;
line: LineChartProPluginsSignatures;
scatter: ScatterChartProPluginsSignatures;
bar: BarChartProPluginsSignatures;
};

export type ChartProApi<
TSeries extends ChartSeriesType = ChartSeriesType,
TSignatures extends
readonly ChartAnyPluginSignature[] = TSeries extends keyof PluginsPerSeriesType
? PluginsPerSeriesType[TSeries]
: AllPluginSignatures,
> = NonNullable<NonNullable<ChartContainerProProps<TSeries, TSignatures>['apiRef']>['current']>;
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The previous implementation would show setZoomData as a valid API for the heatmap chart. This implementation isn't breaking (since it defaults to AllPluginSignatures), but IMO we should encourage users to use ChartProApi<'scatter'> or ChartProApi<'heatmap'> for TypeScript to only suggest functions that are valid.

For composition, I think we should add a composition "series type" that uses the DefaultPluginSignatures. This way, when using composition, users should use ChartProApi<'composition'>, and in the next major we can make the TSeries parameter mandatory.

What do you think, @alexfauquette @JCQuintas?

* `ChartsRootSurface` is a wrapper around the `ChartsSurface` component that provides a reference to the chart root element.
* This is only needed for charts that aren't wrapped in `ChartsWrapper`.
*/
export const ChartsRootSurface = React.forwardRef<SVGSVGElement, ChartsRootSurfaceProps>(
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Had to create this to set the chart root ref. An alternative would be to default to svgRef in the useChartProExport plugin, but I thought the current approach would be cleaner.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This PR might solve your issue by introducing the wrapper to heatmap too
#17943

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, it will. I can wait for that to be merged

@github-actions github-actions bot removed the PR: out-of-date The pull request has merge conflicts and can't be merged label May 20, 2025
Copy link

codspeed-hq bot commented May 20, 2025

CodSpeed Performance Report

Merging #17916 will not alter performance

Comparing bernardobelchior:export-heatmap (3d939ec) with master (48666ad)

Summary

✅ 9 untouched benchmarks

@@ -73,7 +73,7 @@ function ExportParamsSelector({
}

export default function ExportChartAsImage() {
const apiRef = React.useRef<ChartProApi>(undefined);
const apiRef = React.useRef<ChartProApi<'line'>>(undefined);
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unfortunately, I don't think we can keep the current API for ChartProApi. Either we create a new type, or we need to accept this breaking change as a bug fix.

It is a bug because invalid types are accepted. For example, the heatmap's apiRef doesn't contain a setZoomData property, but the type says it does.

It's unlikely a lot of people are using it as it was released in v8.1.0, but it's technically a breaking change if we don't flag it as a bug.

Another option would be to create another type to avoid breaking users and deprecate this one. What are your thoughts?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We could just go with the generic one but still allow users to narrow the types with the <'seriesType'> notation.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That doesn't work either. I suppose it's the same issue as trying to pass a RefObject<HTMLElement> to a HTMLDivElement.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't get it, if the issue is that you are passing a wide type but it expects a narrow type, just make the expectation wide, so it can accept a narrow one.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think I managed to make it work.

I thought it was another case of this issue with HTMLDivElement and HTMLElement:

image

I've kept the ChartProApi<'line'> here because we should encourage users to use it, but it's usable without it as well:

image

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nice

@bernardobelchior bernardobelchior marked this pull request as ready for review May 21, 2025 08:28
@alexfauquette alexfauquette changed the title [charts-pro] allow exporting a heatmap chart [charts-pro] Allow exporting a heatmap chart May 21, 2025
@github-actions github-actions bot added the PR: out-of-date The pull request has merge conflicts and can't be merged label May 22, 2025
Copy link

This pull request has conflicts, please resolve those before we can evaluate the pull request.

@github-actions github-actions bot removed the PR: out-of-date The pull request has merge conflicts and can't be merged label May 22, 2025
@@ -6,7 +6,7 @@ import { useChartContext } from '../context/ChartProvider';
* Get the ref for the root chart element.
* @returns The root chart element ref.
*/
export function useChartRootRef(): React.RefObject<HTMLDivElement | null> {
export function useChartRootRef(): React.RefObject<HTMLElement | SVGElement | null> {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This can probably be reverted?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure to be honest. The reality is that any HTML or SVG elements should be accepted here.

However, I think doing that now would be a breaking change, so I'll revert it. Maybe that's something we want to change for v9?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh, if we need to accept HTMLElement and SVGElement IIRC we should use HTMLElement | (HTMLElement & SVGElement)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

HTMLElement | (HTMLElement & SVGElement)? Why not HTMLElement | SVGElement?

I'd like to make this change, but it's breaking and it's unfortunate that we need to ask users to cast the ref object to use it. I wonder if there's some way to infer the type 🤔

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nvm I couldn't find the reference, I might have been mistaken then 🤔

I was thinking I used that somewhere to solve this issue of needing to cast the ref, but I tried it out and it doesn't work 😢

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you need a broader definition you can also try to use Element instead

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you need a broader definition you can also try to use Element instead

Yeah, that could also work, but we still have the typing issue. I don't know how to fix it, but I haven't dug deeper.

Copy link
Member

@alexfauquette alexfauquette left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The mapping from series type to their pluggin signature is elegant 👍

@bernardobelchior bernardobelchior merged commit ee90fea into mui:master May 23, 2025
24 checks passed
@bernardobelchior bernardobelchior deleted the export-heatmap branch May 23, 2025 07:40
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
scope: charts Changes or issues related to the charts product type: new feature Introduces a new piece of functionality or capability.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants