m2O

2009/12/05 (土)

scriptless で resizable な角丸 SVG 書けた。

|  scriptless で resizable な角丸 SVG 書けた。 - m2O を含むブックマーク

書けた。

--

元ネタはOperaで丸角を実現するCSSを試してみた (解決) - by edvakf in hatena

ここで問題になっているのは「rect の描画が stroke-width の半分だけズレる」こと。

どういうことかというと、例えば

<rect width="100%" height="100%" stroke="red" stroke-width="10"/>

f:id:miya2000:20091205143937p:image (確認ページ)

のように線の太さを 10px で指定しても 5px 幅分しか表示領域に描画されず、残りははみ出してしまいます。これは

<rect x="5" y="5" width="100%" height="100%" stroke="red" stroke-width="10"/>

f:id:miya2000:20091205143938p:image (確認ページ)

のように始点を 5px ずつズラしたものと比べるとわかりやすいかと思います。

width と height が固定であれば描画位置を調整するだけでうまくいくのですが、サイズを可変にしたい場合、width に対して例えば"100%-10px"のような指定ができないのがネックになります。

もちろん script を使って動的にサイズを計算・設定するのは難しくはないのですが、svg 内の script は img 要素や cssbackground-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倍。鏡面効果に使える。)

以下のツールを使用しました。

samurai-logic.com

トラックバック - http://orera.g.hatena.ne.jp/miya2000/20091205

2009/11/24 (火)

SVG のテストページ

| SVG のテストページ - m2O を含むブックマーク

SVG をちょこちょこ弄りながら確認したいなーと思ったので簡単なテストページを作りました。

http://miya2000.jottit.com/svg_test


リサイズできるようにしてますので、ベクターグラフィックのステキな感じが味わえるかも。

あと作業結果を permallink として保存する機能を付けました。

(例)最小ファイルサイズSVGのOperaロゴに挑戦 - もし高校野球の女子マネージャーがOpera Browserを使ったら - チーム俺等Opera のロゴ

--

名前がつけられるようになったり。

ニコニコアイコン

ニコニコ動画のテレビみたいなアイコンは、左目が少し下がってるんですね。気付きませんでした。

トラックバック - http://orera.g.hatena.ne.jp/miya2000/20091124