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"
}
}
@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