개발자
리액트에서 html2pdf 라이브러리를 사용하여 내용물을 A4 규격에 맞추어서 다운로드 하고 싶습니다. printToPDF 함수를 구현하였으나, pdf 파일의 가로, 세로 크기만 A4 규격이고, 아래 이미지 처럼 내용 크기는 축소 되지 않았습니다. (가로 우측 잘림) 내용물을 A4 크기에 맞추어 적용하는 방법 없을까요?
1import { useRecoilValue } from "recoil"
2import { appTestEnrollState } from "./store/stores"
3import { H1, H2, SelectBox } from "./common/Style"
4import styled from "styled-components"
5import { reportTypeOption } from "./common/selectBoxOptions"
6import { t } from "i18next"
7import { useRef, useState } from "react"
8import { ReactComponent as CloseSvg } from "../images/Close.svg"
9import { ReactComponent as DownloadSvg } from "../images/Download.svg"
10import DonutChart from "./DonutChart"
11import { style } from "d3"
12import DetailDonutChart from "./DetailDonutChart"
13import { CompatibilityList } from "./common/TCListArray"
14import html2pdf from "html2pdf.js";
15
16const ModalBackground = styled.div`
17 (생략)
18`
19
20const ModalComponent = styled.div`
21 (생략)
22`
23
24const TestReportWrapper = styled.div`
25
26 width : 270px;
27 height : 48px;
28 gap : 25px;
29 display : flex;
30 align-items : center;
31 justify-content : center;
32`
33
34const TestReportContents = styled.div`
35 width: 942px;
36 margin: 20px auto auto auto;
37 overflow-y: auto;
38 overflow-x: hidden;
39
40 border: 1px solid #494A50;
41
42 display : flex;
43 flex-direction : column;
44 align-items : center;
45 justify-content : center;
46
47
48`;
49
50const TestSummaryWrapper = styled.div`
51
52 width : 864px;
53 height : 92px;
54 background-color : #FFF4E4;
55
56 display : flex;
57 justify-content : center;
58 align-items : center;
59 margin-top : 35px;
60
61`
62
63const TestSummaryItem = styled.div`
64 width : 214px;
65 height : 61px;
66
67 display : flex;
68 flex-direction : column;
69 justify-content : center;
70 align-items : center;
71 gap : 5px;
72
73 font-weight : 700;
74 border-right : 1px solid #D4D6DD;
75
76 &:last-child{
77 border-right : none;
78 }
79`
80...
81
82
83export default function CompatibilityTestReport({setModalOpen}: {[key : string] : Function}) {
84
85 const closeModal = () => {
86 setModalOpen(false)
87 }
88
89...
90 const printToPDF = () => {
91 const modalComponent = document.getElementById("modal-component");
92
93 if (modalComponent) {
94 const pdfOptions = {
95 margin: 10,
96 filename: "compatibility_test_report.pdf",
97 image: { type: "jpeg", quality: 0.98 },
98 html2canvas: { scale: 2 },
99 jsPDF: { unit: "mm", format: "a4", orientation: "portrait" },
100 };
101
102 html2pdf().from(modalComponent).set(pdfOptions).save();
103 }
104 }
105
106
107 return(
108 <ModalBackground>
109 <ModalComponent>
110 <div style={{display : "flex", marginLeft : "57px", marginTop : "40px", flexDirection : "row", alignItems : "center", gap : "540px"}}>
111 <H1>{t('테스트')} {t('리포트')}</H1>
112 <TestReportWrapper>
113 <SelectBox onChange=
114 {(e : React.ChangeEvent<HTMLSelectElement>) =>
115 setReportOption(Number(e.target.value))}
116 placeholder = "선택하세요"
117 value={reportOption}
118 options={reportTypeOption}
119 borderRadius={12}
120 width={172}/>
121 <Download
122 width={32}
123 height={32}
124 onClick={printToPDF}
125 />
126 <Close onClick={closeModal} width={24} height={24}/>
127 </TestReportWrapper>
128 </div>
129 <TestReportContents id ="modal-component">
130 <TestSummaryWrapper>
131 <TestSummaryItem>
132 <p>Test App</p>
133 <p>게임명</p>
134 </TestSummaryItem>
135 ...
136 </ModalComponent>
137 </ModalBackground>
138 )
139}
답변 3
html2pdf 라이브러리 대신 html2canvas + jsPDF 조합을 사용했습니다. => 가로,세로 마진 설정이 잘 적용되었습니다. 하지만 페이지 분할 기능은 추가 구현이 필요했습니다. html2canvas는 현재 출력되는 페이지를 윈도우의 "캡처 도구" 처럼 현재 출력되는 화면을 캡처해서 이미지화 시키며, 별도의 DOM(html)을 분할하는 기능은 지원하지 않는것 같습니다. 따라서, View에서 부터 페이지를 분할해 html2canvas로 전달하는 방법을 생각해 보았습니다. marginBottom을 설정한 이유는 해당 페이지가 마지막일 때(다음 페이지가 존재하지 않을때) (a4 세로길이 - 테이블 세로 길이)를 주기 위해서 입니다. 만약, marginBottom을 적용하지 않으면, html2canvas 설정사항에 따라 세로 길이에 맞춰 마지막 페이지의 테이블이 늘어져서 출력되는 현상이 발생합니다. (marginBottom 설정시 useRef.current.scrollHeight 값도 적용해 보았지만, 적용되지 않았습니다...)
1(이전 코드)
2
3const tableRows = Object.keys(scoresByCombination).map((combinationKey) => {
4 const { questionStr, 0: score1 = 0, 1: score2 = 0, 2: score3 = 0, 3: score4 = 0, 4: score5 = 0 } = scoresByCombination[combinationKey];
5
6 return (
7 <Tr key={combinationKey}>
8 <Td style={{ width: "390px" }}>{t(questionStr!)}</Td>
9 <Td>{score1}</Td>
10 <Td>{score2}</Td>
11 <Td>{score3}</Td>
12 <Td>{score4}</Td>
13 <Td>{score5}</Td>
14 </Tr>
15 );
16
17
18
19// 페이지에 맞게 테이블 갯수 나누기
20 const tableRowsFirst = tableRows.slice(0, 5);
21 const tableRowsSecond = tableRows.slice(5, 28);
22 const tableRowsThird = tableRows.slice(28, 51);
23 const tableRowsFourth = tableRows.slice(51);
24
25
26 /* 결과 리포트 pdf 파일로 저장 */
27
28 const printToPDF = async () => {
29 const pdf = new jsPDF("p", "mm", "a4");
30
31 const addPageContent = async (element : any) => {
32 const canvas = await html2canvas(element);
33 const imgData = canvas.toDataURL("image/jpeg");
34 pdf.addImage(imgData, "JPEG", 10, 10, 190, 277);
35 pdf.addPage();
36 };
37
38 const reportContents = [
39 document.getElementById("report-contents-1"),
40 document.getElementById("report-contents-2"),
41 document.getElementById("report-contents-3"),
42 document.getElementById("report-contents-4"),
43 ];
44
45 for (const reportContent of reportContents) {
46 if (reportContent) {
47 await addPageContent(reportContent);
48 }
49 }
50 pdf.save("test_report.pdf");
51};
52
53
54
55 return(
56// 1 페이지
57<TestReportContents id ="report-contents-1">
58
59...
60 <DetailTable style={{ marginBottom: !tableRowsSecond.length ? `${1200 - 36 * tableRowsFirst.length}px` :"" }}>
61 <Tr>
62 <Th style={{width : "390px"}}>{t('문항')}</Th>
63 <Th>{t('확인불가')}</Th>
64 <Th>{t('발생하지 않음')}</Th>
65 <Th>{t('드물게 발생')}</Th>
66 <Th>{t('빈번하게 발생')}</Th>
67 <Th>{t('100% 발생')}</Th>
68 </Tr>
69 {tableRowsFirst}
70 </DetailTable>
71 </TestReportContents>
72
73// 2페이지
74 {tableRowsSecond.length > 0 && (
75 <TestReportContents id ="report-contents-2">
76 <DetailTable style={{ marginBottom: !tableRowsThird.length ? `${1200 - 36 * tableRowsSecond.length}px` :"" }}>
77 {tableRowsSecond}
78 </DetailTable>
79 </TestReportContents>
80) }
81// 3페이지
82 {tableRowsThird.length > 0 && (
83 <TestReportContents id="report-contents-3">
84 <DetailTable style={{ marginBottom: !tableRowsFourth.length ? `${1200 - 36 * tableRowsThird.length}px` :"" }}>
85 {tableRowsThird}
86 </DetailTable>
87 </TestReportContents>
88 )}
89// 4페이지
90 {tableRowsFourth.length > 0 && (
91 <TestReportContents id="report-contents-4">
92 <DetailTable style={{ marginBottom: `${1200 - 36 * tableRowsFourth.length}px` }}>
93 {tableRowsFourth}
94 </DetailTable>
95 </TestReportContents>
96 )}
97)
98
99
100
101
102/*
103
104//useRef를 활용해서 높이를 구했으나 실패
105
106 const detailTable3Ref = useRef<HTMLDivElement | null>(null)
107
108return(
109...
110 {tableRowsThird.length > 0 && detailTable3Ref.current && (
111 <TestReportContents id="report-contents-3">
112 <DetailTable ref={detailTable3Ref} style={{ marginBottom: !tableRowsFourth.length ? `${1200 - detailTable3Ref.current?.scrollHeight}px` :"" }}>
113 {tableRowsThird}
114 </DetailTable>
115 </TestReportContents>
116 )}
117}
118...
119)
120*/
비공개
개발자 • 2024년 04월 28일
안녕하세요. 혹시 marginBottom 계산 방법에 대해 조금 더 자세하게 설명해주실 수 있을까요?
지금 가입하면 모든 질문의 답변을 볼 수 있어요!
현직자들의 명쾌한 답변을 얻을 수 있어요.
이미 회원이신가요?
커리어리 AI 봇
GPT가 달아주는 답변입니다.
2023년 12월 13일
리액트에서가 제공하는 `html2pdf.js`을 사용하여 내용물을 A4 규격으로 변환하려면, CSS를 사용해 특정 컨텐츠 또는 전체 페이지의 크기를 A4에 딱 맞게 조정해야 합니다. 이 과정에서 가장 중요한 것은 가로 세로 비율이 A4 비율인 1.414 (210mm / 297mm) 를 유지하는 것입니다. 그런 다음 html2canvas 옵션 값을 조절하여 pdf 문서의 확대/축소 비율을 조절할 수 있습니다. 아래는 코드 예시입니다: ```javascript const printToPDF = () => { const modalComponent = document.getElementById("modal-component"); if (modalComponent) { let opt = { margin: [10,10,10,10], filename: 'myfile.pdf', image: { type: 'jpeg', quality: 0.98 }, html2canvas: { scale: window.devicePixelRatio * 1.5 }, // Adjust this value to control the PDF size. jsPDF: { unit: 'in', format: 'a4', orientation: 'portrait' } }; html2pdf().from(modalComponent).set(opt).toPdf().get('pdf').then(function (pdf) { var totalPages = pdf.internal.getNumberOfPages(); for (let i = 1; i <= totalPages; i++) { pdf.setPage(i); pdf.setFontSize(10); } }).save(); } } ``` 위 코드 첫줄에 보면 `html2canvas: { scale: window.devicePixelRatio * 1.5 }` 부분이 있는데, 이 값을 통해 PDF 문서의 크기를 조절할 수 있습니다. 값을 높일수록 PDF가 작아지고, 낮출수록 PDF가 커집니다. 이렇게 하더라도 여전히 문제가 해결되지 않는다면, CSS에서 페이지의 크기를 A4 용지에 맞추어 설정하거나 내용을 줄여야 할 수도 있습니다. 이 부분은 디자인과 내용에 따라 달라질 수 있으므로 상황에 따라 적절히 조정해 주세요.
지금 가입하면 모든 질문의 답변을 볼 수 있어요!