Upgrade to Pro — share decks privately, control downloads, hide ads and more …

SVG + React でつくる レイヤーの自由変形 / Layer Transformation with React + SVG

2f374df92882247e5985413dad8b39b9?s=47 fsubal
March 05, 2019

SVG + React でつくる レイヤーの自由変形 / Layer Transformation with React + SVG

2019/03/05 #https://techsalon.pixiv.co.jp での LT 資料です。

途中で出てくる「ニコナレのこれ」はこちらに移行済 → https://speakerdeck.com/fsubal/karihua-hananfalseyi-nili-tufalseka

2f374df92882247e5985413dad8b39b9?s=128

fsubal

March 05, 2019
Tweet

Transcript

  1. SVG + React でつくる レイヤーの自由変形 Layer Transformation with React +

    SVG pixiv Inc. f_subal 2018/12/07
  2. 2 誰 • 2016年新卒入社 • sensei ➔ pixiv 投稿画面 ➔

    pixivFACTORY • React / Redux / SVG @f_subal
  3. 3

  4. 4

  5. 今日話すこと 5

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

  7. • なぜ SVG を使うのか? • 何が SVG の自由変形に必要か? • 何を実装時に気をつけるか?

    7 レイヤーの自由変形 (っぽいもの)
  8. なぜ SVG か 8

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

  10. もちろんそれもあるが 10

  11. viewBox 11

  12. • SVG 内のキャンバスサイズ的なものを決める属性 ◦ 実際に表示する大きさとは別に決めることはできる • 要件: グッズをつくるエディタ ◦ グッズは物理的な世界にある

    ◦ 物理的な世界にあるってことは、長さが px 単位じゃない ◦ けど画面は長さが px 単位 12 viewBox と単位系
  13. ブラウザに mm を描画したい 13

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

  15. 最高 15

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

  17. で、 17

  18. SVG を drag したい 18

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

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

  21. 21 SVG Element に対応してない

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

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

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

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

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

  27. • SVG 要素を draggable にする • 移動・拡大・回転にまつわる座標計算を書く • マウスの移動量(px)を原稿の大きさ(mm)に換算する •

    以上をコンポーネントにする 27 やるべきこと
  28. まず draggable にしてみよう 28

  29. Snap.svg 29

  30. • Adobe 製 SVG 何でもやる系ライブラリ。 • react-* とかじゃない、Framework Agnostic •

    Snap(el).drag(fn, fn, fn) で要素を draggable にできる • これを使えば優勝…! 30 Snap.svg
  31. と、思いきや 31

  32. • なんと、mousemove にしか対応してない • タッチデバイスは動かない ◦ Snap.svg と同じ API の

    touch 用 draggable ライブラリを自作して対応 • 現状、mouse は Snap.svg、touch は自作ライブラリ になってる ◦ 両方対応ライブラリを目指す… 32 Snap#drag is mouse ONLY
  33. 33

  34. これで基盤が整った 34

  35. 次は 35

  36. 座標を計算する 36

  37. • アフィン変換 ◦ 線形変換 + 平行移動 を行列式で一手に扱う数学のアレ ◦ 「シアー」みたいな複雑な変換も行ける。 •

    ホモグラフィ ◦ ↑ に加えて「台形」とか「ゆがみ」とかもいけるやつ ◦ 任意の四角形にできる 37 アフィン変換 ? ホモグラフィ ?
  38. • 事実上おなじことやってるんだけど、良い感じの行列ライブラリとかないし ◦ Snap.svg の matrix クラスとかあるけど…まぁ… • 移動とか、単に座標の足し算で書いたほうが読み書きしやすいし •

    回転も、回転中心とカーソルの位置から atan2 だけで済むし • ひとまず手早く書けて可読になるだろうと期待して愚直に 38 が、今回は使わずに実装する
  39. 39

  40. • 水平な矩形の拡大は簡単 ◦ マウスカーソルが動いた分を width と height に足すだけ • けど

    30° 右に傾いた矩形の拡大はめんどい ◦ これだけは回転行列を使わないと無理 40 唯一の障壁「回転を考慮した拡大」
  41. • 回転行列の公式を使って求める 41 点A を点O を中心に回転した時の座標 https://ja.wikipedia.org/wiki/回転行列 http://www.geisya.or.jp/~mwm48961/kou2/linear_image3.html

  42. 42

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

  44. 44 その他 気をつけること

  45. • px ➔ mm 変換関数を作る必要がある • 1mm が 何 px

    に相当するかは window の横幅に依存する ◦ リサイズのたびに関数を作り変える • viewBox のある要素を見れば現在 1mm が何 px に相当するか計算できる ◦ dpi なり dpm が求められる 45 単位換算
  46. 46 50x18mm の原稿が、599x215px で表 示されている この情報から px ➔ mm 関数が作れる!!

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

  48. まとめ 48

  49. • SVG の draggable 対応 ◦ 思ったよりライブラリがないので DOM API と戦おう

    • 座標計算 ◦ 行列計算にひるまずに実装しましょう ◦ ただ、基本的な変形は案外足し算レベルでいけたりもします • 単位換算 ◦ px と それ以外が混在する要件に気をつけよう! 49 自由変形に必要なこと (っぽいもの)
  50. 他にも Mobile Safari の SVG がバグりやすいとか number 型ばかりで間違うから型で守る話とか 座標計算そのものよりも原点を揃えるのが大事とか、 絶対座標と相対座標の混在とか、

    <svg> タグがどんどんネストしていく話とか いっぱいあるので懇親会で聞いて下さい!!! 50
  51. SVG + React でつくる レイヤーの自由変形 Layer Transformation with React +

    SVG pixiv Inc. f_subal 2018/12/07