This module implements a pannable and zoomable component.
Default configuration:
{ viewportOffset = { x = 0, y = 0 }
, minScale = Nothing
, maxScale = Nothing
, scalePerScrollPixel = 0.001
, draggableOnChildren = Exclude []
, toSelf = toSelf
}Filters elements by class name.
Include - dragging the content box will only be possible on child elements with any of these class names.
The viewport itself needs to have a class in this list to be draggable.Exclude - dragging the content box will not be possible on child elements with any of these class names.
The viewport itself can have a class in this list to be non-draggable.List of classes.
Contains config and internal state.
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.
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:
overflow: hidden (viewport)box-sizing: border-box (viewport)box-sizing: border-box (content box)transform (content box)Process an event and return a new model.
Mouse events.
Get the scaling of the content box.
Scale of the content box.
Get the position of the center point of the content box.
Two dimensional vector that can represent a point or direction.
Get the mouse position (if the content box is being dragged).
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 }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.
Scale the content box by a relative value (if within the minScale/maxScale bounds).
Given a model where
getScale model == scalethe following holds
getScale (model |> scaleBy factor ContentCenter) == scale * factorScale the content box to an absolute scaling (if within the minScale/maxScale bounds).
Given a model where
getScale model == scalethe following holds
getScale (model |> scaleTo newScale ContentCenter) == newScaleThe anchor point to scale the content box with respect to.
Configuration options for the component.
viewportOffset- Tell the component the offset of the viewport's the top left corner (needed to properly convert between the internal and browser coordinate systems).NOTE: this will not set the offset, only inform the component of the offset. This will allow you to set the viewport offset with CSS yourself.
If your CSS positional logic is too complicated to specify the offset beforehand you can perform these steps:
In your initial
ConfigsetviewportOffsetto the default value ofCall
Browser.Dom.getElementand attempt the task.In the logic receiving the
Msgcontaining theBrowser.Dom.Element, extract the fieldselement.xandelement.yand override the config of yourPanZoom.ModelminScale- 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.scalePerScrollPixel- The factor to scale by when scrolling (per pixel). For example setting this to0.001will zoom in the content box by 0.1 % when scrolling 1px and 1/(1+0.1%) when scrolling -1px.draggableOnChildren- If you want to disable the panning logic when dragging on child elements in the content box.toSelf-- Map this component'sMouseEvents to aMsgso that the parent can properlyupdatethe component.Note: the viewport's default dimensions are
100vwand100vhrespectively but can be overriden by adding your own style attribute inview.