Yesterday, I looked at using the
Range class to detect line-breaks in a text-node within the DOM (Document Object Model). Normally, you don't need to think about the line breaks that the user is seeing in the browser. However, I have a use-case in which I need to render said text to a
<canvas> element. And, since the
CAUTION: Rendering text to the
<canvas>element is a complicated beast with many edge-cases and cross-browser compatibility issues. This post does not attempt to solve any of those problems. This post is merely a demonstration of yesterday's solution being applied to a specific problem-domain.
With the HTML
<canvas> element, you can invoke the
.fillText() method on the 2D context to render text. This renders the text as a single line at a specified X,Y coordinate. As such, in order to render multiple lines of text as a cohesive block, we have to loop over the individual lines and render each line at an increasing Y-offset:
LineY = ( initialY + ( lineHeight * lineIndex ) )
Again, there's a lot of edge-case / cross-browser issues with this relatively simple concept - none of which we are going to address in this post. That said, let's look at how we can use the line-break detection to render wrapped text to a Canvas 2D context. In the following demo, I have two side-by-side panels. On the left is a
<p> element; and, on the right is a
<canvas> element. The call-to-action button extracts the individual lines from the paragraph and then renders them to the canvas, one line at a time.
This uses the
extractLinesFromTextNode() from yesterday to extract the text and then calls a new method,
renderSampleNodeToCanvas(), to render those lines to the Canvas:
As you can see, we're extracting the lines of text (as the user sees them in the browser), then calling
.forEach() on them to render each line, in turn, to the Canvas. And, after each
.fillText(), we're simply incrementing the Y-coordinate by the runtime line-height of the text. And, when we run this, we get the following output:
As you can see, we've faithfully applied the runtime line-breaks of the Paragraph tag to the text-rendering on the Canvas element. This looks really good in Chrome; it looks mostly good in Firefox; and, it looks janky in Safari, which pushes the text down a few pixels. That said, this wasn't a post about flawless canvas rendering - this was a demonstration of how detecting runtime line-breaks in a rendered text-node can be helpful.
Want to use code from this post? Check out the license.