LoginSignup
9
2

More than 5 years have passed since last update.

任意のイベントデータを含んだメッセージを作る方法とBrowser.Domについて

Last updated at Posted at 2018-12-17

こんにちは、うじまるです。

Elmアドベントカレンダー2 18日目の記事です

この記事はElm歴1年ちょいの人が書いたものです。

MouseEventの情報がほしい!!

SVGエディタやCanvasを使ったDrawアプリを作ってるとマウスの座標情報が欲しくなるときがあります。
しかし、ElmのMouseEventのonClickonMouseMoveなどは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の引数に渡ってくるオブジェクトです。
なので、altKeyshiftKeyなどのキーが押されながらクリックされたかなども取得できます。

さて、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みんなで使いましょう!!最高なので!!

以上がポエムでした。

9
2
2

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
9
2