タグ別アーカイブ: サンプル

HTML5 Canvas:円を描く時のパフォーマンス

この記事はHTML5 Advent Calendar 2012の13日目のエントリーになります。

Canvasのクリスマスツリーもう少しでクリスマスなので、HTML5 の canvas でクリスマスツリーに飾り玉を描こうかなと思いました。色んな方法を考えながら、Stack Overflow に「円を円形グラデーションだけで描けるよ」というコメントを見つけました。

ご存知だと思いますが、canvas で円を描くには普通 arc()を使います:

// 普通の円の描き方
ctx.beginPath();
ctx.arc(x, y, radius, 0, Math.PI * 2, true);
ctx.fillStyle = 'rgba(195, 56, 56, 1)';
ctx.fill();
ctx.closePath();

例えば SVG と比べるとちょっと面倒くさい感じがするかも知れません。円形グラデーションを使うのが良いアイディアと思い、それぞれのやり方のパフォーマンスの違いが知りたくなりました。

// 円形グラデーションで円の描き方
var gradient = ctx.createRadialGradient(x, y, 0, x, y, radius);
gradient.addColorStop(0.95, 'rgba(195, 56, 56, 1)');
gradient.addColorStop(1, 'rgba(195, 56, 56, 0)');
ctx.fillStyle = gradient;
ctx.fillRect(x - radius, y - radius, x + radius, y + radius);

この canvas テストページで速さの違いが実際に見えます。

やっぱり arc() より円形グラデーションの方が遅いです。何倍も遅い!テストページを作る前、これに気付くべきでしたが、まぁ、どうせなので3Dっぽい球の描き方も調べる気になりました。

Canvas で球を描くには主に二つの方法があります:

  1. 円形グラデーションを利用する
  2. 既存の画像を利用する
// 円形グラデーションでの描き方
var gradient = ctx.createRadialGradient(x, y, 0, x, y, radius);
gradient.addColorStop(0, 'rgba(255, 255, 255, 1)');
gradient.addColorStop(0.2, 'rgba(255, 85, 85, 1)');
gradient.addColorStop(0.95, 'rgba(128, 0, 0, 1)');
gradient.addColorStop(1, 'rgba(128, 0, 0, 0)');
ctx.fillStyle = gradient;
ctx.fillRect(x - radius, y - radius, x + radius, y + radius);
// 既存の画像での描き方
var img = new Image();
img.src = 'images/baubles.png';
ctx.drawImage(img, x, y, width, height);

先ほどと同じように円形グラデーションの方が数倍遅いみたいです。しかし円形グラデーションの利点はもちろんその効果が動的に作られているため、JavaScript で変更することができます。一方画像を使う場合、ソフトで画像を前もって作る必要があります。JavaScript での編集ができませんが、大きさなら変更できます。色を変更したい時はこの二つの方法のいずれかが使えます:

  1. 複数バージョンのある sprite 画像を利用する。
  2. 白黒の画像を利用し、arc() で半透明のオーバーレイを適用する。

ところで画像のダウンロード時間も忘れてはいけませんので、ユーザを待たせないように画像のプリロード(先読み)がおすすめです。

前述の canvas テストページでそれぞれの速さの比較ができます。

テストから分かるように、半透明オーバーレイの方法は少し遅いですが、色の変更がもっと自由にできます。ただ、元々の画像よりコントラストが少し悪くなります。我慢できる位であるかどうかは皆様にお任せします!。

まとめ

結局簡単なアプリや力のあるデバイスなら速さの違いは気付く程ではないかも知れませんが、アニメーションを使う時、高速ゲームを作る時、もしくはTV用のアプリを作る時、パフォーマンスが重要になります。色々な選択肢がありますので、私からのアドバイスは下記の通りです:

  • 円が描きたい時、arc()を使いましょう。
  • 3Dっぽい球が描きたい時、画像を使いましょう(プリロードを忘れずに)。
  • 色んな色の球が描きたい時、sprite 画像を使いましょう。
  • 動的に色が変わる球が描きたい時、半透明オーバーレイのある画像を使ってみましょう。
  • 円形グラデーションは必要な時だけに使いましょう。

最後にもう一つ学んだことですが、やっぱり数千個の飾り玉のあるクリスマスツリーはオシャレじゃない!

更新:

TwitterでMarceloさんが良いアイディアをつぶやきました。隠されているcanvasに円形グラデーションで円を描いて、それをdrawImage()で元々のcanvasに数回描くというアイディアでした。これで画像を前もって作る必要がないし、動的に色を変えることも可能です。しかも既存画像にdrawImage()を使うよりもパフォーマンスが良いです!(円形グラデーションの描く時間を除けば。)コードはこんな感じです:

// いわゆる「バッファー」canvasを作るけど、ページに追加しない
var tmpCanvas = document.createElement('canvas');
var tmpCtx = tmpCanvas.getContext('2d');

// ここで必要なグラデーションを用意する(上記のサンプルみたいに)

