読者です 読者をやめる 読者になる 読者になる

SVG Girlの公開と内部実装

javascript jsdo.it svg SVG

乗り換え以外で初めてアメリカ行きました。ago@kyo_ago)です。

すでに先週のこととなってしまいましたが、jsdo.it上でSVG Girlというコンテンツを発表したのでご紹介させていただきます。
(現在IE9のリリースに合わせて英語版のみ公開しています。日本語版は26日の日本語版IE9リリースにあわせて公開を予定しています)

SVG Girlって?

SVG GirlはSVGを使ったアニメーション作品で、動画コンテンツの中身をすべてSVGのみで表現しています。

先週開催されたMicrosoft主催のMIX11のキーノートでも発表され(00:08:40ぐらいからご覧いただけます)、大画面に表示されたアニメーションで会場をわかせました。

SVGって?

SVGはテキストで表現されたベクターデータで、XMLで線画情報を保持しています。

ブラウザ上からは通常のDOM API経由で操作することが可能で、JS、CSSから内容を変更することが可能な画像形式です。

内部実装

現在の実装では.ai形式で作成されたアニメーションの各コマを.svg形式で出力したあと、JSでDOM Treeにすべてのコマを追加してsetIntervalでdisplay:noneしています。

当初アニメーション全体をそのままSVGへ変換したところ、未圧縮状態で150MB以上になり、読み込みに3分、読み込み後のメモリ使用量は1.2GBを超えていました。

その状態から最適化を行い、現在では未圧縮状態で40MB、読み込みは早い機種で数秒、メモリ使用量も400MB程度まで軽量化されています。

高速化

高速化に関してはCDNの利用、svgのレイヤー化(今回はsvg内でのレイヤー分けではなく、html上のz-indexを使ってレイヤー化しています)が主な点ですが、それ以外にもJS内で以下のような実装を行っています。

.innerHTML以外の使用

svgはサーバ上からtextとして読み込まれますが、その後DOMノードへ変換するためtextから要素へ変換するための処理が必要となります。

これに関して当初は.innerHTMLを使用していましたが、最終的には以下のような実装を行うことでinnerHTMLに対して2割程度高速化できました。

var range = document.createRange();
if (range.createContextualFragment) {
    parent.appendChild(range.createContextualFragment(text));
    return parent.lastChild;
};
div.insertAdjacentHTML
    ? div.insertAdjacentHTML('afterBegin', text)
    : div.innerHTML = text
;
return parent.appendChild(div.firstChild);

具体的にはcreateContextualFragmentか、insertAdjacentHTMLが使える場合にはinnerHTMLではなくそちらを使用しています。

style要素の動的書き出し

SVG Girlではユーザが簡単に画面上の色を変えることができ、そこで変更された色で動画を再生する機能を持っています。

当初この機能は変更された色情報を元にsvgを読み込み直し、svg text内の色情報を正規表現で置き換える実装になっていましたが、この方法では再読み込み時に時間がかかってしまうため以下のような方法で実装しました。

var selector = '';
var method = $.browser.msie ? 'toLowerCase' : 'toUpperCase';
for (var i = 0, c1; c1 = color[i]; i += 2) {
    var c2 = color[i + 1][method]();
    c1 = c1[method]();
    selector += '[fill="'+c1+'"]{fill:'+c2+'}\n';
};
$('<style class="svg_color_edit" id="svg_color_edit_base">'+selector+'</style>').appendTo('head');

具体的にはsvg要素自体に変更を加えるのではなく、style要素で色情報を書き出すことで、色変更実装の簡略化、再読込無しでの色変更の実施ができるようになっています。

上記コードではブラウザごとに処理を切り分けていますが、これはIE9で属性指定が小文字でしか一致しなかったためです。
(今回唯一ブラウザ実装の差異が発生した点でした)

カヤックではアニメーションが好きな技術者も募集しています!