Slide 1

Slide 1 text

SVG + React でつくる レイヤーの自由変形 Layer Transformation with React + SVG pixiv Inc. f_subal 2018/12/07

Slide 2

Slide 2 text

2 誰 ● 2016年新卒入社 ● sensei ➔ pixiv 投稿画面 ➔ pixivFACTORY ● React / Redux / SVG @f_subal

Slide 3

Slide 3 text

3

Slide 4

Slide 4 text

4

Slide 5

Slide 5 text

今日話すこと 5

Slide 6

Slide 6 text

レイヤーの自由変形をつくる 6 (っぽいもの)

Slide 7

Slide 7 text

● なぜ SVG を使うのか? ● 何が SVG の自由変形に必要か? ● 何を実装時に気をつけるか? 7 レイヤーの自由変形 (っぽいもの)

Slide 8

Slide 8 text

なぜ SVG か 8

Slide 9

Slide 9 text

任意の図形が描ける? 画像ファイルへの変換が楽? 9

Slide 10

Slide 10 text

もちろんそれもあるが 10

Slide 11

Slide 11 text

viewBox 11

Slide 12

Slide 12 text

● SVG 内のキャンバスサイズ的なものを決める属性 ○ 実際に表示する大きさとは別に決めることはできる ● 要件: グッズをつくるエディタ ○ グッズは物理的な世界にある ○ 物理的な世界にあるってことは、長さが px 単位じゃない ○ けど画面は長さが px 単位 12 viewBox と単位系

Slide 13

Slide 13 text

ブラウザに mm を描画したい 13

Slide 14

Slide 14 text

14 50x18mm の原稿が、599x215px で表 示されている 中のオブジェクトは mm で表現

Slide 15

Slide 15 text

最高 15

Slide 16

Slide 16 text

HTML を draggable にしてる 場合じゃない 16

Slide 17

Slide 17 text

で、 17

Slide 18

Slide 18 text

SVG を drag したい 18

Slide 19

Slide 19 text

19 もっというと、 移動・拡大・回転 の 3つがやりたい (厳密にはこの3つだけだと「自由変形」と呼ぶには弱いがゆるして )

Slide 20

Slide 20 text

そういえば HTML 5 Drag & Drop API ってやつが… 20

Slide 21

Slide 21 text

21 SVG Element に対応してない

Slide 22

Slide 22 text

それに依存したライブラリは無理 (react-dnd-html5-backend とか) 22

Slide 23

Slide 23 text

draggable 系ライブラリには 他にも良いのあるけど ( react-draggable とか ) 23

Slide 24

Slide 24 text

移動・拡大・回転 全部は期待できない (たいていは移動だけ、拡大だけ) 24

Slide 25

Slide 25 text

ある程度 自作するものと割り切る 25

Slide 26

Slide 26 text

全部入りではなく シンプルな drag 対応が欲しい 26

Slide 27

Slide 27 text

● SVG 要素を draggable にする ● 移動・拡大・回転にまつわる座標計算を書く ● マウスの移動量(px)を原稿の大きさ(mm)に換算する ● 以上をコンポーネントにする 27 やるべきこと

Slide 28

Slide 28 text

まず draggable にしてみよう 28

Slide 29

Slide 29 text

Snap.svg 29

Slide 30

Slide 30 text

● Adobe 製 SVG 何でもやる系ライブラリ。 ● react-* とかじゃない、Framework Agnostic ● Snap(el).drag(fn, fn, fn) で要素を draggable にできる ● これを使えば優勝…! 30 Snap.svg

Slide 31

Slide 31 text

と、思いきや 31

Slide 32

Slide 32 text

● なんと、mousemove にしか対応してない ● タッチデバイスは動かない ○ Snap.svg と同じ API の touch 用 draggable ライブラリを自作して対応 ● 現状、mouse は Snap.svg、touch は自作ライブラリ になってる ○ 両方対応ライブラリを目指す… 32 Snap#drag is mouse ONLY

Slide 33

Slide 33 text

33

Slide 34

Slide 34 text

これで基盤が整った 34

Slide 35

Slide 35 text

次は 35

Slide 36

Slide 36 text

座標を計算する 36

Slide 37

Slide 37 text

● アフィン変換 ○ 線形変換 + 平行移動 を行列式で一手に扱う数学のアレ ○ 「シアー」みたいな複雑な変換も行ける。 ● ホモグラフィ ○ ↑ に加えて「台形」とか「ゆがみ」とかもいけるやつ ○ 任意の四角形にできる 37 アフィン変換 ? ホモグラフィ ?

Slide 38

Slide 38 text

● 事実上おなじことやってるんだけど、良い感じの行列ライブラリとかないし ○ Snap.svg の matrix クラスとかあるけど…まぁ… ● 移動とか、単に座標の足し算で書いたほうが読み書きしやすいし ● 回転も、回転中心とカーソルの位置から atan2 だけで済むし ● ひとまず手早く書けて可読になるだろうと期待して愚直に 38 が、今回は使わずに実装する

Slide 39

Slide 39 text

39

Slide 40

Slide 40 text

● 水平な矩形の拡大は簡単 ○ マウスカーソルが動いた分を width と height に足すだけ ● けど 30° 右に傾いた矩形の拡大はめんどい ○ これだけは回転行列を使わないと無理 40 唯一の障壁「回転を考慮した拡大」

Slide 41

Slide 41 text

● 回転行列の公式を使って求める 41 点A を点O を中心に回転した時の座標 https://ja.wikipedia.org/wiki/回転行列 http://www.geisya.or.jp/~mwm48961/kou2/linear_image3.html

Slide 42

Slide 42 text

42

Slide 43

Slide 43 text

あとはだいたい 気合でやる 43

Slide 44

Slide 44 text

44 その他 気をつけること

Slide 45

Slide 45 text

● px ➔ mm 変換関数を作る必要がある ● 1mm が 何 px に相当するかは window の横幅に依存する ○ リサイズのたびに関数を作り変える ● viewBox のある要素を見れば現在 1mm が何 px に相当するか計算できる ○ dpi なり dpm が求められる 45 単位換算

Slide 46

Slide 46 text

46 50x18mm の原稿が、599x215px で表 示されている この情報から px ➔ mm 関数が作れる!!

Slide 47

Slide 47 text

【宣伝】詳しくは niconare のコレを見て https://niconare.nicovideo.jp/watch/kn3927 47

Slide 48

Slide 48 text

まとめ 48

Slide 49

Slide 49 text

● SVG の draggable 対応 ○ 思ったよりライブラリがないので DOM API と戦おう ● 座標計算 ○ 行列計算にひるまずに実装しましょう ○ ただ、基本的な変形は案外足し算レベルでいけたりもします ● 単位換算 ○ px と それ以外が混在する要件に気をつけよう! 49 自由変形に必要なこと (っぽいもの)

Slide 50

Slide 50 text

他にも Mobile Safari の SVG がバグりやすいとか number 型ばかりで間違うから型で守る話とか 座標計算そのものよりも原点を揃えるのが大事とか、 絶対座標と相対座標の混在とか、 タグがどんどんネストしていく話とか いっぱいあるので懇親会で聞いて下さい!!! 50

Slide 51

Slide 51 text

SVG + React でつくる レイヤーの自由変形 Layer Transformation with React + SVG pixiv Inc. f_subal 2018/12/07