p5.jsでloadFontでロードしたフォントにtextStyleでイタリックを適用する小ネタ

# はじめに
　textFontでフォントを指定した場合でも、textStyleでITALICを指定すると斜体にできる。

https://p5js.org/reference/p5/textFont/

イタリックを指定しない場合
![nonItalic.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/437349/df88e340-6005-4c62-806e-ee7b2da0a361.png)

指定する場合
![italic.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/437349/c36d6846-5ec9-4d8e-8280-f20b9eb02161.png)

しかしloadFontでロードしたフォントには適用されない。

![italic2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/437349/421330f3-b02b-4ea2-9b48-efafd3cad2b4.png)

これはtextStyleのレファレンスにも書いてある。This function doesn't affect fonts loaded with loadFont().

https://p5js.org/reference/p5/textStyle/

しかし別のやり方でフォントをロードすると、適用されるようになるので、それを紹介する。

## 通常のやり方
　[hui italic font failure](https://openprocessing.org/sketch/2596300)
```js
let hui;

function preload(){
  hui = loadFont("https://inaridarkfox4231.github.io/assets/HuiFont29.ttf");
}

function setup() {
  createCanvas(400, 400);
  draw = () => {
    background(255);
    textFont(hui);
  	textAlign(CENTER, CENTER);
    textSize(36);

  	drawingContext.letterSpacing = "-5px";
    textStyle(ITALIC);
    text("italic font",200,50);
  	textStyle(NORMAL);
  	text("non italic font", 200, 150);

  	drawingContext.letterSpacing = "0px";
    textStyle(ITALIC);
    text("italic font",200,250);
  	textStyle(NORMAL);
  	text("non italic font", 200, 350);
  }
}
```

![nonitalis.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/437349/8855a007-de57-4399-8b03-a79a8fef1517.png)

フリーフォントであるふい字フォントのダウンロードはこちらで実行できる（提供感謝！）：

https://www.vector.co.jp/soft/data/writing/se337659.html

ちなみにこのフォントは洞窟物語のリメイクでも使われている。自分がこのフォントを知ったのは「ジェム」というフリーゲームです。気になった人は「#ジェムフリゲ」で検索してみてください。

https://haineko.fanbox.cc/posts/6805184

当時はフリーだったんですが現在は支援者様限定の特典となっているようです。ユニークなアクションRPGで、ファンシーなキャラクターとダークな世界観が魅力の楽しい作品なのでぜひ！

脱線しすぎた

loadFontで普通にふい字をロードして、textFontで適用する。描画をITALICとNORMALの2種類で実行しているが、いずれも見た目は一緒である。また、letterSpacingも適用できない。ふい字のアルファベットは文字間隔が広いので、これを負の数に設定すると見栄えが良くなるが、それもできない仕様である。
　そこで、次の方法。

## FontFace
　FontFaceというのを使う。次のコードでは、ちゃんとtextStyle(ITALIC)が機能する。もちろんBOLDなども機能する。
　[hui italic font](https://openprocessing.org/sketch/2596106)
```js
function setup() {
  createCanvas(400, 400);
  loadingFont("hui", "https://inaridarkfox4231.github.io/assets/HuiFont29.ttf").then((res) => {
    document.fonts.add(res);
    draw = () => {
      background(255);
      textFont("hui");
      textAlign(CENTER, CENTER);
      textSize(36);

      drawingContext.letterSpacing = "-5px";
      textStyle(ITALIC);
      text("italic font",200,50);
      textStyle(NORMAL);
      text("non italic font", 200, 150);

      drawingContext.letterSpacing = "0px";
      textStyle(ITALIC);
      text("italic font",200,250);
      textStyle(NORMAL);
      text("non italic font", 200, 350);
    }
  });
}

async function loadingFont(name, url){
  const fontFile = new FontFace(name, `url(${url})`);
  await fontFile.load();
  return fontFile;
}
```

![italic!.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/437349/beadcbb8-91b1-4b81-b9ea-707db3c319e6.png)

このように、イタリックになる。文字間隔調整も適用される。

　使っているのは非同期関数のloadingFontである。ここでFontFaceというクラスを使ってファイルを用意している。

https://developer.mozilla.org/ja/docs/Web/API/FontFace

loadで読み込みが実行される。その結果を受け取り、draw関数を定義している。document.fontsにaddしていて、これがポイントになる。
```js
document.fonts.add(res);
```
こうしてフォントを用意すると、textStyleを使ってITALICやBOLDを指定できるようになる。非同期であるので、普通にやると最初の数フレームは適用されなかったりする。それが気になる場合はこのようにPromise構文でdrawを用意する必要があるが、気にならないなら普通に書けばいいと思う。

どういうことかというと、非同期で書かないとこうなる。
```js
function setup() {
  createCanvas(400, 400);
  loadingFont("hui", "https://inaridarkfox4231.github.io/assets/HuiFont29.ttf");
   // draw = () => {
      background(255);
      textFont("hui");
      textAlign(CENTER, CENTER);
      textSize(36);

      drawingContext.letterSpacing = "-5px";
      textStyle(ITALIC);
      text("italic font",200,50);
      textStyle(NORMAL);
      text("non italic font", 200, 150);

      drawingContext.letterSpacing = "0px";
      textStyle(ITALIC);
      text("italic font",200,250);
      textStyle(NORMAL);
      text("non italic font", 200, 350);
  //  }
}

function loadingFont(name, url){
  const fontFile = new FontFace(name, `url(${url})`);
  fontFile.load();
  document.fonts.add(fontFile);
}
```
![failure (1).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/437349/bd6bf0b4-1168-43dd-a798-c3a317691a78.png)

このように最初の数フレームは適用されないので、失敗する。ただtextFontの内容は文字列であるから、ITALICやBOLDは適用されている。ロードしたフォントが無視される、という意味。なおdraw関数を書き換えると...
```js
function setup() {
  createCanvas(400, 400);
  loadingFont("hui", "https://inaridarkfox4231.github.io/assets/HuiFont29.ttf");
}
function draw(){
  background(255);
  textFont("hui");
  textAlign(CENTER, CENTER);
  textSize(36);

  drawingContext.letterSpacing = "-5px";
  textStyle(ITALIC);
  text("italic font",200,50);
  textStyle(NORMAL);
  text("non italic font", 200, 150);

  drawingContext.letterSpacing = "0px";
  textStyle(ITALIC);
  text("italic font",200,250);
  textStyle(NORMAL);
  text("non italic font", 200, 350);
}

function loadingFont(name, url){
  const fontFile = new FontFace(name, `url(${url})`);
  fontFile.load();
  document.fonts.add(fontFile);
}
```
この場合でも適用されないのはせいぜい最初の1,2フレームである。すぐに適用され、こうなる：

![feugufge.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/437349/09ff2c0e-c43c-4c22-8c07-3179c942e83b.png)

適用されないフレームを作りたくないかどうかはスケッチの方針による。

# おわりに
　loadFontで作ったフォントにtextStyle(ITALIC)が使えないのはずっと気になっていたんですが、解消できて良かったです。なおタグで導入する場合もtextStyleが使えるようです。ただjsで完結してる方が分かりやすいのでこっちを採用しました。
　ここまでお読みいただいてありがとうございました。