JohanWinther / elm-pan-and-zoom / PanZoom

This module implements a pannable and zoomable component.

Config


type alias Config msg =
{ viewportOffset : Coordinate
, minScale : Maybe Scale
, maxScale : Maybe Scale
, scalePerScrollPixel : Basics.Float
, draggableOnChildren : ElementFilter
, toSelf : MouseEvent -> msg 
}

Configuration options for the component.

Note: the viewport's default dimensions are 100vw and 100vh respectively but can be overriden by adding your own style attribute in view.

defaultConfig : (MouseEvent -> msg) -> Config msg

Default configuration:

{ viewportOffset = { x = 0, y = 0 }
, minScale = Nothing
, maxScale = Nothing
, scalePerScrollPixel = 0.001
, draggableOnChildren = Exclude []
, toSelf = toSelf
}


type ElementFilter
    = Include ClassList
    | Exclude ClassList

Filters elements by class name.


type alias ClassList =
List String

List of classes.

State


type alias Model msg =
{ state : State
, config : Config msg 
}

Contains config and internal state.

init : Config msg -> { scale : Scale, position : Coordinate } -> Model msg

Creates a Model from a Config and an initial scale and position for the content box.

scale will be clamped by minScale and maxScale if they are set.

position sets the position of the center point of the content box. So in order to position the content box at point p with respect to its top left corner you will need to set

position =
    { x = p.x + width / 2, y = p.y + height / 2 }

where the width and height are the dimensions of the content box specified in pixels.

view : Model msg -> { viewportAttributes : List (Html.Attribute msg), contentAttributes : List (Html.Attribute msg) } -> List (Html msg) -> Html msg

Show the component with some content.

The elements provided as content will become direct descendants of the content box.

It is possible to provide additional HTML attributes to the viewport and the content box. For example it is recommended to add the user-select CSS property to the viewport to prevent text from being selected while dragging.

WARNING: These styles should not be overriden for proper function:

update : MouseEvent -> Model msg -> Model msg

Process an event and return a new model.


type MouseEvent
    = MouseMoved Mouse.Position
    | MousePressed Mouse.Position ClassList
    | MouseReleased
    | WheelScrolled Mouse.Position Basics.Float

Mouse events.

Getters

getScale : Model msg -> Scale

Get the scaling of the content box.


type alias Scale =
Basics.Float

Scale of the content box.

getPosition : Model msg -> Coordinate

Get the position of the center point of the content box.


type alias Coordinate =
{ x : Basics.Float, y : Basics.Float }

Two dimensional vector that can represent a point or direction.

getMousePosition : Model msg -> Maybe Coordinate

Get the mouse position (if the content box is being dragged).

Transformations

Panning

moveBy : Coordinate -> Model msg -> Model msg

Move the content box by a relative distance.

Given a model where

getPosition model == { x = 10, y = 20 }

the following holds

getPosition (model |> moveBy { x = -15, y = 5 }) == { x = -5, y = 25 }

moveTo : Coordinate -> Model msg -> Model msg

Move the content box center point to a new position.

Given a model where

getPosition model == { x = 10, y = 20 }

the following holds

getPosition (model |> moveTo { x = -15, y = 5 }) == { x = -15, y = 5 }

In order to position the content box at point p with respect to its top left corner you will need to call

moveTo { x = p.x + width / 2, y = p.y + height / 2 }

where the width and height are the dimensions of the content box specified in pixels.

Zooming

scaleBy : Basics.Float -> Anchor -> Model msg -> Model msg

Scale the content box by a relative value (if within the minScale/maxScale bounds).

Given a model where

getScale model == scale

the following holds

getScale (model |> scaleBy factor ContentCenter) == scale * factor

scaleTo : Scale -> Anchor -> Model msg -> Model msg

Scale the content box to an absolute scaling (if within the minScale/maxScale bounds).

Given a model where

getScale model == scale

the following holds

getScale (model |> scaleTo newScale ContentCenter) == newScale


type Anchor
    = Point Coordinate
    | ContentCenter

The anchor point to scale the content box with respect to.