キャンバスのタイポグラフィ効果

プレゼンターの自己紹介

私が気に入ったのは、2006 年の Firefox v2.0 のリリース時に <canvas> でした。Ajaxian の記事で変換行列について読んだことがきっかけで、初めての <canvas> ウェブアプリ Color Sphere(2007)を作成しました。それが、色とグラフィック プリミティブの世界に没頭し、ブラウザで「Paint より優れている」アプリケーションを作成する取り組みの一環として、スケッチパッド(2007 ~ 2008 年)が生まれるきっかけとなりました。 こうした試行の結果、私は長年の友人である Charles Pritchard と共にスタートアップ Mugtug を立ち上げました。ダークルームは HTML5 <canvas> で開発中です。Darkroom は、ピクセルベースのフィルタの機能とベクターベースのタイポグラフィや描画を組み合わせた、非破壊的な写真共有アプリです。

はじめに

キャンバス バナーのグラフィック。

<canvas> を使用すると、Javascript プログラマは画面上のベクトルピクセル(モニターの視覚的な構成)を完全に制御できます。

次の例では、<canvas> であまり注目されていない領域、テキスト効果の作成について説明します。<canvas> で作成できるテキスト効果は多種多様です。これらのデモでは、その実現方法のサブセクションを取り上げています。この記事では「テキスト」を扱っていますが、これらのメソッドはあらゆるベクター オブジェクトに適用できるため、ゲームやその他のアプリケーションで魅力的なビジュアルを作成できます。

<canvas> のテキスト シャドウ。
<canvas>CSS のようなテキスト効果、クリッピング マスクの作成、<canvas> での指標の検索、シャドウ プロパティの使用。
ネオンレインボー、ゼブラ リフレクション - チェーン エフェクト。
globalCompositeOperation、createLinearGradient、createPattern を使用した <canvas> の例での Photoshop のようなテキスト効果。
<canvas> の内側と外側のシャドウ
あまり知られていない機能を明らかにする。時計回りと反時計回りの曲線を使用して、逆のドロップ シャドウ(内側のシャドウ)を作成します。
残像 - 生成効果。
<canvas>
生成ベースのテキスト効果。hsl() のカラーサイクリングと window.requestAnimationFrame を使用して動きを表現します。

Canvas のテキスト シャドウ

CSS3 仕様に追加された機能(border-radius、web-gradients など)の中で、私が特に気に入っているのはシャドウを作成する機能です。CSS と <canvas> シャドウの違いを理解することが重要です。具体的には、次の点に注意してください。

CSS では 2 つのメソッドを使用します。box-shadow は div、span などのボックス要素用、text-shadow はテキスト コンテンツ用です。

<canvas> には 1 種類のシャドウがあり、ctx.moveTo、ctx.lineTo、ctx.bezierCurveTo、ctx.quadradicCurveTo、ctx.arc、ctx.rect、ctx.fillText、ctx.strokeText などのすべてのベクター オブジェクトに使用されます。<canvas> でシャドウを作成するには、次の 4 つのプロパティを使用します。

ctx.shadowColor = "red" // string
シャドウの色。RGB、RGBA、HSL、HEX などの入力が有効です。
ctx.shadowOffsetX = 0; // 整数
テキストに対する影の水平方向の距離。
ctx.shadowOffsetY = 0; // 整数
テキストに対するシャドウの垂直距離。
ctx.shadowBlur = 10; // 整数
シャドウのぼかし効果。値が大きいほどぼかしが強くなります。

まず、<canvas> で CSS エフェクトをエミュレートする方法を見てみましょう。Google 画像で「css text-shadow」を検索すると、エミュレートできる優れたデモがいくつか見つかりました。Line25ステレオスコピックシャドウ 3D です。

CSS 3D グラフィック

立体視 3D 効果(詳細についてはアナグリフ画像を参照)は、非常に役立つシンプルなコードの一例です。次の CSS 行を使用すると、3D 赤/青色のメガネ(3D 映画で配布されるもの)で見ると、奥行きのある錯覚を作り出すことができます。

