DEV Community

Kristian Pedersen
Kristian Pedersen

Posted on

#30daysofelm Day 10: Mouse coordinates

This is day 10 of my 30 day Elm challenge

Today's useful little piece of knowledge was how to get information from browser events.

I wanted to get the X and Y position of the mouse pointer, so I found this Stack Overflow answer by O.O.Balance: https://stackoverflow.com/questions/57645824/how-can-i-listen-for-global-mouse-events-in-elm-0-19

In this case, were getting pageX and pageY. To see a full list, you can open your browser's dev tools and paste this:

document.addEventListener("mousemove", event => console.log(event))
Enter fullscreen mode Exit fullscreen mode
module Main exposing (main)

import Browser
import Browser.Events exposing (onMouseMove)
import Html exposing (Html, text)
import Json.Decode as Decode


type alias Model =
    { message : String }


init : flags -> ( Model, Cmd Msg )
init flags =
    ( { message = "Move the mouse pointer on the page" }, Cmd.none )


type alias Msg =
    { x : Int, y : Int }


update : Msg -> Model -> ( Model, Cmd Msg )
update msg model =
    case msg of
        { x, y } ->
            ( { model
                | message =
                    "You moved the mouse to page coordinates "
                        ++ String.fromInt x
                        ++ ", "
                        ++ String.fromInt y
              }
            , Cmd.none
            )


view : Model -> Html Msg
view model =
    text model.message


subscriptions : Model -> Sub Msg
subscriptions model =
    onMouseMove
        (Decode.map2 Msg
            (Decode.field "pageX" Decode.int)
            (Decode.field "pageY" Decode.int)
        )


main : Program () Model Msg
main =
    Browser.element
        { init = init
        , view = view
        , update = update
        , subscriptions = subscriptions
        }
Enter fullscreen mode Exit fullscreen mode

Here's the new program, in which the cursor's X position affects the hue:

module Main exposing (main)

import Browser
import Browser.Events exposing (onMouseMove)
import Color exposing (Color, hsl, rgb255, toCssString)
import Html exposing (Html, div, text)
import Html.Attributes exposing (style)
import Json.Decode as Decode


type alias Model =
    { message : String, color : Color }


init : flags -> ( Model, Cmd Msg )
init flags =
    ( { message = "Move the mouse pointer on the page"
      , color = rgb255 100 100 100
      }
    , Cmd.none
    )


type alias Msg =
    { x : Int, y : Int }


update : Msg -> Model -> ( Model, Cmd Msg )
update msg model =
    case msg of
        { x, y } ->
            ( { model
                | message =
                    "You moved the mouse to page coordinates "
                        ++ String.fromInt x
                        ++ ", "
                        ++ String.fromInt y
                , color = hsl (x |> toFloat |> (\n -> n / 1000)) 0.5 0.5
              }
            , Cmd.none
            )


view : Model -> Html Msg
view model =
    div [ style "background-color" (toCssString model.color) ] [ text model.message ]


subscriptions : Model -> Sub Msg
subscriptions model =
    onMouseMove
        (Decode.map2 Msg
            (Decode.field "pageX" Decode.int)
            (Decode.field "pageY" Decode.int)
        )


main : Program () Model Msg
main =
    Browser.element
        { init = init
        , view = view
        , update = update
        , subscriptions = subscriptions
        }
Enter fullscreen mode Exit fullscreen mode

See you tomorrow!

Top comments (1)

Collapse
 
wolfadex profile image
Wolfgang Schuster

In your update you have

update msg model =
    case msg of
        { x, y } ->
Enter fullscreen mode Exit fullscreen mode

If you wanted to you can destructure both records and types with only a single constructor in the arguments sections like so

type alias Msg =
    { x : Int, y : Int }

update : Msg -> Model -> ( Model, Cmd Msg )
update { x, y } model =
    ...
Enter fullscreen mode Exit fullscreen mode

or

type Msg
    = MousePos Int Int

update : Msg -> Model -> ( Model, Cmd Msg )
update (MousePos x y) model =
    ...
Enter fullscreen mode Exit fullscreen mode

Not that your solution is bad/wrong, but this might feel a little more natural/normal for you.