canvas を HTML マークアップで補完する: 第 2 回 アニメーションとテキスト・レンダリング

層を重ねて障害を克服する

HTML の canvas は、パフォーマンスが優れていることに加え、オーバーヘッドが低く、ピクセルを直接操作できるなど、多くの点で卓越していますが、テキスト・レンダリング、SEO、アクセシビリティー、そしてデバイス非依存のマークアップなどに関しては、HTML のほうが遥かに優れており、canvas では力不足です。この連載第 1 回では、従来の HTML/CSS モデルの長所と canvas API の長所を比較対照し、canvas と HTML のハイブリッド・アプリケーションについて探りました。連載の締めくくりとなる今回の記事では、テキスト・レンダリングを canvas で行うサンプル・アプリケーションの実装方法、そして従来の HTML/CSS モデルと canvas API の長所を組み合わせて、リッチな HTML ベースのユーザー・インターフェースを持つ canvas ベースのゲームを作成する方法を学んでください。

Ryan DeLuca, Software developer, The Nerdery

Ryan DeLuca photoRyan DeLuca は 1998年にプログラミングを始めました。その趣味は、わずか数年後にフリーランス・プログラマーとしての経歴に変わっていました。その経験を形として表すことに決めた彼は、ウィスコンシン州スーペリア校に入学し、2011年に理学士号を取得して卒業しました。卒業から間もなくして、PHP、JavaScript、CSS、および HTML を専門とするソフトウェア・エンジニアとして The Nerdery に入社しました。彼が持つさまざまな能力には、リレーショナル・データベース/SQL とグラフィックスの操作も含まれます。



Kevin Moot, Software Developer, The Nerdery

Kevin Moot photoKevin Moot は、子供の頃に自分の (ずらりと 6 色を揃え、驚異的な 280x192 の解像度を持つ) Apple IIe でゲームを作成して以来、コンピューター・グラフィックスに興味を持っています。HTML5 の Canvas 技術を使用して最先端の Web サイトの数々を作成した彼は、HTML/CSS、JavaScript、.NET などを専門分野にしています。彼は現在、The Nerdery でインタラクティブ・ソフトウェアの開発者として働いています。



2012年 9月 27日

はじめに

頻繁に使用される略語

  • CSS: Cascading Style Sheets
  • DOM: Document Object Model
  • HTML: HyperText Markup Language
  • UI: User Interface

この全 2 回からなる連載記事第 1 回では、リッチ・インターネット・アプリケーションを作成するために、canvas 要素と HTML 要素のそれぞれが持つ最も優れた側面を組み合わせる方法を説明しました。

今回の記事では、まず、アーキテクチャーの中心を canvas と HTML のどちらにするかを選択する際の基準を再検討し、アニメーションに関して検討すべき事項を説明します。次に、テキスト・レンダリングに伴う制約を克服する手段として HTML 要素と canvas 要素を重ね合わせ、それぞれの長所を生かしたテレビ・ゲームの基盤を構築する方法を学びます。図 1 に、この記事でサンプル・アプリケーションとして使用するスペース・シューターの基礎を示します。

図 1. HTML 要素と canvas 要素を組み合わせたサンプル・アプリケーション
HTML 要素と canvas 要素を組み合わせたサンプル・アプリケーション

記事で使用するサンプルのソース・コードは、「ダウンロード」セクションからダウンロードすることができます。


アーキテクチャー

グラフィカル・コンポーネント、インタラクティブなエクスペリエンス、そして視覚化を多用するアプリケーションを設計する際に重要となるのは、そのジョブに利用可能なすべてのツールを認識することです。このセクションでは、HTML による UI コンポーネントの実装と、canvas によるアニメーション化されたコンポーネントの実装について探ります。

ユーザー・インターフェース

canvas は素晴らしいグラフィカル・パフォーマンスを実現する可能性を持っているものの、リッチな UI を実装するには必ずしも最も優れた選択肢となるわけではありません。リッチな UI の実装には、HTML 要素のほうが適している場合もあります。多くのリッチ・インターネット・アプリケーションは多種多様な構成要素から成り、そのそれぞれの要素が異なる目的と要件を持ちます。自分が目指すものを実現するには、canvas 要素と HTML 要素それぞれの最も優れた側面を組み合わせたハイブリッド・アプリケーションが最も効果を発揮する可能性があります。