text-shadow: -0.06em 0 0 red, 0.06em 0 0 cyan;

この文字列を <canvas> に変換するときは、次の 2 つの点に注意してください。

  1. shadow-blur(3 番目の値)がないため、fillText でも同じ結果が得られるため、実際に shadow を実行する必要はありません。
var text = "Hello world!"
ctx.fillStyle = "#000"
ctx.fillText(text, -7, 0);
ctx.fillStyle = "red"
ctx.fillText(text, 0, 0);
ctx.fillStyle = "cyan"
ctx.fillText(text, 7, 0);</pre>
  1. EM は <canvas> ではサポートされていないため、PX に変換する必要があります。PT、PC、EM、EX、PX などを変換するための変換比率は、DOM で同じ font-properties を持つ要素を作成し、幅を測定対象の形式に設定することで確認できます。たとえば、EM から PX への変換をキャプチャするには、「height: 1em」で DOM 要素を測定します。結果の offsetHeight は、各 EM に含まれる PX の数になります。
var font = "20px sans-serif"
var d = document.createElement("span");
d.style.cssText = "font: " + font + " height: 1em; display: block"
// the value to multiply PX 's by to convert to EM 's
var EM2PX = 1 / d.offsetHeight;</pre>

アルファ乗算の防止

Line25 のネオン効果のような複雑な例では、効果を適切にエミュレートするために、shadowBlur プロパティを使用する必要があります。ネオン効果は複数のシャドウに依存しているため、問題が発生します。<canvas> では、各ベクトル オブジェクトに設定できるシャドウは 1 つだけです。そのため、複数のシャドウを描画するには、複数のバージョンのテキストを重ねて描画する必要があります。その結果、アルファ乗算が行われ、最終的にはエッジがギザギザになります。

ネオンのグラフィック

ctx.fillStyle = "rgba(0,0,0,0)" または "transparent" を実行してテキストを非表示にし、シャドウを表示しようとしましたが、これは無駄でした。シャドウは fillStyle アルファの乗算であるため、シャドウが fillStyle よりも不透明になることは決してありません。

幸い、回避策があります。テキストからシャドウをオフセットして描画し、テキストとシャドウを分離して(重ならないように)画面の端にテキストを隠すことができます。

var text = "Hello world!"
var blur = 10;
var width = ctx.measureText(text).width + blur * 2;
ctx.textBaseline = "top"
ctx.shadowColor = "#000"
ctx.shadowOffsetX = width;
ctx.shadowOffsetY = 0;
ctx.shadowBlur = blur;
ctx.fillText(text, -width, 0);

テキスト ブロックの周囲のクリッピング

これを少し整理するには、クリッピング パスを追加して、影を描画しながら、fillText が最初から描画されないようにします。テキストを囲むクリッピング パスを作成するには、テキストの高さ(「em-height」と呼ばれる、印刷機の文字「M」の高さ)とテキストの幅を把握する必要があります。幅は ctx.measureText().width を使用して取得できますが、ctx.measureText().height は存在しません。

幸い、CSS ハック(CSS 測定を使用して <canvas> の古い実装を修正するその他の方法については、タイポグラフィの指標をご覧ください)で、同じ font-properties を持つ <span>offsetHeight を測定してテキストの高さを特定できます。

var d = document.createElement("span");
d.font = "20px arial"
d.textContent = "Hello world!"
var emHeight = d.offsetHeight;

そこから、クリッピング パスとして使用する長方形を作成できます。ダミーシェイプを削除しながら、「シャドウ」を囲みます。

ctx.rect(0, 0, width, emHeight);
ctx.clip();

すべてをまとめ、最適化を進めます。シャドウにぼかしがない場合は、fillText を使用して同じ効果を得ることができるため、クリッピング マスクを設定する必要がなくなります。

var width = ctx.measureText(text).width;
var style = shadowStyles[text];
// add a background to the current effect
ctx.fillStyle = style.background;
ctx.fillRect(0, offsetY, ctx.canvas.width, textHeight - 1)
// parse text-shadows from css
var shadows = parseShadow(style.shadow);
// loop through the shadow collection
var n = shadows.length; while(n--) {
var shadow = shadows[n];
var totalWidth = width + shadow.blur * 2;
ctx.save();
ctx.beginPath();
ctx.rect(offsetX - shadow.blur, offsetY, offsetX + totalWidth, textHeight);
ctx.clip();
if (shadow.blur) { // just run shadow (clip text)
    ctx.shadowColor = shadow.color;
    ctx.shadowOffsetX = shadow.x + totalWidth;
    ctx.shadowOffsetY = shadow.y;
    ctx.shadowBlur = shadow.blur;
    ctx.fillText(text, -totalWidth + offsetX, offsetY + metrics.top);
} else { // just run pseudo-shadow
    ctx.fillStyle = shadow.color;
    ctx.fillText(text, offsetX + (shadow.x||0), offsetY - (shadow.y||0) + metrics.top);
}
ctx.restore();
}
// drawing the text in the foreground
if (style.color) {
ctx.fillStyle = style.color;
ctx.fillText(text, offsetX, offsetY + metrics.top);
}
// jump to next em-line
ctx.translate(0, textHeight);

これらの <canvas> コマンドをすべて手動で入力するのは面倒なので、デモソースにシンプルな text-shadow パーサーを追加しました。これにより、CSS コマンドを入力して <canvas> コマンドを生成できます。これで、<canvas> 要素に適用できるスタイルが大幅に増えました。これらと同じシャドウ効果を、WebFonts や SVG からインポートした複雑な図形、さらには生成ベクター図形など、どのベクター オブジェクトにも適用できます。

キャンバス エフェクトのテキストの影

休憩(ピクセル プッシュに関する余談)

この記事のこのセクションを執筆する際に、立体視の例が気になったので、<canvas> と、少し異なる視点から撮影した 2 つの画像を使用して、3D 映画スクリーン効果を作成するのは難しいですか?あまり難しくはないようです。次のカーネルは、1 つ目の画像(data)の赤色チャンネルと 2 つ目の画像(data2)のシアン チャンネルを結合します。

data[i] = data[i] * 255 / 0xFF;
data[i+1] = 255 * data2[i+1] / 0xFF;
data[i+2] = 255 * data2[i+2] / 0xFF;

2 台の iPhone を額にダクトテープで固定し、同時に [動画を撮影] をクリックするだけで、HTML5 で独自の 3D 映画を作成できるようになりました。どなたかご協力をお願いできますか?

3D メガネ

ネオンレインボー、ゼブラ リフレクション - チェーン エフェクト

<canvas> で複数のエフェクトを連結するのは簡単ですが、globalCompositeOperation(GCO)の基本的な知識が必要です。これらのオペレーションを GIMP(または Photoshop)と比較すると、<canvas> には 12 個の GCO があり、darkerlighter はレイヤのブレンドモードと見なすことができます。他の 10 個のオペレーションは、アルファ マスクとしてレイヤに適用されます(1 つのレイヤが他のレイヤのピクセルを削除します)。globalCompositeOperation は「レイヤ」(この例ではコードの文字列)を結び付け、新しい方法で組み合わせます。

連鎖効果のグラフィック

globalCompositeOperation グラフは、GCO モードが機能している様子を示しています。このグラフでは、色スペクトルの大部分と複数レベルのアルファ透明度を使用して、想定される結果を詳細に確認できます。テキストによる説明については、Mozilla の globalCompositeOperation リファレンスをご覧ください。詳細については、Porter Duff の デジタル画像の合成でオペレーションの仕組みを確認してください。

お気に入りのモードは globalCompositeOperation="lighter" です。Lighter は、光の混合方法と同様に、追加されたピクセルをミックスします。赤、緑、白の光が最大強度になると、白色光になります。これは、特に <canvas> が低い globalAlpha に設定されている場合に、細かい調整とエッジの滑らかさを実現できるため、試してみる価値のある機能です。Lighter はさまざまな用途に使用されています。最近気に入っているのは、http://weavesilk.com/ にある HTML5 デスクトップ バックグラウンド クリエイターです。私のデモの 1 つである Breathing Galaxies(JS1k)も、軽量モードを使用しています。これらの 2 つの例からパターンを描画すると、このモードの効果が見えてきます。

globalCompositeOperation ブラウザ処理

ネオン レインボー ジッター エフェクト

次のデモでは、globalCompositeOperation(ソースイン、明るい、暗い)を使用してエフェクトを連結し、ジッター化されたアウトラインでPhotoshop のようなネオン レインボー グローを実現します。このデモは、「<canvas> でのテキスト シャドウ」デモの進行であり、シャドウをテキストから分離する同じ戦略を使用しています(前のセクションを参照)。

Rainbow Jitter
function neonLightEffect() {
var text = "alert('"+String.fromCharCode(0x2665)+"')";
var font = "120px Futura, Helvetica, sans-serif";
var jitter = 25; // the distance of the maximum jitter
var offsetX = 30;
var offsetY = 70;
var blur = getBlurValue(100);
// save state
ctx.save();
ctx.font = font;
// calculate width + height of text-block
var metrics = getMetrics(text, font);
// create clipping mask around text-effect
ctx.rect(offsetX - blur/2, offsetY - blur/2,
        offsetX + metrics.width + blur, metrics.height + blur);
ctx.clip();
// create shadow-blur to mask rainbow onto (since shadowColor doesn't accept gradients)
ctx.save();
ctx.fillStyle = "#fff";
ctx.shadowColor = "rgba(0,0,0,1)";
ctx.shadowOffsetX = metrics.width + blur;
ctx.shadowOffsetY = 0;
ctx.shadowBlur = blur;
ctx.fillText(text, -metrics.width + offsetX - blur, offsetY + metrics.top);
ctx.restore();
// create the rainbow linear-gradient
var gradient = ctx.createLinearGradient(0, 0, metrics.width, 0);
gradient.addColorStop(0, "rgba(255, 0, 0, 1)");
gradient.addColorStop(0.15, "rgba(255, 255, 0, 1)");
gradient.addColorStop(0.3, "rgba(0, 255, 0, 1)");
gradient.addColorStop(0.5, "rgba(0, 255, 255, 1)");
gradient.addColorStop(0.65, "rgba(0, 0, 255, 1)");
gradient.addColorStop(0.8, "rgba(255, 0, 255, 1)");
gradient.addColorStop(1, "rgba(255, 0, 0, 1)");
// change composite so source is applied within the shadow-blur
ctx.globalCompositeOperation = "source-atop";
// apply gradient to shadow-blur
ctx.fillStyle = gradient;
ctx.fillRect(offsetX - jitter/2, offsetY,
            metrics.width + offsetX, metrics.height + offsetY);
// change composite to mix as light
ctx.globalCompositeOperation = "lighter";
// multiply the layer
ctx.globalAlpha = 0.7
ctx.drawImage(ctx.canvas, 0, 0);
ctx.drawImage(ctx.canvas, 0, 0);
ctx.globalAlpha = 1
// draw white-text ontop of glow
ctx.fillStyle = "rgba(255,255,255,0.95)";
ctx.fillText(text, offsetX, offsetY + metrics.top);
// created jittered stroke
ctx.lineWidth = 0.80;
ctx.strokeStyle = "rgba(255,255,255,0.25)";
var i = 10; while(i--) { 
    var left = jitter / 2 - Math.random() * jitter;
    var top = jitter / 2 - Math.random() * jitter;
    ctx.strokeText(text, left + offsetX, top + offsetY + metrics.top);
}    
ctx.strokeStyle = "rgba(0,0,0,0.20)";
ctx.strokeText(text, offsetX, offsetY + metrics.top);
ctx.restore();
};

ゼブラ リフレクション エフェクト

Zebra Reflection エフェクトは、CSS でページにスパイスを加える方法に関する WebDesignerWall の優れたリソースから着想を得ています。このアイデアをさらに進めると、iTunes に表示されるようなものとして、テキストの「反射」を作成できます。この効果は、fillColor(白)、createPattern(zebra.png)、linearGradient(shine)を組み合わせたものです。これは、各ベクター オブジェクトに複数の塗りつぶしタイプを適用できることを示しています。

ゼブラ効果
function sleekZebraEffect() {
// inspired by - http://www.webdesignerwall.com/demo/css-gradient-text/
var text = "Sleek Zebra...";
var font = "100px Futura, Helvetica, sans-serif";

// save state
ctx.save();
ctx.font = font;

// getMetrics calculates:
// width + height of text-block
// top + middle + bottom baseline
var metrics = getMetrics(text, font);
var offsetRefectionY = -20;
var offsetY = 70;
var offsetX = 60;

// throwing a linear-gradient in to shine up the text
var gradient = ctx.createLinearGradient(0, offsetY, 0, metrics.height + offsetY);
gradient.addColorStop(0.1, '#000');
gradient.addColorStop(0.35, '#fff');
gradient.addColorStop(0.65, '#fff');
gradient.addColorStop(1.0, '#000');
ctx.fillStyle = gradient
ctx.fillText(text, offsetX, offsetY + metrics.top);

// draw reflected text
ctx.save();
ctx.globalCompositeOperation = "source-over";
ctx.translate(0, metrics.height + offsetRefectionY)
ctx.scale(1, -1);
ctx.font = font;
ctx.fillStyle = "#fff";
ctx.fillText(text, offsetX, -metrics.height - offsetY + metrics.top);
ctx.scale(1, -1);

// cut the gradient out of the reflected text 
ctx.globalCompositeOperation = "destination-out";
var gradient = ctx.createLinearGradient(0, offsetY, 0, metrics.height + offsetY);
gradient.addColorStop(0.0, 'rgba(0,0,0,0.65)');
gradient.addColorStop(1.0, '#000');
ctx.fillStyle = gradient;
ctx.fillRect(offsetX, offsetY, metrics.width, metrics.height);

// restore back to original transform state
ctx.restore();

// using source-atop to allow the transparent .png to show through to the gradient
ctx.globalCompositeOperation = "source-atop";

// creating pattern from <image> sourced.
ctx.fillStyle = ctx.createPattern(image, 'repeat');

// fill the height of two em-boxes, to encompass both normal and reflected state
ctx.fillRect(offsetX, offsetY, metrics.width, metrics.height * 2);
ctx.restore();
};

Canvas の内側/外側のシャドウ

<canvas> の仕様では、「内側」と「外側」のシャドウの違いについては触れていません。実際、最初は「内側」のシャドウはサポートされませんが、これは誤りです。有効にするのは少し注意が必要です。F1LT3R の最近の投稿で提案されているように、時計回りと反時計回りのワインディング ルールの独自のプロパティを使用して、内側のシャドウを作成できます。これを行うには、コンテナの長方形を描画して「内側のシャドウ」を作成し、反対の巻き込みルールを使用して切り抜きシェイプを描画し、シェイプの反転を作成します。

次の例では、inner-shadow と fillStyle を色、グラデーション、パターンで同時にスタイル設定できます。パターンの回転は個別に指定できます。ゼブラストライプが互いに垂直になっていることがわかります。境界ボックスのサイズのクリッピング マスクを使用すると、切り抜きシェイプを囲む超大型のコンテナが不要になり、影の不要な部分が処理されなくなるため、速度が向上します。

内側/外側のシャドウ
function innerShadow() {

function drawShape() { // draw anti-clockwise
ctx.arc(0, 0, 100, 0, Math.PI * 2, true); // Outer circle
ctx.moveTo(70, 0);
ctx.arc(0, 0, 70, 0, Math.PI, false); // Mouth
ctx.moveTo(-20, -20);
ctx.arc(30, -30, 10, 0, Math.PI * 2, false); // Left eye
ctx.moveTo(140, 70);
ctx.arc(-20, -30, 10, 0, Math.PI * 2, false); // Right eye
};

var width = 200;
var offset = width + 50;
var innerColor = "rgba(0,0,0,1)";
var outerColor = "rgba(0,0,0,1)";

ctx.translate(150, 170);

// apply inner-shadow
ctx.save();
ctx.fillStyle = "#000";
ctx.shadowColor = innerColor;
ctx.shadowBlur = getBlurValue(120);
ctx.shadowOffsetX = -15;
ctx.shadowOffsetY = 15;

// create clipping path (around blur + shape, preventing outer-rect blurring)
ctx.beginPath();
ctx.rect(-offset/2, -offset/2, offset, offset);
ctx.clip();

// apply inner-shadow (w/ clockwise vs. anti-clockwise cutout)
ctx.beginPath();
ctx.rect(-offset/2, -offset/2, offset, offset);
drawShape();
ctx.fill();
ctx.restore();

// cutout temporary rectangle used to create inner-shadow
ctx.globalCompositeOperation = "destination-out";
ctx.fill();

// prepare vector paths
ctx.beginPath();
drawShape();

// apply fill-gradient to inner-shadow
ctx.save();
ctx.globalCompositeOperation = "source-in";
var gradient = ctx.createLinearGradient(-offset/2, 0, offset/2, 0);
gradient.addColorStop(0.3, '#ff0');
gradient.addColorStop(0.7, '#f00');
ctx.fillStyle = gradient;
ctx.fill();

// apply fill-pattern to inner-shadow
ctx.globalCompositeOperation = "source-atop";
ctx.globalAlpha = 1;
ctx.rotate(0.9);
ctx.fillStyle = ctx.createPattern(image, 'repeat');
ctx.fill();
ctx.restore();

// apply fill-gradient
ctx.save();
ctx.globalCompositeOperation = "destination-over";
var gradient = ctx.createLinearGradient(-offset/2, -offset/2, offset/2, offset/2);
gradient.addColorStop(0.1, '#f00');
gradient.addColorStop(0.5, 'rgba(255,255,0,1)');
gradient.addColorStop(1.0, '#00f');
ctx.fillStyle = gradient
ctx.fill();

// apply fill-pattern
ctx.globalCompositeOperation = "source-atop";
ctx.globalAlpha = 0.2;
ctx.rotate(-0.4);
ctx.fillStyle = ctx.createPattern(image, 'repeat');
ctx.fill();
ctx.restore();

// apply outer-shadow (color-only without temporary layer)
ctx.globalCompositeOperation = "destination-over";
ctx.shadowColor = outerColor;
ctx.shadowBlur = 40;
ctx.shadowOffsetX = 15;
ctx.shadowOffsetY = 10;
ctx.fillStyle = "#fff";
ctx.fill();
};

これらの例からわかるように、globalCompositeOperation を使用すると、効果を連結して、より複雑な効果(マスクとブレンドを使用)を生成できます。画面は自由にカスタマイズできます。

Spaceage - 生成エフェクト

<canvas> では、Unicode 文字 0x2708 から次のように処理されます。

Unicode グラフィック

以下のような陰影付きの例に変更します。

網掛けの例

これは、lineWidth(0.25)を細くして ctx.strokeText() を複数回呼び出し、x オフセットとアルファをゆっくりと小さくして、ベクター要素に動いている感覚を与えることで実現できます。

要素の XY 位置を正弦波または余弦波にマッピングし、HSL プロパティを使用して色を循環させることで、この「バイオハザード」の例のような、より興味深い効果を作成できます。

HSL サイクリング エフェクト

HSL: 色相、彩度、明度(1978)

HSL は、CSS3 仕様で新たにサポートされる形式です。HEX はコンピュータ用に設計されていますが、HSL は人間が読み取れるように設計されています。

HSL の容易さを示します。カラー スペクトルを巡回するには、単に 360 から「hue」をインクリメントします。色相は円柱形でスペクトルにマッピングされます。明るさは色の明るさを制御します。0% は黒いピクセル、100% は白いピクセルを表します。彩度は、色の明るさや鮮やかさを制御します。彩度が 0% のグレー、彩度が 100% の鮮やかな色を作成できます。

HSL グラフィック

HSL は最近の標準であるため、古いブラウザのサポートを継続することもできます。これは、色空間変換によって可能です。次のコードは、HSL オブジェクト { H: 360, S: 100, L: 100} を受け取り、RGB オブジェクト { R: 255, G: 255, B: 255 } を出力します。これらの値を使用して、RGB または rgba 文字列を作成できます。 詳細については、Wikipedia の HSL に関する記事をご覧ください。

