📜 ⬆️ ⬇️

We display text on HTML5 Canvas

HTML5 Canvas is a very extensive topic with many “goodies”, many of which have already been written and will be written. Therefore, I want to tell a little in this article, only about one small, and how at first glance it may seem a banal topic - working with text. I want to show that it is almost as possible to work with it as with plain text on the web, i.e. position, overlay styles and gradients, and write multi-line sentences easily and without problems.


Plain text


To display plain text, you can use the two context functions fillText () and strokeText () .
These functions take three required parameters: the text itself and the X and Y coordinates, i.e. its location, and the last one is optional: the maximum text width, if you specify the maximum text width less than the actual width, the text will be compressed to the width you specified. I do not advise you to set the maximum width, because when compressed, it also becomes a bad form. Instead of such compression, I recommend transferring text to a new line, there is no standard function for this, but I will give an example of how this is easily implemented.
If you simply display the text using such functions, then such text will be small and nondescript. We can fix this by giving it a font in the font context variable. The font is set, as well as in CSS ([font style] [font weight] [font size] [font face]). Example:

ctx.fillStyle = "#00F"; ctx.strokeStyle = "#F00"; ctx.font = "italic 30pt Arial"; ctx.fillText("Fill text", 20, 50); ctx.font = 'bold 30px sans-serif'; ctx.strokeText("Stroke text", 20, 100); 

')
image

Demo

Text layout


There are two standard ways of positioning text relative to its location: vertical and horizontal.
Vertical positioning is set using textBaseline, it is set to one of the possible options: top, hanging, middle, alphabetic, ideographic and bottom .

  ctx.textBaseline = "bottom"; ctx.fillText("bottom", 400, 75); 


image

Demo

And horizontally with textAlign, one of the following parameters can be: center, start, end, left, right .

  context.textAlign = "center"; ctx.textBaseline = "bottom"; context.fillText("center", 250, 20); 


image

Demo

These methods are far from ideal, and with the help of them it is sometimes difficult to position the text, since you want it for you. Below I will describe the way how you can use your positioning, even multi-line text.

Stylization
The simplest way we can stylize a text is to give it a color. The color is set using fillStyle to set the fill color and strokeStyle to set the stroke color.
Just as in CSS3, you can add shadows to text in the canvas. This is done with: shadowColor - setting the color of the shadow, shadowOffsetX and shadowOffsetY - setting the indent and shadowBlur - setting the blur of the shadow.

  ctx.shadowColor = "#F00"; ctx.shadowOffsetX = 5; ctx.shadowOffsetY = 5; ctx.shadowBlur = 5; ctx.strokeText("Shadow text", 20, 100); 


image

Gradients for text are also supported. The gradient itself is created using the createLinearGradient () function. And with the help of the addColorStop () function, the colors and their positions in it are set. The text is filled with a gradient as well as a solid color with fillStyle and strokeStyle .

  var gradient = ctx.createLinearGradient(0, 0, 0, 60); gradient.addColorStop(0.0, 'rgba(0, 0, 255, 1)'); gradient.addColorStop(0.3, 'rgba(128, 0, 255, 0.6)'); gradient.addColorStop(0.6, 'rgba(0, 0, 255, 0.4)'); gradient.addColorStop(1.0, 'rgba(0, 255, 0, 0.2)'); ctx.fillStyle = gradient; 


image

In addition to the usual fill and fill with a gradient, you can also fill it with some kind of texture. To do this, before the start of the text output image texture. And then using createPattern () to create a texture based on it. You can set the image to be repeated or not.

  var pattern = ctx.createPattern(img, 'repeat'); ctx.fillStyle = pattern; 


image

Demo

Text Width and Multiline Text



Suppose you need to write a text on the canvas of unlimited length, whether it is one word or several sentences. If you write it as it is, i.e. insert all the text into fillText (), then only that part will be visible on the screen that does not exceed the width of the canvas in its width. Those. if the width of the canvas is 400 pixels, then you will not miss the text that goes beyond its width. In order to make multi-line text you need to be contrived. But the algorithm is simple. First, we calculate the width of the text, compare it with the maximum width of the area where we want to display this text. If the width of the text does not exceed that width, then print the text, and if it exceeds, then break the text in the most convenient way for you, I prefer to break into spaces.
In order to calculate the width of the text, you can use the measureText () function, which gives the width of the text in the object form (unfortunately this function does not give the height of the text, I hope this feature will be added, but for now it will have to be calculated in other ways, exactly later in the article) .
Example:

 function wrapText(context, text, marginLeft, marginTop, maxWidth, lineHeight) { var words = text.split(" "); var countWords = words.length; var line = ""; for (var n = 0; n < countWords; n++) { var testLine = line + words[n] + " "; var testWidth = context.measureText(testLine).width; if (testWidth > maxWidth) { context.fillText(line, marginLeft, marginTop); line = words[n] + " "; marginTop += lineHeight; } else { line = testLine; } } context.fillText(line, marginLeft, marginTop); } var canvas = document.getElementById("canvas"); var context = canvas.getContext("2d"); var maxWidth = 400; // ,    var lineHeight = 25; /*    ,    ,       */ var marginLeft = 20; var marginTop = 40; var text = "       ,       , " + "     .         , " + " ,   ,      ,      ." + "  ,     ."; context.font = "16pt Calibri"; context.fillStyle = "#000"; wrapText(context, text, marginLeft, marginTop, maxWidth, lineHeight); 


image

Demo

It seems that everything is fine, you do not need to set the coordinates of the text, whether you manually calculate the text by the width or not. Almost everything is automated and looks good, but still a small nuance, the height of the text is hard-coded, so when changing the font or size you have to manually adjust the height of the text each time (in the example, the variable lineHeight ).

Determine the height of the text



When working with text on the canvas, neither the measureText () function, nor any other, allows us to determine the height of the text. You can still cope with this misfortune, the solution to this problem that I want to offer you is not very beautiful, but it still works.
When we set the text style (font size and style) in the font , we set it in the same style, as we would set it in CSS. Fonts and their sizes, of course, if such a font is available in canvas, then it will also be available in regular styles.
And so, the idea is this: we have the size and type of the font in the font variable, we create a new element in the DOM, put the text there, and set the styles from that variable. Next, using offsetHeight, we get the height of the element, which will be the height of our text. After that, we can safely remove this element from the DOM.
An example of the implementation of this idea:

 var text = "        ."; var marginLeft = canvas.width - context.measureText(text).width; var marginTop = canvas.height - getFontHeight(context.font); context.fillText(text, marginLeft, marginTop); function getFontHeight(font) { var parent = document.createElement("span"); parent.appendChild(document.createTextNode("height")); document.body.appendChild(parent); parent.style.cssText = "font: " + font + "; white-space: nowrap; display: inline;"; var height = parent.offsetHeight; document.body.removeChild(parent); return height; } 


Result:

image

Demo

I would be glad if someone offers a more beautiful or correct option to get the height of the text.
Thank.

Source: https://habr.com/ru/post/140235/


All Articles