eKoopmans / html2pdf.js

Client-side HTML-to-PDF rendering using pure JS.
MIT License
4.05k stars 1.37k forks source link

The letters aren't in the middle, they're a little down. #457

Open momo1108 opened 3 years ago

momo1108 commented 3 years ago

I'm using Vue.js for generating reporting page, and using html2pdf try to save reporting page(div element) as pdf file. Almost succeeded, but there is one problem.

If you look at the picture below,

This is the view from web page.

It's almost written in korean, but all text is vertically aligned middle.

but if I save this div element as pdf file,

This is the view from pdf file.

You can see all text except those in the charts, are a little down from middle. Those texts consists of various tags(p, th, td, textarea, span, etc..)

Can you guess any reason for this problem?

FYI, this is the code I'm using to save page as pdf file.

saveResult(){
    html2pdf(this.$refs.pdfarea, {
        filename: `personal_report_${this.$route.query.stu_name}.pdf`,
        html2canvas: { 
            ignoreElements : function( element  ) {
                if( element.id == "commentSaveDiv" ) {
                    return true;
                }
            }
        },
        jsPDF: {orientation: 'landscape', unit: 'mm', format: 'a4'}
    })
},

And, this is little hard to read, but this is the code for the report page.

<template>
  <div class="min-h-screen pt-12 sm:pt-12 md:pt-12 lg:pt-16 xl:pt-20 flex flex-col justify-center items-center"
   style=" background-color:#F9F9F9; font-family:gothic;">
    <div class="pb-2 text-right mt-4" style="width:1200px;">
      <button class="py-1 px-2 mx-1 border rounded-lg bg-white border-gray-400 hover:border-gray-600" @click="setResult">
        <svg xmlns="http://www.w3.org/2000/svg" class="inline-block mr-1" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="#000000" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="3"></circle><path d="M19.4 15a1.65 1.65 0 0 0 .33 1.82l.06.06a2 2 0 0 1 0 2.83 2 2 0 0 1-2.83 0l-.06-.06a1.65 1.65 0 0 0-1.82-.33 1.65 1.65 0 0 0-1 1.51V21a2 2 0 0 1-2 2 2 2 0 0 1-2-2v-.09A1.65 1.65 0 0 0 9 19.4a1.65 1.65 0 0 0-1.82.33l-.06.06a2 2 0 0 1-2.83 0 2 2 0 0 1 0-2.83l.06-.06a1.65 1.65 0 0 0 .33-1.82 1.65 1.65 0 0 0-1.51-1H3a2 2 0 0 1-2-2 2 2 0 0 1 2-2h.09A1.65 1.65 0 0 0 4.6 9a1.65 1.65 0 0 0-.33-1.82l-.06-.06a2 2 0 0 1 0-2.83 2 2 0 0 1 2.83 0l.06.06a1.65 1.65 0 0 0 1.82.33H9a1.65 1.65 0 0 0 1-1.51V3a2 2 0 0 1 2-2 2 2 0 0 1 2 2v.09a1.65 1.65 0 0 0 1 1.51 1.65 1.65 0 0 0 1.82-.33l.06-.06a2 2 0 0 1 2.83 0 2 2 0 0 1 0 2.83l-.06.06a1.65 1.65 0 0 0-.33 1.82V9a1.65 1.65 0 0 0 1.51 1H21a2 2 0 0 1 2 2 2 2 0 0 1-2 2h-.09a1.65 1.65 0 0 0-1.51 1z"></path></svg>
        설정
      </button>
      <button class="py-1 px-2 mx-1 border rounded-lg bg-white border-gray-400 hover:border-gray-600" @click="saveResult">
        <svg xmlns="http://www.w3.org/2000/svg" class="inline-block mr-1" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="#000000" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M19 21H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h11l5 5v11a2 2 0 0 1-2 2z"></path><polyline points="17 21 17 13 7 13 7 21"></polyline><polyline points="7 3 7 8 15 8"></polyline></svg>
        저장
      </button>
    </div>
    <div class="shadow-xl mb-16">
      <div ref="pdfarea" :style="{width: `${pageLayout['width']}px`, height:`${pageLayout['height']}px`, padding:`${pageLayout['paddingY']}px 0 ${pageLayout['paddingY']}px 0`}" class="bg-white flex">
        <div class="border-r border-dashed border-gray-500" :style="{width: `${pageLayout['c1.w']}px`}">
          <div class="flex justify-center items-center" :style="{height: `${pageLayout['c1.h.h']}px`}" style="font-family:gothic;">
            <span class="text-xl font-bold mx-2">{{eduInfo}}</span>
            <!-- <span class="text-xl font-bold mx-2">{{$route.query.stu_name}}</span> -->
          </div>
          <div class="flex flex-col relative items-center" :style="{height: `${pageLayout['c1.t.h']}px`}" style="font-family:gothic;">
            <div class="flex-auto flex flex-col w-full justify-center items-center">
              <table :style="{width: `${pageLayout['c1.t.w']}px`}" class="table-auto bg-white h-full border-collapse border-2 border-black">
                <thead>
                  <tr class="text-lg border-b border-double border-black" :style="{height:`${pageLayout['c1.t.f.h']}px`}">
                    <th class="border-r border-black">시험항목</th>
                    <th class="border-r border-black" v-for="e in finalResult" :key="'thead'+e">{{e[0]}}</th>
                    <th class="">향상도</th>
                  </tr>
                </thead>
                <tbody>
                  <tr v-for="(e, i) in finalEcList" class="border-b border-black" :key="'tbody'+e" :style="{height:`${(pageLayout['c1.t.h']-pageLayout['c1.t.f.h']) / finalEcList.length}px`}">
                    <td class="border-r border-black pl-4 font-bold" :style="{width:`${pageLayout['c1.t.f.w']}px`}">{{e}}</td>
                    <td class="border-r border-black text-center" v-for="(e2, i2) in finalResult" :key="'td-'+i+'-'+i2"
                    :style="{width:`${(pageLayout['c1.t.w']-pageLayout['c1.t.f.w']-pageLayout['c1.t.l.w']) / finalResult.length}px`}">
                      {{e2[1].filter(ec=>ec[0]==e).length?e2[1].filter(ec=>ec[0]==e)[0][1]:'없음'}}
                    </td>
                    <td class=" text-center" :style="{width:`${pageLayout['c1.t.l.w']}px`}">
                      {{finalImprove[i]=='계산불가'?'계산불가':finalImprove[i]>0?'+'+finalImprove[i]:finalImprove[i]==0?finalImprove[i]:finalImprove[i]}}
                    </td>
                  </tr>
                </tbody>
              </table>
            </div>
          </div>
          <div :style="{height:`${pageLayout['c1.f.h']}px`, padding:`20px ${pageLayout.paddingX}px 0 ${pageLayout.paddingX}px`}"
          class="flex flex-col pt-3">
            <p class="font-bold text-lg">강사 코멘트</p>
            <div class="flex flex-auto relative">
              <textarea class="mt-2 py-1 px-2 flex-auto bg-white border rounded resize-none" style="border-color:#555; font-size:15px;" spellcheck="false"
              placeholder="120자 이내의 교육생 평을 달아주세요" v-model="studentComment" @keyup="commentChanged" maxlength="120"></textarea>
              <div id="commentSaveDiv" class="absolute flex items-center" style="bottom: 5px; right:5px;">
                <p class="text-sm mr-2" style="color:#BBB;">{{studentCommentLength}}자 / 120자</p>
                <button id="commentSaveBtn" class="bg-black rounded text-white px-2 hover:font-bold" style="font-size:15px;"
                 @click="saveComment">저장</button>
              </div>
            </div>
          </div>
        </div>
        <div :style="{width: `${pageLayout['c2.w']}px`,height: `${pageLayout['height'] - (pageLayout['paddingY']*2)}px`}"
        class="flex flex-col relative">
          <template>
            <div class="flex justify-center items-center"  :style="{height: `${pageLayout['c2.h.h']}px`}" style="font-family:gothic;">
              <span class="text-xl font-bold mx-2">항목별 차트</span>
            </div>
            <div class="flex-auto flex flex-col w-full items-center" style="">
              <radar-chart :chart-data="datacollection" :styles="myStyles"></radar-chart>
            </div>
            <div class="flex justify-center items-center"  :style="{height: `${pageLayout['c2.h.h']}px`}" style="font-family:gothic;">
              <span class="text-xl font-bold mx-2">시험별 차트</span>
            </div>
            <div class="flex-auto flex flex-col w-full items-center" style="">
              <bar-chart :chart-data="datacollection2" :styles="myStyles"></bar-chart>
            </div>
          </template>
        </div>
      </div>
    </div>
  </div>
