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

Multiline text (aka Word Wrap) #8

Closed
dvdotsenko opened this issue Feb 17, 2012 · 16 comments
Closed

Multiline text (aka Word Wrap) #8

dvdotsenko opened this issue Feb 17, 2012 · 16 comments

Comments

@dvdotsenko
Copy link
Collaborator

Hi.

I am planning to add code that automatically splits long strings into multiple text lines.

Efficient string length calculation is not going to be a problem - will use off-screen DIV to measure length of text, infer chunk lengths and cut appropriately. What is a problem is the obtuseness of DOM manipulation using pure JavaScript (and browser-specific gotchas that come with that). So, naturally will roll with what i know - jQuery, which will make my code jQuery-dependent.

This is fine for us (corporate use, we already have jQuery where that matters), but, understandably could not go well if you want to pull the code into your mainline repo.

Could you mention your suggestions / thoughts on possible addition of line wrapping code to jsPDF?

If you already have some thoughts on that, and would like to have it as part of mainline jsPDF, by all means, chime in so we can try to code in way that helps eventual pull. If you don't really care about auto line wrapping, would be good to know too as it frees our hands.

Cheers.

@MrRio
Copy link
Member

MrRio commented Feb 20, 2012

If you'd like to go ahead with a jQuery implementation - I will assist in getting a succinct non-jQuery dependant version into the mainline branch.

Thanks,
James

@dvdotsenko
Copy link
Collaborator Author

The multiline support is coming in two parts:

  1. Make .text() be able to draw multiple, hand-chopped lines
  2. Add method that "hand-chops" long texts into array of strings, such that they fit to predefined box.

Part 1 was simple and is done:

https://github.com/willowsystems/jsPDF

The base support for multiline text nodes is in 9ad8790
Test for that is in 8239621

Part 2 is the one that will likely depend on running us within a browser, and on jQuery.

Code is heavily rearranged, but not really changed. Rearranging + minor changes were needed for the other features that will come, like templates... Please, don't take the restyling as an insult.

@MrRio
Copy link
Member

MrRio commented Feb 22, 2012

That's absolutely fine. Looking good! I've also kicked off a project that does a similar thing for DOCX files.. http://github.com/MrRio/DOCX.js

@siefkenj
Copy link
Contributor

Since ATM jsPDF only uses the standard fonts, would it not make sense to compute the length of a text string directly from the standard metrics?

@dvdotsenko
Copy link
Collaborator Author

The patch mentioned here just deals with pre-chopped lines. The line "to-size" chopper code is not published.

My Original direction for the chopper was jQuery because code for measuring text in hidden absolute span is already available. I have that working already (code not published), albeit poorly as the "twin" font in browser has different widths, kerning.

Seeing imperfect results of length approximation, I also decided to add actual widths, kerning + chopper as plugin

My problem with that approach was always size. All of the metrics were coming in at 40+kb. We target this at mobile and things like that matter.

After massaging (throwing away data too close to average size, throwing away tiny kerning values) the metrics, i got it down to 17kb, 4.5kb gzipped. Now that I have the metrics db size dealt with, adding proper chopper.

@stu-smith
Copy link

If anyone needs a quick'n'dirty solution to measuring text server-side (i.e. without a browser engine to perform the layout), the following gist contains the basic Adobe font metrics for the Base 14 fonts:

https://gist.github.com/3152705

It only supports ASCII characters at the moment; I wasn't able to find full font metrics for all Unicode characters.

@dvdotsenko
Copy link
Collaborator Author

b9f9f86

^ Added font metrics plugin that does not depend on DOM. It adds gliph sizes as well as kerning. See

https://github.com/MrRio/jsPDF/blob/master/jspdf.plugin.standard_fonts_metrics.js

https://github.com/MrRio/jsPDF/blob/master/jspdf.plugin.split_text_to_size.js

