こんにちは、うじまるです。
Elmアドベントカレンダー2 18日目の記事です
この記事はElm歴1年ちょいの人が書いたものです。
MouseEventの情報がほしい!!
SVGエディタやCanvasを使ったDrawアプリを作ってるとマウスの座標情報が欲しくなるときがあります。
しかし、ElmのMouseEventのonClick
やonMouseMove
などはonClick : msg -> Attribute msg
なので座標情報が入っていません。
そんなときは、on : String -> Decoder msg -> Attribute msg
を使いましょう。
これを使うとこんな感じのものが作れます。
DEMO
マウスがクリックされた位置を取ってくる
さっそくクリックされた座標を取得できるonClickWithPoint : (Int -> Int -> msg) -> Attribute msg
を作ってみましょう。
まずは、デコーダーを作ります。
Json.Decoder
を作るにはelm/json
が必要なのでインストールしましょう。
on
関数に必要なデコーダーの型としては、Decoder (Int -> Int -> msg)
なのですが汎用的に使えるようにmousePointDecoder : (Int -> Int -> msg) -> Decoder msg
という関数にします。
実際に書くとこんな感じ
import Json.Decode as JD
mousePointDecoder : (Int -> Int -> msg) -> Decoder msg
mousePointDecoder msg =
JD.map2 msg
(JD.field "clientX" JD.int)
(JD.field "clientY" JD.int)
察しが良い人は気づきますが(良くなくても気づくか)、on
関数のDecoderでDecodeされるJSONはMouseEventの引数に渡ってくるオブジェクトです。
なので、altKey
やshiftKey
などのキーが押されながらクリックされたかなども取得できます。
さて、Decoderが完成したので次はonClickWithPoint
関数本体を作りましょう。
onClickWithPoint : (Int -> Int -> msg) -> Attribute msg
onClickWithPoint msg =
on "click" <|
mousePointDecoder msg
はい、これだけです。簡単ですね。
あとは普通のMouseEventのように使えます。
Browser.Dom.getViewportOf
これで座標も取ってこれたし、SVGエディタでもDrawアプリでもなんでも作れるぜ!!って思うかもしれません
が、なぜかこれだとグローバルな座標になってしまう(何故か分かる人、対処法が分かる人、コメントください🙏)のでDOM自身の座標が必要になります。
そこで使うのが0.19から追加された、Browser.Dom.getViewportOf : String -> Task Error Element
です。
この関数は、指定したIDのDOMを取得し座標や幅、高さを取得できるものです。
この関数を使って手に入れた座標をマウスイベントで取得した座標から引けば描画したい位置に描画できそうです。
実際に使うには、Task.attempt
を使ってCmd
にして使いましょう。
import Task
import Browser.Dom as Dom
type Msg
= GetCanvasSize (Result Error Element)
update msg model =
case msg of
Hoge ->
(model
, Dom.getViewportOf "canvas"
|> Task.attempt GetCanvasSize
)
みたいな感じです。
まとめ
- 任意のイベントデータを取得するには
on
関数を使いましょう - DOMの座標等を取って来るには
Browser.Dom.getViewportOf
を使いましょう -
Browser.Dom.getViewportOf
は存在しないIDを指定するとErr Error
になってしまうので気をつけてください
さいごに
1年半やってるとElmがめちゃくちゃ使いやすくて最高になってるのですが、インターンの面接で「Elmやってます!」って言うと「ふーん」って感じなので「Vue.jsとか使ってみるかー」って思っても、「Elmでいいやんけ・・・」ってなるのでElmみんなで使いましょう!!最高なので!!
以上がポエムでした。