最近、elm-touch-eventsを使って遊んでみてるので、その簡単な解説をば。
elm-touch-eventsとは
Elmには、デフォルトでタッチイベントを制御する機能は入っていません(Elm 0.18では)。
これでは、スマホ向けに凝ったUIを作るときに、困ったりすることがありそうですね。
そこで便利なpackageが、elm-touch-eventsです。
何ができるの?
DOMをタッチしたときに、「指が触れたとき」、「指を動かしたとき」、「指を離したとき」の3つについて、
それぞれに発火するイベントを作成することができます。
マルチタッチにも対応しています。
デモ
スライド動作によるオブジェクトの移動と、
ピンチアウトによるズーム機能を実装しました。
https://ebiryu.github.io/elm-touch-demo/
(※スマホなどのタッチデバイスじゃないと動作しないです)
使い方
大体のことはpackageのページを見れば書いてありますが、
今回は日本語のドキュメントを増やす意味で書いておきます。
インストール
elm-packageでインストールします。
elm-package install mpizenberg/elm-touch-events
SingleTouch
マルチタッチにも対応していると言いましたが、
シングルタッチはもっと簡単に実装できます。
デモのソースコードを見てみましょう。
https://github.com/ebiryu/elm-touch-demo/blob/master/src/Main.elm
まずはviewから。
objects : Model -> List (Svg Msg)
objects model =
[
...
, polygon
[ SingleTouch.onStart SingleStart
, SingleTouch.onMove SingleMove
...
]
[]
]
このobjects
はviewで読み込んでるsvgの要素ですが、
その中の一つの三角形に、attributeとしてonStart
とonMove
を追加しています。
このonStart
とonMove
は、HtmlのEventsのonInput
のようなものです。
onInput
では、StringをMsgと一緒に返していますが、
onStart
、onMove
では、DOM全体から見たときのタッチした座標をMsgに乗せて返します。
Msgは次のようになります。
type Msg
= SingleStart Touch.Coordinates
| SingleMove Touch.Coordinates
| ...
Touch.Coordinate
は、{clientX : Float, clientY : Float}
という形になっているため、あとはこれらの値をupdate内で使ってあげればいい感じになります。
MultiTouch
MultiTouchでも、同様にonStart
、onMove
などがあるのですが、SingleTouchとは違い、Touch.Coordinates
ではなく、Touch.Event
を返します。
view : Model -> Html Msg
view model =
div
[ ...
, MultiTouch.onStart MultiStart
, MultiTouch.onMove MultiMove
]
[ ...
]
type Msg
= ...
| MultiStart Touch.Event
| MultiMove Touch.Event
このTouch.Event
は、そのままでは扱いづらいので、これを処理する関数もpackageに同梱されています。
それは、Touch.touches
、Touch.changedTouches
、Touch.targetTouches
の3つです。
これらについて詳細は、次のページに書いてあります。
https://www.html5rocks.com/ja/mobile/touch/
touches: 現在画面上にあるすべての指のリスト。
targetTouches: 現在の DOM 要素上にある指のリスト。
changedTouches: 現在のイベントに関与している指のリスト。たとえば、touchend イベントでは、離れた指のリストになります。
これら3つの関数は、指のリストをDict型で返します。
デモでは、次のように、Dict.valuesでList型に変換して使っています。
update : Msg -> Model -> ( Model, Cmd Msg )
update msg model =
case msg of
...
MultiStart event ->
let
...
eventPositions =
Dict.values <| Touch.touches event
...
in
...
MultiMove event ->
let
...
eventPositions =
Dict.values <| Touch.changedTouches event
...
in
...
こんな感じですね。
基本的には、指が触れたときにtouches
でその全部の指の位置を取り値を初期化し、
動いたときにもtouches
、離したときその座標を取りたいときはchangedTouches
を使う感じになりそうです。
svgの移動やズームに使っているtransformについては、以下のページがとても参考になりました。
http://defghi1977.html.xdomain.jp/tech/svgMemo/svgMemo_04.htm
まとめ
elm-touch-eventsを使えば、スマホ向けのリッチなwebアプリもElmで作れそうですね。