Skip to content

Instantly share code, notes, and snippets.

@kidroca
Last active November 29, 2023 04:57
Show Gist options
  • Save kidroca/19e5fe2de8e24aa92a41e94f2d41eda4 to your computer and use it in GitHub Desktop.
Save kidroca/19e5fe2de8e24aa92a41e94f2d41eda4 to your computer and use it in GitHub Desktop.
Render recharts svg chart inside a PDF document created with react-pdf/renderer
import React from 'react';
import { Global } from 'recharts';
import { htmlSvgToPdfSvg } from '../imageFromSvg';
export const ChartSvg = ({ debug, style, children, width, height }) => {
return chartToPdfSvg(children, width, height, debug, style);
};
const chartToPdfSvg = (children, width, height, debug, style) => {
Global.set('isSsr', true);
const component = htmlSvgToPdfSvg(children);
Global.set('isSsr', false);
const result = React.cloneElement(component, { width, height, debug, style });
return result;
};
export default ChartSvg;
import { View } from '@react-pdf/renderer';
import { CartesianGrid, Label, Scatter, ScatterChart, XAxis, YAxis } from 'recharts';
import Chart from './Chart';
export const ExampleUsage = ({ data = getSampleData() }) => (
<View>
<Chart width={600} height={300}>
<MyRechartsChart data={data} />
</Chart>
</View>
);
const MyRechartsChart = ({ width, height, data }) => (
<ScatterChart width={width} height={height}>
<CartesianGrid />
<XAxis name="x" dataKey="x" />
<YAxis name="y" dataKey="y" />
<Scatter name="My Scatter" data={data} isAnimationActive={false} />
</ScatterChart>
)
function getSampleData() {
return [
{ x: 100, y: 100 },
{ x: 200, y: 100 },
{ x: 200, y: 150 },
{ x: 150, y: 200 },
{ x: 125, y: 150 }
]
}
export default ExampleUsage;
import React, { createElement } from 'react';
import ReactDom from 'react-dom/server';
import reactHtmlParser from 'react-html-parser';
export const htmlSvgToPdfSvg = (children) => {
const svgString = ReactDom
.renderToStaticMarkup(children)
.replaceAll('px', 'pt');
const [component] = reactHtmlParser(svgString, { transform: convertToPdfSvg });
return component;
};
function convertToPdfSvg(node, index) {
if (node.type == 'text') {
return node.data;
}
node.props = { key: index };
Object.entries(node.attribs).forEach(([key, value]) => {
const [first, ...rest] = key.split('-');
const newKey = [first, ...rest.map(word => `${word[0].toUpperCase()}${word.slice(1)}`)].join('');
node.props[newKey] = value;
});
node.name = node.name?.toUpperCase();
if (node.name == 'CLIPPATH') node.name = 'CLIP_PATH';
// we're removing nested <defs> because they don't work
if (node.name == 'DEFS' && node.parent.name != 'SVG') return null;
if (node.children) node.children = node.children.map(convertToPdfSvg);
return createElement(node.name, node.props, node.children);
}
export default htmlSvgToPdfSvg;
{
"dependencies": {
"@react-pdf/renderer": "^2.0.16",
"react": "^17.0.2",
"react-dom": "^17.0.2",
"react-html-parser": "^2.0.2",
"recharts": "^2.0.9"
}
}
@jnovak-SM2Dev
Copy link

I'm having the same issue with renderFn. Anyone figure this out?

@leq382121
Copy link

I have digged into the node modules and found out that recharts inner tags "TITLE" and "DEFS" are breaking render function. I've included this line of code to ditch those two values and it's sucessfuly rendered.

if (node.name == "TITLE" || node.name == "DESC") return null;

image

Result:
image

Hope it helps!

@EvHaus
Copy link

EvHaus commented Jun 26, 2023

I just created https://github.com/EvHaus/react-pdf-charts which allows for recharts to be rendered into react-pdf. It had only very basic support at the moment, but I'm hoping with some help from the community -- we can get to full support.

@leq382121
Copy link

leq382121 commented Jun 26, 2023

@EvHaus it does not work properly. I can see that Path is being converted to Line and it's not even found in parsed HTML string.

@leq382121
Copy link

probably Html parser is bringing this issue

@leq382121
Copy link

this is what I get after using an example

image

@EvHaus
Copy link

EvHaus commented Jun 26, 2023

@leq382121 Hmm. Could you open an issue in https://github.com/EvHaus/react-pdf-charts/issues with the code you're using and I'll take a look.

@Kartik0899
Copy link

Kartik0899 commented Aug 17, 2023

@EvHaus @leq382121 I am facing an issue while displaying the BarChart inside my pdf.... So when I am using " import ReactPDFChart from "react-pdf-charts" " this and trying to get my BarChart then Barchart is only showing the CartesianGrid, XAxis and YAxis but no values.
Below is the code with "ReactPDFChart" -

import React from "react";
import ReactPDFChart from "react-pdf-charts";
import { BarChart, Bar, XAxis, YAxis, CartesianGrid } from "recharts";

const data = [
{ name: 'A', uv: 4000, pv: 2400, amt: 2400 },
{ name: 'B', uv: 3000, pv: 1398, amt: 2210 },
{ name: 'C', uv: 2000, pv: 9800, amt: 2290 },
{ name: 'D', uv: 2780, pv: 3908, amt: 2000 },
{ name: 'E', uv: 1890, pv: 4800, amt: 2181 },
{ name: 'F', uv: 2390, pv: 3800, amt: 2500 },
{ name: 'G', uv: 3490, pv: 4300, amt: 2100 },
];

// Silence useLayoutEffect does nothing on the server warnings. These come
// from recharts but they're harmless and just clutter the console output.
const consoleError = console.error;
console.error = function (message) {
if (message?.startsWith('Warning: useLayoutEffect does nothing on the server')) return;
consoleError.apply(console, arguments);
};

const PdfBarChart = () => (
<ReactPDFChart> <BarChart data={data} width={500} height={300}> <XAxis dataKey="name" /> <YAxis /> <CartesianGrid stroke="#ccc" strokeDasharray="3 3" /> <Bar dataKey="uv" fill="#8884d8" /> <Bar dataKey="pv" fill="#82ca9d" /> </BarChart> </ReactPDFChart>
);

export default PdfBarChart;

And when I try the same above code without "ReactPDFChart" it is giving me error like below -

htmlLayer.getElementsByClassName is not a function
TypeError: htmlLayer.getElementsByClassName is not a function
at CartesianAxis.componentDidMount (http://localhost:3000/static/js/bundle.js:144491:28)

So can anyone please guide or help me to figure this out and render the Bar and another Charts in the pdf.

@EvHaus
Copy link

EvHaus commented Aug 17, 2023

@Kartik0899 Could you please open a new issue at https://github.com/EvHaus/react-pdf-charts/issues and we can take it from there.

@omarhsouna-logient
Copy link

BarChart doesn't work properly, ni the PieChart

@Kartik0899
Copy link

BarChart doesn't work properly, ni the PieChart

@omarhsounalogient

You need to add isAnimationActive={false} when rendering BarChart and PieChart component in the browser.
For example -
<Bar isAnimationActive={false} dataKey="uv" fill="#8884d8" />
<Pie isAnimationActive={false} dataKey="value" nameKey="name" cx="25%" cy="50%" outerRadius={50} fill="#000" label />

Hope it helps!

@khanirrfan
Copy link

I'm having the same issue with renderFn. Anyone figure this out?

I degraded the version react-pdf ,and it worked

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment