フキダシの表示
第1回の「Canvasをテクスチャとして読み込み」の応用です。「Canvas」をテクスチャにできるということは、「Canvas」の描画機能で生成した画像を自由にテクスチャに適用できるということです。この方法を使えば、文字列やその背景をテクスチャにできます。この仕組みを使い、フキダシを作成します。
ここから先は、「Canvas」の描画処理の話になります。フキダシを作る際のコツは、「Canvas」の「2d Context」の「textBaseline」属性に、「"middle"」を設定することです。
「Canvas」の文字列描画の仕様は、英語を描画することを想定して作られています。そのため、文字のベースラインのデフォルトは 「"alphabetic"」となっており、アルファベットを書く時の補助線の位置が基準になっています。この線に合わせて配置すると、日本語では問題が生じます。
この文字のベースラインを、日本語の文字の中央位置に指定すれば、上下のフキダシの枠との距離が、上端と下端で等しくなります。
以下、角丸四角でフキダシを作るサンプルとして「crocro.bc.viewFukidasi.js」を掲載します。
//= サンプル:フキダシの表示
//== フキダシの表示
crocro.bc.viewFukidasi = function() {
// 変数の初期化
var d3 = crocro.bc.d3; // 3D格納用
var plt;
// 要素の作成と格納
plt = crocro.bc.mkFukidasi(true); // ポリゴン範囲付き
plt.position.x = -100;
d3.scene.add(plt);
plt = crocro.bc.mkFukidasi(false); // ポリゴン範囲なし
plt.position.x = 100;
plt.position.y = -100;
plt.position.z = 2;
d3.scene.add(plt);
crocro.bc.render();
};
//== 画像ポリゴンの作成
crocro.bc.mkFukidasi = function(isDrwBck) {
// キャンバスの作成
var w = 1024;
var h = 1024;
var cnvs = $('<canvas width=' + w + ' height=' + h + '>').get(0);
var cntxt = cnvs.getContext("2d");
// フキダシ描画
crocro.bc.drwFukidasi(cntxt, w, h, isDrwBck);
// テクスチャの作成
var texture = new THREE.Texture(cnvs);
texture.needsUpdate = true; // 画像読み込み後の更新を指定
// マテリアルとメッシュの作成
var material = new THREE.MeshBasicMaterial({map: texture});
// 透明部分の処理
if (! isDrwBck) {
material.transparent = true; // 透明を有効
material.alphaTest = 0.5; // これを追加するときちんと表示される
}
var mesh = new THREE.Mesh(
new THREE.PlaneGeometry(500, 500, 4, 4),
material
);
// メッシュを戻して終了
return mesh;
};
//== フキダシ描画
crocro.bc.drwFukidasi = function(cntxt, cnvsW, cnvsH, isDrwBck) {
// テクスチャ サイズが分かるように背景を描画
if (isDrwBck) {
cntxt.fillStyle = "#ff0000";
cntxt.globalAlpha = 0.5;
cntxt.fillRect(0, 0, cnvsW, cnvsH);
cntxt.globalAlpha = 1;
}
// 表示する文字列
var strArr = "abcdefg\nあいうえおかきくけこ\n聖徳太子".split("\n");
// 文字列描画の初期化
var fntSz = 64;
cntxt.font = fntSz + 'px ""';
var mrgnX = fntSz;
var mrgnY = fntSz * 0.5;
var lnH = fntSz * 1.4;
// 文字列の最大幅を求める
var maxW = 0;
for (var i = 0; i < strArr.length; i ++) {
var w = cntxt.measureText(strArr[i]).width;
if (w > maxW) maxW = w;
}
// フキダシのサイズを求める
var fkdsW = maxW + mrgnX * 2;
var fkdsH = strArr.length * lnH + mrgnY * 2;
var fkdsX = (cnvsW - fkdsW) / 2;
var fkdsY = (cnvsH - fkdsH) / 2;
var fkdsR = fntSz;
// 角丸矩形の描画
crocro.bc.pathRoundRect(cntxt, fkdsX, fkdsY, fkdsW, fkdsH, fkdsR);
cntxt.fillStyle = "#ffffff";
cntxt.fill(); // 塗り潰し
cntxt.lineWidth = 10;
cntxt.strokeStyle = "#000000";
cntxt.stroke(); // 縁の描画
// 文字列設定の初期化
cntxt.textBaseline = "middle"; // 中央
cntxt.fillStyle = "#000000";
var x = fkdsX + mrgnX;
var y = fkdsY + mrgnY + lnH / 2;
// 文字列の描画
for (var i = 0; i < strArr.length; i ++) {
cntxt.fillText(strArr[i], x, y);
y += lnH;
}
}
//== 角丸矩形
crocro.bc.pathRoundRect = function(cntxt, x, y, w, h, r) {
var pi = Math.PI;
cntxt.beginPath();
cntxt.arc(x + r, y + r, r, -pi, -pi / 2, false);
cntxt.arc(x + w - r, y + r, r, -pi / 2, 0, false);
cntxt.arc(x + w - r, y + h - r, r, 0, pi / 2, false);
cntxt.arc(x + r, y + h - r, r, pi / 2, pi, false);
cntxt.closePath();
}
