I\'ve looked around at similar SO posts related to this, but none deal with exactly what I am looking for. Say I have some text, I throw it in a div, and add some arbitrary
I thought it would be a good ideea to post the solution I came up with for my own question, because it seems pretty elegant. I didn't have to wrap every word in a span—I just used a visibility:hidden test span to see if the next word in the line was going to cause the line to run past the width of the container before actually adding the next word to the line. As I put together each line I added them to an array. I then just appended each line to the container by iterating over the array. It is live here (at least for a while).
/*global console, $, OO*/
/*jslint browser: true*/
(function (undefined) {
"use strict";
$(window).on('load', function (event) {
var str = "Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.",
$container = $('<div>').width('200px').text(str).appendTo('body');
wrapLines($container);
});
function wrapLines($container) {
var text = $container.text(),
words = text.split(' '),
lines = [],
line = $('<span>'),
tmp = $('<span>').css('visibility', 'hidden').appendTo('body');
$container.text("");
$.each(words, function (index, word) {
if (tmp.text(line.text() + " " + word).width() < $container.width()) {
line.text(line.text() + " " + word);
} else {
lines.push(line);
line.remove();
line = $('<span>');
tmp.text("");
}
});
tmp.remove();
for (var kittens = 0 ; kittens < lines.length; kittens++) {
lines[kittens].appendTo($container);
console.log(lines[kittens].width());
}
}
}());
Not sure I completely understand your question, but... You will be able to get the div's height right? Divide that by a (CSS-defined) line-height and you should have the number of lines of text.
You could then check the position of any given character / word by making an invisible div containing part of the original text and performing the abovementioned trick to find its line. Does that help?
The suggestions from the other answers made me curious so i put them to the test, and this is what i came up with:
function wrapLines($container) {
// get the text from the conatiner
var text = $container.text();
// split the text into words
var words = text.split(' ');
// wrap each word in a span and add it to a tmp
var tmp = '';
tmp += '<span>' + words.join('</span><span>') + '</span> ';
// remove the text from the container, and replace it with the wrapped words
$container.html($(tmp));
// prepare the offset variable and tmp
var tmp = '';
var top = null;
$container.find('span').each(function(index, word) {
$word = $(word);
// if this is the first iteration
if (top == null) {
// set the top
top = $word.position().top;
// open the first line
tmp = '<span class="line">';
}
// if this is a new line (top is bigger then the previous word)
if (top < $word.position().top) {
// close the previous line and start a new one
tmp += '</span><span class="line">';
// change the top
top = $word.position().top;
}
// add the content of the word node + a space
tmp += $word.text() + ' ';
});
// close the last line
tmp += '</span>';
// remove the content of the conatiner, and replace it with the wrapped lines
$container.html($(tmp));
}
I added plenty of comments, but feel free to ask if something isn't clear.
To see the code in action (including some fancy colors ;-) ), have a look at my fiddle: http://jsfiddle.net/yZnp8/1/
edit:
I put the code from @orb next to my solution here: http://jsfiddle.net/yZnp8/5/.
A quick comparison with Chrome Inspector shows that there is a big performance diiference. @orbs solution takes 754ms and 17MB while my solution takes 136ms and 14MB.
A little word of advice, try to limit your DOM operations (I marked them in the fiddle). They slow your code down, as the browser needs to render your page all over again. I do only 2
, while you do 3 + 2x number of words + 1x number of lines
. This is probably what explains the big difference in speed. And the longer the text, the bigger the difference will become.
Not trying to break @orb solution down, just trying to be helpful and explain the differences...
Bob Monteverde provided a very nice piece of code to calculate a Strings width here. You could use that and start comparing string widths with the actual width of your div to find single lines.