理系ジン

しばらくPythonに力を入れる予定です。

Canvasについて

概要

Canvasはブラウザで描画するためのHTML5JavaScript APIです。

以下でポイントを簡単に説明します。ソースのコメントにも説明がありますので見て下さい。

今回の図は全て画像ファイルではなくCanvasで描画しています。ブラウザの図上で右クリックするとpngファイルとして保存できるようです。

はてなブログでのCanvasの描画

はてなブログは本文にHTMLを使えます。はてなブログの本文に書いたHTMLはbody要素の内部に書かれます。

Canvasの準備

Canvasを実行するには、描画をおこなうcanvas要素を配置し、script要素でcanvas要素を取得し、canvas要素からCanvasのコンテキストを取得し、CanvasAPIにより描画をおこないます。

JavaScriptは、script要素にべた書きしたり、即時関数(function(){...})()などとして呼び出せばいいです。べた書きした場合、複数script要素内でも同じ変数が使われます。

canvas要素は、JavaScriptから要素を特定できるようにid属性を指定します。他にwidthheightstyle属性等を指定します。

Canvasのコンテキストは、左上が原点(0,0)で、右がX軸方向で下がY軸方向となり、数学でよく使われる座標系とは、原点の位置が異なりY軸の向きが反対です。

Canvas未対応のブラウザで表示

<canvas id="smp1" style="border:1px solid;" width="240" height="120">
Canvas未対応のブラウザで表示</canvas>
<script language="javascript" type="text/javascript">
var cv = document.getElementById("smp1"); // canvas要素取得
var cx = cv.getContext("2d"); // canvas要素からコンテキスト取得
// 処理
cx.textBaseline = "top";
cx.textAlign = "left";
cx.fillText("(0,0)",0,0);
cx.textBaseline = "bottom";
cx.textAlign = "end";
cx.fillText("(240,120)",240,120);
</script>

(2014/10/29追記)幅240px高さ120pxで、左上の座標が(0,0)で右下の座標が(240,120)はおかしいのではないかと思いますが、以下に実験したところ、1ずつ座標を内側にすると確かに角に隙間ができているので正しいようです。Canvasの座標はピクセルをキッチリ指すというより、連続的な座標で計算しピクセルに描画しているようです(SVGやTikZではまだ確認していません)。

Canvas未対応のブラウザで表示

<canvas id="test" width="240" height="120">
Canvas未対応のブラウザで表示</canvas>
<script language="javascript" type="text/javascript">
var cv = document.getElementById("test");
var cx = cv.getContext("2d");
// 四角
cx.beginPath(); // パスを開始
cx.moveTo(0,0); // 始点を指定
cx.lineTo(240,0); // 前の点から、指定した点へ線を引く
cx.lineTo(240,120);
cx.lineTo(0,120);
cx.closePath(); // パスを閉じる
cx.fillStyle = "#48d846"; // 四角の塗りつぶし色の設定
cx.fill(); // 四角の描画
// 枠
cx.beginPath(); // パスを開始
cx.moveTo(1,1); // 始点を指定
cx.lineTo(239,1); // 前の点から、指定した点へ線を引く
cx.lineTo(239,119);
cx.lineTo(1,119);
cx.closePath(); // パスを閉じる
cx.lineWidth = 1; // 線の幅を設定
cx.stroke(); // 枠の線の描画
</script>

CSSカラーによる色指定

Canvasの色指定は、CSSカラーによりおこないます。次のいずれかの様に行います。

  • 色名指定:"blue"
  • 16進指定:"#0000FF""#00F"
  • RGB指定:"rgb(0, 0, 255)""rgba(0, 0, 255, 1)"
  • HSL指定:"hsl(240, 100%, 50%)""hsla(240, 100%, 50%, 1)"

RGB指定とHSL指定の最後のa不透明度を表し、1で不透明、0で透明となります。

色名は、基本色名16色("red"等)と拡張色名147色("mediumblue"等)を使うようです。

16進指定では、RGBそれぞれ、#00(0%)、#33(20%)、#66(40%)、#99(60%)、#cc(80%)、#ff(100%)を組み合わせてできる216色が環境に依存しにくいWebセーフカラーと呼ばれています。

詳細は、参考資料を見て下さい。

また、Canvasでは描画をおこなっていない場所は、黒の透明"rgb(0, 0, 0, 0)"となっています。

CSSフォントによるフォント指定とテキスト描画

Canvasでは、CSSfontプロパティと同じ方法でテキストのフォントを指定します。

具体的には次の値をスペース区切りで指定します。