サンプル・アプリケーションでは、図 2 に示す階層化手法を採用しています。この手法では、リアルタイムのグラフィックとアニメーションの処理の大部分を canvas サーフェスで行い、各種の UI コンポーネントを構成する HTML 要素をその上に重ねます。

図 2. canvas 要素の上に HTML 要素を重ねる
canvas 要素の上に HTML 要素を重ねる

最善の手法を決定するときには、アプリケーションを構成する個々の要素の要件を検討してください。ユーザーとの高度な対話が要求される一方で、リアルタイムの更新を必要としない UI のコンポーネントには、概して HTML 層が最も適しています。そのような要素には、テキスト、ハイパーリング、およびフォーム要素などが該当します。

例えば、サンプル・アプリケーションの大部分を占めるのは canvas ですが、純粋な HTML マークアップを使用するチャット・ウィンドウ・コンポーネントもあります。図 3 に、このチャット・ウィンドウを示します。

テキスト・ボックス、スクロール・バー、ボタンなどのインタラクティブな UI コンポーネントは、単純な HTML タグと CSS ルールを使用して簡単に作成することができます。UI コンポーネントの外観と振る舞いはブラウザーがデフォルトで自動的に用意してくれるので、canvas 内でそれを模倣しようとして開発作業に何時間も費やす理由は何もありません。

図 3. HTML で実装されたチャット・ウィンドウ
HTML で実装されたチャット・ウィンドウ

チャット・ウィンドウは、アニメーションが関係してこない上にコンテンツが更新されることも (新しいチャットが行われたときぐらいで) あまり多くないため、HTML で実装するコンポーネントの有力な候補です。

逆に、以下のようなコンテンツには canvas のほうが遥かに優れたソリューションとなります。

  • 頻繁に (例えばミリ秒ごとに) 更新しなければならないコンテンツ
  • 継続的なアニメーション・サイクルを必要とするコンテンツ
  • ユーザーとの対話性が少ししか要求されないコンテンツ

アニメーション

アニメーション化されたコンテンツは Web サイトで広まり続けています。Web サイトを華やかにするための単純なアニメーション (ナビゲーションにおける遷移時のアニメーションなど) を必要とする場合でも、高度なブラウザー・ベースのゲームを必要とする場合でも、アニメーションの実装手段はいくつかの選択肢のなかから自由に選択することができます。大抵は HTML/CSS モデルを使って比較的簡単にアニメーションを実現できるので、その場合には canvas を使用するまでのことはありません。

jQuery をはじめとする多数のライブラリーは、どのブラウザーでも一貫した出力にするための便利なツールを提供しています。これらのライブラリーのツールと CSS の知識を少し組み合わせることで、アニメーションを実現するための作業を大幅に軽減することができます。これは、かなり複雑な性質のアニメーションにも言えることです。

サンプル・アプリケーションでは、図 4 の宇宙船要素がプレイヤーの操作に応じて移動したり、回転したりします。この動作は、HTML/CSS によるアニメーションだけを使って実現することができます。canvas の知識はまったく必要ありません。

図 4. アニメーション化された宇宙船要素
黒い背景に浮かぶアニメーション化された宇宙船要素

アニメーションに HTML/CSS モデルを適用するという選択は、要素の数が増えてくると、おぼつかなくなってきます。多数の要素を同時にアニメーション化するには、ブラウザーにかなりの負担がかかることから、アプリケーション全体のパフォーマンスが損なわれるためです。

円滑なアニメーションにするには、毎秒何度も DOM 要素を再配置しなければなりません。そのたびに、ブラウザーのレイアウト・エンジンが DOM 階層での要素を再計算して再描画するために大量のオーバーヘッドを要します。要素の数が数十、数百、数千になってくると、最新のコンピューターであっても相当なパフォーマンス・ヒットが認められるはずです。


canvas 上のテキスト