// さきほどの「バッファー」canvasから元々のcanvasに描く
ctx.drawImage(tmpCanvas, x, y, width, height);

つまり、円や玉をたくさん描く時はこの方法が一番お勧めです。Marceloさん、サンキュー!

HTML5、CSS3 で作るポラロイド風写真

HTML5 Advent Calendar の12日目です。
本来のAdvent Calendarとは、12月1日からクリスマスの25日まで、カードに作られた窓を1日に1つずつ開けていくというものです。一方、技術系の Advent Calendar は、12月1日から25日までの間、毎日違う人が特定のテーマに沿ってブログ記事を書くというものです。ここでは、「HTML5」がテーマになります。他にも面白い記事が公開される予定ですので興味のある方は是非チェックしてみてください:http://atnd.org/events/21987

五つのステップでブログとかに活用できるポラロイド風の写真を HTML5 と CSS3 で作りたいと思います。似たサンプルがあっちこっちにありますが、もう少し本物っぽくなるように第5段階でアニメーションの追加があります。
完成すればこういうふうになります: HTML5、CSS3 のポラロイド風写真

さぁ、スタートしましょう!

1. まずは HTML5

ポラロイド風写真その1最初にマークアップを用意しましょう。HTML5 ではいくつかの新しい要素があります。どれをどういうふうに使うかは混乱しやすいですが、一つの簡単な要素は <figure> です。画像かビデオに使う要素で、実はそれだけであまり利点がなさそうですが、画像やビデオに説明の文章がある場合、<figcaption> との併用で役立ちます。使い方はこんな感じです:

<!-- HTML ファイル -->
<figure id="polaroid">
  <img src="santa.jpg" alt="本物のサンタさん">
  <figcaption>Merry Christmas !</figcaption>
</figure>

現在のブラウザはこれで満足していますが、IE の古いバージョンでは HTML5 要素に CSS の摘要できません。解決方法の一つは Remy Sharp 氏が作った簡単な JavaScript です:

<!-- HTML ファイル -->
<!--[if lt IE 9]>
<script src="//html5shiv.googlecode.com/svn/trunk/html5.js"></script>
<![endif]-->

2. 次はポラロイド風に

ポラロイド風写真その2ポラロイド写真のような効果はもちろん白い紙が必要なので、画像の周りにマージンを追加し、背景を白にします:

/* CSS ファイル */
#polaroid {
  background: #fff;
  color: #111;
  display: block;
  height: 425px;
  margin: 2em auto;
  width: 350px;
}
#polaroid img {
  border: solid 1px #ddd;
  margin: 24px;
}
#polaroid figcaption {
  display: block;
  font-size: 32px;
  line-height: 1;
  text-align: center;
}

ところで、HTML5 パーサーの入っていないブラウザは <figure><figcaption> みたいな要素が認識されず、インライン要素として扱われます。そのため、display: block; を指定します。そうすると、IE6 でもポラロイドっぽく見えます。

3. CSS3 で面白く

ポラロイド風写真その3やっと CSS3 の番になりました。細かい効果を追加するともう少し本格的になります。例えば影の引用、少しの回転、そして角を微妙に丸くしましょう:

/* CSS ファイル */
#polaroid {
  box-shadow: 0 2px 4px #777;
  border-radius: 3px;
  -webkit-transform: rotate(5deg);
  -moz-transform: rotate(5deg);
  -ms-transform: rotate(5deg);
  -o-transform: rotate(5deg);
  transform: rotate(5deg);
}

多くの CSS3 プロパティの長所は古いブラウザで表示されなくてもデザインが崩れることは殆どありません。ただ、最も最新のプロパティができるだけ多くのブラウザで表示されるように、上記みたいにベンダープレフィックスが必要になります。

4. 一言メッセージをおしゃれに

ポラロイド風写真その4今のところ、結構完成に近い感じがしますが、画像の下にあるメモはメモらしくないですね。ここでウェブフォントを使いましょう。ウェブフォントを使う時はもちろん利用する許可が必要です。このデモに使うフォントは Jesús Gorriti がコピーライト無しで公開している Gorri Sans です。

ウェブフォントは IE6 を含めてたくさんのブラウザで使うことができますが、ちょっとしたコツが必要です。Paul Irish 氏、Richard Fink 氏や Ethan Dunham 氏が色んな環境でテストして、一つの結果としてはこのコードがあります:

/* CSS ファイル */
@font-face {
  /* Font source: http://gorriti.com/2009/02/05/mi-aportacion-al-mundo-brutista/ */
  font-family: 'GorriSans';
  src: url('GorriSans.eot?') format('eot'), url('GorriSans.woff') format('woff'), url('GorriSans.ttf') format('truetype');
}
#polaroid figcaption {
  font-family: GorriSans, arial, sans-serif;
}

因みに上記のフォントフォーマット(EOT式、WOFF式など)への変換は、Font Squirrel の @font-face ジェネレーターをおすすめします。

