先日、SVG によるサイコロのサンプルを使用して最新の SVG のデモンストレーション (英語) を行いました。このサンプルは、現在、Internet Explorer 9 Test Drive サイト (英語) でご利用いただけます。このサンプルの作成を通じて、私は SVG にとってパフォーマンスと相互運用性は微妙につながっているものであり、別物ではないことに気付きました。私はこの点を重視し、今週の SVG Open カンファレンス (英語) に向けた、「SVG と HTML5 の未来 (英語)」というタイトルのプレゼンテーションを変更して、SVG 開発者たちが SVG の相互運用性を高められるようにいくつかの手法を紹介することにしました。

SVG のテストと SVG の試動

SVG はそもそもドキュメント形式を基にしています。現在も、最も一般的な用途は静的ドキュメント形式です。複雑な機械製図などの図は、拡大縮小の機能、高品質の印刷、移植性が要求されるという点から考えて SVG が最適です。

HTML5 とともに、SVG は次世代の対話型グラフィック Web に向かおうとしています。これは SVG の新しい使用方法と言えます。コミュニティとしては SVG の仕様をテストする新しい方法を考える必要があります。

SVG のテスト

W3C SVG Test Suite は、仕様が実装されているかどうかを "テスト" しますが、私たちの作業グループではそれだけでは不十分であると考えました。このテストだけでは、開発者が同一のマークアップを使用してそれがすべてのブラウザーで動作するという相互運用性が保証されません。W3C SVG Test Suite は、準拠をテストするためのものではなく、仕様が実装されているかどうかをテストするためのものです。W3C SVG テスト Wiki (英語) には次のように書かれています。

「W3C SVG Test Suite は、準拠をテストするための必要条件であって、十分条件ではありません。"テストに合格したサポート" という表現は、SVG の複雑な機能を多くサポートしているということであり、SVG の全体的なサポートを正確に示すものではありません。」

つまり、現在の W3C SVG Test Suite では、ブラウザーが仕様に準拠しているかどうかをテストできません。このため、私たちは SVG 作業グループと緊密に協力して SVG DOM 1.1 準拠テスト (英語) の作成を支援しています。これは実際には、外部的な活動として SVG Interest Group によって作成されています。この記事の執筆時点において、IE9 はこの自動テストに 100% 合格しています。私たちは SVG 作業グループとの協力と継続的な貢献によって、SVG Test Suite をいっそう強化することで相互運用性の問題への対応を支援しています。

また、SVG 仕様の各モジュール内の要件の数に対して、それぞれの要件の SVG Test Suite 内のテストの数は足りていません。Internet Explorer チームは、テスト資産の提供を通じてこの不足の解消を支援していますが、まだ十分ではありません。既に 56 個のテストを提供していますが、今後も長期的に貢献していく予定です。

SVG の試動

準拠とその先にある相互運用性を適切に検証するためには、Web 向けのさらに複雑な SVG を開発することが有効な手段だと考えられます。私自身、SVG によるサイコロ (英語) のデモを開発して SVG を試動させた経験から、SVG の相互運用性に関してコミュニティとして今後対応が必要である部分を明確に知ることができました。

SVG の仕様には、2,000 種類を超える要件があります。この個数は他の Web 仕様と比較すると多いものであり、複数の解釈が成り立つ余地が大きいことを意味します。私たちは SVG W3C 作業グループでこれらの違いを明らかにしようと取り組みました。各種のブラウザーで動作するという要件で行ったこの SVG デモの開発では、Web 開発者が直面する困難のいくつかが浮かび上がってきました。

相互運用性の問題の多くは、多数の要件の併用や、他の仕様への依存性が原因となっています。また、機能が開発者とブラウザー ベンダーの両者によって同じように解釈されていることを確認するだけの十分なコンテンツが Web 上にないことも原因です。HTML や CSS が何十年もかけて多数のユーザーによって改良されてきたのに対して、SVG は Web 開発者にとって比較的新しい領域であり、まだ同水準の使用や精密さには達していません。

今回、SVG が HTML5 の一部になったことにより、これまでの Web 開発者も、ベクター グラフィックを使用してユーザー エクスペリエンスを向上させる新しく優れた方法を身に付けてくれると期待しています。前回の SVG Face to Face ミーティング (英語) で、SVG 作業グループは次世代のグラフィカルな Web を中心とする使用に向けて SVG のシナリオ (英語) を組み立てました。SVG は、ここで重要な役割を果たします。

実装の比較