画面にテキストをレンダリングするのは、どの Web サイトでも基本的なタスクであるため、私たちはレンダリングのために背後で動いている簡単な仕組みを当たり前のもののように思うかもしれません。画面にテキストを表示したいと思ったら、そのテキストを (場合によっては多少の CSS を添えて) HTML 要素タグの間に入力するだけでよいのです。後はブラウザーに任せれば、テキストがレンダリングされます。しかし、canvas ではそうは行きません。

canvas でテキストをレンダリングするときは、いくつかの基本的なツールを使用することができます。これらのツールを使用すれば、レンダリングに関するほとんどどんなことを行う際にも必要な、ほぼすべての基本機能が提供されますが、canvas アプリケーションを開発するときに簡単に使いこなせるツールであるとは言えません。

基本

canvas の context オブジェクトには、テキストをレンダリングするときに設定できる各種のプロパティーがあるだけでなく、実際のレンダリングを行うための関数もあります。以下で、このオブジェクトのいくつかのプロパティーについて説明します。

  • context.font

    context.font の値を設定して、レンダリングするテキストのフォントの種類、サイズ、太さ、スタイルを制御することができます。設定する値は、複数のオプションをつなぎ合わせてスペースで区切った単一のストリングです。

    この入力フォーマットは少し面倒です。というのも、例えばフォントの種類は、値の更新があるたびに毎回ストリングに指定しなければなりません。リスト 1 に、小さいフォントを設定する場合を記載します。

    リスト 1. 小さいフォントを設定する
    context.font = 'italic 8px Arial';
    context.fillText('Variety is the spice of life!', 0, 50);

    リスト 2 に、大きいフォントを設定する場合を記載します。

    リスト 2. 大きいフォントを設定する
    context.font = 'italic 20px Arial';
    context.fillText('Variety is the spice of life!', 0, 50);

    ユーザーがフォントの種類を 1 回設定すれば、後は画面にレンダリングしたいテキストに応じて他のオプションを調整するだけで済むというわけにはいきません。この問題を修正する方法については後で説明します。

  • context.fillStyle

    context.fillStyle は、canvas のさまざまな操作に使用します。テキストの場合で言うと、このプロパティーには、画面にレンダリングするフォントの色を制御する値を設定します。指定する値の入力フォーマットは、CSS の入力フォーマットに従います。以下の入力例は、すべて有効です。

    • 塗りつぶしの色: 'red'、'blue'、'green' など
    • 16 進値: '#rrggbb'
    • 'rgb(r, g, b)'
    • 'rgba(r, g, b, a)'

    fillStyle は、例えば context.fillStyle = 'red'; のように設定します。

  • context.fillText()

    canvas 上にテキストをレンダリングするには、この関数を呼び出します。この関数は以下のパラメーターを取ります。

    • (string) text: canvas 上に描画するテキスト。
    • (float) x: テキストを描画する位置の x 座標。
    • (float) y: テキストを描画する位置の y 座標。
    • [オプション] (float) maxWidth: テキストを収める最大幅。可能な場合には、指定された幅に収まるように幅の狭いフォントが使用されたり、より小さいフォントが使用されたりすることすらあります。

その他のツール

その他に使用できるツールのうち、重要なのは context オブジェクトの measureText() という関数です。この関数は引数として、ストリングを 1 つ取ります。この関数を使用すると、指定されたストリングのサイズの測定値が含まれたオブジェクトが返されます (リスト 3 を参照)。

リスト 3. テキスト・ストリングの幅を判断する
context.font = '30px Arial';
var dim = context.measureText(
    'Hello, world!'
);
 
alert(
    'width: ' + dim.width + '\n' +
    'height: ' + dim.height
);

リスト 3 によって表示されるアラートと出力は、リスト 4 のような内容になります。

リスト 4. アラート
    width: 164
    height: undefined

高さの値は「undefined」となっていることに注意してください。奇妙なことに、すべてのブラウザーが返すのは常に未定義という結果です。したがって、measureText() 関数を使って正確なテキストの高さを判断することは実質的に不可能ですが、ある程度正確な値を見定めるための手法はいくつかあります。例えばその 1 つとして、多くのフォントでは特定の文字 (M など) がほぼ正方形であるため、このような文字のいずれかの幅を測定して、その値をフォントの高さの近似値として使用することができます。

