I can use Range.getClientRects() to determine the coordinates of each wrapped line of a text node:
var range = document.createRange(),
cr,
r,
div;
range.selectNode(document.body.childNodes[0]);
cr= range.getClientRects();
for(r = 0 ; r < cr.length ; r++) {
div = document.createElement('div');
div.style.cssText= `position: absolute;
left : ${cr[r].left}px;
top : ${cr[r].top}px;
width : ${cr[r].width}px;
height : ${cr[r].height}px;
border : 1px solid green;
`;
document.body.appendChild(div);
}
body {
width: 300px;
font: 13px Arial;
text-align: center;
}
* {
box-sizing: border-box;
}
Lorem ipsum dolor sit amet, consectetur adipiscing 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.
However, there doesn't seem to be a simple way to determine the text content of each of those lines.
I can brute force a solution by adding each word one at a time to an element until it wraps, like I've done in the Snippet below:
var div = document.querySelector('div'),
s = div.textContent.split(' '),
word,
line = '',
lines = [],
h = 0;
div.textContent = '';
while(s.length) {
word = s.shift() + ' ';
div.textContent += word;
if(div.clientHeight !== h) {
h = div.clientHeight;
if(line) {
lines.push(line);
}
line= '';
}
line += word;
}
lines.push(line);
console.log(lines);
body {
width: 300px;
font: 13px Arial;
}
* {
box-sizing: border-box;
}
<div>Lorem ipsum dolor sit amet, consectetur adipiscing 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.</div>
But that gets messy quickly when dealing with multiple element nodes.
Is there a better way?