5. フェードイン効果の追加

いよいよ最後の仕上げになりましたが、それはもちろん写真の現像です。本物のポラロイド写真みたいに、このデモの写真が目の前でゆっくりと現れます。JavaScript を使うことが可能ですが、CSS のみの方法でやってみましょう。アニメーションそのものは簡単であり、画像の透明度にトランジションを利用します。つまり、1分の間、opacity が 0(透明)から 1(不透明)に変わります。

どのトランジションでも、二つ以上の状態が必要です。この場合、ページ自体が第1状態になり、第2状態を作るには target の疑似要素(pseudo-element)を使います。トランジションを起動するには、<body> 要素に「demo」という ID を加え、ページの URL にも「#demo」を追加します。そうすると、ページがロードする時、画像が透明の状態から段々画像が見える target の状態に変わります。

<!-- HTML ファイル -->
<body id="demo">
  ...
</body>

/* CSS ファイル */
#polaroid img {
  opacity: 0;
  -webkit-transition-duration: 60s;
  -moz-transition-duration: 60s;
  -ms-transition-duration: 60s;
  -o-transition-duration: 60s;
  transition-duration: 60s;
}
#demo:target #polaroid img {
  opacity: 1;
}

完成したデモ: kyokodaniel.com/tech/css3/polaroid/index.html#demo

さぁ、これで更にクリスマスの雰囲気になったでしょうか?来年の HTML5、CSS3などのウェブ技術の発展が楽しみですね。皆さん、have a Merry Christmas and a Happy New Year!

Modernizr で HTML5 の使用が楽に

Modernizr「それぞれのブラウザはどこまで HTML5 を対応していますか。比較表はありますか。」
最近よく聞かれます。聞かれると最初の反応は「oh no!」です。

ブラウザの対応を調べようとすると、このような問題が出てしまいます:

  • ブラウザのバージョンは日々変わっています。
  • HTML5 仕様そのものは日々変わっています。
  • あるブラウザは、今日の◯◯版の対応は昨日の◯◯版の対応と違うかもしれません。
  • あるブラウザの Windows 版の対応は Mac 版、Linux 版、携帯版、テレビ版、ゲーム機版やタブレット版の対応と違うかもしれません。
  • HTML5 対応は true/false ではなく、部分的な対応の方が普通です。
  • 既存の比較表は例外がとても多く、分かりづらいです。
  • ユーザーエージェントはよく嘘を付き、ブラウザの判断としては理想的ではありません。

比較表をいつも更新するのは限りがない作業で大変だし、比較表をいつも参照しないといけないウェブ開発者がかわいそうです。この道を辿ればストレスが溜まりアッという間に白髪が増えてしまいます。おかげさまで楽な方法があります:

ブラウザの対応ではなく、使いたい機能の対応を調べましょう

JavaScript を利用すればある要素、若しくはある属性の存在を調べることができます。このための関数を作ることは難しくありませんが、便利な HTML5 や CSS3 の対応が検出できるライブラリーは既にあります: Modernizr

Modernizr は開発中のため、SVG や Opera 10.5 のトランジションとトランスフォームの検出はまだできませんが、HTML5 がすぐに使いたいウェブ開発者にお勧めです。残念ながら日本語の資料はまだ少ないようなので、使い方を簡単に説明したいと思います。

他の JavaScript ライブラリーと同じように、まずウェブページの <head> にリンクを挿入します:

<!-- HTML -->
<script src="modernizr-1.1.min.js"></script>

次は使いたい HTML5 の機能を対応しないブラウザのためのコードを書きます。JavaScript を対応しないブラウザや JavaScript を無効にしているユーザーのため、ベーシックな HTML だけを利用します:

<!-- HTML -->
<select id="level">
<option disabled selected>選択してください</option>
<option value="0">0</option>
<option value="1">1</option>
<option value="2">2</option>
<option value="3">3</option>
<option value="4">4</option>
</select>

実際に使いたい機能(例えば HTML5 Forms の「range」スライダー)の対応は下記のように Modernizr のオブジェクトで判断できます:

// JavaScript
if (Modernizr.inputtypes.range) {
    ...
}

ブラウザが対応する場合、不必要になった要素を削除し、使いたい要素をページに追加します:

// JavaScript
var fieldset = document.getElementById('fieldset');

// 不必要なセレクトボックスを削除する
fieldset.removeChild(document.getElementById('level'));

// スライダーの input を作る
var level = document.createElement('input');
level.setAttribute('id', 'level');
level.setAttribute('type', 'range');
fieldset.appendChild(level);

上記のコードを利用して簡単なサンプルを作りました: HTML5 対応を判断するサンプル

このような方法で行うと、過去のブラウザでも、未来のブラウザでもユーザビリティが良く、そして常に変化している HTML5 のサポートを気にする必要はありません。是非機能の対応を判断しながら HTML5 を使ってみて下さい。