また別の方法としては、指定されたフォント・サイズを実際の高さの基準としてそのまま使用することです。上記の例で 30px が指定された場合には、これに縦方向のパディングとして数ピクセルを足した値を、高さの近似値として使用することができます。

ビルディング・ブロック

開発プロセスを効率化するために、単純なラッパー・クラスを作成することで、前述のツールを使用して慣れ親しんだ方法で基本操作を実行することができます。ラッパー・クラスは、context オブジェクトの各種プロパティーの設定および切り替えを自動的に行い、最後に目的のテキストを canvas にレンダリングするように要求します。context.font プロパティーの問題は、この方法で自動化することが可能です。リスト 5 に、連載第 1 回で使用したサンプル・コードを記載します。

リスト 5. 動的スタイルを使用してテキストを canvas でレンダリングする
context.font = '18px Arial';
context.fillStyle = 'green';
context.fillText('Variety', 0, 50);
context.translate(60, 0);  //move 60 pixels to the right (a)

context.font = '12px Arial';
context.fillStyle = 'blue';
context.fillText('is the', 0, 50);
context.translate(35, 0); //move 35 pixels to the right (b)

context.font = 'italic bold 12px Arial';
context.fillStyle = 'red';
context.fillText('spice of life!', 0, 50); // (c)

図 5 に、canvas にテキストをレンダリングするリスト 5 の 3 つのステップを示します。

図 5. 動的スタイルを適用したテキストを canvas でレンダリングする
動的スタイルを適用したテキストを canvas でレンダリングする

canvas API をそのまま使用する場合は、かなりの量のコードを作成しなければなりませんでした。上記のレンダリングを行うために必要なコードを簡素化できるとしたら、canvas にテキストをレンダリングする際の作業を効率化することができます。例えば、canvas API をそのまま使用した何行ものコードの代わりに、リスト 6 のコードを使用することができます。

リスト 6. canvas のテキスト・レンダリングを補完するワークフローの概念
var myText = new CanvasText();
myText
    .family('Arial')
    .size('18px')
    .weight('bold')
    .color('green')
    .append('Variety')
    
    .size('12px')
    .weight('normal')
    .color('blue')
    .append('is the')
    
    .style('italic')
    .color('red')
    .append('spice of life!')
    
    .render();

リスト 6 のコードによる結果は、図 6 に示すとおりです。この例ではチェーニングを使用しています。チェーニングは、jQuery と jQuery プラグインで共通して使用されている簡潔かつ単純な構文です。

図 6. canvas のテキスト・レンダリングを補完する
canvas のテキスト・レンダリングを補完する

この方法では、レンダリングのプロセスが単純になります。コードの行数はほとんど変わらないとは言え、各行の複雑さは大幅に軽減されます。しかも、それぞれにスタイルの異なるテキストのブロックを 1 つひとつ手作業で配置する必要がありません。したがって、後でいずれかのテキスト・ブロックのプロパティーを調整することにしたとしても、その後に続くブロックを手作業で再配置する必要がなくなります。

canvas.font プロパティーは、テキスト・レンダリングの方法を決定する複数のプロパティーの組み合わせであることを思い出してください。上記のコードでは、「Variety」とそれに続くブロックの値に、フォントの種類を指定する必要はありませんでした。「is the」ブロックと「spice of life!」ブロックの間にフォントのサイズと太さを指定する必要もありませんでした。このコードでは、前に適用したプロパティーを記憶するための単純なメカニズムが用いられているため、前に適用した所望のテキスト・プロパティーの値を再設定する必要性が軽減されています。実際に動作する CanvasText クラスのコード・サンプルについては、「参考文献」を参照してください。

上記の結果を実現するには、まず、レンダリングするテキストのスタイル設定プロパティーをグループ化し、それぞれのスタイル設定プロパティーを指定します。そして、各グループを閉じ、そのグループを後で使えるように保管する CanvasText オブジェクトの append() 関数を呼び出せばよいのです。テキストをレンダリングするときは、これらのグループをループ処理して、指定されたスタイルを適用していきます。グループを繰り返し処理する際には、前のスタイルの適用状態を維持し、必要に応じてスタイルを変更します。これらのアクションによって、スタイルが記憶され、canvas にテキストをレンダリングするために必要な指定が少なくなります。これが、canvas にテキストをレンダリングするプロセスを自動化するためにラッパー・クラス、つまりビルディング・ブロック一式を採用する唯一の利点です。

