尝试从包含文本、表格和图形的 React 组件的 HTML 页面生成 PDF。使用 jsPDF 和 html2canvas 成功创建了 PDF,但面临文本呈现为单个图像的问题,阻碍了单个文本元素的选择。附上生成的 PDF 示例以供参考。
要求在下载 PDF 时能够选择文本内容和表格数据。寻求帮助来确定必要的代码更改以满足此要求。其他包如react-pdf已经尝试过,但没有达到预期的结果。
代码
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;
我能够使用给定 HTML 中的可选文本创建 pdf:
我改变了downloadPdf的功能:
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;
// }
// New code
await pdf.html(element, {
margin: [20, 20, 20, 20],
autoPaging: "text",
width: 170,
windowWidth: element.offsetWidth,
});
const chartCanvas = await html2canvas(chartRef.current);
pdf.addImage(
chartCanvas,
"PNG",
110,
20,
chartCanvas.width / 7,
chartCanvas.height / 7
);
// 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");
};
我使用了 .html 方法,它添加了可选择的文本,而不是图像中的文本。不幸的是,jsPDF 在添加 svg 文件时遇到一些问题,因此我必须调整代码以将 svg 转换为 png,然后添加它。可以有更好、更方便的方法来做到这一点。我想提一下,我将chartCanvas的宽度和高度除以7,因为这是chartCanvas宽度与pdf页面宽度的一半之间的比率。这可以用公式代替。另外,我还添加了一个名为 ChartRef 的引用,并将其添加到保存图表的 Col 元素中。我想提一下,我在 repo 中添加了带有大量 CSS 的代码,因为文本可能看起来不太好。如果有一些特定的字体,它们也必须添加到jsPDF中。