2014年3月23日日曜日

svgビュー指定って知ってますか?

svgをimg要素等から参照する場合,直接ファイル名を指定する他に「svgビュー指定」と呼ばれるパラメータを渡すことが出来るんです.これってグラフィックの作画に直接関わる機能じゃないので,あまり知られていないのですが,憶えておくと結構便利ですから是非マスターして下さいね.

2014/03/24 ちょこっと内容を追加.基本は変わらず.
※注意:記事を書いては見たものの,その後いろいろ試してみたら結構な動作不良っぽいものがザクザクと.
ですから,フル活用する前にきっちりと動作検証をして下さいね.
私はブラウザベンダーにフィードバック入れときます.


率直にsvgビュー指定って何?


簡単に言うと,「svgファイルのviewBox指定をsvgの呼び出し側で指定する仕組み」のことです.

通常svgをブラウザで表示する場合,urlバーやimgやobject要素にsvgファイルへのパスを指定しますが,この場合svgファイルの最も外側のsvg要素のビュー設定に応じてグラフィックが描かれることになります.




大抵はこれで良いのですが,使い方によってはグラフィックの一部を拡大したり内容を回転させて表示させたいケースがあります.このような場合,素朴に考えるとjavascriptなりのプログラム的な処理を挟むことでグラフィックを書き換える方法を想像しがちですが,実はそんなことをしなくともsvgファイルへのパス文字列の後ろに特定のハッシュ値(#から始まる文字列)を指定することで対処できます.

例)containsView.svg#svgView(viewBox(100 100 250 250))


このハッシュ値のことをsvgビュー指定と呼びます.

svgビュー指定で指定可能なパラメータ


svgビュー指定では次の3つのパラメータを指定することが出来ます.
  • viewBox
    svgグラフィックにおける描画範囲や座標軸を定義する
    例)containsView.svg#svgView(viewBox(100 100 250 250))

  • preserveAspectRatio
    アスペクト比の取り扱い方を指定する
    例)containsView.svg#svgView(viewBox(100 100 250 150);preserveAspectRatio(none))

    ※この例のように複数の指定を記述する場合は「;」で区切って列挙します.
  • transform
    グラフィックに対する変形を行う
    例)containsView.svg#svgView(transform(rotate(30,100,100)))

いずれもsvgのソースコードではおなじみのものでしょう.

※この他にも仕様では二つパラメータ(zoomAndPan,target指定)が定義されているのですが,いずれも利用頻度が低いためにブラウザ上では動作しないか実装されていないため無視しています.

これらのsvgビュー指定を含んだurl文字列を使えば,例えばリンクをクリックした際にsvgグラフィックの描画内容を切り替えると言った処理も簡単に実現することができるのです.
例えばこのように.

※って実際に試してみると上手く行かないケースもあるねorz...

view要素・・・svgビュー指定を予め定義しておく


先ほどのsvgビュー指定はsvgファイルを使う側でsvgのビュー(見た目・表示範囲)を指示するものでした.
が,その中でもよく使われるものについてはsvgファイル内にview要素として定義しておくことが可能です.
この場合,svgファイルを使う側ではview要素のid値をurlのハッシュ値として指定することでview要素を選択することができます.

例)containsView.svg#view


上手にid値を定義できれば扱いやすいsvg画像となるでしょう.

:target擬似クラスと組み合わせる


view要素による描画範囲の変更について,そのままでは単にグラフィックの内容が拡大・縮小されるだけなのですが,view要素が選択されることで:target擬似クラスが有効となることに着目すると,次のように特定のviewが選択された時のみに表示されるグラフィックを定義することが可能となります.

例)上から#red,#blue,#green,#orangeを指定したもの
※コードは本記事の最後に掲載






立ちはだかるクロスブラウザの壁


・・・なのですが,現状クロスブラウザではありません.firefoxではview要素に対する:targetが有効とならないようです.残念.
また,chromeではimg要素で動作しなかったり,transformがブラウザによって動作が異なるなど中々検討すべき点はあります.

想定されるユースケース


例えばフロアマップなどはいかがでしょうか?
1枚のsvgグラフィックで全体のフロアマップを作り,各フロア毎のサブマップはview要素指定で行うのです.その際の詳細説明は:target擬似クラスを使って表示・非表示を切り替えます.

このように,無理にスクリプトを介さずとも様々な仕組みを実現できるのがsvgの楽しさです.みなさんも面白い使い方を考えてみて下さい.

ヒント


  • svg画像においてviewBox属性が定義されておらず,いざグラフィックを表示してみたら内容が見きれてしまった場合,svgビュー指定を追加することでオリジナルのsvgファイルに手を入れずに対処できるかもしれません.

コードサンプル


<?xml version="1.0" standalone="no"?>
<svg width="300px" height="300px" viewBox="0 0 300 300" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
 <style><![CDATA[
circle{
 fill:none;
 fill-opacity:0.5;
 stroke-width:2;
 stroke-dasharray:3;
}
view#red:target~circle[stroke=red]{fill:red;}
view#blue:target~circle[stroke=blue]{fill:blue;}
view#green:target~circle[stroke=green]{fill:green;}
view#orange:target~circle[stroke=orange]{fill:orange;}
rect:target{
 fill:yellow;
}
 ]]></style>
 <!--予め定義しておいたview要素-->
 <view id="view" viewBox="0 0 150 100" preserveAspectRatio="none"/>
 <view id="red"  viewBox="0 0 200 200"/>
 <view id="blue" viewBox="100 0 200 200"/>
 <view id="green" viewBox="0 100 200 200"/>
 <view id="orange" viewBox="100 100 200 200"/>
 <!--以下グラフィック-->
 <circle cx="75" cy="75" r="70" stroke="red"/>
 <circle cx="225" cy="75" r="70" stroke="blue"/>
 <circle cx="75" cy="225" r="70" stroke="green"/>
 <circle cx="225" cy="225" r="70" stroke="orange"/>
</svg>

0 件のコメント:

コメントを投稿