JavaScript Canvas - Text, Typography & SVG
Written by Ian Elliot   
Monday, 04 November 2019
Article Index
JavaScript Canvas - Text, Typography & SVG
SVG Text

For a Canvas object, drawing text is just another path to render. You can select a font and then render the shapes or glyphs it defines using stroke and fill methods. Going beyond this there are a lot of ways of positioning glyphs that control the typography and this is very specialized. In this extract from a chapter in my new book on JavaScript Graphics we look at how it works.

 

Now available as a paperback or ebook from Amazon.

JavaScript Bitmap Graphics
With Canvas

largecover360

 

Contents

  1. JavaScript Graphics
  2. Getting Started With Canvas
  3. Drawing Paths
      Extract: Basic Paths
      Extract: SVG Paths
      Extract: Bezier Curves
  4. Stroke and Fill
      Extract: Stroke Properties 
      Extract: Fill and Holes
      Extract: Gradient & Pattern Fills
  5. Transformations
      Extract: Transformations
      Extract: Custom Coordinates 
      Extract  Graphics State
  6. Text
      Extract: Text, Typography & SVG 
      Extract: Unicode
  7. Clipping, Compositing and Effects
      Extract: Clipping & Basic Compositing
  8. Generating Bitmaps
      Extract:  Introduction To Bitmaps
      Extract :  Animation 
  9. WebWorkers & OffscreenCanvas
      Extract: Web Workers
      Extract: OffscreenCanvas
  10. Bit Manipulation In JavaScript
      Extract: Bit Manipulation
  11. Typed Arrays
      Extract: Typed Arrays **NEW!
  12. Files, blobs, URLs & Fetch
      Extract: Blobs & Files
      Extract: Read/Writing Local Files
  13. Image Processing
      Extract: ImageData
      Extract:The Filter API
  14. 3D WebGL
      Extract: WebGL 3D
  15. 2D WebGL
    Extract: WebGL Convolutions

<ASIN:1871962625>

<ASIN:B07XJQDS4Z>

<ASIN:1871962579>

<ASIN:1871962560>

<ASIN:1871962501>

<ASIN:1871962528>

What is important is that as text is just another example of a path it can be used with all of the techniques we have learned so far. This is good, but Canvas text processing is very primitive in terms of typography. Finally there is the problem of Unicode. We have moved beyond the 128 or 256 characters available in ASCII - how does this work in JavaScript?

In chapter but not in extract:

  • fillText and strokeText

Typographic Positioning - textBaseline and textAlign

The meaning of the x,y in the positioning of text is more complicated than you might think. If you accept the defaults then it more or less corresponds to the bottom left corner of the text's bounding box.

You can change the horizontal positioning relative to the x value specified by setting textAlign property to one of:

start or left The text is drawn just after the x position.

center The center of the text is located at the x position.

end or right The end of the text is located the x position.

 

You can use these values to left or right justify or center text. For example:

ctx.font="normal normal 20px arial";
ctx.textAlign="right";
ctx.fillText("line of text followed by",200,60);
ctx.fillText("A shorter line of text",200,60+20*115/100);

gives:

text2

The textBaseline property determines how y alters the vertical position of the text relative to the horizontal line, the baseline. It can be set to one of:

  • alphabetic Bottom of vertically oriented glyphs (default)

  • ideographic Bottom of horizontally oriented glyphs

  • top Text is aligned based on the top of the tallest glyph

  • bottom Text is aligned based on bottom of the glyph

  • middle Text is aligned according to the middle of the text

  • hanging Used by Tibetan and other indic scripts

 You can see the essential details in this chart from the WHATWG specification:

text3

Notice that the bounding box is the maximum area a font can use and not all glyphs fill it. In some fonts the majority of glyphs use a much smaller area of the total allowed to them. The key measurement is the em square. This is a square with sides equal to the current point size of the font.

When you render text onto the canvas you simply specify x,y and perhaps a maximum width. The x value gives the horizontal alignment and the y value sets the baseline - so what is the bounding box?

The answer is that the bounding box depends on the font in use and you can use the measureText() method to return a TextMetrics object which contains all of the information on the layout of a particular string in the current font as read only properties. The only problem at the moment is that this is only fully supported on Safari and on Chrome but only if you enable Experimental Web Platform Features using chrome://flags. All browsers support the TextMetrics object and at least the width property:

  • width

calculated width of the text. This is not the width of the bounding box but the number of pixels needed to the end of the text. That is, it is the y distance in pixels you need to move to continue the text in the same font.

  • actualBoundingBoxLeft actualBoundingBoxRight

distance from x,y to the left and right edge of the bounding box. Notice that these depend on the alignment used.

  • fontBoundingBoxAscent fontBoundingBoxDescent
    actualBoundingBoxAscent actualBoundingBoxDescent

distance from x,y to the top and bottom of the bounding rectangle. The actual version of the properties gives you the top and bottom of the bounding rectangle for the actual text used in the call and the other two properties give the value for the font. This means the "actual" versions give a bounding box for the current text and the other two give a bounding box that includes any text in the font.

  • emHeightAscent emHeightDescent

the distance from x,y to the top and bottom of the em square in the line box, in pixels. This gives you the font's "point" size measured in pixels.

  • hangingBaseline alphabeticBaseline ideographicBaseline

the distance from x,y given baseline in pixels.

For example, suppose you want the actual bounding box for a specific piece of text:

ctx.font="normal normal 40px arial";
text="Hello Text World";
metric=ctx.measureText(text);
x=200;y=60;
boxL=x-metric.actualBoundingBoxLeft;
boxR=x+metric.actualBoundingBoxRight;
boxT=y-metric.actualBoundingBoxAscent;
boxB=y+metric.actualBoundingBoxDescent;
ctx.strokeRect(boxL,boxT,boxR-boxL,boxB-boxT);
ctx.fillText(text,x,y);

Where boxL,boxT is the top left corner of the bounding box and boxR,boxB is the bottom right corner. This produces a tight bounding box for the text you specify:

text4

If you change the program to read:

boxL=x-metric.actualBoundingBoxLeft;
boxR=x+metric.actualBoundingBoxRight;
boxT=y-metric.fontBoundingBoxAscent;
boxB=y+metric.fontBoundingBoxDescent;

then you will get a bounding box that will contain any text from the font:

text5

That is, there are characters in the font that will use the apparently extra space in the bounding box.

Note these programs currently only work on Chrome or Safari.

It is likely that support for typographic metrics will improve and it is worth checking the current state before making use of any of these properties. There are font libraries that can extract typographic metrics from font files and this might be the only way to perform accurate layout until browsers implement the full textMetric object.

There is also the direction property which can be set to one of:

  • ltr left to right

  • rtl right to left

  • inherit default

 

<ASIN:1871962625>

<ASIN:B07XJQDS4Z>



Last Updated ( Saturday, 09 November 2019 )