Greg
Greg

Reputation: 1842

How do I draw condensed text in a canvas using javascript?

I am new to javascript and need to condense text drawn into a canvas using java script. w3schools suggests this can be done.

JavaScript syntax: object.style.fontStretch="expanded"

I noticed in css syntax however that neither font-stretch: condensed nor font-stretch: expanded appear to work and a comment in the example in w3schools also states no browsers support the font-stretch property. I am also aware this property will not work on just any font.

var can = document.getElementById("textCanvas");
var ctx = can.getContext("2d");
    				
ctx.font = "120px Arial Bold Italic";
ctx.font.fontStretch="ultra-condensed"; //condensed”; // expanded”;
ctx.fillStyle = "red";
ctx.textAlign = "center";
ctx.fillText("NAME", 100, 100);
<canvas id="textCanvas"  width="200" height="200" style="border: 1px solid black"></canvas>
    			

Using font-stretch made no difference. I also tried font-kerning and font-size-adjust. How do I condense the font ?

Upvotes: 1

Views: 1436

Answers (1)

Kaiido
Kaiido

Reputation: 137171

ctx.font is a string. Setting fontStretch or anything else on it won't change it.

Now, the correct syntax is the same as CSS font property:

ctx.font = "[ [ <'font-style'> || <font-variant-css2> || <'font-weight'> || <font-stretch-css3> ]? <'font-size'> [ / <'line-height'> ]? <'font-family'> ] | caption | icon | menu | message-box | small-caption | status-bar"`

So for setting only the font-stretch, the minimal is

ctx.font = "<font-stretch-css3> <'font-size'> <'font-family'>"

For example ctx.font = "ultra-condensed 18px LeagueMonoVariable"; would do.

However you'll face the same limitations as with CSS: browser support is limited, only a few fonts can be used, and in Chrome you need to define the font-stretch in the font-face declaration.

// This example seems to work only on Chrome, as does the MDN's example
const font = '18px "LeagueMonoVariable"';
document.fonts.load(font)
  .then(() => {
    const canvas = document.getElementById('canvas')
    const ctx = canvas.getContext('2d');
    ['ultra-condensed', 'condensed', 'expanded', 'ultra-expanded'].forEach((stretch, i) => {
      ctx.font = stretch + ' ' + font;
      ctx.fillText('Hello ' + stretch + ' World', 10, i * 30 + 30);
    });
  });
/* borrowed from https://developer.mozilla.org/en-US/docs/Web/CSS/font-stretch */
/*
  This example uses the League Mono Variable font, developed by
  Tyler Finck (https://www.tylerfinck.com/) and used here under
  the terms of the SIL Open Font License, Version 1.1:
  http://scripts.sil.org/cms/scripts/page.php?item_id=OFL_web
*/

@font-face {
  src: url('https://tylerfinck.com/leaguemonovariable/LeagueMonoVariable.ttf');
  font-family: 'LeagueMonoVariable';
  font-style: normal;
  font-stretch: 1% 500%;
}
<canvas id="canvas" width="500"></canvas>

Chrome output for the ones using an other browser.

Also note that apparently the percentage notation (n% font-size font-family) is not supported in Chrome from context's font.


Given all these limitations, it might be worth considering an alternative solution, and the best alternative is probably to have the variant font as a separate font-face and use it as simply as possible.

Promise.all([
  document.fonts.load("18px Roboto"),
  document.fonts.load("18px 'Roboto Condensed'")
])
  .then(() => {
    const canvas = document.getElementById('canvas')
    const ctx = canvas.getContext('2d');
    ctx.font = "18px Roboto";
    ctx.fillText('Hello World', 10, 30);
    ctx.font = "18px 'Roboto Condensed'";
    ctx.fillText('Hello condensed World', 10, 60);
  });
<link href="https://fonts.googleapis.com/css?family=Roboto|Roboto+Condensed&display=swap" rel="stylesheet"> 
<canvas id="canvas" width="500"></canvas>

Upvotes: 3

Related Questions