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

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

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

fsubal

March 05, 2019
Tweet

More Decks by fsubal

Other Decks in Technology

Transcript

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

    View Slide

  2. 2

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

    View Slide

  3. 3

    View Slide

  4. 4

    View Slide

  5. 今日話すこと
    5

    View Slide

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

    View Slide

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

    View Slide

  8. なぜ SVG か
    8

    View Slide

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

    View Slide

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

    View Slide

  11. viewBox
    11

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  15. 最高
    15

    View Slide

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

    View Slide

  17. で、
    17

    View Slide

  18. SVG を drag したい
    18

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  28. まず draggable にしてみよう
    28

    View Slide

  29. Snap.svg
    29

    View Slide

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

    View Slide

  31. と、思いきや
    31

    View Slide

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

    View Slide

  33. 33

    View Slide

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

    View Slide

  35. 次は
    35

    View Slide

  36. 座標を計算する
    36

    View Slide

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

    View Slide

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

    View Slide

  39. 39

    View Slide

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

    View Slide

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

    View Slide

  42. 42

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  48. まとめ
    48

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide