kyoncy です。2023年に入社してから estie 物流リサーチの開発をしています。
週末はよく車で物流施設を巡ったりしています。同士の方、話しましょう!
estie ではデザインエンジニアとして働いていて自分は主にフロントエンドの開発を担当することが多いのですが、開発してる中で気になってるけどちゃんと調べてなかったなぁを解決する記事です。
アイコンを表示する際に Fontawesome のようなライブラリを使ったり、イラレでアイコンを作ったり、ロゴをSVGで表示することがありますが、なんかよくわからないコードが書いてあって import したら表示された から脱却しようという記事です。
この記事を読んでSVGファイルをエディタに表示してSVGIconGuessr(そんな言葉はない)しましょう!
SVGってなに…
アイコンなどの2次元のベクターグラフィックをするためのXMLベースのマークアップ言語です。
ベクター画像は数式や直線・曲線などを利用するため、ラスター画像のように「ここはこの色」といったピクセルの概念がありません。それゆえJPEGやPNGなどのラスター画像と比較した以下の特徴があります。
JPEG, PNG, … | SVG |
---|---|
ラスター | ベクター |
デジタル写真などに適している | デジタルイラスト、ロゴなどに適している |
サイズ拡大すると画質が下がってしまう | 画質を損なわずにサイズ拡大ができる |
ファイルサイズが大きい | ファイルサイズが小さい |
SVGはこんなやつです、って画像を貼ろうと思ったのですがそれだとSVGじゃないことに気づきました。なのでコードを貼っておきます。
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none"> <path d="M 12 12 m -9 0 a 9 9 0 1 0 18 0 a 9 9 0 1 0 -18 0" /> <path d="M 12 10 m -3 0 a 3 3 0 1 0 6 0 a 3 3 0 1 0 -6 0" /> <path d="M 6.168 18.849 a 4 4 0 0 1 3.832 -2.849 h 4 a 4 4 0 0 1 3.849 2.849" /> </svg>
svg
タグで囲み、子要素に path
などのタグを書いてイラストなどを表現します。
解析やっていき!
.svgファイルを開いたときに大抵の人は解読しようとは思わないのですが、特に敬遠させてる存在は path
君、あなたですよ…
<path d="M 12 12 m -9 0 a 9 9 0 1 0 18 0 a 9 9 0 1 0 -18 0" />
安心してください、1から解説するので一緒にSVGスキルのレベルアップしていきましょう!
レベル1からレベル5になるぞ
SVGは左上の座標を0として右方向にX軸、下方向にY軸が伸びています。ここでは circle
polygon
g
について例を挙げながら説明します。
circle
名前から分かる通りで円です、イメージがつきやすいですね。
- cx: 円の中心のx座標
- cy: 円の中心のy座標
- r: 半径
<circle cx="50" cy="50" r="20" stroke="red" stroke-width="3" fill="none" />
(50, 50) の位置に半径 20 の円があって、太さ3の赤い枠線、塗りつぶしなしを表現しています。
polygon
直線の区間で作られる閉じた図形を作ります。
- points: 多角形を描く (x,y) の点をリストで記述する(点はなくてもOK)
<polygon points="20,90 50,10 80,90 5,37 95,37 " fill="none" stroke="black" />
点が多すぎなければ頭の中でどういう線が描かれてるのかまだ分かりやすいですね。
(20,90) (50,10) (80,90) (5,37) (95,37) の区間で構成される閉じた図形(星)を表現しています。
g
他のSVG要素をグループ化するために使います。グループなので g というのは分かりやすい最高!
Duotone のアイコンで色ごとにグループ化しておくといった使い方をすると読みやすくなりますね。
<g fill="none" stroke="red"> <circle cx="50" cy="50" r="20" stroke-width="3" /> <polygon points="20 90 50 10 80 90 5 37 95 37 " /> </g>
それぞれに設定するのではなく親である g
で規定したfill, strokeの情報が、子である circle
, polygon
に継承されます。
レベル15くらいを目指す
ここまで基礎的なSVGの要素を例を交えて説明したところで問題の path
に戻ります。
<path d="M 12 12 m -9 0 a 9 9 0 1 0 18 0 a 9 9 0 1 0 -18 0" />
path
の読み方についての決まりなのですが
d
の値を左から読んでいく英単語から次の英単語の手前までを1コマンド(
M 12 12
, ```a 9 9 0 1 0 18 0‘‘‘)- 今回の例だと、英単語が4つあるので4コマンド
ということを覚えておきましょう。各コマンドを細かく見ていきます。コッカラッス
MoveTo
まずは M 12 12
は MoveTo を表しており現在地の座標を (12, 12) に移動することを表してます。
次の m -9 0
も同じく MoveTo なのですが、現在位置からの相対位置への移動を表しています。そのため、この時点では (3, 12) にいることになります(なぜ2回移動した)
次以降にも出てきますが大文字なら絶対位置、小文字なら相対位置で覚えましょう。
Arc
次は a 9 9 0 1 0 18 0
ですが長いですね… a は Arc(円弧) を表しています。見るべき数字が多いので一旦記号に置き換えると a rx ry angle large-arc-flag sweep-flag dx dy
となります。
rx, ry は楕円の半径(同じなら真円)を表しており、dx, dy は現在位置から (dx, dy) 移動した点に円弧を描くかを表しています。
angleはX軸に対しての楕円の角度(傾き)を表しており、large-arc-flag が1なら大きく0なら小さく円弧を、sweep-flag が1なら時計回りに0なら反時計回りに円弧を描きます。
<svg viewBox="0 0 40 40" xmlns="http://www.w3.org/2000/svg" fill="none"> <path d="M 12 12 a 9 18 0 1 1 9 9" stroke="black" /> <path d="M 12 12 a 9 18 90 1 1 9 9" stroke="red" /> <path d="M 12 12 a 9 18 0 1 0 9 9" stroke="green" /> <path d="M 12 12 a 9 18 90 1 0 9 9" stroke="blue" /> </svg>
今回の例 a 9 9 0 1 0 18 0
で言うと (3, 12) からX軸に18進んだ位置への半径9の半円になるため large-arc-flag は0でも1でも同じで、sweep-flag が1のため下半円となります。
ここも A と a があり、Aであれば移動する点は絶対位置、a であれば相対位置へ円弧を描きます。
最後の a 9 9 0 1 0 -18 0
も (21, 12) からX軸に-18進んだ半径9の半円になるため元の位置に戻ります。
つまりこの path
は円を表してることになります。
LineTo
もちろん直線も書くことができます。
- L x y: 現在位置から (x, y) に直線を描く(l であれば相対座標)
- H x: 現在位置のX座標だけ x に移動した点に直線を描く(h であればX軸の相対座標)
- V y: 現在位置のY座標だけ y に移動した点に直線を描く(v であればY軸の相対座標)
その他
そのほかにもベジエ曲線を書くことができますが、レベル50くらいになるので SVGIconGuessr で遭遇したらスルーしましょう…
このアイコンなーんだ?
この記事の最初に例示した以下を解読してみましょう。
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"> <path d="M 12 12 m -9 0 a 9 9 0 1 0 18 0 a 9 9 0 1 0 -18 0" /> <path d="M 12 10 m -3 0 a 3 3 0 1 0 6 0 a 3 3 0 1 0 -6 0" /> <path d="M 6.168 18.849 a 4 4 0 0 1 3.832 -2.849 h 4 a 4 4 0 0 1 3.849 2.849" /> </svg>
次の3つのうちのどれかが正解です、推測できるまでスクロールしないで 🙇
1行目は先ほどと同じなので、中心が (12, 12) で半径が9の円です。これを元に2行目を見ると、1行目と似ていますね。
1, 2行目を比較すると、2行目については1行目より少し上 (12, 10) からX軸に-3進んだところから半径3の円を描いてることが分かるかと思います。以下のように読み替えることもできますね(なぜこうじゃなかったのか…)
<circle cx="12" cy="12" r="9" /> <circle cx="12" cy="10" r="3" />
もう答えが分かってしまったかと思いますが、最後の M 6.168 18.849 a 4 4 0 0 1 3.832 -2.849 h 4 a 4 4 0 0 1 3.832 2.849
を見ていきましょう。
(6.168, 18.849) に移動してますが、左下あたりに位置し1行目で描いた円の上から出発してるかも?くらいの推測はできそうですね。
その後 a 4 4 0 0 1 3.832 -2.849
を見ると現在位置から右上の方に半径4で、large-arc-flag=0, sweep-flag=1 なので小さい円弧を時計回りに描いてることが分かります。
そこからX軸方向に4の直線を描いてます。
そして最後は現在位置から右下の方に半径4で先ほどと同じく小さい円弧を時計回りに描いてます。
最後の座標に到達した時、Y軸はスタートと同じで 18.849 ですが、X軸は 11.664 に移動したため 17.832 となり (17.832, 18.849)、6.168 + 17.832 = 24 なので X = 12 で線対象になっていそうですね。
ユーザーアイコンっぽいシルエットが見えた方は大正解です、SVGIconGuessrしましょう!
最後に
どんどんプロダクトが増えていたり扱えるデータの種類も量も増えてきており、やらなきゃいけないこともやりたいことも山盛りです!
熱い想いを持つメンバーと一緒に estie で一緒に産業の真価を、さらに拓きましょう!