-
-
Save kidroca/19e5fe2de8e24aa92a41e94f2d41eda4 to your computer and use it in GitHub Desktop.
| 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" | |
| } | |
| } |
Hi kidroca! Thanks for sharing to the community 🙌🏼
I'm following this steps, but I'm not able to render properly any recharts component, except the Line Chart one.
Here is the link to the code in a Github repository https://github.com/griselmatosm/recharts-react-pdf-test
Thanks a lot in advance!
Hi @griselmatosm,
The exact same code from this gist is still used in our project and there are no problems
The only difference is we pass a isAnimationActive={false} prop to the chart when we want to render it in PDF
The isAnimationActive={false} is then set on the <Scatter> component:
<Scatter
isAnimationActive={isAnimationActive}
name={referenceDataLabel}
data={referenceRecords}
r={5}
strokeWidth={2}
/>So maybe that's all that you need to do
Hi @griselmatosm,
The exact same code from this gist is still used in our project and there are no problems The only difference is we pass a
isAnimationActive={false}prop to the chart when we want to render it in PDF TheisAnimationActive={false}is then set on the<Scatter>component:<Scatter isAnimationActive={isAnimationActive} name={referenceDataLabel} data={referenceRecords} r={5} strokeWidth={2} />So maybe that's all that you need to do
Thanks so much! That's it!
Hello, tell me please. I get this error: TypeError: renderFn is not a function .
Trying to figure this out myself. I also see: TypeError: renderFn is not a function
Hello @dylnclrk, my reason was npm conflict. Try create new app, for testing. And I created GitHub tutorial, how I made this.
i am using same configs in my tupescript project, but getting renderFn is not a function, and I don't think there are any conflicts.
I'm having the same issue with renderFn. Anyone figure this out?
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.
@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.
probably Html parser is bringing this issue
@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.
@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.
@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
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!
You save my life, after like 4 hours with this issue your advice work



Instead of rendering to string and then using
reactHtmlParserwe can probably iteratechildrenand achieve a similar result