font-style、 font-variant、 font-weight(ここまで順不同)、 font-size(必須)、 line-height、 font-family(必須)

font-familyでは複数のフォント名を指定でき、左から優先して使われ、該当フォントがインストールされていなければデフォルトのフォントが利用されます。フォント名の指定はアルファベットで指定しないと上手く行かない場合があります。フォント名にスペースがある場合は、フォント名を'"で囲む必要があります。

詳細は、参考資料のフォント関連のものを見て下さい。

パソコンにインストールされているフォントの確認は、Macでは標準添付のFont Book.appでできます。Windowsでは、標準では良いフォント管理ソフトが無いようなので、NexusFontを使うのが一般的なようです。

日本語フォントはWindowsMacLinuxで殆ど異なっているので、それぞれの環境で使える似たフォントを指定するか、フォントをアプリ等にインストールする(してもらう)か、Webフォントを利用する必要があるようです。

Webフォントはサーバーやアプリ等に配置して利用するようですが、Google Fontsはインストールせずに使えます。Google Fontsは日本語には対応していないようです。

具体的には、Google Fontsのサイトにあるフォントリスト(現在651種類)から好きなフォントの[Quick-use]ボタンをクリックして、表示されたlink要素をHTMLに入れれば、そのフォントが利用できるようになります。

Webフォントの一般的な使い方は参考資料をご覧ください。

テキストの描画については、Canvasリファレンス - HTML5.JPの一番下のテキストのfont、textAlign、textBaselineをご覧下さい。

フォントの指定とGoogle Fontsの利用例

Canvas未対応のブラウザで表示

<link href='http://fonts.googleapis.com/css?family=Audiowide' rel='stylesheet' type='text/css'>
<link href='http://fonts.googleapis.com/css?family=Roboto' rel='stylesheet' type='text/css'>
<canvas id="fonttest" style="border:1px solid;" width="280" height="120">
Canvas未対応のブラウザで表示</canvas>
<script language="javascript" type="text/javascript">
var cv = document.getElementById("fonttest");
var cx = cv.getContext("2d");
//
cx.textBaseline = "top"; // テキストのベースラインを上端に設定
cx.textAlign = "left"; // テキストのアラインメントを左端に設定
// font-sizeと(Mac、Windows、Linux用の)font-familyを設定
cx.font = "20px 'Hiragino Mincho Pro','MS Mincho','TakaoMincho'";
cx.fillText("インストールされている明朝",0,0); // テキストの描画、文字列と座標(0,0)
cx.font = "20px 'Audiowide'"; // Google Font、Audiowideを設定
cx.fillText("Google FontsのAudiowide",0,40);
cx.font = "20px 'Roboto'"; // Google Font、Robotoを設定
cx.fillText("Google FontsのRoboto",0,80);
</script>

説明と例

Canvasの解説は、Canvas - HTL5.JPを見て頂くのがいいと思います。

円弧の描画について少し補足します。arcメソッドにより、中心と半径をもとにして、開始角(ラジアン単位)から終了角まで、反時計回り(または時計回り)に、円弧のパスが作られます。数学でよく使われる座標系とは、角0が右方向なのは同じですが、角の向きは反対向きになっているので注意が必要です。

理系ジンのアイコンを、シンプルな化学式風に描いてみました。説明はソースのコメントを見て下さい。

Canvas未対応のブラウザで表示

<canvas id="rz" style="border:1px solid;"  width="240" height="240">
Canvas未対応のブラウザで表示</canvas>
<script language="javascript" type="text/javascript">
var cv = document.getElementById("rz");
var cx = cv.getContext("2d");
// 処理
// 影
cx.shadowBlur = 10; // 影のぼかしのサイズを設定
cx.shadowOffsetX = 10; // 影の右方向のオフセットを設定
cx.shadowOffsetY = 10; // 影の下方向のオフセットを設定
cx.shadowColor = "#333"; // 影の色を設定
// 枠
cx.beginPath(); // パスを開始
cx.moveTo(20,20); // 始点を指定
cx.lineTo(220,20); // 前の点から、指定した点へ線を引く
cx.lineTo(220,220);
cx.lineTo(20,220);
cx.closePath(); // パスを閉じる
cx.lineWidth = 20; // 線の幅を設定
cx.strokeStyle = "#999"; // 線の色を設定
// 線の端のスタイルを設定:butt(無し、default)、round(丸)、square(四角)
cx.lineCap = "round";
// 線の交わりのスタイルを設定:bevel(無し)、round(丸)、miter(尖る、default)
cx.lineJoin = "round";
cx.stroke(); // 枠の線の描画
// 影を無しに
cx.shadowBlur = 0;
cx.shadowOffsetX = 0;
cx.shadowOffsetY = 0;
cx.shadowColor = "#FFF";
// 枠の内側の白い四角
cx.fillStyle = "#FFF"; // 四角の塗りつぶし色の設定
cx.fill(); // 枠の内側の白い四角の描画
// 理の文字
cx.fillStyle = "#999"; // テキストの塗りつぶし色の設定
cx.font = "200px 'Hiragino Kaku Gothic Pro','MS UI Gothic','TakaoGothic'";
cx.textBaseline = "top";
cx.textAlign = "left";
cx.fillText("理",20,20);
</script>

