WebOS Goodies

WebOS の未来を模索する、ゲームプログラマあがりの Web 開発者のブログ。

WebOS Goodies へようこそ! WebOS はインターネットの未来形。あらゆる Web サイトが繋がり、共有し、協力して創り上げる、ひとつの巨大な情報システムです。そこでは、あらゆる情報がネットワーク上に蓄積され、我々はいつでも、どこからでも、多彩なデバイスを使ってそれらにアクセスできます。 WebOS Goodies は、さまざまな情報提供やツール開発を通して、そんな世界の実現に少しでも貢献するべく活動していきます。
Subscribe       

canvas : 描画スタイルの指定(グラデーション編)

はい、本日は前回の続きで、 canvas のグラデーション描画をご紹介します。 2 回に分けてもまだ文字数が多すぎると言われるので(´Д`;、今回のソースコードは色分けなしです。申し訳ありません。 canvas のグラデーション指定はけっこう多機能で、通常の線形グラデーションに加えて円形グラデーションもサポートしており、さらにグラデーションの通過色も自由に指定できます。指定方法の基本的な考え方はパターンと同じで、まずグラデーションパラメータを格納したオブジェクトを作成し、それを strokeStyle もしくは fillStyle 属性に設定することで描画できます。それでは、順にご紹介していきましょう。

線形グラデーション

最初は線形グラデーションです。開始座標と終了座標を指定し、それらを結ぶ線分と平行にグラデーションをかけます。線分の外側の領域はそれぞれの端点の色で塗り潰されます。グラデーションの方向・範囲はどんな角度にも指定できますので、後述の通過色(カラーストップ)指定を組み合わせれば、かなりバラエティー豊かなグラデーション表現が可能です。というところで、サンプルです。

canvas : 線形グラデーションのサンプル
 座標
開始 ,
終了 ,

ソースコードは以下のようになっています。

<script type="text/javascript">
var page = new Object; // 名前空間オブジェクト

page.drawLinearGradation = function() // window.onload から呼び出される
{
  var canvas = document.getElementById("page_canvas_linear");
  if(canvas.getContext)
  {
    var x0 = document.getElementById("page_linear_x0").value;
    var y0 = document.getElementById("page_linear_y0").value;
    var c0 = document.getElementById("page_linear_c0").value;
    var x1 = document.getElementById("page_linear_x1").value;
    var y1 = document.getElementById("page_linear_y1").value;
    var c1 = document.getElementById("page_linear_c1").value;

    var ctx = canvas.getContext("2d");
    var grd = ctx.createLinearGradient(x0, y0, x1, y1);
    grd.addColorStop(0, c0);
    grd.addColorStop(1, c1);
    ctx.clearRect(0, 0, 200, 200);
    ctx.fillStyle = grd;
    ctx.fillRect(0, 0, 200, 200);
  }
};
</script>

<canvas id="page_canvas_linear" width="200" height="200" style="position:relative;"></canvas><br/>

<table>
<tr>
<td>&nbsp</td><th>座標</th><th>色</th>
</tr>
<tr>
<th>開始</th>
<td><input id="page_linear_x0" type="text" value="0" onkeyup="page.drawLinearGradation();" />,
    <input id="page_linear_y0" type="text" value="0" onkeyup="page.drawLinearGradation();" /></td>
<td><input id="page_linear_c0" type="text" value="white" onkeyup="paeg.drawLinearGradation();" /></td>
</tr>
<tr>
<th>終了</th>
<td><input id="page_linear_x1" type="text" value="0" onkeyup="page.drawLinearGradation();" />,
    <input id="page_linear_y1" type="text" value="200" onkeyup="page.drawLinearGradation();" /></td>
<td><input id="page_linear_c1" type="text" value="black" onkeyup="page.drawLinearGradation();" /></td>
</tr>
</table>

線形グラデーションオブジェクトを作成するには前述のとおり createLinearGradient メソッドを使用します。このメソッドの書式は以下のようになります。

createLinearGradient(<開始X座標>, <開始Y座標>,
                     <終了X座標>, <終了Y座標>);

二組の座標を使ってグラデーションの方向、範囲を指定します。それぞれの効果は上のサンプルでお確かめください。グラデーションの色は createLinearGradient で作成したオブジェクトのメソッドである addColorStop で指定します。これに関しては後述します。

円形グラデーション

次は円形グラデーションです。こちらはけっこう面白い指定の仕方をします。開始円と終了円の 2 つの円(の中心座標と半径)を指定し、開始円の円周から終了円の円周に向かってグラデーションがかかります。中心座標をうまくずらすことで、立体的な球や彗星のような表現ができて楽しいです。こちらもサンプルを用意しましたのでお試しください。

canvas : 円形グラデーションのサンプル
 座標半径
開始 ,
終了 ,

続いて、ソースコードです。

<script type="text/javascript">
var page = new Object(); // 名前空間オブジェクト

page.drawRadialGradation = function() // window.onload から呼び出される
{
  var canvas = document.getElementById("page_canvas_radial");
  if(canvas.getContext)
  {
    var x0 = document.getElementById("page_radial_x0").value;
    var y0 = document.getElementById("page_radial_y0").value;
    var r0 = document.getElementById("page_radial_r0").value;
    var c0 = document.getElementById("page_radial_c0").value;
    var x1 = document.getElementById("page_radial_x1").value;
    var y1 = document.getElementById("page_radial_y1").value;
    var r1 = document.getElementById("page_radial_r1").value;
    var c1 = document.getElementById("page_radial_c1").value;

    var ctx = canvas.getContext("2d");
    var grd = ctx.createRadialGradient(x0, y0, r0, x1, y1, r1);
    grd.addColorStop(0, c0);
    grd.addColorStop(1, c1);
    ctx.clearRect(0, 0, 200, 200);
    ctx.fillStyle = grd;
    ctx.fillRect(0, 0, 200, 200);
  }
};
</script>

<canvas id="page_canvas_radial" width="200" height="200" style="position:relative;"></canvas><br/>

<table>
<tr>
<td>&nbsp</td><th>座標</th><th>半径</th><th>色</th>
</tr>
<tr>
<th>開始</th>
<td><input id="page_radial_x0" type="text" value="100" onkeyup="page.drawRadialGradation();" />,
    <input id="page_radial_y0" type="text" value="100" onkeyup="page.drawRadialGradation();" /></td>
<td><input id="page_radial_r0" type="text" value="10" onkeyup="page.drawRadialGradation();" /></td>
<td><input id="page_radial_c0" type="text" value="white" onkeyup="page.drawRadialGradation();" /></td>
</tr>
<tr>
<th>終了</th>
<td><input id="page_radial_x1" type="text" value="100" onkeyup="page.drawRadialGradation();" />,
    <input id="page_radial_y1" type="text" value="100" onkeyup="page.drawRadialGradation();" /></td>
<td><input id="page_radial_r1" type="text" value="100" onkeyup="page.drawRadialGradation();" /></td>
<td><input id="page_radial_c1" type="text" value="black" onkeyup="page.drawRadialGradation();" /></td>
</tr>
</table>

円形グラデーションオブジェクトを作成するには前述のとおり createLinearGradient メソッドを使用します。このメソッドの書式は以下のようになります。

createRadialGradient(<開始円中心X座標>, <開始円中心Y座標>, <開始円半径>
                     <終了円中心X座標>, <終了円中心Y座標>, <終了円半径>);

原則として、開始円は終了円の内側になければなりません。開始円が終了円からはみ出た場合の処理はブラウザによって違うようですが、いずれも正確には描画されません。グラデーションの色は線形グラデーションと同様に createRadialGradient メソッドで作成したオブジェクトの addColorStop で指定します。

グラデーションの色指定

canvas のグラデーション描画では、開始・終了の色以外に任意の数の通過点の色を指定できます。これらの色は createLinearGradient, もしくは createRadialGradient メソッドが返したオブジェクトの addColorStop メソッドで指定できます。書式は以下のようになっています。

addColorStop(<位置>, <色>);

位置
色を指定する位置を、開始位置を 0.0、終了位置を 1.0 とした浮動小数点値で指定する。
指定した位置の色を指定する。使える表現は strokeStyle などに単色を指定する場合と同じ(描画スタイルの指定(前編)を参照)。

以下、サンプルを用意しましたのでお確かめください。

canvas : グラデーションの通過色指定のサンプル
 位置
ColorStop1 ,
ColorStop2 ,
ColorStop3 ,
ColorStop4 ,

このサンプルでは通過色を 4 つまでしか指定できませんが、実際には addColorStop を何度も呼び出すことで任意の数の通過色を指定できます。また、同じ位置に 2 つの通過色を指定すると、不連続なグラデーション(?)を表現できます。例えば上記のサンプルで ColorStop2 と ColorStop3 の位置をともに 0.5 にし、別々の色を設定すれば、グラデーションの中央で色が分かれるのが確認できると思います。

サンプルのソースは以下のようになっています。

var page = new Object(); // 名前空間オブジェクト

<script type="text/javascript">
page.drawColorStop = function() // window.onload から呼び出される
{
  var canvas = document.getElementById("page_canvas_colorstop");
  if(canvas.getContext)
  {
    var p1 = document.getElementById("page_colorstop1_p").value;
    var c1 = document.getElementById("page_colorstop1_c").value;
    var p2 = document.getElementById("page_colorstop2_p").value;
    var c2 = document.getElementById("page_colorstop2_c").value;
    var p3 = document.getElementById("page_colorstop3_p").value;
    var c3 = document.getElementById("page_colorstop3_c").value;
    var p4 = document.getElementById("page_colorstop4_p").value;
    var c4 = document.getElementById("page_colorstop4_c").value;

    var ctx = canvas.getContext("2d");
    var grd = ctx.createLinearGradient(0, 0, 200, 0);
    grd.addColorStop(p1, c1);
    grd.addColorStop(p2, c2);
    grd.addColorStop(p3, c3);
    grd.addColorStop(p4, c4);
    ctx.clearRect(0, 0, 200, 30);
    ctx.fillStyle = grd;
    ctx.fillRect(0, 0, 200, 30);
  }
};
</script>

<canvas id="page_canvas_colorstop" width="200" height="30" style="position:relative;"></canvas><br/>

<table>
<tr>
<td>&nbsp</td><th>位置</th><th>色</th>
</tr>
<tr>
<th>ColorStop1</th>
<td><input id="page_colorstop1_p" type="text" value="0.0" onkeyup="page.drawColorStop();" />,
<td><input id="page_colorstop1_c" type="text" value="red" onkeyup="page.drawColorStop();" /></td>
</tr>
<tr>
<th>ColorStop2</th>
<td><input id="page_colorstop2_p" type="text" value="0.3" onkeyup="page.drawColorStop();" />,
<td><input id="page_colorstop2_c" type="text" value="green" onkeyup="page.drawColorStop();" /></td>
</tr>
<tr>
<th>ColorStop3</th>
<td><input id="page_colorstop3_p" type="text" value="0.6" onkeyup="page.drawColorStop();" />,
<td><input id="page_colorstop3_c" type="text" value="blue" onkeyup="page.drawColorStop();" /></td>
</tr>
<tr>
<th>ColorStop4</th>
<td><input id="page_colorstop4_p" type="text" value="1.0" onkeyup="page.drawColorStop();" />,
<td><input id="page_colorstop4_c" type="text" value="white" onkeyup="page.drawColorStop();" /></td>
</tr>
</table>

単純に水平の線形グラデーションを作成し、指定されたパラメータで 4 つの通過色を追加しているだけです。 addColorStopcanvas のコンテキストではなく、 createLinearGradient メソッドが返したオブジェクトのメソッドであることに注意してください。

ブラウザごとの非互換性

グラデーション描画もオプショナルな機能であるため、ブラウザごとに実装に細かな違いがあります。対象を OperaFirefox に限った場合、もっとも大きな相違点はグラデーション範囲外の扱いです。 Opera は範囲外を完全透明として扱いますが、 Firefox は 0.0 または 1.0 の色を延長して描画します。 Web Applications 1.0 のドラフト では「ColorStop が指定されていない場合は透明な黒として扱う」と規定されていて、これがグラデーション範囲外にも適用されるなら Opera の仕様が正しいことになりますが、明らかに Firefox の仕様のほうが扱いやすいですね。できれば Firefox 仕様で統一してほしいところです。

なお、IE6 + ExplorerCanvas の環境では、かなり中途半端なサポートになっているようです。線形グラデーションは常に垂直で描画範囲の上端から下端までのグラデーションになり、両端の色しか指定できません。また、円形グラデーションはよくわからない効果になります。 IE6 ではグラデーションは使えないと思っておいたほうが良いでしょう。

以上、基本編画像パターン編、そして今回のグラデーション編と 3 回に分けて canvas の描画スタイル指定をご紹介しました。描画スタイルの指定に関しては網羅できているはずです。しかし、 canvas の表現力は描画スタイルだけで賄われているわけではありません。座標変換や合成などを組み合わせることによって、可能性がさらに広がります。ということで、まだまだ canvas シリーズは続きますよ!進みが遅くて申し訳ありませんが、どうかお付き合いくださいませ m(_ _)m

関連記事

この記事にコメントする

Recommendations
Books
「Closure Library」の入門書です。
詳しくはこちらの記事をどうぞ!
Categories
Recent Articles