개발자
리액트에서 html2pdf 라이브러리를 사용하여 내용물을 A4 규격에 맞추어서 다운로드 하고 싶습니다. printToPDF 함수를 구현하였으나, pdf 파일의 가로, 세로 크기만 A4 규격이고, 아래 이미지 처럼 내용 크기는 축소 되지 않았습니다. (가로 우측 잘림) 내용물을 A4 크기에 맞추어 적용하는 방법 없을까요?
답변 3
html2pdf 라이브러리 대신 html2canvas + jsPDF 조합을 사용했습니다. => 가로,세로 마진 설정이 잘 적용되었습니다. 하지만 페이지 분할 기능은 추가 구현이 필요했습니다. html2canvas는 현재 출력되는 페이지를 윈도우의 "캡처 도구" 처럼 현재 출력되는 화면을 캡처해서 이미지화 시키며, 별도의 DOM(html)을 분할하는 기능은 지원하지 않는것 같습니다. 따라서, View에서 부터 페이지를 분할해 html2canvas로 전달하는 방법을 생각해 보았습니다. marginBottom을 설정한 이유는 해당 페이지가 마지막일 때(다음 페이지가 존재하지 않을때) (a4 세로길이 - 테이블 세로 길이)를 주기 위해서 입니다. 만약, marginBottom을 적용하지 않으면, html2canvas 설정사항에 따라 세로 길이에 맞춰 마지막 페이지의 테이블이 늘어져서 출력되는 현상이 발생합니다. (marginBottom 설정시 useRef.current.scrollHeight 값도 적용해 보았지만, 적용되지 않았습니다...)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120
(이전 코드) const tableRows = Object.keys(scoresByCombination).map((combinationKey) => { const { questionStr, 0: score1 = 0, 1: score2 = 0, 2: score3 = 0, 3: score4 = 0, 4: score5 = 0 } = scoresByCombination[combinationKey]; return ( <Tr key={combinationKey}> <Td style={{ width: "390px" }}>{t(questionStr!)}</Td> <Td>{score1}</Td> <Td>{score2}</Td> <Td>{score3}</Td> <Td>{score4}</Td> <Td>{score5}</Td> </Tr> ); // 페이지에 맞게 테이블 갯수 나누기 const tableRowsFirst = tableRows.slice(0, 5); const tableRowsSecond = tableRows.slice(5, 28); const tableRowsThird = tableRows.slice(28, 51); const tableRowsFourth = tableRows.slice(51); /* 결과 리포트 pdf 파일로 저장 */ const printToPDF = async () => { const pdf = new jsPDF("p", "mm", "a4"); const addPageContent = async (element : any) => { const canvas = await html2canvas(element); const imgData = canvas.toDataURL("image/jpeg"); pdf.addImage(imgData, "JPEG", 10, 10, 190, 277); pdf.addPage(); }; const reportContents = [ document.getElementById("report-contents-1"), document.getElementById("report-contents-2"), document.getElementById("report-contents-3"), document.getElementById("report-contents-4"), ]; for (const reportContent of reportContents) { if (reportContent) { await addPageContent(reportContent); } } pdf.save("test_report.pdf"); }; return( // 1 페이지 <TestReportContents id ="report-contents-1"> ... <DetailTable style={{ marginBottom: !tableRowsSecond.length ? `${1200 - 36 * tableRowsFirst.length}px` :"" }}> <Tr> <Th style={{width : "390px"}}>{t('문항')}</Th> <Th>{t('확인불가')}</Th> <Th>{t('발생하지 않음')}</Th> <Th>{t('드물게 발생')}</Th> <Th>{t('빈번하게 발생')}</Th> <Th>{t('100% 발생')}</Th> </Tr> {tableRowsFirst} </DetailTable> </TestReportContents> // 2페이지 {tableRowsSecond.length > 0 && ( <TestReportContents id ="report-contents-2"> <DetailTable style={{ marginBottom: !tableRowsThird.length ? `${1200 - 36 * tableRowsSecond.length}px` :"" }}> {tableRowsSecond} </DetailTable> </TestReportContents> ) } // 3페이지 {tableRowsThird.length > 0 && ( <TestReportContents id="report-contents-3"> <DetailTable style={{ marginBottom: !tableRowsFourth.length ? `${1200 - 36 * tableRowsThird.length}px` :"" }}> {tableRowsThird} </DetailTable> </TestReportContents> )} // 4페이지 {tableRowsFourth.length > 0 && ( <TestReportContents id="report-contents-4"> <DetailTable style={{ marginBottom: `${1200 - 36 * tableRowsFourth.length}px` }}> {tableRowsFourth} </DetailTable> </TestReportContents> )} ) /* //useRef를 활용해서 높이를 구했으나 실패 const detailTable3Ref = useRef<HTMLDivElement | null>(null) return( ... {tableRowsThird.length > 0 && detailTable3Ref.current && ( <TestReportContents id="report-contents-3"> <DetailTable ref={detailTable3Ref} style={{ marginBottom: !tableRowsFourth.length ? `${1200 - detailTable3Ref.current?.scrollHeight}px` :"" }}> {tableRowsThird} </DetailTable> </TestReportContents> )} } ... ) */
비공개
개발자 • 4월 28일
안녕하세요. 혹시 marginBottom 계산 방법에 대해 조금 더 자세하게 설명해주실 수 있을까요?
지금 가입하면 모든 질문의 답변을 볼 수 있어요!
현직자들의 명쾌한 답변을 얻을 수 있어요.
이미 회원이신가요?
지금 가입하면 모든 질문의 답변을 볼 수 있어요!