

・SVG芸人
・イラストレーター
・複雑GUI会
・Vue.js Japan UG
・deno_ja
hashrock


SVG芸人が
よく聞かれる質問
「何でSVG?」
- なんで数ある技術の中からSVGなの?
- SVGの何が嬉しいの?
- っていうかSVG芸人って何?
即答できない
- 一言で説明しづらい
- 一切使わなくてもフロントエンドは作れる
- 使ってるうちに楽しくなってくる系
「使って楽しい」が
伝わればいいな…
お品書き
- 平成のワードアート
- 未来のワードアート
- ワードアートのSVG実装
- ついでにエディタの実装
ワードアートとは



ワードアート
- テキストをデザインできるMS Officeの共通モジュール
- かなり昔のOfficeからある
- 確認した中で最古のWordArtは1994年
- https://makewordart.com/

特徴的な極太書体
波打ってる

激しいグラデーション

ドロップシャドウ
3D風変形エフェクト

MS WordでのWordArtの
つくりかた



1994年(平成6年)
当時のWordArt
令和のワードアート
SVGならどこまでできる?
SVGで作ってみました
踊る

回る

セレクタブル

contenteditable

SVGすごい!
っていうかブラウザがすごい
SVGでのワードアートの作り方
<text x="40" y="80">Hello World</text>

1.テキスト要素

<text x="40" y="80">Hello World</text>
<path
fill="none"
stroke="blue"
stroke-width="3"
d="M 28 152 C 28 152 49 78 100 67 C 151 56 210 164 255 148 C 300 133 295 59 295 59"
/>
2.テキスト
曲線
<text x="40" y="80">
<textPath href="#MyPath">
Hello World
</textPath>
</text>
<path
id="MyPath"
fill="none"
stroke="blue"
stroke-width="3"
d="M 28 152 C 28 152 49 78 100 67 C 151 56 210 164 255 148 C 300 133 295 59 295 59"
/>

3.テキスト
+曲線
<textPath>を追加
テキストと曲線を
関連付ける
<path
id="MyPath"
fill="none"
stroke="blue"
stroke-width="3"
d="M 28 152 C 28 152 49 78 100 67 C 151...."
/>
「d属性」が曲線を定義している
しかし手書きはきつい
リアルタイム編集できれば便利そう…
SVG DOM は DOM Level 2 と互換性を保つように構築されている。
(W3C SVG 1.1 仕様)
SVGもDOMから扱える
ReactやVueなどのFWはSVGに対応している
バインディングも当然可能

Vueで曲線エディタを実装
3次ベジェ曲線
よく使うやつ
<path d="M70 110 C 70 140, 110 140, 110 110" />

<path d="M70 110 C 70 140, 110 140, 110 110" />

a
b
c
d
a
b
c
d
4つの制御点をもとに曲線を描画

ベジェ曲線を手描きしてみよう






<path :d="curvesStr" id="path1" />
points: [
{ x: 200, y: 200 },
{ x: 240, y: 200 },
{ x: 210, y: 250 },
{ x: 250, y: 250 }
]
curvesStr() {
return this.curves
.map(i => {
return `M ${i.points[0].x},${i.points[0].y} C ${i.points[1].x},${i.points[1].y} ${i.points[2].x},${i.points[2].y} ${i.points[3].x},${i.points[3].y}`;
})
.join(" ");
}
座標の配列(data内)
computedで文字列化してd属性に渡す
<path :d="curvesStr" id="path1" />
points: [
{ x: 200, y: 200 },
{ x: 240, y: 200 },
{ x: 210, y: 250 },
{ x: 250, y: 250 }
]
curvesStr() {
return this.curves
.map(i => {
return `M ${i.points[0].x},${i.points[0].y} C ${i.points[1].x},${i.points[1].y} ${i.points[2].x},${i.points[2].y} ${i.points[3].x},${i.points[3].y}`;
})
.join(" ");
}
この4つの点を
編集するUIを作ればOK
頂点・ハンドルの
ドラッグ

基本的にはHTML要素のドラッグと
変わらないはず
ただし注意点あり

ユーザー単位の世界
(単位なし)
スクリーン単位の世界
(px)

MouseEventから取れる座標は単位px
SVG側の単位に変換が必要
function screenToSvg(point, el, svg) {
const pt = svg.createSVGPoint();
pt.x = point.x;
pt.y = point.y;
return pt.matrixTransform(el.getScreenCTM().inverse());
}
ユーティリティ関数を作って対応
詳しくはviewBox / getScreenCTMなどの
キーワードで検索

きちんと対応すれば変形がかかった要素内でも
正常にドラッグ可能


ついでに作ったカラーピッカー
派手にする

Drop Shadow
SVGフィルタ
- defs下に定義する
- 組み合わせるといろんなフィルタを作れる
- そのものズバリのDrop Shadowはない
<filter id="dropshadow">
<feGaussianBlur in="SourceAlpha" stdDeviation="1" />
<feOffset dx="5" dy="5" result="offsetblur" />
<feComponentTransfer>
<feFuncA type="linear" slope="0.5" />
</feComponentTransfer>
<feMerge>
<feMergeNode />
<feMergeNode in="SourceGraphic" />
</feMerge>
</filter>


グラデーション

線形グラデーション
- (x1, y1), (x2, y2)の2点間をグラデーションする
- グラデーション定義もバインディングして変更できる
<linearGradient
gradientUnits="userSpaceOnUse"
id="rainbow"
:x1="gradient.start.x"
:y1="gradient.start.y"
:x2="gradient.end.x"
:y2="gradient.end.y"
>
<stop offset="0%" stop-color="#ff0000" />
<stop offset="16.7%" stop-color="#ffff00" />
<stop offset="33.3%" stop-color="#00ff00" />
<stop offset="50.0%" stop-color="#00ffff" />
<stop offset="66.7%" stop-color="#0000ff" />
<stop offset="83.3%" stop-color="#ff00ff" />
<stop offset="100%" stop-color="#ff0000" />
</linearGradient>
DEMO
できなかったこと
-
グラデーションエディタの実装
-
SVG出力(Inkscapeで読むと壊れます)
-
キーボード操作対応
-
複数選択
-
3D変形
どうしてSVGなのか?
svgをGUI構築フレームワークとして考えることも可能
UIコンポーネント構築のベースとして
使い勝手が良い
自由度が高く
hackyになりにくい
(テキスト周りは除く)
作ったものが
自分の想定を
超えてくる感がある
(個人の感想です)
作ったものの使いみちが特にないので…

とりあえずTシャツにしました
SVGでワードアート
By hash rock
SVGでワードアート
- 9,470