Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Page-breaks: Add modes and ability to specify elements #153

Merged
merged 25 commits into from
Oct 20, 2018

Conversation

eKoopmans
Copy link
Owner

@eKoopmans eKoopmans commented Sep 15, 2018

This PR attempts to combine the features added by #41, #111, #118, and #138.

Highlights

  • New html2pdf opt.pagebreak option with 4 fields:
    • mode: one (or more) of 'css', 'legacy', 'avoid-all', or 'whiteline' (descriptions below)
    • before, after, and avoid: strings or arrays of CSS selectors to explicitly set page-breaks before or after elements, or avoid page-breaks on elements.

Modes

Mode Description
avoid-all Automatically adds page-breaks to avoid splitting any elements across pages.
css Adds page-breaks according to the CSS break-before, break-after, and break-inside properties. Only recognizes always/left/right for before/after, and avoid for inside.
legacy Adds page-breaks after elements with class html2pdf__page-break.
whiteline Graphically scans rows of pixels for a white line on which to break before the end of each page. (Not yet supported)

Example usage

// Avoid page-breaks on all elements, and add one before #page2el.
html2pdf().set({
  pagebreak: { mode: 'avoid-all', before: '#page2el' }
});

// Enable all 'modes', with no explicit elements.
html2pdf().set({
  pagebreak: { mode: ['avoid-all', 'css', 'legacy', 'whiteline'] }
});

// No modes, only explicit elements.
html2pdf().set({
  pagebreak: { before: '.beforeClass', after: ['#after1', '#after2'], avoid: 'img' }
});

Todo

  • Manual testing!
  • Adding unit tests to html2pdf!!
  • Test clientRect values if container isn't at the top of the screen, and/or if things are scrolled
  • Refactor to streamline when CSS option isn't selected (Not viable)
  • Low priority: Add better CSS support (avoid on before/after, multiple pages for left/right)

To everyone

Please test and let me know if anything needs to be added/removed/changed! To test you will need to pull this branch (feature/pagebreaks) then build with npm run build. Thanks!

@Greensahil
Copy link

Greensahil commented Sep 16, 2018

For page breaks to not cut my elements in half is this all I need to do?

function downloadpdf(){
         var element = document.getElementById('element-to-print');
        var opt = {
  margin:       0,
  filename:     'myfile.pdf',
  image:        { type: 'jpeg', quality: 0.98 },
  html2canvas:  { scale:1},
  jsPDF:        { unit: 'mm', format: 'a4', orientation: 'p' },
   pageBreak: { mode: 'avoid-all'}
};

mode:avoid-all did not do anything for me. To use css property I have to set break-before or break-after to every single elements which I have a lot of because my page can increase or decrease in height based on user input. whiteline looks like exactly what I need

P.S. Thanks for being active again

@campsoftware
Copy link

I haven't tested this yet as I don't have html2pdf set up anywhere, but does this page / html break properly?: http://CampSoftware.com/labs/htmlToPDF.htm

That html uses the following CSS to avoid page breaks.
section, tr {
page-break-after: auto;
page-break-inside: avoid !important;
page-break-before: auto;
}

Thanks so much! So far, only https://wkhtmltopdf.org/ seems to support avoiding page breaks. I'd much rather use html2pdf since wkhtmltopdf is a binary...

@ZabbyCapurin
Copy link

ZabbyCapurin commented Sep 18, 2018

so far using after or before doesn't looking to be working.

For my environment, I have 2 tables. The 2nd table is supposed to be on a new page. Replacing .html2pdf__page-break with after/before no longer keeps it on the 2nd page.

Still doing some testing with the other page breaks, but it's at least no longer splitting text between letters?

using

pageBreak: {
  mode:   ['avoid-all', 'css'],
  after: '#firstPage',
  before: '#nextPage'
}

@ZabbyCapurin
Copy link

ZabbyCapurin commented Sep 18, 2018

https://jsfiddle.net/y27zgowd/12/
Placed a sample of how I'm using it. Not quite breaking at points I'm expecting in my env, but it is here sort of. Still fiddling.
This is a test1537305331392.pdf
TEST 1537307266541.pdf

EDIT: Confused why it's not cutting exactly like in my env, I guess the different text lengths? Regardless, forcing the page break doesn't work

@ZabbyCapurin
Copy link

Not sure how related or it'll help, but for the css, could it also include page-break-* alongside the breaks-*? I unfortunately have a case where I need to use IE 8 :(

@eKoopmans
Copy link
Owner Author

Hi all, sorry I've had such limited time to devote to html2pdf lately. I'm going to be without Internet for the next two weeks or so, but I will have a chance to work on a few pieces over that time so I hope to come back with a working (and tested) pageBreak module when I return.

@Greensahil avoid-all should do exactly what you want, it looks like I just need to put a bit of testing in.

@campsoftware I'll have to test that page when I return, remind me!

@ZabbyCapurin thanks for the tests, sounds like I need to do some fixes. I literally didn't have time to test at all. page-break-* is meant to be supported in this build, along with break-*. Hopefully I can get it all sorted out in these next two weeks!

@eKoopmans eKoopmans mentioned this pull request Sep 23, 2018
@eKoopmans
Copy link
Owner Author

eKoopmans commented Oct 7, 2018

Hi everyone, it should be all fixed! Thanks for your patience. A few details:

  • I renamed the option to pagebreak (from pageBreak, got rid of the camel-case)
  • I removed the whiteline mode - unlike the other modes, it would need to occur after the image is created, which causes other issues (specifically with hyperlinks)
  • I've added a manual tester in test/manual/pagebreaks.html, it's not automated but it gets the job done for now!
  • I've added avoid-all to the default behaviour, so now all three options ['avoid-all', 'css', 'legacy'] are enabled by default

I'll merge this in soon, and create a new release in master (v0.9.1) with it included. Let me know if any issues come up!

@manateelazycat
Copy link

@eKoopmans When you merge those great PR?

I can't wait for test page break feature.

@Greensahil
Copy link

Has the
pagebreak: { mode: 'avoid-all'} worked for anyone?

I really need this and it is not working at all for me. Do I need to remove all tags for this tow work?

@sometimescode
Copy link

Is there a way for me to specify it to only ever add a pagebreak to a specific element if necessary? Before and after are immediate and listing down elements in avoid hasn't led me to be lucky. It's a web part that I have no control over the build unfortunately.

@eKoopmans eKoopmans merged commit 0d88d34 into develop Oct 20, 2018
@eKoopmans eKoopmans deleted the feature/pagebreaks branch October 20, 2018 15:57
@Braybrookr
Copy link

I've been using html2pdf for awhile now. We take html reports and send them via pdf to customers. I've recently had to start supporting multiple different style reports. I switched to format of 'A4' and since then I've been having issues with page breaks not understanding the page size.

Break occurs close to where you place it (tried avoid all, legacy, etc) and it breaks but puts say the header of the next page on the bottom.

I switch back to letter and this no longer occurs. I was wondering if that is a separate issue, or am i not using the new features correctly?

@sometimescode
Copy link

sometimescode commented Nov 13, 2018

@Braybrookr
It doesn't seem like an issue related to this updated. It's possible that the element that you're passing to generate the PDF has been constrained to fit within the dimensions of letter format, and from what I've experienced that'll lead to a problem with the generated pdf if the formats don't match. You will have to adjust the dimensions of that element as well when you switch to format the output as 'A4'.

Hope this helps if the issue hasn't been solved yet.

@cablegunmaster
Copy link

cablegunmaster commented Nov 13, 2018

I still got a issue with one giant DIV which overlaps to multiple pages.
The html2pdf breaks the text in the middle of the letters.
I tested with a giant Square of Lorem ipsum. which spans 5 pages.

onedivhtmltopdf

V0.9.1 used from Master branch grabbed today.

Settings used:

            window.setTimeout(() => {
            html2pdf(element, {
                margin: 5,
                filename: filename + '.pdf',
                image: {type: 'jpeg', quality: 0.98},
                pagebreak: { mode: ['avoid-all','legacy'] },
                html2canvas: {
                    dpi: 192,
                    letterRendering: true,
                    logging: true
                },
                jsPDF: {
                    unit: 'mm',
                    format: 'a4',
                    orientation: 'portrait'
                }
            });
        }, 0);

For the multiple divs it does not work as well,
Its to big for it to cut it clean.
It cuts the otherhalf on the other page.

Situation what I want it to do:
All I want it to do is set the text on either the next page or on the former page. without cut ups.

@AbelVM
Copy link

AbelVM commented Dec 4, 2018

Same behavior with 3 small tables (like 4 rows), each of them split by page breaks (2 rows before and after the break), and the rest of the pages, blank. :(

@KaiOrange
Copy link

I used "avoid-all" in my object .I found that in a table, if tbody happens to be one page long, this is what happens:
image
The first page has only one thead and the second page has all the tbody content.

@eKoopmans
Copy link
Owner Author

Hi all! I haven't had much time to devote to html2pdf recently, but I'll be doing what I can over the next couple weeks. For those of you who have posted in this thread, if you still have a problem please post it to a separate issue. This thread is for discussion of a specific pull request which has been merged at this point. Thanks!

@cablegunmaster @AbelVM, please open an issue for the text cut-off - I was hoping to avoid the "white-line" mode (#41) but it may be necessary. @KaiOrange the solution to your problem is probably to not use 'avoid-all', and instead specify the kinds of elements you want it to break on (e.g. ['div', 'p', 'h1'] etc.).

@AbelVM
Copy link

AbelVM commented Dec 30, 2018

@eKoopmans I opened a ticket as of #184

The STR is... any! I have tested all the possible combinations of options related to page break and I get more or less the same result. 😞

@Larissa-Guimaraes
Copy link

I had some problems implementing html2pdf. However, most of the problems were with my HTML and not with html2pdf itself. So, be aware of the HTML adjustments that must be made for html2pdf to work correctly.
I have a page with dynamic content, so the text can grow and shrink constantly. I solved the problem by applying these adjustments to my TS:

onExportClick() {
const options = {
margin: 0.25,
filename: 'Analitico_dia_detalhado.pdf',
image: {type: 'pdf', quality: 0.98 },
html2canvas: {dpi: 96, letterRendering: false },
jsPDF: {unit: 'in', format: 'letter', orientation: 'portrait'},

pagebreak: { mode: ['legacy'] },
};

const content: Element = document.getElementById('element-to-export');

html2pdf()
.from(content)
.set(options)
.save();
}

Another thing, my content came out of a modal, where I had placed a height of 400px, this caused the content of my page to be cut in the PDF whenever the modal reached the limit of 400px, ignoring everything else. So I made an adjustment to my HTML, put the scroll bar before exporting the id:

<div class="modal-body" >
		 <perfect-scrollbar style=" max-height: calc(100vh - 400px);" [config]="config">  
		<div class="kt-portlet__body" id="element-to-export" style="margin-bottom: 50px;">
			
			<div class="label-name" style="text-align: center;">
				<label>{{this.nomeSetor}} {{this.msg}} - {{this.date | date: 'dd-MM-yyyy' }} </label>
			</div>			
			<div *ngIf="viewLoading" class="loading-indicator">
				<div class="kt-spinner kt-spinner--md kt-spinner--danger"></div>
			</div>
			<div class="kt-widget4">
				<div class="kt-widget4__item" *ngFor="let p of analiticoDiaDetalhado">
					<div class="kt-widget4__info">
						<div class="kt-widget4__username">
							<!-- <span class="kt-widget3__status kt-font-primary"> -->
								{{p.bloco}} 
							<!-- </span> -->
						</div>
						<div class="margin-box" *ngFor="let dados of p.dados">
							<p class="kt-widget4__text">
								<label class="padding-linha"></label>								
							</p>
							<p class="kt-widget4__text">
								<label class="label-name">Nome do Médico:</label>
								<label class="label-text">{{dados.nomeMedico | uppercase }}</label>
							</p>
							<p class="kt-widget4__text">
								<label class="label-name">Setor Espelho:</label>
								<label class="label-text">{{dados.setorEspelho | uppercase }}</label>								
							</p>
							<p class="kt-widget4__text"> 
								<label class="label-name" *ngIf="dados.nomePaciente != ''">Nome do Paciente:</label>
								<label class="label-text">{{dados.nomePaciente  | uppercase }}</label>
								<label class="label-text">{{dados.sigla}} {{dados.familia}}</label>
							</p>
						</div>
					</div>
					
				</div>
			</div>
		</div>
		</perfect-scrollbar>  
	</div>

My text was also being cut in half whenever I reached the last line of the PDF, I solved this problem by applying a css to the body of my content: margin-bottom: 50px. As you can see in the code above.
Well, I hope to help someone. Because I took a little to discover these things on my own. Sorry for the english of the google translator.
Cya
XD

@cablegunmaster
Copy link

cablegunmaster commented May 5, 2020

I would say as a general advice; try to use as minimal CSS as possible.
the more margins / paddings you add the more confused the html2pdf is about page breaks.

@Larissa-Guimaraes
Copy link

I often say that CSS can be your best friend or your worst enemy. In my case it helped a lot. Just have common sense and know how to use wisely.

.<

@muneebshafiq
Copy link

Using form.io, can't alter CSS.
Facing pagebreak issues even thought using:
type: 'pdf', elementId: 'dynamicDivToPrintOrExport', download: true, options: { margin: 10, pagebreak: { mode: ['avoid-all', 'css', 'legacy'] } }

image
image

Any help will be appreciated.

@ramesh-619
Copy link

ramesh-619 commented Aug 10, 2023

Using form.io, can't alter CSS. Facing pagebreak issues even thought using: type: 'pdf', elementId: 'dynamicDivToPrintOrExport', download: true, options: { margin: 10, pagebreak: { mode: ['avoid-all', 'css', 'legacy'] } }

image image

Any help will be appreciated.

@munnebshafiq, are you using formio? Me too using the formio. So the rendered form is to be downloaded as Pdf but I am facing issue with page breaks and text not selectable issue using this library.

@muneebshafiq
Copy link

@ramesh-619 unfortunately, yes pagebreak issue still exists.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.