Tablica pełnej strony TCPDF

11

Próbowałem wielu sposobów, aby dopasować tabelę do strony (A4), jak pokazano na zdjęciu: wprowadź opis zdjęcia tutaj Dużo szukałem, ale nie znalazłem nic przydatnego w Internecie. Korzystam z tabeli dynamicznej, wszystko jest w porządku, z wyjątkiem szerokości tabeli. oto mój kod:

$content = '<table><thead><tr><th class="bg-dark text-white" align="center">#</th><th align="center" class="bg-dark text-white">Code</th><th align="left" class="bg-dark text-white">Description</th><th align="center" class="bg-dark text-white">Item Type</th></tr></thead><tbody><tr style="background-color: #f2f2f2;"><td align="center">1</td><td align="center">1001</td><td align="left">Pofak</td><td align="center">Fixed Price</td></tr><tr ><td align="center">2</td><td align="center">1002</td><td align="left">Ice</td><td align="center">Weight</td></tr><tr style="background-color: #f2f2f2;"><td align="center">3</td><td align="center">1003</td><td align="left">Minoo</td><td align="center">Fixed Price</td></tr><tr ><td align="center">4</td><td align="center">1004</td><td align="left">Bastani</td><td align="center">Fixed Price</td></tr><tr style="background-color: #f2f2f2;"><td align="center">5</td><td align="center">1005</td><td align="left">Chocolate</td><td align="center">Weight</td></tr><tr ><td align="center">6</td><td align="center">1006</td><td align="left">Brush</td><td align="center">Fixed Price</td></tr><tr style="background-color: #f2f2f2;"><td align="center">7</td><td align="center">1007</td><td align="left">Apple</td><td align="center">Weight</td></tr><tr ><td align="center">8</td><td align="center">1008</td><td align="left">Water</td><td align="center">Fixed Price</td></tr><tr style="background-color: #f2f2f2;"><td align="center">9</td><td align="center">1009</td><td align="left">Cleaner</td><td align="center">Fixed Price</td></tr><tr ><td align="center">10</td><td align="center">1001</td><td align="left">Pofak</td><td align="center">Fixed Price</td></tr><tr style="background-color: #f2f2f2;"><td align="center">11</td><td align="center">1002</td><td align="left">Ice</td><td align="center">Weight</td></tr><tr ><td align="center">12</td><td align="center">1003</td><td align="left">Minoo</td><td align="center">Fixed Price</td></tr><tr style="background-color: #f2f2f2;"><td align="center">13</td><td align="center">1004</td><td align="left">Bastani</td><td align="center">Fixed Price</td></tr><tr ><td align="center">14</td><td align="center">1005</td><td align="left">Chocolate</td><td align="center">Weight</td></tr><tr style="background-color: #f2f2f2;"><td align="center">15</td><td align="center">1006</td><td align="left">Brush</td><td align="center">Fixed Price</td></tr></tbody></table>';
$newContent = '
    <style type="text/css">
    table{width:100%;}
    table, table td, table th{
        border-collapse: collapse;
        border: solid 1px #ababab;
    }
    .text-dark, table td{
        color: #343a40;
    }
    .text-white{
        color: #ffffff;
    }
    table td,
    table th {
        font-size: 11px;
        padding: 3px;
        line-height: 1.2;
        font-family:arial;
    }

    .bg-dark {
        background-color: #343a40;
    }
    .bg-secondary {
        background-color: #6c757d;
    }
    .bg-white {
        background-color: #ffffff;
    }
    .text-left {
        text-align: left;
    }
    .text-right {
        text-align: right;
    }
    .text-center {
        text-align: center;
    }
    </style>
    ';
    $newContent .= '<page>'.$content.'</page>';

    try {
        $html2pdf = new Html2Pdf('P', 'A4', 'en', true, 'UTF-8', 5);
        $html2pdf->pdf->SetDisplayMode('real');
        $html2pdf->writeHTML($newContent);
        $PDFName = "ItemLists_".date('Y.m.d_H.i.s').".pdf";
        $html2pdf->output($PDFName, 'I');
    } catch (Html2PdfException $x) {
        $html2pdf->clean();

        $formatter = new ExceptionFormatter($x);
        echo $formatter->getHtmlMessage();
    }

Wielkie dzięki

Mohsen Newtoa
źródło
To jest właściwie błąd w bibliotece Html2PDF. Patrząc na potencjalne obejście.
EPB
Warto zauważyć, że Html2PDF używa własnego parsera HTML. style="width: 100%"przechowuje poprawnie przekonwertowaną szerokość w MM (chociaż atrybut width nie!) Jednak Html2PDF nie wydaje się używać go podczas renderowania tabeli.
EPB

Odpowiedzi:

4

HTML2PDF nie używa systemu analizatora / renderowania HTML TCPDF. Implementuje swój własny i jego implementacja nie powiększy kolumn automatycznie, aby wypełnić 100% przestrzeni.

Jako taki, w Html2PDF nie tylko musisz ustawić 100% szerokości w tabeli, ale musisz ustawić procentowe szerokości dla każdej komórki. (A ze względu na dziwne zachowanie z widthatrybutem w Html2PDF, użyj CSS, aby ustawić szerokości.)

Natywny TCPDF writeHTMLustawi każdą kolumnę na taką samą szerokość bez innych specyfikacji. (Na przykład 4-kolumnowa tabela ma wszystkie komórki na poziomie 25%). Jednak nie obsługuje CSS, którego używasz, więc znaczniki wymagałyby drobnych poprawek, aby przejść tę trasę.

Aby naśladować to podstawowe zachowanie w Html2PDF, możesz po prostu jawnie dodać równoważne szerokości do swoich komórek. Na przykład dodanie specyfikacji szerokości do table td, table threguł stylu.

Oto przykład z następującymi regułami CSS dla tabeli czterokolumnowej:

table { width: 100%; }
table th, table td { width: 25%; }

Oczywiście najlepiej wygląda po określeniu szerokości pasujących do treści.

Przykład z równoważnymi kolumnami


AKTUALIZACJA

Poniżej zostawię trochę dyskusji na temat TCPDF, ponieważ prowadzi to w pewnym stopniu do stworzenia potencjalnie użytecznej klasy Html2pdf. TCPDF ma kilka użytecznych metod pomiaru długości łańcucha. Jeśli zmierzysz rozmiar ciągów znaków wewnątrz kolumn, możesz stworzyć swój własny automatyczny rozmiar kolumny.

Stworzyłem klasę proof-of-concept na github na https://github.com/b65sol/random-classes

Po pierwsze, używamy tej klasy do pośredniczenia w konstrukcji HTML. Dzieje się tak, dlatego dodaje się klasy kolumn do ustawiania szerokości i nie musimy analizować kodu HTML w celu wyodrębnienia mierzonej zawartości.

Następnie musimy wybrać strategię wyboru szerokości kolumn. Na przykład poniższe demo mierzy kolumny i znajduje minimalne wartości procentowe szerokości dla każdej na podstawie najdłuższego słowa. (Zapobiega podziałom słów) Następnie rozdziela dodatkowe miejsce proporcjonalnie na podstawie różnicy między najdłuższym słowem a najdłuższą pełną zawartością komórki. Nie nazwałbym tej produkcji gotową, ponieważ jest to dowód koncepcji, ale mam nadzieję, że ty (lub inni poszukiwacze) uznacie ją za przydatny punkt wyjścia.

Kluczową częścią tego jest to: $tablebuilder->determine_column_widths_by_minimum_strategy('100%', 'aaa')

Pierwszy parametr podaje odniesienie do rozmiaru, z którym pracujemy (100% strony, ponieważ potrzebowałem tego, aby pomiary były przydatne), a drugi zapewnia pewne wstępnie ustawione znaki wypełniania, które można dodać do naszych pomiarów, aby uwzględnić styl tekstu i tabelę różnice wypełnienia.

Oto jego wersja demonstracyjna: https://b65sol.com/so/59517311_new.php

Sama klasa jest dostępna tutaj: https://github.com/b65sol/random-classes

Kod tego pokazu znajduje się tutaj:

<?php
require 'vendor/autoload.php';
include 'random-classes/html2pdf-full-table-optimizer.php';
use Spipu\Html2Pdf\Html2Pdf;

//First let's build a random table!
$wordlist = ['Chocolate', 'Cake', 'Brownies', 'Cupcakes', 'Coreshock', 'Battery', 'Lead', 'Acid', 'Remilia'];
$wordlist2 = ['Reinforcement Learning', 'Initial Latent Vectors', 'Bag-of-Words', 'Multilayer Perceptron Classifier',
  'Deconvolutional Neural Network', 'Convolutional Neural Network'];
$number_of_columns = rand(3,11);
$number_of_rows = rand(8, 15);
$possible_column_names = ['Unit', 'Description', 'Variable', 'Moon', 'Cheese', 'Lollipop', 'Orange', 'Gir', 'Gaz', 'Zim', 'Dib'];
$possible_column_content_generators = [
  function() {return rand(10,100); },
  function() {return rand(1000, 1999); },
  function() use ($wordlist) {return $wordlist[rand(0, count($wordlist)-1)]; },
  function() use ($wordlist) {return $wordlist[rand(0, count($wordlist)-1)] . ' '. $wordlist[rand(0, count($wordlist)-1)];},
  function() use ($wordlist2) {return $wordlist2[rand(0, count($wordlist2)-1)];},
];

shuffle($possible_column_names);
$list_of_generators = [];
$column_classes = [];
$column_names = [];
for($i = 0; $i < $number_of_columns; $i++) {
  $list_of_generators[$i] = $possible_column_content_generators[rand(0, count($possible_column_content_generators)-1)];
  $column_classes[$i] = ['text-left', 'text-right', 'text-center'][rand(0,2)];
  $column_names[$i] = $possible_column_names[$i];
}
//Got our random stuff, onward to generator!

try {
    $html2pdf = new Html2Pdf('P', 'A4', 'en', true, 'UTF-8', 5);
    $html2pdf->pdf->SetDisplayMode('real');
    $tablebuilder = new Html2PdfTableOptimizer($html2pdf->pdf, '11px', 'helvetica');

    //run table builder... using random data for testing.
    for($i = 0; $i < $number_of_columns; $i++) {
      /*Add a header cell, content is the first parameter, CSS class attribute is second.*/
      $tablebuilder->add_header_cell($column_names[$i], $column_classes[$i] . ' bg-dark text-white');
    }

    for($i = 0; $i < $number_of_rows; $i++) {
      //Start a row.
      $tablebuilder->start_data_row();
      for($col = 0; $col < $number_of_columns; $col++) {
        //Add content and our column classes for td elements
        $tablebuilder->add_data_row_cell($list_of_generators[$col](), $column_classes[$col]);
      }
      //End the row.
      $tablebuilder->end_data_row();
    }
    //Get the table HTML.
    $render = $tablebuilder->render_html();

    $newContent = '
      <style type="text/css">
      table{width:100%;}
      table, table td, table th{
          border-collapse: collapse;
          border: solid 1px #ababab;
      }
      .text-dark, table td{
          color: #343a40;
      }
      .text-white{
          color: #ffffff;
      }
      table td,
      table th {
          font-size: 11px;
          padding: 3px;
          line-height: 1.2;
          font-family:arial;
      }

      .bg-dark {
          background-color: #343a40;
      }
      .bg-secondary {
          background-color: #6c757d;
      }
      .bg-white {
          background-color: #ffffff;
      }
      .row-even {
        background-color: #d1d1d1;
      }
      .text-left {
          text-align: left;
      }
      .text-right {
          text-align: right;
      }
      .text-center {
          text-align: center;
      }

      '.$tablebuilder->determine_column_widths_by_minimum_strategy('100%', 'aaa').'

      </style>
      ';
      $newContent .= '<page>'.$render.'</page>';

      if(!empty($_GET['html'])) {
        echo $newContent;
      } else {
        $html2pdf->writeHTML($newContent);
        $PDFName = "ItemLists_".date('Y.m.d_H.i.s').".pdf";
        $html2pdf->output($PDFName, 'I');
      }
} catch (Html2PdfException $x) {
    $html2pdf->clean();

    $formatter = new ExceptionFormatter($x);
    echo $formatter->getHtmlMessage();
}

KONIEC AKTUALIZACJI


Jeśli nie chcesz jawnie określać szerokości, możesz użyć TCPDF writeHTMLzamiast Html2PDFbiblioteki, ale wystarczy użyć kolumn o równej wielkości. Właściwie pomyślałem, że wykonałoby to ponowne obliczenie rozmiarów kolumn, jeśli podałeś tylko jeden lub dwa, ale nie miałem racji. Co więcej, TCPDF podlega tym samym ograniczeniom, co Html2PDF- jeśli określisz rozmiar jednej kolumny, nie będzie automatycznie zmieniać rozmiaru innych kolumn, aby pasowały.

Nie dopasowuje też kolumn do zawartości w sposób, w jaki robi to przeglądarka. W rzeczywistości jest to dość trudne do zrobienia, więc nie jestem zaskoczony, że TCPDF tego nie próbuje. Potencjalnie nie wymagającym wysiłku rozwiązaniem byłoby otagowanie kolumn proporcjonalnym rozmiarem i obliczenie szerokości w locie dla każdej z nich w zależności od liczby wybranych kolumn o proporcjonalnej wielkości. (np. kolumny numeryczne są „małe”, a kolumna opisu byłaby „duża”, a zatem rozbija dwie małe kolumny po 10% każda i pojedynczy opis przy 80%. Dwie małe przy 5% i do dużych kolumn przy 45% każdy. Wymagałoby to eksperymentów).

EPB
źródło
dziękuję za poświęcony czas, problem polega na tym, że korzystam z tabeli dynamicznej. Użytkownicy mają do wyboru 10 kolumn, może 5 kolumn lub 8 kolumn, a może 2 kolumny, co jest opcjonalne. Istnieje inny sposób, aby to zrobić. : table th, table td { <?=floor(100 / count($cols))?>%;}ale szukam lepszego rozwiązania
Mohsen Newtoa
1
Jak Html2PDFbardzo jesteś zaangażowany ? Całe moje czytanie kodu i przykładów sugeruje, że jest to jedyny sposób. TCPDF może to zrobić dzięki nieco mniej wydajnemu analizowaniu CSS, ale ma lepszy system układu. Mogę zasugerować znaczniki dla prostego TCPDF.
EPB
Wypróbowałem TCPDF i zdałem sobie sprawę, że używają tej samej metody, której używam, ale nadal nie rozwiązuje mojego problemu. Jeśli zmienię jedną komórkę, wpłynie to na inne komórki, a szerokość tabeli nadal nie będzie pasować do strony, różnica między TCPDF a HTML2PDF polega na tym, że TCPDF używa domyślnego rozmiaru tabeli tak jak mójtable th, table td { <?=floor(100 / count($cols))?>%;}
Mohsen Newtoa
Rzeczywiście, na ten problem też wpadłem. Ja myślałem , że to pozwoli mi określić rozmiar tylko konkretnych zer i auto-adjust resztę kiedy skonfigurować test (który jednocześnie nie Ideałem byłoby spojrzeć rozsądnie ładny z niewielkim wysiłkiem), ale to nie ... w ogóle . Zrobię trochę więcej kopania i zobaczę, czy istnieje jakiś mało wymagający sposób automatycznego rozmiaru kolumn. Musiałby to być jakiś proces wstępnego przetwarzania, ponieważ żaden z nich Html2PDFlub TCPDFwydaje się, że robi to po wyjęciu z pudełka.
EPB
Nie jestem pewien, czy powiadamia o aktualizacjach, ale dodałem klasę, która dynamicznie dostosowuje tabele tekstowe na podstawie ich zawartości. Istnieje również strategia o nazwie, determine_column_widths_evenlyktóra pozwala określić kilka znanych rozmiarów i równomiernie rozdzielić pozostałe miejsce.
EPB
0

Praca ze stroną PDF nie jest świetna dla CSS. Czy próbowałeś używać tylko HTML?

Na przykład:

<table width="100%">
  <!-- your table code -->
</table>

Alternatywnie możesz spróbować:

<table style="width: 100%;">
  <!-- your table code -->
</table>

Oto CodePen, który demonstruje to działanie w przeglądarce. https://codepen.io/tinacious/pen/PowJRbb

Tina
źródło
Próbowałem tych wszystkich: <table width="100%"> <table style="width:100%;"> <table class="w100"> <link rel="stylesheet" href="style.css" />problem polega jednak na tym, że działa on dobrze na html, ale kiedy chcę go zapisać jako plik PDF, będzie on podobny do obrazu.
Mohsen Newtoa
0

zdjęcie: wprowadź opis zdjęcia tutaj

Myślę, że najlepszym sposobem dla tego typu tabel jest użycie tej metody:

table th, table td { width:<?=floor(100 / count($cols))?>%;}

na TCPDF nie zrobili nic specjalnego, tabela i tak nie mieści się na stronie.

Mohsen Newtoa
źródło