ワード・ラップ

多くの人々は、ワード・ラップ (折り返し) を当然のことのように思っています。1 行には収まりきらない長いコンテンツが HTML 要素に含まれている場合、ワード・ラップによってコンテンツが折り返されます。テキストの長さや、コンテナーの幅などを気にする必要はありません。しかし、canvas の場合、それほど単純な話ではありません。現在、HTML の canvas 要素にはこのような事態を管理するための組み込み関数が含まれていないため、これまでに説明したツールとメソッドを使用して、ワード・ラップ関数をプログラムで作成する必要があります。

例えば、テキストがコンテナーの幅を超える場合にそのテキストを折り返すには、そのコンテナーの幅、レンダリングするテキストの幅、そしてテキスト行の高さを知らなければなりません。また、仮想コンテナーを作成し、そのコンテナーの幅を指定するメソッドを提供することも必要です。ワード・ラップを行うためのプロセスを作成してからでないと、canvas でワード・ラップを行うために必要なロジックの詳細に着手することはできません。

リスト 7 には、リスト 6 の概念を具体化し、CanvasText クラスのコンストラクターに渡す引数を指定したものです。

リスト 7. CanvasText クラスのコンストラクターに引数を渡す
var myText = new CanvasText(
    {x: 50, y: 50},
    {width: 100, height: 200}
);
myText
    .family('Arial')
    .size('18px')
    .weight('bold')
    .color('green')
    .append('Variety')
    
    .size('12px')
    .weight('normal')
    .color('blue')
    .append('is the')
    
    .style('italic')
    .color('red')
    .append('spice of life!')
    
    .render();

上記で追加された引数は、レンダリングするテキストの位置の x 座標と y 座標、そしてコンテナーのサイズを表します。コンテンツの折り返しを抑制するために、明示的な幅が指定されていることに注意してください。

適合基準とするコンテナーのサイズが決定したところで、次は所望の結果を実現するための関数を作成します。それぞれ異なるスタイルをループ処理するだけでなく、各単語もループ処理して、実際にレンダリングされたときのテキストの幅に関するデータを取得する必要があります。この情報から、すでにレンダリングされたテキストの幅を把握し、次の単語をレンダリングするとコンテナーのサイズを超えてしまうかどうかを判断することができます。幸い、measureText() 関数がまさに必要な情報を提供してくれます。

リスト 8 に、CanvasText クラスでワード・ラップを実装するために必要なコードを記載します。

リスト 8. ワード・ラップ関数を組み込む
// use measure text 
var currentWordWidth = context.measureText(currentWord).width

// word wrap code here
if (textAdjustment.x + currentWordWidth > this._size.x || textToDraw == '\n') {
    textAdjustment.x = 0;
    textAdjustment.y += parseInt(previousFontOptions.size, 10);
}

図 7 に、最終結果を示します。

図 7. ワード・ラップの結果
ワード・ラップの結果

ワード・ラップを使用した CanvasText クラスの実動サンプルについては、「参考文献」を参照してください。

かなり単純なラッパー・クラスで、canvas でのスタイル設定とワード・ラップ・タスクを自動化することができました。今や canvas でテキストをレンダリングする必要があるときには、いつでもこのラッパー・クラスを使用することができます。


すべての構成要素を結合する

私たちは便利な UI を当たり前のものと思いがちです。HTML から Flash、そして Silverlight に至るまで、いずれも必須の UI コンポーネント一式をテキスト、メニュー、スクロール・バー、フォーム要素という形で提供しています。

次に取り上げる例は、単純なスペース・シューター・ゲームの基盤となる設計です。これから、ゲーム領域を飛び回ることのできる宇宙船コンポーネント、チャット・ウィンドウ、そして (パワーアップ・アイテムを購入するための) ショップ・ウィンドウを作成します。コンポーネントのなかには、アニメーションが必要となるもの、あるいは頻繁に更新またはレンダリングしなければならないテキスト情報を表示するものがあります。

