excanvas.js のハマリどころ, G_vmlCanvasManager.initElement の使い方
追記: uupaa-excanvas.js をリリースしました。
excanvas.js は IE で canvas 要素のエミュレートを行う Google 謹製の JavaScript ライブラリです。
このライブラリは、最初のとっかかりが結構難しいです。
実体験を元に、ハマリポイントを列挙してみます。
動的に生成したcanvas要素は、すぐにドキュメントツリーに追加し、その場で初期化する必要がある。
以下が、動的にcanvas要素を生成し2Dコンテキストを取得する例です。が…
var e = document.createElement("canvas"); document.body.appendChild(e); var ctx = e.getContext("2d");
上記のコードでは、IEでは動作しません(Firefox,Safari,OperaはOK)。
動的に生成したcanvas要素は、G_vmlCanvasManager.initElement(element) で初期化する必要があります。
初期化はドキュメントツリー追加後に実行します。が…
var e = document.createElement("canvas"); document.body.appendChild(e); G_vmlCanvasManager.initElement(e); // canvas要素の初期化 var ctx = e.getContext("2d");
実は、上記のコードも動作しません。
G_vmlCanvasManager.initElement(element) は初期化されたcanvas要素を返すため、戻り値に対して getContext() を行います。
var e = document.createElement("canvas"); document.body.appendChild(e); e = G_vmlCanvasManager.initElement(e); // 初期化された要素が返るので、eに再代入 var ctx = e.getContext("2d");
これでやっと動作するようになります。
initElement は兄弟を皆殺しにする
先ほど、「すぐにドキュメントツリーに追加し、その場で初期化する必要がある。」と書きましたが、その理由をここで述べます。
このような要素片を生成するためには…
<div class="window-bone"> <canvas class="window-canvas"></canvas> <div class="window-body"></div> <div class="window-title"></div> </div>
こんな感じのコードをイメージすると思いますが…
var context = document.body; var bone, canvas, body, title; bone = document.createElement("div"); canvas = document.createElement("canvas"); body = document.createElement("div"); title = document.createElement("div"); context.appendChild(this.db.bone); bone.appendChild(canvas); bone.appendChild(body); bone.appendChild(title); bone.className = "window-bone"; body.className = "window-body"; canvas.className = "window-canvas"; title.className = "window-title"; if (ie) { canvas = G_vmlCanvasManager.initElement(canvas); }
実行結果は、なぜかこのような要素片になります。
<div class="window-bone"> <canvas class="window-canvas"></canvas> </div>
実は、G_vmlCanvasManager.initElement(element) を実行すると、内部で走る G_vmlCanvasManager_::fixElement_() によりelementの兄弟要素や子孫要素が抹殺されます。
ですので、クロスブラウザなコードは以下となります。
var context = document.body; var bone, canvas, body, title; bone = document.createElement("div"); canvas = document.createElement("canvas"); body = document.createElement("div"); title = document.createElement("div"); context.appendChild(this.db.bone); bone.appendChild(canvas); if (ie) { canvas = G_vmlCanvasManager.initElement(canvas); } bone.appendChild(body); bone.appendChild(title); bone.className = "window-bone"; body.className = "window-body"; canvas.className = "window-canvas"; title.className = "window-title";
ほんのさわりだけの説明になりましたが、excanvas.jsを初めて使う人は、「絵が出ない」「中身が消える」といった奇怪な現象に出会うかもしれません。
「excanvasのバグだ!」とあわてる前に、このブログエントリを思い出してください。