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

Handling touch events.


type alias Event =
{ keys : Keys
, changedTouches : List Touch
, targetTouches : List Touch
, touches : List Touch 
}

Type that get returned by a browser touch event. Its purpose is to provide all useful properties of JavaScript TouchEvent in the context of the elm programming language.

This event contains key modifiers that may have been pressed during touch event, and lists of Touch objects corresponding to JavaScript Touch objects.


type alias Keys =
{ alt : Basics.Bool
, ctrl : Basics.Bool
, meta : Basics.Bool
, shift : Basics.Bool 
}

Keys modifiers pressed during the event. Checking if the ctrl key was pressed when the event triggered is as easy as:

isCtrlKeyPressed : Touch.Event -> Bool
isCtrlKeyPressed touchEvent =
    touchEvent.keys.ctrl

Beware that it may not be working on some platforms, returning always false.


type alias Touch =
{ identifier : Basics.Int
, clientPos : ( Basics.Float
, Basics.Float )
, pagePos : ( Basics.Float
, Basics.Float )
, screenPos : ( Basics.Float
, Basics.Float ) 
}

A Touch object. It has a unique identifier, kept from start to end of a touch interaction. Client, page, and screen positions are provided for API completeness, however, you shall only need to use the clientPos property. For example, to get the coordinates of a touch event:

touchCoordinates : Touch.Event -> ( Float, Float )
touchCoordinates touchEvent =
    List.head touchEvent.changedTouches
        |> Maybe.map .clientPos
        |> Maybe.withDefault ( 0, 0 )

Touch Events

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

Triggered on a "touchstart" event. Let's say that we have a message type like this:

type Msg
    = StartMsg ( Float, Float )
    | MoveMsg ( Float, Float )
    | EndMsg ( Float, Float )
    | CancelMsg ( Float, Float )

We can listen to touchstart events like follows:

div
    [ Touch.onStart (\event -> StartMsg (touchCoordinates event)) ]
    [ text "touch here" ]

In a curried style, this can also be written:

div
    [ Touch.onStart (StartMsg << touchCoordinates) ]
    [ text "touch here" ]

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

Triggered on a "touchmove" event. Similarly than with onStart, we can write:

div
    [ Touch.onMove (MoveMsg << touchCoordinates) ]
    [ text "touch here" ]

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

Triggered on a "touchend" event. Similarly than with onStart, we can write:

div
    [ Touch.onEnd (EndMsg << touchCoordinates) ]
    [ text "touch here" ]

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

Triggered on a "touchcancel" event. Similarly than with onStart, we can write:

div
    [ Touch.onCancel (CancelMsg << touchCoordinates) ]
    [ text "touch here" ]

Advanced Usage


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

Options for the event.

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

Personalize the html event options. If for some reason the default behavior of this package (prevent default) does not fit your needs, you can change it like follows:

onStart : (Touch.Event -> msg) -> Html.Attribute msg
onStart =
    { stopPropagation = False, preventDefault = True }
        |> Touch.onWithOptions "touchstart"

eventDecoder : Json.Decode.Decoder Event

Touch event decoder. The decoder is provided so that you can extend touch events if something you need is not provided.

touchDecoder : Json.Decode.Decoder Touch

Touch object decoder. The decoder is provided so that you can extend touch events if something you need is not provided.

touchListDecoder : Json.Decode.Decoder a -> Json.Decode.Decoder (List a)

Personalized TouchList decoder. This decoder is provided so that you can extend touch events if something you need is not provided. If for example, you need the Touch.force property, (which is not implemented by this package since not compatible with most browsers) and can guaranty in your use case that it will be used with a compatible browser, you could define:

type alias MyTouchEvent =
    { changedTouches : TouchWithForce
    }

type alias TouchWithForce =
    { touch : Touch
    , force : Float
    }

decodeMyTouchEvent : Decoder MyTouchEvent
decodeMyTouchEvent =
    Decode.map MyTouchEvent
        (Decode.field "changedTouches" (touchListDecoder decodeWithForce))

decodeWithForce : Decoder TouchWithForce
decodeWithForce =
    Decode.map2 TouchWithForce
        Touch.touchDecoder
        (Decode.field "force" Decode.float)