スペース・シューター・ゲームの完全な実動サンプルについては、「参考文献」を参照してください。

HTML による手法

最初のステップは、基本的な HTML マークアップを使用して、ゲーム・コンポーネントのそれぞれを作成することです。CSS の知識が多少あれば、宇宙船やチャット・システムなどの UI コンポーネントはごく簡単に作成することができます。

ここからが楽しい部分です。これから、宇宙船を作成します。HTML で実装する場合、単純な DIV 要素を作成して宇宙船の背景画像をアタッチし、プレイヤーの名前やライフなどを表示するための要素を追加します。ここまでのところは、これらのコンポーネントのコードをサンプル・アプリケーションの HTML と CSS だけで作成します。

リスト 9 に、宇宙船とその下に表示するテキストに必要な CSS のコードを記載します。player クラスでの DIV の位置が、宇宙船をアニメーションにするために後で DOM の render 関数で更新する対象です。

リスト 9. プレイヤーの宇宙船、名前、ライフをスタイル設定するための CSS
.player {
    position: absolute;
    width: 100px;
    height: 100px;
}

.text-under-ship {
    position: absolute;
    top: 100px;
    left: 0;
    width: 100px;
}

.name {
    font-family: Georgia;
    font-size: 15px;
    font-weight: bold;
    color: red;
}

.health {
    font-family: Georgia;
    font-size: 10px;
    color: yellow;
}

この時点で、ゲームのロジックを処理するために必要なコードに取り掛かることができます (リスト 10 を参照)。コードの大部分は、JavaScript の Game オブジェクトの中に集められます。このコードが、ユーザー入力を処理し、関連するコンポーネントの update 関数と render 関数を呼び出します。

リスト 10. アプリケーションを駆動するための gameLoop 関数
gameLoop: function() {

    // calculate time elapsed since last update
    var currentTime = new Date().getTime();
    var elapsed = currentTime - this._previousTime;

    // call updates
    Ship.update(elapsed);

    // call renders
    if (this._canvasRendering) {
        CanvasManager.render();
        Ship.renderCanvas();
    } else {
        Ship.renderDOM();
    }

    // store current time as the previous update time
    this._previousTime = currentTime;
}

上記のサンプル・コードで重要な部分は、Ship クラスの update 関数です。この関数が、レンダリング・コードで使用される宇宙船の速度、方向、位置を管理および更新します。

ここまでのところで作成したものはほとんど、レンダリング手法に関わらず再利用可能です。リスト 11 は、DOM と canvas との間の rendering 関数の違いを掘り下げて捉えています。

リスト 11. HTML の rendering 関数
renderDOM: function() {
    var player = jQuery('#player');

    player .css({
        left: this._position.x,
        top: this._position.y
    });

    var rotationTransform = 'rotate(' + (this._rotation / 100 * 360) + 'deg)';
    var ship = player.find('#ship')
        .css('transform', rotationTransform )
        .css('-webkit-transform', rotationTransform )
        .css('-moz-transform', rotationTransform )
        .css('-ms-transform', rotationTransform )
        .css('-o-transform', rotationTransform );
}

リスト 11 は、宇宙船を配置して回転させるために jQuery を使用しているため、必要最小限のコードになっています。ブラウザー間で真の互換性を実現するには、さまざまなベンダー固有のフレーバーを transform プロパティーに設定する必要があります。

HTML の手法は、比較的簡単に実装されていて、複雑さはほとんどなく、わずかな量のコードしか必要ありません。その反面、DOM 要素をレンダリングする際のブラウザーのオーバーヘッドにより、許容可能なフレーム・レートを達成できない可能性を伴うという欠点があります。

canvas による手法

canvas に着手する前に、扱う対象となる canvas オブジェクトへの参照が必要です。参照を用意した後、canvas オブジェクトを扱う際の context オブジェクトを初期化します。これは、記事の前半で説明した context であり、canvas 要素を扱う手段となります。

リスト 12 に示すように、単純な canvas の manager クラスを使用します。

