2012年9月7日金曜日

svgを使って枠線の幅を指定可能なテンプレートを作る

svg2.0のワーキングドラフトが公開されました.ひと通り見た感じではsvg1.1で使いにくかったmarker要素が非常に使いやすくなるのが目玉っぽいのですが使えるようになるのはいつなんでしょうか.
それはともかく,あれれ?vector-effect属性がまだ記述されていない?まぁ,次の版で追加されていることを期待してここではvector-effect属性を紹介します.
なおvector-effect属性はもともとsvg1.2 tinyで定義されたもので,svg1.1には存在しないもののsvg2.0で導入されることを見越しfirefox,chrome,operaで実装されています.  

図形をtransform属性を使って変形した際,通常はstroke幅もこの変形に伴い変化してしまいますが,線を図形の境界として利用する場合も多く,このケースにおいてはstroke幅を固定しつつ領域のみを変形したい場合もあります.このような場合にvector-effect属性を用いる事ができます.

この属性に設定可能な値は次の通りです.
  • non-scaling-stroke
    スケールに依存しないストローク幅
  • none
    スケールに依存したストローク幅
ここでのスケールとはtransform属性やviewBox属性から計算されるスケールを指します.non-scaling-strokeを設定した図形のstrokeは常に固定幅で表示されます.実際に試してみましょう.animateTransform要素を使って大きさを変化させています.


<svg version="1.2" baseProfile="tiny" viewBox="-100 -100 200 200">
    <rect x="-20" y="-20" width="40" height="40" rx="5" ry="5" stroke="blue" stroke-width="2" fill="none">
        <animateTransform
 attributeName="transform" type="scale" values="5,5;1,1;5,5" 
keyTimes="0;0.5;1" repeatCount="indefinite" begin="0s" dur="5s"/>
    </rect>
    <rect
 vector-effect="non-scaling-stroke" x="-20" y="-20" width="40" 
height="40" rx="5" ry="5" stroke="red" stroke-width="2" fill="none">
        <animateTransform
 attributeName="transform" type="scale" values="1,1;5,5;1,1" 
keyTimes="0;0.5;1" repeatCount="indefinite" begin="0s" dur="5s"/>
    </rect>
</svg>
赤い四角形は大きさが変化しているにもかかわらずstroke幅が変化していない事が判ります.

さて,このように様々な場面で使えそうな機能ですが,ここではsymbol要素に応用し,図形の大きさ,fill,stroke,stroke-widthを自由に設定可能な汎用性の高いテンプレートを定義してみましょう.

通常symbol要素においてもstroke幅は図形の大きさに従い変化してしまいますが,元となる図形のvector-effect属性にnon-scaling-strokeを指定することでsymbol要素を使う側から自由にstroke-widthを指定することが可能となります.この例ではstrokeの上にfillを乗せるようにテンプレートを定義することで,丁度htmlにおける「border:solid」のような効果を得ています.なお,non-scaling-stroke属性の値は子要素に継承されないようです.g要素でまとめて設定することは(現時点では)できないようです.


<?xml version="1.0" standalone="no"?>
<svg width="300" height="300" viewBox="0 0 300 300" preserveAspectRatio="none" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
 <defs>
  <path id="star" d="m 75.074678,89.367818 c -5.298931,3.709302 -18.468742,-10.1107 -24.93591,-10.2245 -6.467169,-0.1138 -20.114986,13.234302 -25.280154,9.341 -5.165167,-3.8934 3.90873,-20.6892 2.018482,-26.875 -1.890248,-6.1858 -18.8025017,-15.04088 -16.695821,-21.15636 2.106682,-6.11548 20.88447,-2.67589 26.183401,-6.38514 5.298931,-3.70925 8.4944,-22.53012 14.961568,-22.41633 6.467169,0.11378 8.998583,19.03541 14.16375,22.92877 5.165168,3.89336 24.052331,1.11647 25.942579,7.30227 1.890248,6.18579 -15.32304,14.44039 -17.429722,20.55589 -2.106681,6.1155 6.370758,23.2202 1.071827,26.9294 z" vector-effect="non-scaling-stroke"/>
  <symbol id="borderedStar" viewBox="0 0 100 100" preserveAspectRatio="none" overflow="visible">
   <use xlink:href="#star" fill="none" x="0" y="0"/>
   <use xlink:href="#star" stroke="none" x="0" y="0"/>
  </symbol>
 </defs>
 <use x="0" y="0" width="70" height="70" xlink:href="#borderedStar" fill="orange" stroke="red" stroke-width="10"/>
 <use x="70" y="0" width="130" height="130" xlink:href="#borderedStar" fill="red" stroke="pink" stroke-width="5"/>
 <use x="150" y="80" width="100" height="100" xlink:href="#borderedStar" fill="yellow" stroke="#0f0" stroke-width="15"/>
 <use x="0" y="100" width="150" height="150" xlink:href="#borderedStar" fill="blue" stroke="aqua" fill-opacity="0.5" stroke-width="20"/>
</svg>

symbol要素を外部svgファイルで定義すれば後から再利用するのも簡単です.
また,放物線グラフを頻繁に描く場合は,このテクニックを使ってsymbol要素で定義しておけば,あとは縦・横方向への伸縮のみで自由にグラフを描くことが可能となります.

0 件のコメント:

コメントを投稿