2019/03/05 #https://techsalon.pixiv.co.jp での LT 資料です。
途中で出てくる「ニコナレのこれ」はこちらに移行済 → https://speakerdeck.com/fsubal/karihua-hananfalseyi-nili-tufalseka
SVG + React でつくるレイヤーの自由変形Layer Transformation with React + SVGpixiv Inc.f_subal2018/12/07
View Slide
2誰● 2016年新卒入社● sensei ➔ pixiv 投稿画面 ➔ pixivFACTORY● React / Redux / SVG@f_subal
3
4
今日話すこと5
レイヤーの自由変形をつくる6(っぽいもの)
● なぜ SVG を使うのか?● 何が SVG の自由変形に必要か?● 何を実装時に気をつけるか?7レイヤーの自由変形(っぽいもの)
なぜ SVG か8
任意の図形が描ける?画像ファイルへの変換が楽?9
もちろんそれもあるが10
viewBox11
● SVG 内のキャンバスサイズ的なものを決める属性○ 実際に表示する大きさとは別に決めることはできる● 要件: グッズをつくるエディタ○ グッズは物理的な世界にある○ 物理的な世界にあるってことは、長さが px 単位じゃない○ けど画面は長さが px 単位12viewBox と単位系
ブラウザに mm を描画したい13
1450x18mm の原稿が、599x215px で表示されている中のオブジェクトは mm で表現
最高15
HTML を draggable にしてる場合じゃない16
で、17
SVG を drag したい18
19もっというと、移動・拡大・回転 の3つがやりたい(厳密にはこの3つだけだと「自由変形」と呼ぶには弱いがゆるして )
そういえばHTML 5 Drag & Drop APIってやつが…20
21SVG Element に対応してない
それに依存したライブラリは無理(react-dnd-html5-backend とか)22
draggable 系ライブラリには他にも良いのあるけど( react-draggable とか )23
移動・拡大・回転全部は期待できない(たいていは移動だけ、拡大だけ)24
ある程度自作するものと割り切る25
全部入りではなくシンプルな drag 対応が欲しい26
● SVG 要素を draggable にする● 移動・拡大・回転にまつわる座標計算を書く● マウスの移動量(px)を原稿の大きさ(mm)に換算する● 以上をコンポーネントにする27やるべきこと
まず draggable にしてみよう28
Snap.svg29
● Adobe 製 SVG 何でもやる系ライブラリ。● react-* とかじゃない、Framework Agnostic● Snap(el).drag(fn, fn, fn) で要素を draggable にできる● これを使えば優勝…!30Snap.svg
と、思いきや31
● なんと、mousemove にしか対応してない● タッチデバイスは動かない○ Snap.svg と同じ API の touch 用 draggable ライブラリを自作して対応● 現状、mouse は Snap.svg、touch は自作ライブラリ になってる○ 両方対応ライブラリを目指す…32Snap#drag is mouse ONLY
33
これで基盤が整った34
次は35
座標を計算する36
● アフィン変換○ 線形変換 + 平行移動 を行列式で一手に扱う数学のアレ○ 「シアー」みたいな複雑な変換も行ける。● ホモグラフィ○ ↑ に加えて「台形」とか「ゆがみ」とかもいけるやつ○ 任意の四角形にできる37アフィン変換 ? ホモグラフィ ?
● 事実上おなじことやってるんだけど、良い感じの行列ライブラリとかないし○ Snap.svg の matrix クラスとかあるけど…まぁ…● 移動とか、単に座標の足し算で書いたほうが読み書きしやすいし● 回転も、回転中心とカーソルの位置から atan2 だけで済むし● ひとまず手早く書けて可読になるだろうと期待して愚直に38が、今回は使わずに実装する
39
● 水平な矩形の拡大は簡単○ マウスカーソルが動いた分を width と height に足すだけ● けど 30° 右に傾いた矩形の拡大はめんどい○ これだけは回転行列を使わないと無理40唯一の障壁「回転を考慮した拡大」
● 回転行列の公式を使って求める41点A を点O を中心に回転した時の座標https://ja.wikipedia.org/wiki/回転行列http://www.geisya.or.jp/~mwm48961/kou2/linear_image3.html
42
あとはだいたい気合でやる43
44その他気をつけること
● px ➔ mm 変換関数を作る必要がある● 1mm が 何 px に相当するかは window の横幅に依存する○ リサイズのたびに関数を作り変える● viewBox のある要素を見れば現在 1mm が何 px に相当するか計算できる○ dpi なり dpm が求められる45単位換算
4650x18mm の原稿が、599x215px で表示されているこの情報から px ➔ mm 関数が作れる!!
【宣伝】詳しくは niconare のコレを見てhttps://niconare.nicovideo.jp/watch/kn392747
まとめ48
● SVG の draggable 対応○ 思ったよりライブラリがないので DOM API と戦おう● 座標計算○ 行列計算にひるまずに実装しましょう○ ただ、基本的な変形は案外足し算レベルでいけたりもします● 単位換算○ px と それ以外が混在する要件に気をつけよう!49自由変形に必要なこと(っぽいもの)
他にもMobile Safari の SVG がバグりやすいとかnumber 型ばかりで間違うから型で守る話とか座標計算そのものよりも原点を揃えるのが大事とか、絶対座標と相対座標の混在とか、 タグがどんどんネストしていく話とかいっぱいあるので懇親会で聞いて下さい!!!50