リスト 12. canvas の manager クラス
var CanvasManager = {
    canvas: null,
    context: null,
    _size: null,

    init: function() {
        this.canvas = document.getElementById('canvas-game-area');
        this.context = this.canvas.getContext('2d');

        this._size = {
            x: this.canvas.width,
            y: this.canvas.height,
        }
    },

    render: function() {
        this.context.clearRect(0, 0, this._size.x, this._size.y);
    }
}

ほとんどのアプリケーションで canvas 上にレンダリングされたものを更新する必要がある場合には、必ず最初にレンダリング済みの要素を消去して、表示域をクリアしなければなりません。表示域をクリアするには、clearRect() 関数を使用することができます (リスト 13 を参照)。

リスト 13. canvas をレンダリングする関数
renderCanvas: function() {
    var context = CanvasManager.context;
    
    // save the context to prepare for our 
    // upcoming translation and rotation
    context.save();

    // translate the canvas to the ship's center position
    context.translate(
        this._position.x + 50, 
        this._position.y + 50
    );

    // rotate the canvas to show the angle the ship is pointing
    context.rotate(this.getRotationInRadians());

    // draw the ship with an offset of half the height
    // and width to center the image
    context.drawImage(
        this._displayImage, 
        -50,
        -50
    );

    // restore the context
    context.restore();

    this._playerName.render();
}

リスト 13 のコードは、canvas 手法の利点と欠点を示しています。主な利点は、パフォーマンスの改善です。レンダリングするコンポーネントが多ければ、この効果はなおさら強調されます (図 8 を参照)。

図 8. 宇宙船の数を増やしてパフォーマンスの違いを強調する
レンダリングする宇宙船の数を増やしてパフォーマンスの違いを強調する

このサンプル・アプリケーションでは、50 基の宇宙船が重なり合ってレンダリングされるようになっています (実動サンプルについては「参考文献」を参照)。HTML バージョンの場合、かなりの遅延が生じることは明らかです。canvas バージョンに切り替えることで、パフォーマンスは劇的に改善されます。

一方で、コードの量には著しい違いがあります。HTML による手法では jQuery を使用することで、1 回の関数呼び出しで宇宙船を配置することができます。canvas 手法の場合には、それだけでは済みません。

リスト 13 には、プレイヤーの名前を描画するための呼び出しも追加されています。HTML による手法では、配置する要素に宇宙船とそれに伴うテキストの両方が含まれるため、このような呼び出しの追加は必要ありませんでした。canvas 手法には、このような利便性はありません。プレイヤーの名前をレンダリングするために、例では CanvasText クラスを使用しました。これにより、宇宙船とその付随テキストをレンダリングするための作業は事実上すべて、DOM から canvas に取り込まれました。


まとめ

この全 2 回からなる連載では、アーキテクチャーの中心を canvas にするか、または HTML にするかを選択する際の基準を探りました。今回の記事では、アニメーションに関して検討すべき事項と、テキスト・レンダリングに関する制約を克服する方法を学びました。サンプル・コードによって、canvas 手法の概念と HTML による手法の概念を統合する方法を示し、ハイブリッド canvas-HTML アーキテクチャーを扱うためのさまざまな手法を明らかにしました。


ダウンロード

内容ファイル名サイズ
Article source codecanvashtmlpt2sourcecode.zip20KB

参考文献

