From 8b0d644364716184310e927355e24e6ba5c600ab Mon Sep 17 00:00:00 2001 From: fOppenheimer <80682747+fOppenheimer@users.noreply.github.com> Date: Wed, 16 Jun 2021 11:48:28 +0200 Subject: [PATCH] Feat/final pdf (#99) * changes for vaccination * changes for test and recovery * changes for test and recovery * justify text in pdf * rotated third page with block * revised rotated justify block * revised * label for disease recovery is different from test and vaccination * show certificate as table Co-authored-by: Gordon Grund --- src/assets/i18n/en/translation.json | 30 +- src/assets/i18n/fr/translation.json | 29 +- src/components/pdf-generater.component.tsx | 413 ++++++++++++++++----- 3 files changed, 343 insertions(+), 129 deletions(-) diff --git a/src/assets/i18n/en/translation.json b/src/assets/i18n/en/translation.json index a4141be..003c1a8 100644 --- a/src/assets/i18n/en/translation.json +++ b/src/assets/i18n/en/translation.json @@ -67,31 +67,31 @@ "pdfCi":"Unique certificate identifier", "pdfGreenCertificate" : "EU Digital COVID Certificate", "pdfMemberPlaceholder" : "Member State Placeholder", - "pdfInfoText" : "This certificate is not a travel document. The scientific evidence on COVID-19 vaccination, testing and recovery continues to evolve, also in view of new variants of concern of the virus. Before traveling, please check the applicable public health measures and related restrictions applied at the point of destination.", + "pdfInfoText" : "This certificate is not a travel document. The scientific evidence on COVID-19 vaccination, testing and recovery continues to evolve, including with regard to new virus variants of concern. Before travelling, please check the applicable public health measures and related restrictions applicable at the point of destination.", "pdfRelevantInformation" : "Relevant information can be found here:", "pdfInfoURL" : "https://reopen.europa.eu/en", "pdfFoldingInstruction" : "Folding instructions", "pdfHeaderVaccination" : "Vaccination certificate", - "pdfDisease" : "Disease or agent targeted", - "pdfVaccineProphylaxis" : "Vaccine/prophylaxis", - "pdfVaccineMedicalProduct" : "Vaccine medicinal product", - "pdfVaccineManufacturer" : "Vaccine marketing authorisation holder or manufacturer", + "pdfDisease" : "Disease or agent targeted: diseaseName\n(SARS-CoV-2 or one of its variants)", + "pdfVaccineProphylaxis" : "COVID-19 vaccine or prophylaxis", + "pdfVaccineMedicalProduct" : "COVID-19 vaccine medicinal product", + "pdfVaccineManufacturer" : "COVID-19 vaccine marketing authorisation holder or manufacturer", "pdfNumberOfDoses" : "Number in a series of vaccinations/doses and the overall number of doses in the series", - "pdfDateOfVaccination" : "Date of vaccination", - "pdfMemberStateOfVaccination" : "Member State of vaccination", + "pdfDateOfVaccination" : "Date of vaccination, indicating the date of the latest dose received", + "pdfMemberStateOfVaccination" : "Member State in which the vaccine was administered", "pdfCertificateIssuer" : "Certificate issuer", "pdfHeaderTest" : "Test Certificate", "pdfTypeOfTest" : "Type of test", - "pdfTestName" : "Test name (optional for NAAT)", - "pdfTestManufacturer" : "Test manufacturer (optional for NAAT)", + "pdfTestName" : "Test name (optional for NAAT test)", + "pdfTestManufacturer" : "Test manufacturer (optional for NAAT test)", "pdfDateSampleCollection" : "Date and time of the test sample collection", - "pdfDateTestResult" : "Date and time of the test result production (optional for RAT)", "pdfTestResult" : "Result of the test", - "pdfTestingCentre" : "Testing centre or facility", - "pdfStateOfVaccination" : "Member State of vaccination", + "pdfTestingCentre" : "Testing centre or facility (optional for rapid antigen test )", + "pdfStateOfVaccination" : "Member State in which the test was carried out", "pdfHeaderRecovery" : "Certificate of Recovery", - "pdfDatePositiveTestResult" : "Date of first positive test result", - "pdfStateOfTest" : "Member State of test", + "pdfDatePositiveTestResult" : "Date of the holders’ first positive NAAT test result", + "pdfStateOfTest" : "Member State in which test was carried out", "pdfValidFrom" : "Certificate valid from", - "pdfValidTo" : "Certificate valid until (not more than 180 days after the date of first positive test result)" + "pdfValidTo" : "Certificate valid until (not more than 180 days after the date of first positive test result)", + "pdfDiseaseRecovery" : "Disease or agent from which the\nholder has recovered : diseaseName\n(SARS-CoV-2 or one of its variants)" } \ No newline at end of file diff --git a/src/assets/i18n/fr/translation.json b/src/assets/i18n/fr/translation.json index 378647b..c21ff73 100644 --- a/src/assets/i18n/fr/translation.json +++ b/src/assets/i18n/fr/translation.json @@ -4,26 +4,27 @@ "pdfCi": "Identifiant unique du certificat", "pdfGreenCertificate": "Certificat numérique européen COVID", "pdfHeaderVaccination": "Certificat de vaccination", - "pdfDisease": "Maladie ou agent ciblé", - "pdfVaccineProphylaxis": "Vaccin/prophylaxie", - "pdfVaccineMedicalProduct": "Médicament vaccinal", - "pdfVaccineManufacturer": "Fabricant ou titulaire de l’autorisation de mise sur le marché du vaccin", - "pdfNumberOfDoses": "Nombre dans une série de vaccins/doses", - "pdfDateOfVaccination": "Date of vaccination", - "pdfMemberStateOfVaccination" : "État membre de vaccination", + "pdfDisease": "Maladie ou agent ciblé: diseaseName\n(SARS-CoV-2 ou l’un de ses variants)", + "pdfVaccineProphylaxis": "Vaccin or prophylaxie contre la COVID-19", + "pdfVaccineMedicalProduct": "Médicament vaccinal contre la COVID-19", + "pdfVaccineManufacturer": "Fabricant ou titulaire de l’autorisation de mise sur le marché du vaccin contre la COVID-19", + "pdfNumberOfDoses": "Nombre dans une série de vaccins/doses et nombre total de doses dans la série", + "pdfDateOfVaccination": "Date de la vaccination, indiquant la date de la dernière dose reçue", + "pdfMemberStateOfVaccination" : "État membre dans lequel le vaccin a été administré", "pdfCertificateIssuer" : "Émetteur du certificat", "pdfHeaderTest" : "Certificat de test", "pdfTypeOfTest" : "Type de test", - "pdfTestName" : "Nom du test (facultatif pour TAAN)", + "pdfTestName" : "Nom du test (facultatif pour un test TAAN)", "pdfTestManufacturer" : "Fabricant du test (facultatif pour un test TAAN)", "pdfDateSampleCollection" : "Date et heure du prélèvement de l’échantillon", - "pdfDateTestResult" : "Date et heure de la production des résultats du test", "pdfTestResult" : "Résultat du test", - "pdfTestingCentre" : "Centre ou installation de test", - "pdfStateOfVaccination" : "État membre de vaccination", + "pdfTestingCentre" : "Centre ou installation de test (facultatif pour les tests rapides de détection d’antigènes)", + "pdfStateOfVaccination" : "État membre dans lequel le test a été effectué", "pdfHeaderRecovery" : "Certificat de rétablissement", - "pdfDatePositiveTestResult" : "Date du premier résultat de test posifif", - "pdfStateOfTest" : "État membre du test", + "pdfDatePositiveTestResult" : "Date du premier résultat de test TAAN positif du titulaire", + "pdfStateOfTest" : "État membre du test dans lequel le test a été effectué", "pdfValidFrom" : "Certificat valable à partir du", - "pdfValidTo" : "Certificat valable jusqu’au (180 jours au maximum après la date du premier résultat positif)" + "pdfValidTo" : "Certificat valable jusqu’au (180 jours au maximum après la date du premier résultat positif)", + "pdfDiseaseRecovery" : "Maladie ou agent dont le citoyen s’est\nrétabli : diseaseName (à savoir aussi\nSARS-CoV2 ou l’un de ses variants)" + } \ No newline at end of file diff --git a/src/components/pdf-generater.component.tsx b/src/components/pdf-generater.component.tsx index 1f1ab26..fc08a8d 100644 --- a/src/components/pdf-generater.component.tsx +++ b/src/components/pdf-generater.component.tsx @@ -87,6 +87,11 @@ interface IPageParameter { space: number } +interface IWordInfo { + text: string; + wordLength: number; +} + const usePdfGenerator = (qrCodeCanvasElementProp: any, eudccProp: EUDCC1 | undefined, onIsInit: (isInit: boolean) => void, onIsReady: (isReady: boolean) => void) => { const { t } = useTranslation(); const french = i18n.getDataByLanguage('fr'); @@ -446,17 +451,16 @@ const usePdfGenerator = (qrCodeCanvasElementProp: any, eudccProp: EUDCC1 | undef } } + const prepareThirdPage = () => { if (pdf) { - - for (let page = 1; page < 3; page++) { pdf.setPage(page); if (page === 1) { prepareThirdPageRotated(); } else { - let lblLength = params.a6width - params.paddingRight - params.paddingRight - mm2point(14); + let lblLength = params.a6width - params.paddingLeft - params.paddingRight - mm2point(14); let space = mm2point(3); let imageWidth = 225.75; let imageHeight = 54.75; @@ -477,19 +481,22 @@ const usePdfGenerator = (qrCodeCanvasElementProp: any, eudccProp: EUDCC1 | undef pdf.setFont('arial', 'normal'); y += mm2point(40) + params.lineHeight9; + x = params.paddingLeft; setTextColorBlack(); pdf.setFont('arial', 'normal'); pdf.setFontSize(params.fontSize8); let infotext = t('translation:pdfInfoText'); - infotext = pdf.splitTextToSize(infotext, lblLength); - pdf.text(infotext, x, y, { align: 'center', maxWidth: lblLength }); + infotext = pdf.splitTextToSize(infotext, params.a6width - params.paddingLeft - params.paddingRight); + justify(t('translation:pdfInfoText'), x, y, params.a6width - params.paddingLeft - params.paddingRight); + // pdf.text(infotext, x, y, { align: 'justify', maxWidth: params.a6width - params.paddingLeft - params.paddingRight }); y += mm2point(2) + params.lineHeight9 * infotext.length; + x = params.a6width / 2; infotext = t('translation:pdfRelevantInformation'); infotext = pdf.splitTextToSize(infotext, lblLength); - pdf.text(infotext, x, y, { align: 'center', maxWidth: lblLength }); + pdf.text(infotext, x, y, { align: 'center', maxWidth: lblLength, isSymmetricSwapping: true }); - y += space + params.lineHeight9 * infotext.length; + y += mm2point(1) + params.lineHeight9 * infotext.length; setTextColorBlue(); pdf.setFontSize(params.fontSize10); infotext = t('translation:pdfInfoURL'); @@ -529,28 +536,33 @@ const usePdfGenerator = (qrCodeCanvasElementProp: any, eudccProp: EUDCC1 | undef x = params.a6width * 2; y = centerSplittedText(header, x, y); - y -= mm2point(40); + y -= mm2point(50); setTextColorBlack(); pdf.setFont('arial', 'normal'); pdf.setFontSize(params.fontSize8); let infotext = t('translation:pdfInfoText'); infotext = pdf.splitTextToSize(infotext, lblLength); - y = centerSplittedText(infotext, x, y); + justify(t('translation:pdfInfoText'), + x - params.paddingRight, + y, + params.a6width - params.paddingLeft - params.paddingRight, + true); + y -= params.lineHeight9 * 2 + mm2point(2); - y -= mm2point(2); infotext = t('translation:pdfRelevantInformation'); infotext = pdf.splitTextToSize(infotext, lblLength); - y = centerSplittedText(infotext, x, y); + y = centerSplittedText(infotext, x, y) - params.lineHeight9; + y += mm2point(3); setTextColorBlue(); pdf.setFontSize(params.fontSize10); infotext = t('translation:pdfInfoURL'); infotext = pdf.splitTextToSize(infotext, lblLength); y = centerSplittedText(infotext, x, y); - pdf.line(params.a6width + params.paddingLeft, y + 4, params.a6width * 2 - params.paddingRight, y + 4); + pdf.line(params.a6width + params.paddingLeft, y - 2, params.a6width * 2 - params.paddingRight, y - 2); - y -= params.lineHeight9; + y -= params.lineHeight9 + mm2point(2); setTextColorBlack(); pdf.setFontSize(params.fontSize9); pdf.setFont('arial', 'italic'); @@ -582,7 +594,7 @@ const usePdfGenerator = (qrCodeCanvasElementProp: any, eudccProp: EUDCC1 | undef const lineHeight = params.lineHeight10; - let y = printCertificateHeader(t('translation:pdfHeaderVaccination'), french.translation.pdfHeaderVaccination, params.paddingTop); + let y = printCertificateHeader(t('translation:pdfHeaderVaccination'), french.translation.pdfHeaderVaccination); y += params.space; //For the labels on the left side @@ -590,49 +602,51 @@ const usePdfGenerator = (qrCodeCanvasElementProp: any, eudccProp: EUDCC1 | undef pdf.setFontSize(params.fontSize10); - y = printVerticalBlock(xLeft, y, - t('translation:pdfDisease'), - french.translation.pdfDisease, - getValueSetDisplay(vaccinationSet.tg, diseaseAgentsData), - lineHeight, true); + let disease = getValueSetDisplay(vaccinationSet.tg, diseaseAgentsData); + let lblDisease = t('translation:pdfDisease'); + lblDisease = lblDisease.replace("diseaseName", disease ? disease : ''); + let lblFrench = french.translation.pdfDisease; + lblFrench = lblFrench.replace("diseaseName", disease ? disease : ''); + + y = printDisease(xLeft, y, lineHeight, lblDisease, lblFrench); - y = printVerticalBlock(xLeft, y, + y = printAsTableRow(xLeft, y, t('translation:pdfVaccineProphylaxis'), french.translation.pdfVaccineProphylaxis, getValueSetDisplay(vaccinationSet.vp, vaccines), lineHeight, true); - y = printVerticalBlock(xLeft, y, + y = printAsTableRow(xLeft, y, t('translation:pdfVaccineMedicalProduct'), french.translation.pdfVaccineMedicalProduct, getValueSetDisplay(vaccinationSet.mp, vacMedsData), lineHeight, true); - y = printVerticalBlock(xLeft, y, + y = printAsTableRow(xLeft, y, t('translation:pdfVaccineManufacturer'), french.translation.pdfVaccineManufacturer, getValueSetDisplay(vaccinationSet.ma, vaccineManufacturers), lineHeight, true); - y = printVerticalBlock(xLeft, y, + y = printAsTableRow(xLeft, y, t('translation:pdfNumberOfDoses'), french.translation.pdfNumberOfDoses, vaccinationSet.dn.toString() + ' / ' + vaccinationSet.sd.toString(), lineHeight, true); - y = printVerticalBlock(xLeft, y, + y = printAsTableRow(xLeft, y, t('translation:pdfDateOfVaccination'), french.translation.pdfDateOfVaccination, vaccinationSet.dt, lineHeight, true); - y = printVerticalBlock(xLeft, y, + y = printAsTableRow(xLeft, y, t('translation:pdfMemberStateOfVaccination'), french.translation.pdfMemberStateOfVaccination, vaccinationSet.co, lineHeight, true); - printVerticalBlock(xLeft, y, + printAsTableRow(xLeft, y, t('translation:pdfCertificateIssuer'), french.translation.pdfCertificateIssuer, vaccinationSet.is, @@ -644,11 +658,48 @@ const usePdfGenerator = (qrCodeCanvasElementProp: any, eudccProp: EUDCC1 | undef } } + const printDisease = (x: number, y: number, lineHeight: number, value: string, lblFrench: string): number => { + if (pdf && french) { + pdf.setFont('arial', 'bold'); + value = pdf.splitTextToSize(value, params.a6width); + pdf.text(value, x, y); + + y += lineHeight * value.length + mm2point(1); + + pdf.setFont('arial', 'italic'); + lblFrench = pdf.splitTextToSize(lblFrench, params.a6width); + pdf.text(lblFrench, x, y); + + y += lineHeight * lblFrench.length + mm2point(2); + } + + return y; + } + + const printDiseaseRotated = (x: number, y: number, lineHeight: number, value: string, lblFrench: string): number => { + if (pdf && french) { + pdf.setFont('arial', 'bold'); + value = pdf.splitTextToSize(value, params.a6width); + pdf.text(value, x, y, { align: 'left', angle: 180 }); + + y -= lineHeight * value.length + mm2point(1); + + pdf.setFont('arial', 'italic'); + + lblFrench = pdf.splitTextToSize(lblFrench, params.a6width); + pdf.text(lblFrench, x, y, { align: 'left', angle: 180 }); + + y -= lineHeight * lblFrench.length + 6; + } + + return y; + } + const prepareFourthPageVaccinationRotated = () => { if (pdf && vaccinationSet && french) { - const lineHeight = params.lineHeight10; + const lineHeight = params.lineHeight9; - let y = printCertificateHeaderRotated(t('translation:pdfHeaderVaccination'), french.translation.pdfHeaderVaccination, params.paddingTop); + let y = printCertificateHeaderRotated(t('translation:pdfHeaderVaccination'), french.translation.pdfHeaderVaccination); y += params.space; //For the labels on the left side @@ -656,49 +707,54 @@ const usePdfGenerator = (qrCodeCanvasElementProp: any, eudccProp: EUDCC1 | undef pdf.setFontSize(params.fontSize10); - y = printVerticalBlockRotated(xLeft, y, - t('translation:pdfDisease'), - french.translation.pdfDisease, - getValueSetDisplay(vaccinationSet.tg, diseaseAgentsData), - lineHeight, true); + let disease = getValueSetDisplay(vaccinationSet.tg, diseaseAgentsData); + let lblDisease = t('translation:pdfDisease'); + lblDisease = lblDisease.replace("diseaseName", disease ? disease : ''); + let lblFrench = french.translation.pdfDisease; + lblFrench = lblFrench.replace("diseaseName", disease ? disease : ''); + + y = printDiseaseRotated(xLeft, y, + lineHeight, + lblDisease, + lblFrench); - y = printVerticalBlockRotated(xLeft, y, + y = printAsTableRowRotated(xLeft, y, t('translation:pdfVaccineProphylaxis'), french.translation.pdfVaccineProphylaxis, getValueSetDisplay(vaccinationSet.vp, vaccines), lineHeight, true); - y = printVerticalBlockRotated(xLeft, y, + y = printAsTableRowRotated(xLeft, y, t('translation:pdfVaccineMedicalProduct'), french.translation.pdfVaccineMedicalProduct, getValueSetDisplay(vaccinationSet.mp, vacMedsData), lineHeight, true); - y = printVerticalBlockRotated(xLeft, y, + y = printAsTableRowRotated(xLeft, y, t('translation:pdfVaccineManufacturer'), french.translation.pdfVaccineManufacturer, getValueSetDisplay(vaccinationSet.ma, vaccineManufacturers), lineHeight, true); - y = printVerticalBlockRotated(xLeft, y, + y = printAsTableRowRotated(xLeft, y, t('translation:pdfNumberOfDoses'), french.translation.pdfNumberOfDoses, vaccinationSet.dn.toString() + ' / ' + vaccinationSet.sd.toString(), lineHeight, true); - y = printVerticalBlockRotated(xLeft, y, + y = printAsTableRowRotated(xLeft, y, t('translation:pdfDateOfVaccination'), french.translation.pdfDateOfVaccination, vaccinationSet.dt, lineHeight, true); - y = printVerticalBlockRotated(xLeft, y, + y = printAsTableRowRotated(xLeft, y, t('translation:pdfMemberStateOfVaccination'), french.translation.pdfMemberStateOfVaccination, vaccinationSet.co, lineHeight, true); - printVerticalBlockRotated(xLeft, y, + printAsTableRowRotated(xLeft, y, t('translation:pdfCertificateIssuer'), french.translation.pdfCertificateIssuer, vaccinationSet.is, @@ -716,7 +772,7 @@ const usePdfGenerator = (qrCodeCanvasElementProp: any, eudccProp: EUDCC1 | undef prepareFourthPageTestRotated(); } else { - const lineHeight = params.lineHeight10; + const lineHeight = params.lineHeight9; let y = printCertificateHeader(t('translation:pdfHeaderTest'), french.translation.pdfHeaderTest); @@ -724,55 +780,57 @@ const usePdfGenerator = (qrCodeCanvasElementProp: any, eudccProp: EUDCC1 | undef pdf.setFontSize(params.fontSize9); - y = printVerticalBlock(x, y, - t('translation:pdfDisease'), - french.translation.pdfDisease, - getValueSetDisplay(testSet.tg, diseaseAgentsData), - lineHeight, true); + let disease = getValueSetDisplay(testSet.tg, diseaseAgentsData); + let lblDisease = t('translation:pdfDisease'); + lblDisease = lblDisease.replace("diseaseName", disease ? disease : ''); + let lblFrench = french.translation.pdfDiseaseRecovery; + lblFrench = lblFrench.replace("diseaseName", disease ? disease : ''); - y = printVerticalBlock(x, y, + y = printDisease(x, y, lineHeight, lblDisease, lblFrench); + + y = printAsTableRow(x, y, t('translation:pdfTypeOfTest'), french.translation.pdfTypeOfTest, getValueSetDisplay(testSet.tt, testTypeValueSet), lineHeight, true); - y = printVerticalBlock(x, y, + y = printAsTableRow(x, y, t('translation:pdfTestName'), french.translation.pdfTestName, testSet.nm, lineHeight, true); - y = printVerticalBlock(x, y, + y = printAsTableRow(x, y, t('translation:pdfTestManufacturer'), french.translation.pdfTestManufacturer, getValueSetDisplay(testSet.ma, testManufacturersValueSet), lineHeight, true); - y = printVerticalBlock(x, y, + y = printAsTableRow(x, y, t('translation:pdfDateSampleCollection'), french.translation.pdfDateSampleCollection, convertDateToOutputFormat(testSet.sc), lineHeight, true); - y = printVerticalBlock(x, y, + y = printAsTableRow(x, y, t('translation:pdfTestResult'), french.translation.pdfTestResult, getValueSetDisplay(testSet.tr, testResultValueSet), lineHeight, true); - y = printVerticalBlock(x, y, + y = printAsTableRow(x, y, t('translation:pdfTestingCentre'), french.translation.pdfTestingCentre, testSet.tc, lineHeight, true); - y = printVerticalBlock(x, y, + y = printAsTableRow(x, y, t('translation:pdfStateOfVaccination'), french.translation.pdfStateOfVaccination, testSet.co, lineHeight, true); - printVerticalBlock(x, y, + printAsTableRow(x, y, t('translation:pdfCertificateIssuer'), french.translation.pdfCertificateIssuer, testSet.is, @@ -793,57 +851,62 @@ const usePdfGenerator = (qrCodeCanvasElementProp: any, eudccProp: EUDCC1 | undef let x = params.a6width - params.paddingInnerLeft; - pdf.setFontSize(params.fontSize9); + pdf.setFontSize(params.fontSize10); - y = printVerticalBlockRotated(x, y, - t('translation:pdfDisease'), - french.translation.pdfDisease, - getValueSetDisplay(testSet.tg, diseaseAgentsData), - lineHeight, true); + let disease = getValueSetDisplay(testSet.tg, diseaseAgentsData); + let lblDisease = t('translation:pdfDiseaseRecovery'); + lblDisease = lblDisease.replace("diseaseName", disease ? disease : ''); + let lblFrench = french.translation.pdfDiseaseRecovery; + lblFrench = lblFrench.replace("diseaseName", disease ? disease : ''); - y = printVerticalBlockRotated(x, y, + y = printDiseaseRotated(x, y, + lineHeight, + lblDisease, + lblFrench); + + y = printAsTableRowRotated(x, y, t('translation:pdfTypeOfTest'), french.translation.pdfTypeOfTest, getValueSetDisplay(testSet.tt, testTypeValueSet), lineHeight, true); - y = printVerticalBlockRotated(x, y, + y = printAsTableRowRotated(x, y, t('translation:pdfTestName'), french.translation.pdfTestName, testSet.nm ? testSet.nm : ' ', lineHeight, true); - y = printVerticalBlockRotated(x, y, + y = printAsTableRowRotated(x, y, t('translation:pdfTestManufacturer'), french.translation.pdfTestManufacturer, getValueSetDisplay(testSet.ma, testManufacturersValueSet), lineHeight, true); - y = printVerticalBlockRotated(x, y, + y = printAsTableRowRotated(x, y, t('translation:pdfDateSampleCollection'), french.translation.pdfDateSampleCollection, convertDateToOutputFormat(testSet.sc), lineHeight, true); - y = printVerticalBlockRotated(x, y, + y = printAsTableRowRotated(x, y, t('translation:pdfTestResult'), french.translation.pdfTestResult, getValueSetDisplay(testSet.tr, testResultValueSet), lineHeight, true); - y = printVerticalBlockRotated(x, y, + y = printAsTableRowRotated(x, y, t('translation:pdfTestingCentre'), french.translation.pdfTestingCentre, testSet.tc, lineHeight, true); - y = printVerticalBlockRotated(x, y, + y = printAsTableRowRotated(x, y, t('translation:pdfStateOfVaccination'), french.translation.pdfStateOfVaccination, testSet.co, lineHeight, true); - printVerticalBlockRotated(x, y, + printAsTableRowRotated(x, y, t('translation:pdfCertificateIssuer'), french.translation.pdfCertificateIssuer, testSet.is, @@ -872,36 +935,38 @@ const usePdfGenerator = (qrCodeCanvasElementProp: any, eudccProp: EUDCC1 | undef pdf.setFontSize(params.fontSize10); - y = printVerticalBlock(xLeft, y, - t('translation:pdfDisease'), - french.translation.pdfDisease, - getValueSetDisplay(recoverySet.tg, diseaseAgentsData), - lineHeight, true); + let disease = getValueSetDisplay(recoverySet.tg, diseaseAgentsData); + let lblDisease = t('translation:pdfDiseaseRecovery'); + lblDisease = lblDisease.replace("diseaseName", disease ? disease : ''); + let lblFrench = french.translation.pdfDiseaseRecovery; + lblFrench = lblFrench.replace("diseaseName", disease ? disease : ''); + + y = printDisease(xLeft, y, lineHeight, lblDisease, lblFrench); - y = printVerticalBlock(xLeft, y, + y = printAsTableRow(xLeft, y, t('translation:pdfDatePositiveTestResult'), french.translation.pdfDatePositiveTestResult, recoverySet.fr); - y = printVerticalBlock(xLeft, y, + y = printAsTableRow(xLeft, y, t('translation:pdfStateOfTest'), french.translation.pdfStateOfTest, recoverySet.co, lineHeight, true); - y = printVerticalBlock(xLeft, y, + y = printAsTableRow(xLeft, y, t('translation:pdfCertificateIssuer'), french.translation.pdfCertificateIssuer, recoverySet.is, lineHeight, true); - y = printVerticalBlock(xLeft, y, + y = printAsTableRow(xLeft, y, t('translation:pdfValidFrom'), french.translation.pdfValidFrom, recoverySet.df, lineHeight, true); - printVerticalBlock(xLeft, y, + printAsTableRow(xLeft, y, t('translation:pdfValidTo'), french.translation.pdfValidTo, recoverySet.du, @@ -929,36 +994,41 @@ const usePdfGenerator = (qrCodeCanvasElementProp: any, eudccProp: EUDCC1 | undef pdf.setFontSize(params.fontSize10); - y = printVerticalBlockRotated(xLeft, y, - t('translation:pdfDisease'), - french.translation.pdfDisease, - getValueSetDisplay(recoverySet.tg, diseaseAgentsData), - lineHeight, true); + let disease = getValueSetDisplay(recoverySet.tg, diseaseAgentsData); + let lblDisease = t('translation:pdfDiseaseRecovery'); + lblDisease = lblDisease.replace("diseaseName", disease ? disease : ''); + let lblFrench = french.translation.pdfDiseaseRecovery; + lblFrench = lblFrench.replace("diseaseName", disease ? disease : ''); + + y = printDiseaseRotated(xLeft, y, + lineHeight, + lblDisease, + lblFrench); - y = printVerticalBlockRotated(xLeft, y, + y = printAsTableRowRotated(xLeft, y, t('translation:pdfDatePositiveTestResult'), french.translation.pdfDatePositiveTestResult, recoverySet.fr); - y = printVerticalBlockRotated(xLeft, y, + y = printAsTableRowRotated(xLeft, y, t('translation:pdfStateOfTest'), french.translation.pdfStateOfTest, recoverySet.co, lineHeight, true); - y = printVerticalBlockRotated(xLeft, y, + y = printAsTableRowRotated(xLeft, y, t('translation:pdfCertificateIssuer'), french.translation.pdfCertificateIssuer, recoverySet.is, lineHeight, true); - y = printVerticalBlockRotated(xLeft, y, + y = printAsTableRowRotated(xLeft, y, t('translation:pdfValidFrom'), french.translation.pdfValidFrom, recoverySet.df, lineHeight, true); - printVerticalBlockRotated(xLeft, y, + printAsTableRowRotated(xLeft, y, t('translation:pdfValidTo'), french.translation.pdfValidTo, recoverySet.du, @@ -1018,6 +1088,42 @@ const usePdfGenerator = (qrCodeCanvasElementProp: any, eudccProp: EUDCC1 | undef return result; } + const printAsTableRow = (x: number, y: number, lbl: any, lblFrench: any, value?: string, lineHeight?: number, isItalic?: boolean): number => { + let result = y; + let lblRightLength = params.a6width / 4; + let lblLeftLength = lblRightLength * 2 + mm2point(12); + let xRight = x + lblLeftLength + mm2point(2); + lineHeight = lineHeight ? lineHeight : params.lineHeight; + + if (pdf) { + pdf.setFont('arial', 'bold'); + lbl = pdf.splitTextToSize(lbl, lblLeftLength); + pdf.text(lbl, x, y); + + if (value) { + // pdf.setFont('arial', 'normal'); + value = pdf.splitTextToSize(value, lblRightLength); + pdf.text(value!, xRight, y, { align: 'left' }); + } + + if (value) { + y += lineHeight * (lbl.length > value.length ? lbl.length : value.length / 1.35); + } else { + y += lineHeight * lbl.length; + } + + pdf.setFont('arial', 'italic'); + + const frenchText = pdf.splitTextToSize(lblFrench, lblLeftLength); + pdf.text(frenchText, x, result + lineHeight * lbl.length); + y += lineHeight * frenchText.length; + + result = y + mm2point(2); + } + + return result; + } + const printHorizontalBlockPerson = (x: number, y: number, lbl: any, lblFrench: any, value?: string): number => { let result = y; @@ -1075,18 +1181,46 @@ const usePdfGenerator = (qrCodeCanvasElementProp: any, eudccProp: EUDCC1 | undef return result; } - // const printBlock = (xLeft: number, xRight: number, y: number, lblLeft: any, lblLeftFrench: any, value?: string, space?: number): number => { - // let result = y; + const printAsTableRowRotated = (x: number, y: number, lbl: any, lblFrench: any, value?: string, lineHeight?: number, isItalic?: boolean): number => { + let result = y; + let lblRightLength = params.a6width / 4; + let xLeft = params.paddingLeft + lblRightLength - mm2point(2); + let lblLeftLength = lblRightLength * 2 + mm2point(12); + lineHeight = lineHeight ? lineHeight : params.lineHeight; + let tmpPosition = 0; - // if (pdf && value) { - // const valueText = pdf.splitTextToSize(value, lblLength); - // pdf.text(valueText, xRight, y); - // result = printSplittedLine(xLeft, y, lblLeft, lblLeftFrench); - // result += space ? space : params.lineHeight10 + params.space; - // } + if (value && pdf) { + pdf.setFont('arial', 'bold'); + lbl = pdf.splitTextToSize(lbl, lblLeftLength); + y = leftSplittedTextRotated(lbl, x, y); - // return result; - // } + if (value) { + //pdf.setFont('arial', 'normal'); + value = pdf.splitTextToSize(value, lblRightLength); + tmpPosition = leftSplittedTextRotated(value!, xLeft, result); + if (y > tmpPosition) { + console.log(y); + console.log(tmpPosition); + y = tmpPosition; + } + } + + if (isItalic) { + pdf.setFont('arial', 'italic'); + } else { + pdf.setFont('arial', 'normal'); + } + const frenchText = pdf.splitTextToSize(lblFrench, lblLeftLength); + tmpPosition = leftSplittedTextRotated(frenchText, x, result - lineHeight * lbl.length); + if (y > tmpPosition) { + y = tmpPosition; + } + + result = y - 3; + } + + return result; + } const printCertificateHeader = (header: any, frenchHeader: string, paddingTop?: number): number => { let result = 0; @@ -1190,10 +1324,89 @@ const usePdfGenerator = (qrCodeCanvasElementProp: any, eudccProp: EUDCC1 | undef pdf!.setTextColor(256, 256, 256); } - return pdf; -} + const justify = (text: string, xStart: number, yStart: number, textWidth: number, rotation?: boolean) => { + if (pdf) { + rotation = rotation ? rotation : false; + text = text.replace(/(?:\r\n|\r|\n)/g, ' '); + text = text.replace(/ +(?= )/g, ''); + const lineHeight = pdf.getTextDimensions('a').h * 1.15; + const words = text.split(' '); + let lineNumber = 0; + let wordsInfo: IWordInfo[] = []; + let lineLength = 0; + let txtLines: Array = new Array(); + for (const word of words) { + const wordLength = pdf.getTextWidth(word + ' '); + if (wordLength + lineLength > textWidth) { + if (!rotation) { + writeLine(pdf, wordsInfo, lineLength, lineNumber++, xStart, yStart, lineHeight, textWidth); + } else { + let words: IWordInfo[] = [...wordsInfo] + txtLines.push(words); + } + wordsInfo = []; + lineLength = 0; + } + wordsInfo.push({ text: word, wordLength }); + lineLength += wordLength; + } + if (wordsInfo.length > 0) { + if (!rotation) { + writeLastLine(wordsInfo, pdf, yStart, lineNumber, lineHeight, textWidth); + } else { + txtLines.push(wordsInfo); + for (let i = txtLines.length - 1; i >= 0; --i) { + if (i === txtLines.length - 1) { + writeLastLineRotated(txtLines[i], pdf, yStart, lineHeight, textWidth); + } else { + writeLineRotated(pdf, txtLines[i], lineNumber++, xStart, yStart, lineHeight, textWidth); + } + } + } + } + } + } + + const writeLastLine = (wordsInfo: IWordInfo[], pdfGen: jsPDF, yStart: number, lineNumber: number, lineHeight: number, textWidth: number) => { + const line = wordsInfo.map(x => x.text).join(' '); + let xStart = params.paddingLeft + (textWidth / 2); + pdfGen.text(line, xStart, yStart + lineNumber * lineHeight, { align: 'center' }); + } + + const writeLastLineRotated = (wordsInfo: IWordInfo[], pdfGen: jsPDF, yStart: number, lineHeight: number, textWidth: number) => { + let line = wordsInfo.map(x => x.text).join(' '); + let xStart = params.a6width * 2; + line = pdfGen.splitTextToSize(line, textWidth); + centerSplittedText(line, xStart, yStart - lineHeight); + } + + const writeLine = (pdfGen: jsPDF, wordsInfo: IWordInfo[], lineLength: number, lineNumber: number, xStart: number, yStart: number, lineHeight: number, textWidth: number) => { + const wordSpacing = (textWidth - lineLength) / (wordsInfo.length - 1); + let x = xStart; + const y = yStart + lineNumber * lineHeight; + for (const wordInfo of wordsInfo) { + pdfGen.text(wordInfo.text, x, y); + x += wordInfo.wordLength + wordSpacing; + } + } + const writeLineRotated = (pdfGen: jsPDF, wordsInfo: IWordInfo[], lineNumber: number, xStart: number, yStart: number, lineHeight: number, textWidth: number) => { + let lineLength = 0; + for (const wordInfo of wordsInfo) { + lineLength += wordInfo.wordLength; + } + const wordSpacing = (textWidth - lineLength) / (wordsInfo.length - 1); + let x = xStart; + const y = yStart + lineNumber * lineHeight; + for (const wordInfo of wordsInfo) { + pdfGen.text(wordInfo.text, x, y, { align: 'left', angle: 180 }); + x -= wordInfo.wordLength + wordSpacing; + } + } + + return pdf; +} export default usePdfGenerator;