「Canvas始めました」でCanvasのローレベルAPIを使って投稿をしてきました。
昨年(2011)9月にあるところで”Canvas”について話す機会があり、その時にお見せしたデモ・コードを再検証がてら記事にしてきました。
その時もお話ししたのですが、HTML 5(Canvas)を使ったインタラクティブ・コンテンツ制作はかなり大変、だということをあらためて、本当にあらためて実感しました。
Canvas API操作はJavaScriptを使います。
私のJavaScriptスキルやCanvas APIへの理解が心もとないせいだと言われれば反論のしようも無いのですが、ご興味があれば長文ですが少しおつきあいください。
繰返しになりますが、Canvasでインタラクティブなものを作るのは大変!
大変だと思った理由を書いていきます。
無知によるものもあるかもしれません、その時はぜひコメントなどで教えてください。
エディタが無い
デバッグ環境が心もとない、と書くべきかもしれません。
JavaScriptを書けば良いのでWeb制作時に使うエディタをそのまま使用するのですが、開発->デバッグ・プレビューが一々面倒です。
デバッグ時はブラウザ側のツールを使わないといけなくなります。
エディタから離れてしまうのでシームレスな開発ができないのがたまらなくいやです。
Canvasに描画したものは一枚の画像になってしまうので、図形を描画したときに、意図しない位置・形状などになった時に「どんな状態(プロパティ設定)」になっているのかを確かめる術がコードを追うことしかありません。
DOMの状態を調べるFirebugやWebインスペクタなどの便利なツールがありません。
これは時間が解決してくれるのかもしれません。
「Canvas始めました」はJetBrains社謹製のPhpStormを使っています。
Canvasへの描画テストができる自前のWebアプリのようなものを作り、そこでテストしました。
いつかこれも公開できればと考えています。
APIすくな!
Canvas専用のAPIは少ないです。
マジでって驚くばかりです。
HTML Canvas 2D Context Editor’s Draft 7 March 2012
html5.jp Canvas リファレンスが詳しいです。
たったこれだけです。
イベントはもともとあるJavaScriptに定義されているのを使うってのはあるけど、それでもです。
描画した図形を回転させるの大変
描画図形を回転させるには次のような手順をとります。
- Canvas state 保存
- tarnsformation Matrixを初期化(identity)する, context.setTransform(1,0,0,1,0,0);
- translateで移動
- rotateで回転
- fillRect座標を矩形の幅と高さの半分をネガティブ側へオフセットさせて描く
- Canvas state 復元
一枚の画像にしかならないことに起因していると思うのですが、回転させるたびにこの計算をしなくてはいけないのは気を失いそうです。
Canvas始めました – 矩形を回転させる
描画サイクルを自作しないといけない
APIが少ない中で困ったのがアニメーションなどで必須の繰返しです。
FlashやProcessingなどではもともと用意されているenterFrameやdrawを使うだけで良いのですが、setInterval, setTimeout, requestAnimationFrameなどを使い自作ループルーチンを作る必要があります。
Canvasで位置や形状変化のあるアニメーションを行うときのサイクルは以下のようになります。
Canvas全体をクリア -> 位置や形状変化を計算 -> 描画
ひとつの図形ならまだしも複数のものを動かしながらになると軽いパニックになってしまいます。
動いたところに絵を描くだけなので図形(オブジェクト)自身にx, y, width, height, alpha…などのプロパティがありません。
後で図形(オブジェクト)にプロパティ情報を問合せて処理ができるFlashのありがたさが身にしみました。
それぞれの図形(オブジェクト)のプロパティを保持するFlashのMovieClipやSpriteみたいな変数やClassなどの仕組みを産み出さないと管理ができないように思います。
また描画するルーチンは一カ所にしておかないと描画タイミングのずれが発生したり意図と違うことが起きやすくなります。
FlashのようにどこからでもaddEventListenerで描画ルーチンに参加させることができるのは素晴らしいと思わずにはいられません。
重なり順の変更が可能なコンテンツを作りたかったらその仕組みも考えだす必要があります。
マウスイベント
何度目になるか分かりませんが、Canvasに描いた図形は一枚の画像にしかならないので図形にマウスアクションを実装するのがかなり大変です。
HTMLElementにaddEventListenerしたりFlashのInteractiveObjectの便利な機能がどれほど羨ましかったか。
CanvasあるいはWindowにマウスアクションを設定し、取得したマウス位置から検出したい図形の座標と当たり判定を行って対象図形へのマウスアクションかどうかを調べる必要があります。
ボタンへのマウスオーバー処理ひとつとっても大変です。
Canvas上にボタンが一個しかなかったらそんなことも無いのですが、実コンテンツではそんなことありえません。
複数のボタンと複数の動いているものの組み合わせになることが多いと思います。
マウスオーバーとアニメーションを組み合わせる時は、ループ処理の中でマウスオーバー時の形状や色変化を行わないと、動いている図形と整合性がとれなくなりことがあります。
当たり判定でマウスオーバーのアクションを検出し何らかの描画をする時は、描画を予約し、次のループ処理で描画し予約を破棄する、のような処理が必要になるように思います。
マウスオーバーなのでCanvas上にマウスが存在するときは常にマウス位置をチェックし、マウスオーバー処理が必要な図形全てと当たり判定をしなければなりません。
Canvas上にいなければ当たり判定をする必要は無いのでそれも監視しなければいけません。
MouseEvent.MOUSE_OVERを設定すれば済むのとは大違いです。
動いている図形にマウスオーバーが必要だったら四分木を使った処理も必要になるかもしれません。
なんでこんなことまで自前でやんなきゃなんないだよー、と愚痴のひとつも言いたくなります。
Canvas始めました – マウスアクション(click)を使う最初の一歩
Canvas始めました – マウスを追っかけるアニメーション
Canvas始めました – ボタンを作る
JavaScriptを使うしかない
所詮JavaScriptです。
global変数に依存した、型が存在しない、Classがない、だから継承がないJavaScriptです。
この言語を使うしかありません。
様々な方法で極力global変数を使わない方法があることは知っています。
型付けできる言語で書いてJavaScriptに変換する方法があることは知っています。
Classのように振る舞える機能を作れることは知っています。
もちろんClassのような機能が作れるので継承もできるのは知っています。
JavaScriptがOOPな言語だということも理解しているつもりです。
本来ない機能を補完するのって本末転倒な気がします。
おっぱいが小さいのに上げ底でごまかしてる感じがするんですよねぇ。
中身が少ないのを上げ底でごまかしてるお土産のお菓子セットのような気がするんですよねぇ。
例えが下手でごめんなさい。
誤解されたくないのは「JavaScriptが好きだ」ってことです。
最近の生活費のほとんどを稼ぎだしているからというだけでなく、矛盾するようですがClassやextendや型付けせずにコードを書けることはこの上なく楽しい作業です。
引き換えにコードの精度が落ち開発時間がかかっているようには思います。
もともと、型付けのない言語でOOPやデザインパターンを知らずにScriptを覚えたので、ここらへんは私個人の問題の方が大きいのでしょう。
ライブラリがあるじゃん
でもしかし…
JavaScriptでの開発にライブラリは欠かせません。
今まではブラウザ互換を気にせずコードを書くために使用していました。
Canvasでは低レベルAPIをラップして使いやすくしてくれるライブラリが必要です。
ありがたいことに多数のライブリがあります。
Adobe一押しのCreateJS。
他にもProcessingを移植したProcessing.js。
Paper.js, jCanvas, BitmapData.js…etc
WebGLだとThree.js。
Cocos2dを移植したcocos2d-html5にもWebGLの記述が見られます。
他にも色々とあるのだろうと思います。
ライブラリを使うと結局そのライブラリに依存してしまって、後で泣きを見ることにならないかとそれだけが心配です。
prototype.jsの今の不甲斐なさを5年前に知ることはできませんでした。
JavaScriptに限った話ではないのですが…
しかし、とても低レベルAPIをラップするライブラリを自作できそうにもありません。
Flashって良くできたツールだった
Flash, ActionScriptを書いてた頃には実感が無かったのですが、「良くできたツール」だと改めて思い知りました。
「良く落ちる」とか「遅い」とか「高い」とか愚痴ってごめんなさいって感じです。
描画ルーチンの提供があるのはありがたい限りです。
ENTER_FRAMEにaddすれば動きだしremoveすれば止まるのがこんなにステキなことだったとは。
instance.rotateで回転できたり、x, yプロパティで動かせたりと抱きしめたくなりました。
MouseEventの処理もinstanceに直接設定できるのは嬉しい機能です。
他にもあるけど、これくらいにしとこう。
Canvasの使い道
ところでCanvasってどう使うといいのだろう。
スペシャルサイト・コンテンツとして魅力的なものが出始めてきています。
とても良くできた素晴らしいコンテンツです。
でもこんな使い道しかないのかなぁ、と思ってしまいます。
通常Webコンテンツの一部に使われるとしたらどんな使い方があるのだろう。
画面の端っこでチマチマ動く広告?
なんかやだなぁ。
このボンクラ脳では答えを導くのは難しそうです。
今まで出来ないことが出来るようになったのは魅力的です。
無い知恵絞ってCanvasを使ったステキなものを作りたい、「へ〜あれってCanvas使ってるんだ」と言われるのがいいな。
Canvasでなんかすること自体もう新しさは無いけど、自分の中では挑戦してる感じでスキです。
さて、何しよう。
update
この記事から2年後「Canvas 2Dライブラリを作ろうとして感じたこととDisplayObject」ての書きました。
自分の中では【続編】のようなものです。
根っこの考え方(Canvas超大変)は変わらないのですが、実案件(非ゲーム)でCanvasを使用したりと環境は変わってきてます。
取り残されないように何とか対応できるようにしなくてはと考えています。
実案件では数あるライブラリを使用せず、スクラッチでコードをがりゴリ書いて描画しました。
ゲームほど操作要素が多くなかったのが理由です。
今後要件が複雑化するとどうするかはその時考えます。
2012.06.07 20:40
Flashが簡単になんでも作れるおかげで、色んな機能をてんこ盛りに
した挙句重くなったアプリが出来てFlashは重いという評価を受けがちですね。
CanvasではFlashで問題だった事がよくなってくれるんでしょうか
2012.06.07 21:02
どうなんでしょう?
道具は何を使っても作り手しだい、代理店しだい、クライアントしだいになると思います。
ユーザーも作り手も代理店もクライアントも満足できるものが作れるといいですけど。
ピンバック: Canvas 2Dライブラリを作ろうとして感じたこととDisplayObject « イナヅマTVログ