SVG によるサイコロのデモは、仕様の私自身の解釈に基づき、 Internet Explorer 9 を使って作成し、その後で他の各種のブラウザーでテストしました。動作が一致しなかった場合でも、その多くでは少なくとも 2 つのブラウザーが同じ動作を見せました。Internet Explorer の動作は、ときには Chrome または Safari と一致し、ときには Firefox または Opera と一致しました。Internet Explorer は最も最近の実装なので、あいまいさや矛盾の少なくとも一部は仕様の中で既に解消されている最新版の SVG 仕様 (英語) に基づいているというメリットがあります。もちろん、他にもメリットはあります。

当初はあまり考慮していなかったのですが、パフォーマンスは今回の開発作業に大きな影響がありました。

開発者の立場としては、一貫した相互運用性のあるユーザー エクスペリエンスを実現するために、すべてのブラウザーでぼかし、グラデーション、マスクなどの同じグラフィック機能を使用したかったのですが、パフォーマンスの問題からそれは不可能でした。Windows での全面的にハードウェア アクセラレートされたグラフィックでは、グラフィックに関する大量の計算を GPU に移行できました。低画質のモード ("Low Fidelity") を追加して、GPU を完全には活用できないブラウザーでもこのデモを体験できるようにしました。これには、SVG の CSS によるスタイル指定のデモンストレーションという面白い副次的な効果もありました。

予定外の切り替え

さまざまなブラウザーでデバッグしているうちに、開発者にとってはきわめて興味深い "切り替え" を行うことになりました。IE9 デバッグ ツールに未解決のバグがいくつかあり (現在は修正済み)、SVG で作業するときにコード内にブレークポイントを置けませんでした。このため、私は Firefox の有名なアドオンである Firebug の使用に切り替えました。しかし、Firefox でデモを実行したところ非常に遅かったので、やはり Internet Explorer 9 でデバッグすることにしました。

最終的には、大部分の非互換性についてブラウザー固有のコードを記述することなく回避できることがわかりましたが、そこまでの手間は予想よりも、また妥当であると考えられるよりもはるかに大きなものでした。 SVG の同一マークアップを確実にするためにはコミュニティとしてすべきことがまだたくさんあることがわかりました。

コード

SVG は古くからある仕様ですが、多くの開発者にとっては新しいものなので、このデモのコードと概念の一部を詳細に見ていきます。

ドキュメント構造

最初の例ですが、HTML5 の SVG をサポートしているブラウザーはまだ多くないため、ドキュメントは SVG をインラインで埋め込む XHTML として構成する必要がありました。

<!DOCTYPE html>
<html id="demohtml" xmlns="http://www.w3.org/1999/xhtml" class="testdrive">
<head>
<title>
SVG Dice
</title>
</head>
<body id="demobody" onload="Setup()">
<audio id="sndRemove" volume="1" src="assets/remove.mp3" preload="true" ></audio>
<svg overflow="visible" id="theSVG" xmlns=http://www.w3.org/2000/svg
xmlns:xlink="http://www.w3.org/1999/xlink" width="100%" height="100%" >
</svg>
</body>
</html>

上の単純な <!DOCTYPE html> によって、Internet Explorer 9 は SVG がサポートされる "標準モード" で実行するように設定されます。SVG が HTML に直接埋め込まれていることに注目してください。CSS とスクリプトは、どちらも指定されているとおりにこの HTML 要素からリンクされます。

<script type="text/javascript" src="demo.js"></script>
<link rel="Stylesheet" type="text/css" href="demo.css" />

これで、基本的な HTML と SVG ドキュメント、スタイル シート、スクリプト ファイルの構造ができました。次に、アニメーションやユーザー エクスペリエンスのために必要なグラフィカル要素を構築し、スタイルを用意し、スクリプトを記述する必要があります。

コンテンツの追加

Web 開発コミュニティの大きな利点であり、特徴でもある点の 1 つに、いわゆる "コピー/貼り付け" の使用があります。だれでも、著作権などで保護されていない SVG アートを Wikimedia などから簡単に検索して、自分のアプリケーションやサイトにそのまま使用できます。その他にも、コンテンツの新規生成や既存コンテンツの変更に使用できるツールがいくつかあります。たとえば、SVG に特化したオープン ソースとしては Inkscape があります。またマイクロソフトや Adobe も、SVG へのエクスポートを可能にするグラフィック ツールを提供しています。今回は、サイコロと船に既存のオープン ソースのクリップ アートを使用しました。

当初は、分離のためにこれらの SVG ソースを別々のファイルに保存していました。しかし残念ながら、サイズ指定や SVG イメージのサポートなど、各ブラウザーでさまざまな問題が発生したので、1 つの HTML ファイルにすべての SVG を含めざるを得ませんでした。

