JohanWinther/elm-pan-and-zoom/1.0.0

NOTE: the latest version is 3.0.0

PanZoom

This module implements a pannable and zoomable component.

Config

type alias Config msg =
{ id : Maybe String
, width : Float
, height : Float
, minScale : Maybe Scale
, maxScale : Maybe Scale
, scrollScaleFactor : Float
, draggableOnChildren : ElementFilter
, toSelf : MouseEvent -> msg
}

Configuration options for the component.

  • id - Adds an id HTML attribute to the viewport element. Needs to be set for getViewport to return a Just.

  • width - Width of the content box in pixels.

    WARNING: this can be overriden by adding the width CSS property to the content box, but this will break the scaling logic.

  • height - Height of the content box in pixels.

    WARNING: this can be overriden by adding the width CSS property to the content box, but this will break the scaling logic.

  • minScale - Set a minimum possible scale. This will decide how far you can zoom out.

  • maxScale - Set a maximum possible scale. This will decide how far you can zoom in.

  • scrollScaleFactor - The factor to scale by when scrolling. For example setting this to 1.1 will scale the content box by 10 % on every scroll.

  • draggableOnChildren - If you want to disable the panning logic when dragging on child elements in the content box.

  • toSelf -- Map this component's MouseEvents to a Msg so that the parent can properly update the component.

Note: the viewport's default height is 100vh but can be overriden by adding your own style attribute in view.

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

Default configuration:

{ id = Nothing
, width = 1920
, height = 1080
, minScale = Nothing
, maxScale = Nothing
, scrollScaleFactor = 1.1
, draggableOnChildren = Exclude []
, toSelf = toSelf
}
= Include ClassList
| Exclude ClassList

Filters elements by class name.

  • Include - dragging the content box will only be possible on child elements with any of these class names.
  • Exclude - dragging the content box will not be possible on child elements with any of these class names.
type alias ClassList =
List String

List of classes.

State

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

Contains config and internal state.

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

Creates a Model with a Config and an initial state.

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

Show the component with some content.

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

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

WARNING: Some attributes/styles should not be overriden for proper function. For the viewport these are:

  • id HTML attribute (set in Config instead)
  • overflow CSS property

For the content box these are:

  • transform CSS property
  • position CSS property
  • width CSS property (set in Config instead)
  • height CSS property (set in Config instead)
update : MouseEvent -> Model msg -> Model msg

Process an event and return a new model.

= MouseMoved Position
| MousePressed Position ClassList
| MouseReleased
| WheelScrolled Position ScrollDirection

Mouse events.

Getters

getScale : Model msg -> Scale

Get the scaling of the content box.

type alias Scale =
Float

Scale of the content box.

getPosition : Model msg -> Coordinate

Get the position of the content box.

type alias Coordinate =
{ x : Float
, y : 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 to a point.

Given a model where

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

the following holds

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

Zooming

scaleBy : Float -> Anchor -> Model msg -> Maybe (Model msg)

Scale the content box by a relative value.

Given a model where

getScale model == scale

the following holds

getScale (model |> scaleBy factor ContentCenter) == scale * factor
scaleTo : Scale -> Anchor -> Model msg -> Maybe (Model msg)

Scale the content box to an absolute scaling.

Given a model where

getScale model == scale

the following holds

getScale (model |> scaleTo newScale ContentCenter) == newScale
type Anchor
= Point Coordinate
| ViewportCenter Viewport
| ContentCenter

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

To use the ViewportCenter you need to provide a Viewport which can be created with getViewport.

getViewport : Model msg -> Maybe (Cmd (Result Error Viewport))

Maybe creates a Cmd to get the dimensions of the viewport.

The function will return Nothing if model.config.id == Nothing.

Viewport position and dimensions.

Can only be created with getViewport.