</template>
mikey0000 commented 3 years ago

possibly fixed by my PR in html2canvas

arnaudambro commented 1 year ago

@mikey0000 the PR you're talking about is https://github.com/niklasvh/html2canvas/pull/2708.

As it's not merged and it seems it's not going to be, today I used patch-package to patch html2canvas@1.4.1 for the project I'm working on. And it's working!

Here is the diff that solved my problem:

diff --git a/node_modules/html2canvas/dist/html2canvas.js b/node_modules/html2canvas/dist/html2canvas.js
index 84cb30d..8f2c75f 100644
--- a/node_modules/html2canvas/dist/html2canvas.js
+++ b/node_modules/html2canvas/dist/html2canvas.js
@@ -6572,6 +6572,8 @@
             container.style.margin = '0';
             container.style.padding = '0';
             container.style.whiteSpace = 'nowrap';
+            container.style.position = 'absolute';
+            container.style.top = '-1000px';
             body.appendChild(container);
             img.src = SMALL_IMAGE;
             img.width = 1;
@@ -6579,10 +6581,13 @@
             img.style.margin = '0';
             img.style.padding = '0';
             img.style.verticalAlign = 'baseline';
+            img.style.display = 'inline-block';
             span.style.fontFamily = fontFamily;
             span.style.fontSize = fontSize;
             span.style.margin = '0';
             span.style.padding = '0';
+            span.style.lineHeight = 'normal';
+            span.style.height = 'auto';
             span.appendChild(this._document.createTextNode(SAMPLE_TEXT));
             container.appendChild(span);
             container.appendChild(img);

This issue body was partially generated by patch-package.

nicooprat commented 1 year ago

It didn't work for me; I had to replace:

- const baseline = img.offsetTop - span.offsetTop + 2;
+ const baseline = img.offsetTop - span.offsetTop - 8;

https://github.com/niklasvh/html2canvas/pull/2708/files#diff-bcebfa45a8a25bf0172b11406e4eaffb93e5c065810c9bccbeda4c1a8d0dbe56L49

And

- const middle = img.offsetTop - container.offsetTop + 2;
+ const middle = img.offsetTop - container.offsetTop - 8;

https://github.com/niklasvh/html2canvas/pull/2708/files#diff-bcebfa45a8a25bf0172b11406e4eaffb93e5c065810c9bccbeda4c1a8d0dbe56L57