7

Adding long text inside an HTML element such as a DIV, the element wraps that text. Exactly like this Question text, actually. How can I take the text from such an HTML element and determine where it breaks? i.e. where a new line is inserted.

For instance, in this box, there's a new line after "...like this", one after "...where it" and two after "...is inserted."

Andrei Oniga
  • 8,219
  • 15
  • 52
  • 89
  • [This might be of some help.](http://stackoverflow.com/questions/320184/how-to-prevent-long-words-from-breaking-my-div) – xan Jun 27 '12 at 18:37
  • Or http://stackoverflow.com/questions/4719777/finding-line-breaks-in-textarea-that-is-word-wrapping-arabic-text – Theo Jun 27 '12 at 18:40
  • What are you trying to accomplish in the end? – katspaugh Jun 27 '12 at 18:54
  • 1
    Unless the element is constrained by assigned width and height (or rows and cols in a testarea) , the newlines wrap according to the available width, and can change if the window is resized. Also, a user with a different screen size, or preferences for a different text size (even with the same viewport as you), will not see the same line break positions. – kennebec Jun 27 '12 at 19:03
  • http://stackoverflow.com/questions/4671713/detecting-line-breaks-with-jquery – jeffjenx Jun 27 '12 at 19:19
  • @katspaugh I need to be able to take that text and split it in multiple strings. Each string will hold the message on a single line. And it should not matter if the CSS 'word-wrap' rule is set to 'break-word', I still need to detect each single line of text. This is all for converting some standard HTML elements which hold text and/or a photo into an HTML5 canvas. And unfortunately, the '.fillText()' method is not smart enough to break a piece of text for me, so I need to "manually" detect each line. – Andrei Oniga Jun 27 '12 at 19:54
  • @kennebec Obviously, but this is not an issue. Whatever the size of the element and the screen resolution, I simply need to break such a wrapped text into sub-strings, each sub-string constituting a line of text from the original element. – Andrei Oniga Jun 27 '12 at 20:01

2 Answers2

2

So, the problem is actually how to do word-wrapping in HTML5 canvas:

This is all for converting some standard HTML elements which hold text and/or a photo into an HTML5 canvas. And unfortunately, the '.fillText()' method is not smart enough to break a piece of text for me, so I need to "manually" detect each line.

What you might do is measureText subsequently adding one word at a time. Measure the first word, and if it fits to the width of your container (ctx2d.measureText(words).width <= containerWidth), then you can add another word and measure again. Until the string of words doesn't fit. If it doesn't – you have to fillText on the next line.

As for the manually inserted line breaks, they are specifically represented in HTML, either by \n or \r characters in textareas or by HTML elements, like <br \>. Thus, before measuring the text you might want to split it by paragraphs.

In textareas:

var paragraphs = textarea.value.split('\n');

In non-form elements:

var paragraphs = [];

// getting all <p> and elements in a typical HTML element
// as well as individual text nodes (they are just DOM-nodes),
// separated by <br /> elements
var innerNodes = nonFormElement.childNodes;

for (var i = 0, len = innerNodes.length; i += 1) {
    // if a sub-element has some text in it,
    // add the text to our list
    var content = innerNodes[i].textContent;
    if (content) {
        paragraphs.push(content);
    }
}
katspaugh
  • 17,449
  • 11
  • 66
  • 103
  • I believe this is the closest solution to what I'm trying to accomplish. Basically, to take the full text and start adding a character at a time to a 'buffer' string and after each insertion, measure the length (in pixels) of that buffer. However, this doesn't solve the problem of actual line breaks. That is, I might be able to leave a few blank lines. How would I then detect these lines? – Andrei Oniga Jun 28 '12 at 12:01
  • To be completely honest, I don't understand the approach on non-form elements. Nevertheless, I'm using a textarea to append the content to it, then use the .split() method to detect the newline characters, and in conjunction with the measureText() method, I believe I'll be able to reach my goal. Thanks! – Andrei Oniga Jun 28 '12 at 15:25
  • @AndreiOniga, I've annotated the non-form approach to clarify. Good look! – katspaugh Jun 28 '12 at 18:36
1

I'm not sure what you're trying to achieve. But here's a simple trick you can use to identify the positions of single words. See this fiddle


var $text = $('#text'),
    breaks = [],
    top;

// wrap words (\w+) and punctuation (\S+) [well, non-word and non-space]
// in <spans> we can easily identify
$text.html($text.text().replace(/(\w+|\S+)/g, '<span>$1</span>'));

$text.children().each(function() {
    var $this = $(this),
        _top = $this.position().top;

    if (top === undefined) {
        top = _top;
    } else if (top < _top) {
        top = _top;
        // moved a row down
        breaks.push($this.prev());
        $this.prev().css('color', 'red');
    }
});


console.log(breaks);
rodneyrehm
  • 13,442
  • 1
  • 40
  • 56
  • Rod, I appreciate your help on this. However, as I've commented on katspaugh's answer, I don't see how this can solve the issue of line breaks. Because I may (or may not) press 'Return' a few times and insert 1 or more blank lines. And I'd not be able to detect those lines and draw them as they are, on the canvas. Any ideas on how to 'fix' this problem? – Andrei Oniga Jun 28 '12 at 12:05