mpizenberg / elm-pointer-events / Html.Events.Extra.Pointer

Handling pointer events.


type alias Event =
{ pointerType : DeviceType
, pointer : Html.Events.Extra.Mouse.Event
, pointerId : Basics.Int
, isPrimary : Basics.Bool
, contactDetails : ContactDetails 
}

Type that get returned by a pointer event.

Since the JS class PointerEvent inherits from MouseEvent, the pointer attribute here is of type Mouse.Event.

So to get the relative (offset) position of a pointer event for example:

relativePos : Pointer.Event -> ( Float, Float )
relativePos event =
    event.pointer.offsetPos

And to know if the shift key was pressed:

isShiftKeyPressed : Pointer.Event -> Bool
isShiftKeyPressed event =
    event.pointer.key.shift


type DeviceType
    = MouseType
    | TouchType
    | PenType

The type of device that generated the pointer event


type alias ContactDetails =
{ width : Basics.Float
, height : Basics.Float
, pressure : Basics.Float
, tiltX : Basics.Float
, tiltY : Basics.Float 
}

Details of the point of contact, for advanced use cases.

Basic Usage

onDown : (Event -> msg) -> Html.Attribute msg

Listen to pointerdown events.

Let's say that we have a message type like this:

type Msg
    = DownMsg ( Float, Float )
    | MoveMsg ( Float, Float )
    | UpMsg ( Float, Float )

And we already have defined the relativePos : Pointer.Event -> ( Float, Float ) function (see Pointer.Event doc). Then we could listen to pointerdown events with something like:

div [ Pointer.onDown (relativePos >> DownMsg) ] [ text "click here" ]

However, since the Pointer API is not well supported by all browsers, I strongly recommend to use it in pair with the elm-pep polyfill for compatibility with Safari and Firefox < 59. It is also recommended that you deactivate touch-action to disable browsers scroll behaviors.

div
    [ Pointer.onDown ...
    , Pointer.onMove ...
    , Pointer.onUp ...

    -- no touch-action (prevent scroll etc.)
    , Html.Attributes.style [ ( "touch-action", "none" ) ]
    ]
    []

onMove : (Event -> msg) -> Html.Attribute msg

Listen to pointermove events.

Similarly than with onDown, we can write something like:

div [ Pointer.onMove (relativePos >> MoveMsg) ] [ text "move here" ]

onUp : (Event -> msg) -> Html.Attribute msg

Listen to pointerup events.

Similarly than with onDown, we can write something like:

div [ Pointer.onUp (relativePos >> UpMsg) ] [ text "click here" ]

onCancel : (Event -> msg) -> Html.Attribute msg

Listen to pointercancel events.

Similarly than with onDown, we can write something like:

div [ Pointer.onCancel (relativePos >> UpMsg) ] [ text "move here" ]

onOver : (Event -> msg) -> Html.Attribute msg

Listen to pointerover events.

Similarly than with onDown, we can write something like:

div [ Pointer.onOver (relativePos >> UpMsg) ] [ text "move in here" ]

onEnter : (Event -> msg) -> Html.Attribute msg

Listen to pointerenter events.

Similarly than with onDown, we can write something like:

div [ Pointer.onEnter (relativePos >> UpMsg) ] [ text "move in here" ]

onOut : (Event -> msg) -> Html.Attribute msg

Listen to pointerout events.

Similarly than with onDown, we can write something like:

div [ Pointer.onOut (relativePos >> UpMsg) ] [ text "move out of here" ]

onLeave : (Event -> msg) -> Html.Attribute msg

Listen to pointerleave events.

Similarly than with onDown, we can write something like:

div [ Pointer.onLeave (relativePos >> UpMsg) ] [ text "move out of here" ]

Advanced Usage


type alias EventOptions =
{ stopPropagation : Basics.Bool
, preventDefault : Basics.Bool 
}

Options for the event.

onWithOptions : String -> EventOptions -> (Event -> msg) -> Html.Attribute msg

Choose the pointer event to listen to, and specify the event options.

If for some reason the default behavior of this lib (prevent default) does not fit your needs, you can change it with for example:

myOnDown : (Pointer.Event -> msg) -> Html.Attribute msg
myOnDown =
    { stopPropagation = False, preventDefault = True }
        |> Pointer.onWithOptions "pointerdown"

eventDecoder : Json.Decode.Decoder Event

An Event decoder for pointer events.

Similarly than with the Mouse module, the decoder is provided so that you can extend Pointer.Event with specific properties you need. If you need for example the tangentialPressure attribute of the pointer event, you could extend the present decoder like:

type alias MyPointerEvent =
    { pointerEvent : Pointer.Event
    , tangentialPressure : Float
    }

myEventDecoder : Decoder MyPointerEvent
myEventDecoder =
    Decode.map2 MyPointerEvent
        Pointer.eventDecoder
        (Decode.field "tangentialPressure" Decode.float)

And use it like as follows:

type Msg
    = TangentialPressureMsg Float

div
    [ myOnDown (.tangentialPressure >> TangentialPressureMsg) ]
    [ text "Use pen here to measure tangentialPressure" ]

myOnDown : (MyPointerEvent -> msg) -> Html.Attribute msg
myOnDown tag =
    let
        decoder =
            myEventDecoder
                |> Decode.map tag
                |> Decode.map options

        options message =
            { message = message
            , stopPropagation = False
            , preventDefault = True
            }
    in
    Html.Events.custom "pointerdown" decoder

BEWARE that the minimalist elm-pep polyfill may not support all properties. So if you rely on it for compatibility with browsers not supporting pointer events, a decoder with an unsupported attribute will silently fail. If such a need arises, please open an issue in elm-pep.