Attempting to generate a PDF from a React component's HTML page containing text, tables, and graphs. Successfully created a PDF using jsPDF and html2canvas, but facing an issue where text is rendered as a single image, hindering the selection of individual text elements. A sample of the generated PDF is attached for reference.
The requirement is to enable the selection of both text content and tabular data upon downloading the PDF. Assistance is sought in identifying the necessary code changes to meet this requirement. Other packages like react-pdf have been experimented with, but the desired outcome has not been achieved.
Code
import React, { useRef, useEffect } from 'react';
import { Row, Col, Table } from 'react-bootstrap';
import Highcharts from 'highcharts';
import HighchartsReact from 'highcharts-react-official';
import { Container, Button } from 'react-bootstrap';
import html2canvas from 'html2canvas';
import jsPDF from 'jspdf';
const EcommerceInIndiaPage = ({ generatePDF }) => {
const componentRef = useRef();
const ecommercePieChartOptions = {
chart: {
type: 'pie',
},
title: {
text: 'E-commerce Market Share in India',
},
series: [
{
name: 'Categories',
colorByPoint: true,
data: [
{
name: 'Electronics',
y: 30,
},
{
name: 'Fashion',
y: 25,
},
{
name: 'Grocery',
y: 20,
},
{
name: 'Home & Furniture',
y: 15,
},
{
name: 'Others',
y: 10,
},
],
},
],
};
const downloadPDF = async () => {
const element = componentRef.current; // Reference to the component
const canvas = await html2canvas(element);
const data = canvas.toDataURL('image/png');
let pdf = new jsPDF('p', 'mm', 'a4');
let pageWidth = pdf.internal.pageSize.getWidth();
let pageHeight = pdf.internal.pageSize.getHeight();
// Calculate the number of pages.
let imgHeight = canvas.height * pageWidth / canvas.width;
let heightLeft = imgHeight;
let position = 0;
// Add content to the first page.
pdf.addImage(data, 'PNG', 0, position, pageWidth, imgHeight);
heightLeft -= pageHeight;
while (heightLeft >= 0) {
position = heightLeft - imgHeight;
pdf.addPage();
pdf.addImage(data, 'PNG', 0, position, pageWidth, imgHeight);
heightLeft -= pageHeight;
}
// Additional Pages with Dummy Data
// Adding a new page for conclusion
pdf.addPage();
pdf.setFontSize(10);
pdf.text("Conclusion", 10, 10);
pdf.text("This is a conclusion section with some insights and final thoughts about the E-commerce market trends in India.", 10, 20);
// Adding a content page with dummy data
pdf.addPage();
pdf.setFontSize(10);
pdf.text("Content Page", 10, 10);
pdf.text("Here you can describe the document's structure or provide any additional information.", 10, 20);
// Save the PDF
pdf.save('ecommerce-in-india-report.pdf');
};
useEffect(() => {
// Call the generatePDF function with the HTML content when the component mounts
if (generatePDF && componentRef.current) {
const htmlContent = componentRef.current.innerHTML;
generatePDF(htmlContent);
}
}, [generatePDF]);
return (
<Container className="mt-4" ref={componentRef}>
<div>
<Row>
<Col>
<h1>E-commerce in India</h1>
<p>
E-commerce has experienced tremendous growth in India over the past decade, transforming the way
people shop and businesses operate. The diverse and dynamic nature of the Indian market has led to
the rise of various e-commerce segments, catering to a wide range of consumer needs.
</p>
<h2>Market Trends</h2>
<p>
The Indian e-commerce market is characterized by the dominance of categories such as Electronics,
Fashion, Grocery, Home & Furniture, and more. According to recent studies, the electronics segment
holds a significant market share, followed closely by the fashion and grocery sectors.
</p>
<h2>Consumer Behavior</h2>
<p>
With the advent of affordable smartphones and widespread internet connectivity, more and more
consumers in India are embracing online shopping. The convenience of browsing through a vast
assortment of products, coupled with attractive discounts and doorstep delivery, has contributed to
the popularity of e-commerce.
</p>
{/* React Bootstrap Table */}
<h2>E-commerce Market Overview</h2>
<Table striped bordered hover>
<thead>
<tr>
<th>#</th>
<th>Category</th>
<th>Market Share</th>
</tr>
</thead>
<tbody>
{[
{ category: 'Electronics', marketShare: '30%' },
{ category: 'Fashion', marketShare: '25%' },
{ category: 'Grocery', marketShare: '20%' },
{ category: 'Home & Furniture', marketShare: '15%' },
{ category: 'Others', marketShare: '10%' },
].map((item, index) => (
<tr key={index}>
<td>{index + 1}</td>
<td>{item.category}</td>
<td>{item.marketShare}</td>
</tr>
))}
</tbody>
</Table>
<h3>Challenges and Opportunities</h3>
<p>
While the e-commerce sector in India continues to thrive, it faces challenges such as logistical
complexities and regulatory frameworks. However, the market presents immense opportunities for
innovation, technological advancements, and the integration of e-commerce into various aspects of
daily life.
</p>
</Col>
<Col>
{/* Highcharts Pie Chart */}
<HighchartsReact highcharts={Highcharts} options={ecommercePieChartOptions} />
</Col>
</Row>
<Button onClick={downloadPDF}>Download as PDF</Button>
</div>
</Container>
);
};
export default EcommerceInIndiaPage;
I was able to create pdf with selectable text from the given HTML:
I changed the function downloadPdf:
I used the method .html, which adds selectable text, not text from image. Unfortunately jsPDF have some problem with adding svg files, so I had to tweak the code to convert the svg to png and then to add it. There can be better and more convenient way of doing that. I want to mention that I divide the chartCanvas width and height by 7, because this is the ratio between the chartCanvas width and half of the width of the pdf page. This can be replaced by formula. Also, I added one more reference called chartRef and added it to the Col element, which holds the chart. I want to mention that I added the code inside repo with a lot of CSS, for that maybe the text is not looking very good. If there are some specific fonts, they have to be added to jsPDF too.