みかづきブログ・カスタム

基本的にはちょちょいのほいです。

html2canvasがwriting-mode: vertical-rlに対応しきれていないのでCanvasで縦書きを実現する 📝

writing-mode: vertical-rlを使えばCSSで縦書きを簡単に実現できます。

developer.mozilla.org

DEMO

普段はこれでまったく問題ないのですが、html2canvasを使ってHTMLを画像書き出ししようとすると、writing-mode: vertical-rlがうまく評価されません。
検証のためにdownloadボタンを押した際に、html2canvasでHTMLを画像化できるようにしていますが、

と、いう感じで書き出されました。
座標がずれる点は書き出す際の工夫でなんとかなるようなきもしますが、「ー」が90度回転せずに書き出されてしまうのは、Canvasにレンダリングする際に回転させるべき文字、そうじゃない文字の判定が入っていない以上、どうしようもない気がします。

そこで今回は、CSSではなく、Canvasで文字を縦書きにする方法を検証しました。

DEMO

縦書きにする方法といっても便利なメソッドが用意されているわけではないので、一文字ずつfillTextでレンダリングしていきます。
今回は簡易的に、

  1. 改行なし
  2. 「ー」のみ90度回転で処理

という仕様にしました。
本当は「〜」とか、他にも90度回転させなければならない文字もありますし、「っ」とかポジションを調整しないといけない文字もあるので、もっと複雑になると思います。

ソースコード

const canvas = document.querySelector('canvas');
const ctx = canvas.getContext('2d');
const subCanvas = document.createElement('canvas');
const subCtx = subCanvas.getContext('2d');
const size = 48;
const fontSize = 20;
const kerning = .6;
const text = 'ステーキハウス';


canvas.width = size;
canvas.height = size * kerning * text.length + (size * (1 - kerning));


[...text].forEach((txt, i) => {
  subCanvas.width = subCanvas.height = size * 2;
  subCtx.textAlign = 'center';
  subCtx.textBaseline = 'middle';
  subCtx.font = `bold ${ fontSize * 2 }px sans-serif`;

  if (txt === 'ー') { // ーは90度回転
    subCtx.translate(size, size) ;
    subCtx.rotate(90 * Math.PI / 180) ;
    subCtx.translate(-size, -size) ;
  }

  subCtx.fillText(txt, size, size);

  if (txt === 'ー') {
    subCtx.translate(size, size) ;
    subCtx.rotate(-90 * Math.PI / 180) ;
    subCtx.translate(-size, -size) ;
  }

  ctx.drawImage(subCanvas, 0, size * kerning * i, size, size);
});

Canvasでレンダリングしているので当然ですが、バッチリhtml2canvasで書き出すことができました。