学ぶために

  • CanvasText クラスの実動サンプル
  • 折り返しを使用した CanvasText クラスの実動サンプル
  • この記事で取り上げたスペース・シューター・ゲームの完全な実動サンプル
  • 重なり合った 50 基の宇宙船の実動サンプル
  • jQuery: HTML 文書のトラバース、イベント処理、動画化、そして Ajax 対話を単純にして Web 開発を迅速化する、この手軽で軽量な JavaScript ライブラリーの詳細を学んでください。
  • jQuery Fundamentals」(Rebecca Murphey 著、2010年): jQuery JavaScript ライブラリーの概要を包括的に紹介しています。
  • jQuery Events API: ユーザーがブラウザーと対話するときに適用する振る舞いを登録するためのメソッドについて詳しく学んでください。
  • HTML5 の Canvas を使って素晴らしいグラフィックスを作成する」(developerWorks、2011年2月): canvas を使用して Web ページの機能を強化する方法を学んでください。canvas は HTML5 の単純な要素ですが、強力な機能が満載されています。
  • HTML5 Canvas: Canvas API の使用法に焦点を当てたこのデモを見て、極めて単純なアニメーションの色を設定する方法を学んでください。
  • HTML5 の基礎: 第 4 回 最後の仕上げ」(developerWorks、2011年7月): HTML5 と HTML5 の canvas 要素での変更内容の詳細を学んでください。
  • Canvas Pixel Manipulation: Safari Dev Center に用意されているこのデモを見て、canvas を管理して効果的なビジュアル・アセットを開発する方法を学んでください。
  • WHATWG: W3C と協力して HTML5 の微調整に取り組んでいるこの開発者コミュニティーについて調べてください。
  • Canvas チュートリアル: Mozilla の開発者たちによるこのチュートリアルで、独自の HTML ページに canvas 要素を実装する方法を学んでください。
  • HTML5 Canvas リファレンス: W3Schools.com のリファレンスに用意されているエクササイズを使用して、canvas の知識に磨きをかけてください。
  • developerWorks Web architecture ゾーン: さまざまな Web ベースのソリューションを話題にした記事を調べてください。広範な技術に関する記事とヒント、チュートリアル、標準、そして IBM Redbooks については、Web 開発の技術文書一覧を参照してください。
  • developerWorks の Technical events and webcasts: これらのセッションで最新情報を入手してください。
  • developerWorks Live! briefings: IBM の製品およびツールについての情報や IT 業界の動向についての情報を迅速に把握してください。
  • developerWorks オンデマンド・デモ: 初心者向けの製品のインストールおよびセットアップから熟練開発者向けの高度な機能に至るまで、さまざまに揃ったデモを見てください。
  • developerWorks は Twitter を利用しています。今すぐ developerWorks のツイートをフォローしてください。

製品や技術を入手するために

  • jQuery: このよく使われている JavaScript ライブラリーを入手してください。HTML 文書のトラバース、イベント処理、アニメーション化、そして Ajax 対話を単純化するこのライブラリーは、迅速な Web 開発に役立ちます。
  • Kibo: 特定のブラウザーに依存しない高速キーボード・イベント処理を目的に作成された Kibo も、よく使われているライブラリーです。
  • IBM 製品の評価版: DB2、Lotus、Rational、Tivoli、および WebSphere のアプリケーション開発ツールとミドルウェア製品を体験するには、評価版をダウンロードするか、IBM SOA Sandbox のオンライン試用版を試してみてください。

議論するために

コメント

developerWorks: サイン・イン

必須フィールドは(*)で示されます。


IBM ID が必要ですか?
IBM IDをお忘れですか?


パスワードをお忘れですか?
パスワードの変更

「送信する」をクリックすることにより、お客様は developerWorks のご使用条件に同意したことになります。 ご使用条件を読む

 


お客様が developerWorks に初めてサインインすると、お客様のプロフィールが作成されます。会社名を非表示とする選択を行わない限り、プロフィール内の情報(名前、国/地域や会社名)は公開され、投稿するコンテンツと一緒に表示されますが、いつでもこれらの情報を更新できます。

送信されたすべての情報は安全です。

ディスプレイ・ネームを選択してください



developerWorks に初めてサインインするとプロフィールが作成されますので、その際にディスプレイ・ネームを選択する必要があります。ディスプレイ・ネームは、お客様が developerWorks に投稿するコンテンツと一緒に表示されます。

ディスプレイ・ネームは、3文字から31文字の範囲で指定し、かつ developerWorks コミュニティーでユニークである必要があります。また、プライバシー上の理由でお客様の電子メール・アドレスは使用しないでください。

必須フィールドは(*)で示されます。

3文字から31文字の範囲で指定し

「送信する」をクリックすることにより、お客様は developerWorks のご使用条件に同意したことになります。 ご使用条件を読む

 


送信されたすべての情報は安全です。


static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=60
Zone=Web development, Open source
ArticleID=836356
ArticleTitle=canvas を HTML マークアップで補完する: 第 2 回 アニメーションとテキスト・レンダリング
publish-date=09272012