SVG には、<defs> という概念があります。これは、要素をスタイルと属性で定義するために使用され、定義した要素は後から <use> で再利用できます。この 2 つの概念は、きわめて強力です。これにより、さまざまなサイズのサイコロを大量に作成し、カップ上のサイコロの画像や、ゲームの実行中にカップに入っていくサイコロ、画面を横切って転がっていくサイコロとして使用することができました。私は、さまざまなファイルから <defs> をドキュメントの先頭の SVG タグの直後に配置しました。

<defs>
<!-- for left die -->
<linearGradient id="grad21" x1=".445" x2=".554" y1=".442" y2=".555">
<stop stop-opacity=".9" offset="0" stop-color="#470808"/>
<stop stop-opacity=".9" offset=".65" stop-color="#700d0d"/>
<stop stop-opacity=".9" offset="1" stop-color="#8c1111"/>
</linearGradient>
</defs>

これらの <defs> は、後から次のように参照されます。

<!-- edges -->
<path d="M 2474 4434 L 4860 2945 C 5009 " fill="url(#grad21)"/>

<defs> を配置し、メインのクリップ アート コンテンツをインラインで記述した後、エクスペリエンスの残りをデザインしました。このとき、SGV は上のレイヤーから下のレイヤーに向かって表示することを意識します。残りの主なコンテンツは、スコアボード、フェルト、テキスト、カップでした。

ユーザーの対話型操作およびアニメーションの追加

このデモでとても難しかった点の 1 つは、サイズ変更の処理でした。コードでは、最初にサイズ変更イベントを登録し、<svg> とそこに含まれる svg フラグメントの寸法を設定しました。簡潔にするために、<g> でグループ化して、拡大縮小および配置を個別に適用できるようにしました。

document.getElementById("theSVG").setAttribute("width", surfaceWidth.toString() + "px");

ここですぐに気付くことは、この JavaScript コードは DOM を操作する標準の JavaScript であり、Web 開発者にとって見慣れたものであるということです。SVG には独自の DOM メソッドがありますが、今回は DOM Level 2 構造にほぼ従っています。SVG 作業グループ全体での見解としては、SVG DOM を再検討する必要があると考えています。

次に、静的な 2 つのサイコロを SVG フラグメントとして使用し、それらを複製するコードを作成する必要がありました。さらに、参照をプロパティ付きで配列として格納し、アニメーション効果用に変形を操作し、物理エンジンがサイコロを適切に認識できるようにする必要がありました。サイコロを作成するループは簡単です。必要なサイコロの数だけループを繰り返して、オリジナルを DOM に複製し、それらを管理する配列を作成します。

