SVG女子が話題を呼んでいることもあり、連休中にSVGに触れました。作ったのはJavascriptで動的に図形を描画したり動かしたりするもの。ジャンルとしてはSRPGやタワーディフェンスゲームに近いと言えます。
forked from: SRPG Map (Hex, SVG) - jsdo.it - share JavaScript, HTML5 and CSS
その他にもいくつか書きましたので、興味をお持ちの方はご覧いただけると嬉しいです。
以下、気づいたことをメモしておきます。なお開発環境はMac OSX 10.6.7 + Chrome 11.0.696.65でした。
SVGはjQueryとの相性が悪い
今回はjQuery 1.5.2を利用しましたが、attr()やaddClass()がrectなどのDOM要素に使えませんでした。具体的には、attr()などで書き換えた属性やクラスが描画に反映されませんでした。Chromeの開発者ツールで見る限り、属性の更新には成功しているようなのですが……。
stackoverflowなどを見る限りではこの問題は既知らしく、一般にはjQuery SVGなどのjQueryプラグインを利用して回避するようです。が、jsdo.itで手軽に書きたかったこととSVGを直に触っておきたかったことから、今回はjQueryを使わずにDOM要素を生成・操作する方法をとりました。例えば矩形(マップチップ)を生成して配置するスクリプトは以下のようになります。
var rect = document.createElementNS('http://www.w3.org/2000/svg', 'rect'); rect.setAttribute('x', 32); rect.setAttribute('y', 64); rect.setAttribute('width', CHIP_SIZE); rect.setAttribute('height', CHIP_SIZE); rect.setAttribute('class', 'chip chipKind1'); rect.id = 'x1y2'; $svg.append(rect);
見栄えに関する情報はCSSに切り出せる
SVGをcanvasと比較した場合、最も大きな利点はこれではないかと思います。Javascriptのコードからデザインに関する記述を除き、ロジックに集中させることが可能です。
SVGの特徴としてよく言及される「拡大してもボケない」も確かに利点なのですが、そもそも拡大する機会が少ないのであまり嬉しくありません。iPadのようなタブレットで動くようになると、わりと嬉しいんでしょうか。
今回はマップチップの着色をCSSで行いました。stroke-widthプロパティで線の太さを、strokeプロパティで線の色を、fillプロパティで塗りつぶす色を指定しています。
.chip { stroke-width: 2; stroke: #000; } .chipKind0 { fill: #0f0; }
z-indexは使えない
SVGの要素同士が重なりあった場合、後から追加された要素が手前側に表示されます。cssのz-indexが使えればよかったのですが、少なくとも今のところはそのような挙動になっていません。試した限りでは、兄弟要素同士でもダメでした。
@uupaa SVG では z-index も一応あるけど、同一親要素に対する兄弟同士でのみ有効=親子関係が優先ですね。http://bit.ly/c9R3Ba DOM いじるしかないと SVG Wiki に書いてあります http://bit.ly/ddqYOM
今回は「手前に表示したい」ケースだけで「奥に表示したい」というケースはなかったので、持ってきたい要素をSVG要素から削除して追加しなおすメソッドを用意しました。
function moveToTop(id) { var e = document.getElementById(id); svg.removeChild(e); svg.appendChild(e); }
座標系が面倒
Javascript標準のMath.cos()などは角度を弧度法で扱いますが、SVGは角度を度数法で扱います。このため図形を回転させる場合などは“ラジアン→度”の変換が必要です。
var deg = rad * 180 / Math.PI;
また回転させた図形をsetAttributeで移動させる際にも注意が必要です。図形を回転させた際に図形の座標系も回転している事に気づかず、時間をロスしました。
// from http://jsdo.it/eller86/qcC9 $.each(weapons, function(i, w){ var elem = document.getElementById(w.id); if (!elem) { return; } elem.setAttribute('x', w.r); // X座標しか変更していないが、回転時の角度に沿って斜めに移動してくれる };