Last active
June 6, 2024 00:01
-
-
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
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{ | |
"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" | |
} | |
} |
@Kartik0899 Could you please open a new issue at https://github.com/EvHaus/react-pdf-charts/issues and we can take it from there.
BarChart doesn't work properly, ni the PieChart
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!
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
@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.