2009/12/05 (土)
scriptless で resizable な角丸 SVG 書けた。
svg |
--
元ネタはOperaで丸角を実現するCSSを試してみた (解決) - by edvakf in hatena。
ここで問題になっているのは「rect の描画が stroke-width の半分だけズレる」こと。
どういうことかというと、例えば
<rect width="100%" height="100%" stroke="red" stroke-width="10"/>
(確認ページ)
のように線の太さを 10px で指定しても 5px 幅分しか表示領域に描画されず、残りははみ出してしまいます。これは
<rect x="5" y="5" width="100%" height="100%" stroke="red" stroke-width="10"/>
(確認ページ)
のように始点を 5px ずつズラしたものと比べるとわかりやすいかと思います。
width と height が固定であれば描画位置を調整するだけでうまくいくのですが、サイズを可変にしたい場合、width に対して例えば"100%-10px"のような指定ができないのがネックになります。
もちろん script を使って動的にサイズを計算・設定するのは難しくはないのですが、svg 内の script は img 要素や css の background-image に指定した svg では動かないし、ページ側の script から制御するのも面倒です。
というわけで svg 内で完結して script を使わずにサイズを可変にする方法を考えてみました。
<?xml version="1.0" encoding="utf-8"?> <svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"> <defs> <rect id="base" x="5" y="5" width="100%" height="100%" rx="30" ry="30" fill="#E4F2FD" stroke="#dddddd" stroke-width="10" /> <clipPath id="tl"> <rect x="0%" y="0%" width="50%" height="50%" /> </clipPath> <clipPath id="tr"> <rect x="50%" y="0%" width="100%" height="50%" /> </clipPath> <clipPath id="bl"> <rect x="0%" y="50%" width="50%" height="100%" /> </clipPath> <clipPath id="br"> <rect x="50%" y="50%" width="100%" height="100%" /> </clipPath> </defs> <use xlink:href="#base" clip-path="url(#tl)" /> <use xlink:href="#base" clip-path="url(#tr)" x="-10" /> <use xlink:href="#base" clip-path="url(#bl)" y="-10" /> <use xlink:href="#base" clip-path="url(#br)" x="-10" y="-10" /> </svg>
やっているのは簡単で、元になる rect を 4 分割してそれぞれの位置を調整して配置しているだけです。元にした svg は角丸にするためにライブラリを作ってみる (Opera 用コードの試作) | ヨモツネットから。
ちょっと凝ったことをやろうとすると難しいですが、描画のロジックがプログラムから分離できるところが SVG の魅力ですね。
--
テストページは Firefox 3.5.5 で表示されませんが、SVG をファイルに保存して開くと表示されます。どうも svg を data スキームで表示すると use 要素が使えていないようです。
--
フキダシが完成しました。(確認ページ)
<?xml version="1.0" encoding="utf-8"?> <svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"> <defs> <rect id="base" x="1" y="1" width="100%" height="100%" rx="20" ry="20" fill="#FFF" stroke="#000" stroke-width="2" /> <clipPath id="tl"><rect x="0%" y="0%" width="50%" height="50%" /></clipPath> <clipPath id="tr"><rect x="50%" y="0%" width="100%" height="50%" /></clipPath> <clipPath id="bl"><rect x="0%" y="50%" width="50%" height="100%" /></clipPath> <clipPath id="br"><rect x="50%" y="50%" width="100%" height="100%" /></clipPath> <g id="rrect"> <use xlink:href="#base" clip-path="url(#tl)" x="0" /> <use xlink:href="#base" clip-path="url(#tr)" x="-18" /> <use xlink:href="#base" clip-path="url(#bl)" x="0" y="-18" /> <use xlink:href="#base" clip-path="url(#br)" x="-18" y="-18" /> </g> <g id="fukidashi"> <path d="M 17 20 L 17 50" stroke="#FFF" stroke-width="2" /> <path d="M 17 20 Q 14 30 2 35 Q 14 40 17 50" fill="#FFF" stroke="#000" stroke-width="2" /> </g> <g id="lfuki"><use xlink:href="#fukidashi" transform="matrix( 1, 0, 0, 1, 0, 0)"/></g> <g id="rfuki"><use xlink:href="#fukidashi" transform="matrix(-1, 0, 0, 1, 0, 0)"/></g> <g id="tfuki"><use xlink:href="#fukidashi" transform="matrix( 0, 1, 1, 0, 0, 0)"/></g> <g id="bfuki"><use xlink:href="#fukidashi" transform="matrix( 0,-1, 1, 0, 0, 0)"/></g> </defs> <!-- left --> <!-- <use xlink:href="#rrect" x="16" y="0" /> <use xlink:href="#lfuki" x="0" y="0"/> --> <!-- right --> <!-- <use xlink:href="#rrect" x="0" y="0" /> <use xlink:href="#rfuki" x="100%" y="0"/> --> <!-- top --> <!-- <use xlink:href="#rrect" x="0" y="16" /> <use xlink:href="#tfuki" x="0" y="0" /> --> <!-- bottom --> <!-- <use xlink:href="#rrect" x="0" y="0" /> <use xlink:href="#bfuki" x="0" y="100%" /> --> <!-- bottom(右寄せ) --> <use xlink:href="#rrect" x="16" y="0" /> <use xlink:href="#bfuki" x="100%" y="100%" transform="translate(-70,0)"/> </svg>
matrix の引数は忘れがちだからメモ。
matrixでの表現 | 代替のtransform | 補足 |
---|---|---|
matrix( 1, 0, 0, 1, 0, 0) | translate(0,0) | そのまま |
matrix(-1, 0, 0, 1, 0, 0) | scale(-1,1) | 左に反転(x軸に-1倍) |
matrix( 0, 1, 1, 0, 0, 0) | rotate(-90);scale(1,-1) | -90度回転して上に反転 |
matrix( 0,-1, 1, 0, 0, 0) | rotate(-90) | -90度回転 |
matrix( 1, 0, 0,-1, 0, 0) | scale(1,-1) | 上に反転(y軸に-1倍。鏡面効果に使える。) |
以下のツールを使用しました。
2009/11/24 (火)
SVG のテストページ
svg |
SVG をちょこちょこ弄りながら確認したいなーと思ったので簡単なテストページを作りました。
http://miya2000.jottit.com/svg_test
リサイズできるようにしてますので、ベクターグラフィックのステキな感じが味わえるかも。
あと作業結果を permallink として保存する機能を付けました。
(例)最小ファイルサイズSVGのOperaロゴに挑戦 - もし高校野球の女子マネージャーがOpera Browserを使ったら - チーム俺等のOpera のロゴ。
--
名前がつけられるようになったり。
ニコニコ動画のテレビみたいなアイコンは、左目が少し下がってるんですね。気付きませんでした。