Edited at
Quad incDay 21

JSでカーニングエンジンを作ってみる 2回目

More than 3 years have passed since last update.

Fallout4面白いですね。日本語の行間とか最悪ですね。読みづらすぎますね。

前回はとりあえず実現可能性を探っていましたが、今回は本格的に機能を検討したいとお思います。


カーニングデータを分離

エンジン部分とデータを分離しておいた方が、Fontごとにデータを作ることができて便利ですよね。JSONも良いですが、今回は別のJSファイルに記述します。

実際に使う場合はconcatしても良いと思います。今回はヒラギノフォント用で進めます。

JSファイル名を「PIPKerningHiragino.js」としてます。

JSのクラス名は「PIPKergninTable」、これはすべてのフォントで同じです。ファイル名で識別します。


PIPKerningHiragino.js

(function(global){

"use strict";

// モジュール設定
global["pipboy"] = global.pipboy || {};
var module = global.pipboy;

module.PIPKerningTable = function(){

};

})((this || 0).self || global);



行頭データを追加する

まずは行頭ぞろえ用のデータを検討します。

"「"

"("

は文字の半分だけ内側に入ってしまいます。これ毎回きになりますよね。CSSではネガティブマージンで調整することができます。

クラス変数にマージンの値をもたせます。


PIPKerningHiragino.js

// Beginning of Line (行頭)

module.PIPKerningTable.BOL = {
'': '-0.5',
'': '-0.5'
}

これで行頭ぞろえの準備はできたので、一旦エンジン側に移ります。行頭以外のカーニングは、エンジンの基本的な実装ができてから再度設定します。


カーニングエンジンの設計

カーニングを適用する方法はシンプルにCSSのクラス設定のみにします。

カーニング指定するDOMに「pip-kerning」クラスを指定してください。あとは自動的に設定されると便利ですね。

<h1 class="pip-kerning">「見出し1」です。classにpip-kerningを設定</h1>

自動的に実装するので、


  • DOM要素を抽出

  • spanタグで一文字づつ囲みカーニング設定

  • 行頭設定

の順番で検討してみます。


PIPKerningクラスを作る

カーニングエンジンJSを作ります。「PIPKerning.js」とします。クラス名も「PIPKerning」です。

module.PIPKerning = function(){

// プロパティなど
};

まずは「pip-kerning」でDOM要素を抽出します。

var $elements = document.getElementsByClassName('pip-kerning');

これでHTML上のすべての要素を取得しました。$elementsは配列です。

各要素をそれぞれ処理します。

var $elements = document.getElementsByClassName('pip-kerning');

var len = $elements.length;
for(var i = 0; i < len; ++i){
var str = $elements[i].innerHTML;
var newHTML = this.__define(str); // __defineはプライベートメソッド
$elements[i].innerHTML = newHTML;
}

innerHTMLでテキストを抜き出し、this.defineでspanタグ実装します。最後に新しいhtmlを追加します。

次にdefineの実装をします。

処理部分を抜き出すのこんな感じです。文字をバラバラにしてspanで囲むだけです。カーニング設定はまだです。

ただし、インラインスタイルで「inline-block」を必ず指定してください。これは行頭ぞろえで使います。


PIPKerning.js

var characters = str.split('');

var table = module.PIPKerningTable.table;
var len = characters.length;
var output = "";
for(var i = 0; i < len; ++i){
output += '<span style="display: inline-block;">' + characters[i] + '</span>';
}
return output;


行頭ぞろえ

次に行頭ぞろえの処理を実装します。行頭はウィンドウサイズで変わる可能性があります。(デバイスサイズ依存)

これは面倒くさいですね。

今回はカーニング領域のサイズを取得し、各文字のサイズと領域のサイズを比較し行頭を見つけます。


PIPKerning.js

// 行頭処理

var $childs = $elements[i].getElementsByTagName("span"); // 各文字(1文字)
var rowWidth = $elements[i].clientWidth;
var currentRowWidth = 0; // 行
for(var j = 0; j < $childs.length; ++j){
currentRowWidth += $childs[j].clientWidth; // 行の横幅を加算していく。文字数が増えれば大きくなる
if(currentRowWidth >= rowWidth || j == 0) { // 行の幅と、最初の一文字目を行頭と判定
var bol = PIPKerningTable.BOL[$childs[j].innerHTML] + 'em';
if(bol) {
$childs[j].style.marginLeft = bol;
trace($childs[j].style.marginLeft)
}
currentRowWidth = 0;
}
}

行の横幅はclientWidthで取得し、forループの中で各文字のサイズを調べます。inline-block設定がないと、spanの横幅を取得できません。ご注意ください。

これで行頭ぞろえが実現できました! 

ブラウザのリサイズは上の処理を再度実行すればできますね。その辺は次回に...

今回はここまでです。つぎは本題の文字ごとのカーニング実装です。