// HSL (1978) = H: Hue / S: Saturation / L: Lightness
HSL_RGB = function (o) { // { H: 0-360, S: 0-100, L: 0-100 }
var H = o.H / 360,
    S = o.S / 100,
    L = o.L / 100,
    R, G, B, _1, _2;

function Hue_2_RGB(v1, v2, vH) {
if (vH < 0) vH += 1;
if (vH > 1) vH -= 1;
if ((6 * vH) < 1) return v1 + (v2 - v1) * 6 * vH;
if ((2 * vH) < 1) return v2;
if ((3 * vH) < 2) return v1 + (v2 - v1) * ((2 / 3) - vH) * 6;
return v1;
}

if (S == 0) { // HSL from 0 to 1
R = L * 255;
G = L * 255;
B = L * 255;
} else {
if (L < 0.5) {
    _2 = L * (1 + S);
} else {
    _2 = (L + S) - (S * L);
}
_1 = 2 * L - _2;

R = 255 * Hue_2_RGB(_1, _2, H + (1 / 3));
G = 255 * Hue_2_RGB(_1, _2, H);
B = 255 * Hue_2_RGB(_1, _2, H - (1 / 3));
}

return {
R: R,
G: G,
B: B
};
};

requestAnimationFrame によるアニメーションの作成

以前は、JavaScript でアニメーションを作成するには、setTimeoutsetInterval の 2 つの方法がありました。

window.requestAnimationFrame は、両方を置き換える新しい標準です。ブラウザが使用可能なリソースに基づいてアニメーションを調整できるようにすることで、世界の電力を節約し(そして、コンピュータの負荷を軽減します)。重要な機能は次のとおりです。

  • ユーザーがフレームから離れると、アニメーションが遅くなったり完全に停止したりして、不要なリソースの使用を防ぐことができます。
  • フレームレートの上限は 60 FPS です。これは、人間が認識できるレベルをはるかに超えているためです(ほとんどの人間にとって、30 FPS ではアニメーションは「滑らか」に見えます)。

執筆時点では、requestAnimationFrame を使用するにはベンダー固有の接頭辞が必要です。Paul Irish は、スマートなアニメーション化のための requestAnimationFrame で、クロスベンダー サポートを備えた shim レイヤを作成しました。

// shim layer with setTimeout fallback
window.requestAnimFrame = (function(){
return  window.requestAnimationFrame       || 
        window.webkitRequestAnimationFrame || 
        window.mozRequestAnimationFrame    || 
        window.oRequestAnimationFrame      || 
        window.msRequestAnimationFrame     || 
        function(/* function */ callback, /* DOMElement */ element){
        window.setTimeout(callback, 1000 / 60);
        };
})();

さらに一歩進んで、より野心的な場合は、requestAnimationFrame.js などのポリフィル(調整が必要な機能がいくつかあります)と組み合わせて、この新しい標準に切り替えながら、古いブラウザをさらにサポートできます。

(function animate() {
var i = 50;
while(i--) {
    if (n > endpos) return;

    n += definition;
    ctx.globalAlpha = (0.5 - (n + startpos) / endpos) * alpha;
    if (doColorCycle) {
        hue = n + color;
        ctx.strokeStyle = "hsl(" + (hue % 360) + ",99%,50%)"; // iterate hue
    }
    var x = cos(n / cosdiv) * n * cosmult; // cosine
    var y = sin(n / sindiv) * n * sinmult; // sin
    ctx.strokeText(text, x + xoffset, y + yoffset); // draw rainbow text
}
timeout = window.requestAnimationFrame(animate, 0);
})();
メモのぼかしグラフィック
アニメーション画像
マトリックス グラフィック

ソースコード

ブラウザのベンダー圏全体からのサポートにより、<canvas> の今後について疑いの余地はありません。PhoneGap を使用して iPhone/Android/デスクトップの実行可能ファイルに移植できます。

チタニウム