メモ: ここでは簡潔にするためにサンプルのコードの大部分を省略していますが、Platform Preview サイト (http://ie.microsoft.com/testdrive/Performance/SVGDice/Default.xhtml、英語) ですべてのコードを見ることができます。

最初に、既定の属性を設定しながら、プロトタイプを複製し、DOM に追加します。transform の構造を使用して、サイコロを移動 (translate)、回転 (rotate)、サイズ変更 (scale) します。

// create an instance of die #1 and add it to the SVG Doc
this.die1 = createElement("g");
var tmpChild = this.die1.appendChild(createElement("g"));
var tmpNode = this.die1.appendChild(tmpChild);
tmpNode.appendChild(nodeDie1.cloneNode(true));
// set some default attributes
this.die1.setAttribute("id", "die_1_" + number.toString());
this.die1.setAttribute("transform",
"translate(" + this.x.toString() + "," + this.y.toString() + ")
scale ("
+ this.scale.toString() + ")");

ここで、SVG フラグメントのグループを複製する便利な方法として、<use> 要素を使用するつもりでした。残念なことに、<use> の実装は、特にスタイル設定やイベントについてブラウザーによって異なります。

次に、サイコロを徐々に小さくするために、SVGDOM getBBox() メソッドを使用してサイコロの寸法を取得します。このメソッドは、物理エンジン内で衝突を検出するために使用される SVGRect を返します。

var rectSize = this.die1.getBBox(); // calculate dimensions for use with physics
this.height = rectSize.height;
this.width = rectSize.width;

このサンプルの作成において良かった点の 1 つは、物理的処理を簡単にしてくれる Box2DJS エンジンを発見して、使用できたことです。このエンジンは多くのプロジェクトで使用されており、現在は Web 開発でも使用されるようになっています。サイコロを作成する前に、周囲の世界 (world) を初期化します。

function createWorld(width, height) {
var worldAABB = new b2AABB();

var world = new b2World(worldAABB, gravity, doSleep);
createGround(world, width, height);
// Side
createBox(world, 0, 0, 30, height);
createBox(world, width, 0, 30, height);
createBox(world, 0, 0, width + 30, 30);
createBox(world, 0,height , width+30,30);

return world;
}

そしてサイコロの作成過程で各サイコロをこの世界に追加し、最初の速度を設定します。

// add this dice to the physics engine
this.circleBody = createBall(world, this.xTrans, this.yTrans, this.width);
// give the force a slightly random starting velocity
this.circleBody.SetLinearVelocity(initialForce);

サイコロを追加するユーザー操作を追加したら、サイコロを取り除く処理、カップを揺らす処理も追加します。次にタイマーを作成し、時間を進めます。

timer = window.setInterval(DoStuff, 16);
// move the world
world.Step(timeStep, iteration);

Die クラスには、タイマーのステップに合わせて呼び出されるプロトタイプ更新関数が含まれています。サイコロを動かす最初のメカニズムは、物理エンジンから座標を取得し、当初に作成した要素のすべてで transform プロパティを設定することです。

var transFormString = "translate(" + Math.round(this.circleBody.m_position.x)
+ "," + Math.round(this.circleBody.m_position.y) + ") scale (" +
this.scale.toString() + ") rotate(" + Math.round(this.rotation).toString()
+ "," + Math.round(this.xTrans).toString() + "," +
Math.round(this.yTrans).toString() + ")";

これでサイコロが移動、回転、衝突します。

実装によっては、transform 属性を使用することが最速の方法とは限りません。前に説明したように、setTranslate() や setRotate() などのメソッドを提供する SVGDOM は使用しませんでした。ここで選択したメソッドは、将来 CSS Transform (英語)CSS Transitions (英語)CSS Animations (英語) とともに使用する可能性を考慮しています。

グラフィックのスタイル指定

最後に、DOM に統合されている SVG の利点を活かし、CSS を使用してシーンのスタイルを変更します。オリジナルのアートはデザイン ツールで作成されているので、色を表す RGB 値と不透明度が含まれています。

<linearGradient id="cgrad2c" x1="1" x2=".17" y1="0" y2=".58">
<stop stop-opacity=".9" offset="0" stop-color="#700d0d"/>
<stop stop-opacity=".9" offset="1" stop-color="#b51616"/>
</linearGradient>

これらの RGB 値をスタイルで置き換えました。

<linearGradient id="cgrad2c" x1="1" x2=".17" y1="0" y2=".58">
<stop class="diceCorner6"/>
<stop class="diceCorner7">
</linearGradient>

これにより、次のように各スタイルのスタイル シートを作成できました。

g#classHandler.vegas .diceCorner6 {stop-opacity:.9;offset:0;stop-color:#700d0d;}
g#classHandler.vegas .diceCorner6 {stop-opacity:.9;offset:1;stop-color:#b51616;}

g#classHandler.lowfidielity .diceCorner6 {offset:0;stop-color:#000000;}
g#classHandler.lowfidielity .diceCorner6 {offset:1;stop-color:#000000;}

次に、ドキュメント先頭の 1 つのクラス プロパティを設定して、ドキュメント内のすべてのスタイルを変更しました。

// set the overall stylesheet via class
document.getElementById("classHandler").setAttribute("class", style);

スタイルがいつ変更されても DOM には影響がないので、サイコロが転がっている途中でもユーザーがスタイル シートを変更することができます。Internet Explorer 9 では、ハードウェア アクセラレートされたグラフィックによりこれがきわめて高速に処理されます。

今後のステップ

Internet Explorer 9 で SVG の使用を開始します。最新の Platform Preview リリースの IE9 は、SVG のプラットフォームとしては完成しています。各種の機能を試し、非互換性やバグを発見したら、問題を報告するコマンドや、Microsoft Connect を使用してぜひお知らせください。

IE チームは、サイト、ライブラリ、Web 上のその他の SVG コンテンツをテストしています。私たちの目的は、コンテンツの作成者をサポートし、機能セットのバグを見つけることです。重要なベスト プラクティスは、SVG のサポートをテストするときに、ブラウザーではなく機能を検出することです。私たちは、開発者が機能性ではなくブラウザーを検出している場所を見つけ、オープン ソース ライブラリへの変更を行ったり、コンテンツの作成者に連絡して、発生する可能性がある問題を修正しようとしています。どうかお手伝いください。

Web 開発者がこのテクノロジの使用を始めている様子を見ると本当に嬉しく思います。SVG を使ってグラフィックを充実させた、次世代 Web サイトの登場を楽しみにしています。

Patrick Dengler
シニア プログラム マネージャー
Internet Explorer