JavaScript
HTML5
canvas

HTML5 Canvasで日本語縦書き

縦書きしたいよね

Canvasに縦書きで文章を書いて、画像化したい。禁則処理にも対応したい。という試みです。

https://gist.github.com/aya-eiya/1721182#file-2_howtowriteverticallytocanvas-html
を参考にさせていただいて、句読点とかぎかっこの行末ぶら下げを実装。
フォントはフリーフォントを縦書き用にサブセットフォント化して、別途CSSでWebフォントとして指定。

サブセットフォントメーカー
https://opentype.jp/subsetfontmk.htm
WOFFコンバータ
https://opentype.jp/woffconv.htm

以下、実際使ってるソースをサンプル用に書き直したので、おかしかったらすみません。

※実際はWebフォントのロード待ちでこちらを使用してます
http://defghi1977-onblog.blogspot.jp/2013/02/canvasweb.html

HTML

<canvas id="layer1" width="200" height="200"></canvas>

フォント指定のCSS

@font-face {
  font-family: "myfont";
  src: url("font/SourceHanSerifJP-Regular.woff2") format('woff2'),
       url("font/SourceHanSerifJP-Regular.woff")  format('woff'),
       url("font/SourceHanSerifJP-Regular.otf") format('opentype');
}

縦書き部分のJS

window.onload = function(){
    var hp = 0;
    var vp = 0;
    var hps =  160; // 開始位置のX座標
    var vps_base = 0; // 開始位置のY座標
    var vps = vps_base;
    var fontsize = 20; // 文字サイズ
    var fontname = 'myfont'; // フォント名
    var lineheight = 1.7; // 行間
    var color = #000; // 文字色
    var val = '春はあけぼの。ようよう白くなりゆくやまぎは、少しあかりて、紫立ちたる雲の細くたなびきたる。'; // テキスト
    var hp_flag;
    var c = 0;
    var v= 1;
    var t_height = 20; // 1行の文字数
    var t_max = t_height + 3; // 禁則処理で扱う最大文字数

    var layer1 = document.getElementById("layer1");
    var layer1Ctx = layer1.getContext("2d");
    layer1Ctx.clearRect(0,0,200,200);
    layer1Ctx.font = fontsize + 'px "' + fontname + '"';
    layer1Ctx.fillStyle  = color;
    for(var i=0;i<val.length;i++){
    vp = fontsize;
    chr = val.charAt(i);
    if (c > t_height) { // 最大字数オーバー
        if ((chr.match(/、|。|」|)|』|】/)) &&(c < (t_height + 3))){ // 禁則処理
            if (c > (t_height+1)) {
                vps = vps_base + (fontsize *  (c-0.5)); // 位置
            } else {
                vps = vps_base + (fontsize * c); // 位置
            }
        } else {
            hps -= fontsize * lineheight; // 改行
            vps = vps_base; // 行頭へ
            c = 0; // 縦位置カウント
            v++; // 行カウント
        }
    } else if (chr == "\n") { // 改行
            hps -= fontsize * lineheight; // 改行
            vps = vps_base; // 行頭へ
            c= 0;
            v++;
        } else {
            vps = vps_base + (fontsize * c); // 文字の描画位置
        }
    if  (!chr == "\n") {
        layer1Ctx.fillText(chr, hps, vps ); // 改行以外であれば文字を入力
    }
    c++;
}