(緑(#48d846)と白(f0f0f0)を使ったアイコンに変更、2014/10/29)

(黒(#202020)と透明を使ったアイコンに変更、2014/11/12)

<script language="javascript" type="text/javascript">
function manipulateImage(cx, top, left, width, height){
  var imageData = cx.getImageData(top, left, width, height);
  var data = imageData.data;
  for (var x = top; x < width; ++x) {
    for (var y = left; y < height; ++y) {
      var index = (x + y * width) * 4;
      console.log(":" + index + ":" +data[index + 3]);
      // 透明の黒、白い分だけ透明に
      if(data[index + 0] > 32){ // #20 = 32
        data[index + 3] = 255 - data[index + 0]; // A
        data[index + 0] = 0; // R
        data[index + 1] = 0; // G
        data[index + 2] = 0; // B
      };
    };
  };
  imageData.data = data;
  cx.putImageData(imageData, top, left);
}
</script>

<canvas id="ghrz420"  width="420" height="420">
Canvas未対応のブラウザで表示</canvas>
<script language="javascript" type="text/javascript">
var cv = document.getElementById("ghrz420");
var cx = cv.getContext("2d");
// 処理
// 枠
cx.beginPath(); // パスを開始
cx.moveTo(52,52); // 始点を指定
cx.lineTo(368,52); // 前の点から、指定した点へ線を引く
cx.lineTo(368,368);
cx.lineTo(52,368);
cx.closePath(); // パスを閉じる
cx.lineWidth = 104; // 線の幅を設定
cx.strokeStyle = "#202020"; // 線の色を設定
// 線の端のスタイルを設定:butt(無し、default)、round(丸)、square(四角)
cx.lineCap = "round";
// 線の交わりのスタイルを設定:bevel(無し)、round(丸)、miter(尖る、default)
cx.lineJoin = "round";
cx.stroke(); // 枠の線の描画
// 枠の内側の四角
cx.fillStyle = "#202020"; // 四角の塗りつぶし色の設定
cx.fill(); // 枠の内側の四角の描画
// 理の文字
cx.fillStyle = "#ffffff"; // テキストの塗りつぶし色の設定
cx.font = "420px 'Hiragino Kaku Gothic Pro','MS UI Gothic','TakaoGothic'";
cx.textBaseline = "top";
cx.textAlign = "left";
cx.fillText("理",0,0);
manipulateImage(cx, 0, 0, 420, 420);
</script>

MarkdownエディタのCanvas対応

一部のMarkdownエディタのCanvas対応を調べました。

MouとMacDownでは、Canvasが正常に表示されました。

AtomのMarkdown Previewでは、canvas要素は表示されます。script要素等は無効になるので描画はされません。(20141004追記)

Kobitoでは、タイトルになる一行目にcanvas要素を書いた時だけ、Canvasの描画処理がおこなわれるようです。

StackEditでは、殆どのHTML要素は無視されてしまい、Canvasは全く使えません。

今回はMacDownで文章を作成しました。Canvasの描画をするとすぐに結果が見られて便利でした。今回公開時に一度記事が消えてしまいましたのでMacDownを使っていなかったら危なかったです。

理系ジンの意見

Canvasで比較的容易に図を描けます。数学の座標系とは、原点の位置が異なりY軸方向の向きが反対です。Canvasだけで数式のグラフを描画するのは難しそうです。グラフ描画に関しては、いずれライブラリ等を調べたいと思います。

今回はCanvasの詳細な解説を書いていましたが、結局HTML5.JPの解説で十分だと気が付き参照させて頂いて簡単に説明するようにしました。

フォントはHTML5アプリには特に重要であると考えられます。必要に応じて更に調べたいと思います。

予定

次回は、SVGとそのツールの記事を予定しています。週に1回は更新したいと思います。

参考資料

Canvas

Canvasの解説は、HTML5.JPのCanvasの解説で十分だと思われます。

CSSカラー・CSSフォント

Webフォント