szubtsovskiy/elm-visualization/1.0.1

Unavailable. Nobody can download this version any more, with elm or with the Lamdera compiler: github.com/szubtsovskiy/elm-visualization is gone (deleted or private); Software Heritage not asked yet (this run's --swh-calls were used up); no fork with tag 1.0.1 found (54 same-name repos checked); no cached copy. Use another version.

Details

Zoom

This module implements a convenient abstraction for panning and zooming: it lets the user focus on a regions of interest in a visualization. It is quite intuitive in that dragging the mouse coresponds to panning, mouse wheel zooming, and touch interactions are also supported.

The implementation is agnostic about the DOM, so it can be used with HTML, SVG, or WebGL.

Setting up zooming in your app

While there are many ways to use this module, a typical setup will look like this:

import Zoom exposing (OnZoom, Zoom)


type alias Model =
    { zoom : Zoom
    }


type Msg
    = ZoomMsg OnZoom


-- ...

Next, initialize and configure the zoom model:

init : () -> ( Model, Cmd Msg )
init () =
    ( { zoom = Zoom.init { width = width, height = height } }
    , Cmd.none
    )

Note that you will need to provide the width and height of the element that you want to setup the zooming behavior for. If you don't know this information, then you might want to use Browser.Dom.getElement to get it.

Next setup a subscription:

subscriptions : Model -> Sub Msg
subscriptions model =
    Zoom.subscriptions model.zoom ZoomMsg

Then handle update:

update : Msg -> Model -> ( Model, Cmd Msg )
update msg model =
    case msg of
        ZoomMsg zoomMsg ->
            ( { model
                | zoom = Zoom.update zoomMsg model.zoom
              }
            , Cmd.none
            )

Finally, set up your view:

view : Model -> Html Msg
view model =
    svg
        (A.width width
            :: A.height height
            :: Zoom.transform model.zoom
            :: Zoom.events model.zoom ZoomMsg
        )
        [ myChildrenElements ]

Configuring the zoom behavior

type Zoom

This type will go into your model as it stores the internal state and configuration necessary to support the various user interactions.

{ width : Float
, height : Float
}
-> Zoom

Creates a brand new Zoom. You have to pass in the dimensions (in pixels) of the element that you want to make zoom-eable.

scaleExtent : Float -> Float -> Zoom -> Zoom

Allows you to set a minimum and maximum scale that the user will be able to zoom to.

Typically there is only limited resolution to the data, so setting the maximum such that the maximum resolution is comfortably visible (remember accessibility - some people will want to zoom a fair bit more than you might find necessary) would be a good idea.

The miminum zoom will always be asymptotically approaching zero, but setting a higher number is good, because the view can be "lost" if it gets too small. Typically you would set it such that the whole dataset fits into the view.

translateExtent : ( ( Float, Float ), ( Float, Float ) ) -> Zoom -> Zoom

Allows you to set a boundary where a user will be able to pan to. The format is ((left, top), (right, bottom)).

Typically you will want to set this to ((0, 0), (width, height)), however you can restrict it however you like. For example maps typically only restrict vertical movement, but not horizontal movement.

Updating the zoom

type OnZoom

This is the Msg type used. You will want to pass these to Zoom.update.

Note that when handling these messages, it is also extremely likely that the zoom transform has somehow changed, so you can also use that place in your update function to react to that. For example in a map application, you may want to fetch a different tile based on the zoom level:

update : Msg -> Model -> ( Model, Cmd Msg )
update msg model =
    case msg of
        Zoomed onZoom ->
            let
                oldTransform =
                    Zoom.asRecord model.zoom


                newZoom =
                    Zoom.update onZoom model.zoom


                newTransform =
                    Zoom.asRecord newZoom


                cmd =
                    if toTileCoords oldTransform /= toTileCoords newTransform then
                        fetchTile (toTileCoords newTransform)


                    else
                        Cmd.none
            in
            ( { model | zoom = newZoom }, cmd )

This is what you need to set up in your update function.

subscriptions : Zoom -> (OnZoom -> msg) -> Sub msg

Subrscriptions are used for allowing drags to continue outside the element as well for animated zooms on double-click.

Manipulating the zoom transform programmatically

-> { scale : Float
, translate :
{ x : Float
, y : Float
}
}
-> Zoom
-> Zoom

Change the zoom transform programmatically.

Enumerates the ways a zoom transform can be changed.

Changes the zoom transform instantly.

animatedAround : ( Float, Float ) -> TransitionOption

Animates the zoom transform minimizing movement around the specified point.

View

transform : Zoom -> Attribute msg

A convenience for setting up the tranform attribute for SVG elements.

-> { scale : Float
, translate :
{ x : Float
, y : Float
}
}

Returns the actual transform for the view relative to the top left corner. You can then use these numbers to transform the view as necessary.

Handling User Events

events : Zoom -> (OnZoom -> msg) -> List (Attribute msg)

Sets up the event handlers necessary to support this behavior on various devices.

It is merely a convenience, implemented such:

events zoom tagger =
    Zoom.onDoubleClick zoom tagger
        :: Zoom.onWheel zoom tagger
        :: Zoom.onDrag zoom tagger
        ++ Zoom.onGesture zoom tagger
        ++ Zoom.onTouch zoom tagger

So if you want to customize the user experience, you can for example omit the onWheel handler in your own defintion.

onDoubleClick : Zoom -> (OnZoom -> msg) -> Attribute msg

Zooms in on double click, zooms out on double click while holding shift.

onWheel : Zoom -> (OnZoom -> msg) -> Attribute msg

Zooms on mousewheel.

onDrag : Zoom -> (OnZoom -> msg) -> List (Attribute msg)

Allows panning on mouse drag.

onGesture : Zoom -> (OnZoom -> msg) -> List (Attribute msg)

Supports pinch to zoom on desktop Safari.

onTouch : Zoom -> (OnZoom -> msg) -> List (Attribute msg)

Supports pinch to zoom on mobile devices.