(There is a fix coming later today for split_text_to_size. It had "split long word" code unfinished.

@stu-smith
Copy link

Will there be any functions exposed to measure text, or right- and center-align text?

Cheers,
Stu

@dvdotsenko
Copy link
Collaborator Author

@stu-smith
RE: "Will there be any functions exposed to measure text"
There are such function exposed. getCharWidthsArray(text, options) and getStringUnitWidth(text, options) - part of jspdf.plugin.split_text_to_size.js.

Both operate on "font unit" sizes, meaning, they all return values as if the font size is 1 point. You would scale it up to actual points width by multiplying by desired font size. Example:

var actualTextWidth = pdf.getStringUnitWidth(text, {fontName:'Times', fontStyle:'Roman'}) * fontSizeInPoints  / toYourUnitsScaleRatio

RE: "or right- and center-align text?"

For me this is a problem that rides on top of a bigger problem. The bigger problem is: "how do you communicate FORMATTED text to pdf and just have it render it right?"

By formatted i mean, something like "Markdown" or "HTML", as I, personally, have no desire reinventing "formatted text" spec just for jsPDF. Formatted text has different font styling and padding within a line of text. Just measuring glyphs is not enough. Without first supporting in-line multi-format, I, personally, don't see a point coding in "justify" or other "final touches"

We have a BETA (Functionality, API is unfinished) HTML to PDF converter plugin in WIllow Systems's jsPDF repo - https://github.com/willowsystems/jsPDF/blob/stable/jspdf.plugin.from_html.js

It relies on browser and jQuery for parsing and extraction of formatting from a snippet of HTML. (Yes, Node.js, server-side JavaScript people, I don't care about you :) ) See Examples -> Text Elements -> FromHTML plugin.

We (at Willow Systems) do have a plan to add "justify" and "text-indent" (first line indent) support to it. I did not think about "center" CSS scraping yet. (Well, I did, but it complicates CSS scraping a bit, so I did not think about it further.) If you think you can contribute to the fromHTML plugin some code that does scraping and rendering of centered, right-aligned formatted text, will gladly take it, as our goals are elsewhere right now.

Daniel
Willow Systems

@stu-smith
Copy link

My apologies - I hadn't noticed getStringUnitWidth - that's exactly what I needed.

To put my request in context - I'm writing a diagramming tool of sorts, and it needs PDF output, so jsPDF is perfect as it sits nicely in the node.js backend. I needed the ability to output text aligned to a particular point, so I can now right- and center-align nicely, now that I can calculate the width of the text.

Many thanks for the help - it's all moving along nicely now.

@vegarringdal
Copy link

question

What is really "toYourUnitsScaleRatio"?
Dont really understand that one :-)

@diegocr diegocr closed this as completed Feb 8, 2014
@saurabhgis
Copy link

Multiline Text is not supported with drawText

@Sarfarazsajjad
Copy link

doc.text(text,left,top,'center') can be used to center text. It can be used with array of lines as well but when it is used with array the center does not work right so I have used it in a loop for every object in the array.

    var lMargin=15; //left margin in mm
    var rMargin=15; //right margin in mm
    var pdfInMM=210;  // width of A4 in mm
    var pageCenter=pdfInMM/2;
    
    var doc = new jsPDF("p","mm","a4");
    var paragraph="Apple's iPhone 7 is officially upon us. After a week of pre-orders, the latest in the iPhone lineup officially launches today.\n\nEager Apple fans will be lining up out the door at Apple and carrier stores around the country to grab up the iPhone 7 and iPhone 7 Plus, while Android owners look on bemusedly.\n\nDuring the Apple Event last week, the tech giant revealed a number of big, positive changes coming to the iPhone 7. It's thinner. The camera is better. And, perhaps best of all, the iPhone 7 is finally water resistant.\n\nStill, while there may be plenty to like about the new iPhone, there's plenty more that's left us disappointed. Enough, at least, to make smartphone shoppers consider waiting until 2017, when Apple is reportedly going to let loose on all cylinders with an all-glass chassis design.";
		
    var lines =doc.splitTextToSize(paragraph, (pdfInMM-lMargin-rMargin));
    var dim = doc.getTextDimensions('Text');
    var lineHeight = dim.h
    for(var i=0;i<lines.length;i++){
      lineTop = (lineHeight/2)*i
      doc.text(lines[i],pageCenter,20+lineTop,'center'); //see this line
    }
    doc.save('Generated.pdf');

@Uzlopak
Copy link
Collaborator

Uzlopak commented Sep 16, 2017

This is not a multiline solution but a workaround... :(

@pavelgronsky
Copy link

This is my solution:

this.pageStart = 20;
this.step = 5;
this.line = 20;

var splitTitle = this.doc.splitTextToSize(text, 180);
for (var i = 0; i < splitTitle.length; i++) {
this.doc.text(splitTitle[i], marginX, this.line);
this.addLine(this.step)
}

Where addLine is function for count line and split content by page

addLine(step) {
if (this.line >= 275) {
this.doc.addPage();
this.line = this.pageStart;
}
this.line += step;
}

@rownac
Copy link

rownac commented Sep 3, 2022

how to justify text in jsPDF?

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

No branches or pull requests