mpizenberg / elm-2d-viewer / Viewer

A 2D viewer, providing helper functions for zooming and translations.

The Viewer type


type alias Viewer =
{ size : ( Basics.Float
, Basics.Float )
, origin : ( Basics.Float
, Basics.Float )
, scale : Basics.Float 
}

A viewer has:

Its size (or dimension) corresponds to the size, in CSS pixels that the viewer is taking in the DOM. It has to be kept up to date if the viewer dimensions change due to responsive layout.

Contrary to the size, the origin is given in "image" coordinates, i.e. the coordinates sytem of the content displayed in the viewer.

The scale acts as a multiplier coefficient between the viewer coordinates (in CSS pixels) and the image coordinates. This means that for any two points, with a distance of d pixels between each other in the web page, their distance in the image coordinates is actually scale * d.

withSize : ( Basics.Float, Basics.Float ) -> Viewer

Initialize a viewer of a given size. Default origin is (0,0) and scale 1.0.

resize : ( Basics.Float, Basics.Float ) -> Viewer -> Viewer

Update the viewer size while keeping its origin and scale.

Viewer properties

coordinatesAt : ( Basics.Float, Basics.Float ) -> Viewer -> ( Basics.Float, Basics.Float )

Transform viewer coordinates into image coordinates.

Viewer.coordinatesAt ( 0, 0 ) viewer
    == viewer.origin

Viewer.coordinatesAt ( x, y ) viewer
    == (viewer.origin + viewer.scale * ( x, y ))

coordinatesAtCenter : Viewer -> ( Basics.Float, Basics.Float )

Image coordinates at the center of the viewer.

Viewer.coordinatesAtCenter viewer
    == Viewer.coordinatesAt (0.5 * viewer.size)

coordinatesInViewer : Viewer -> ( Basics.Float, Basics.Float ) -> ( Basics.Float, Basics.Float )

Transform image coordinates into viewer coordinates. Inverse of coordinatesAt.

Viewer.coordinatesAt ( x, y ) viewer
    |> Viewer.coordinatesInViewer viewer
    == ( x, y )

Viewer translations

centerAtCoordinates : ( Basics.Float, Basics.Float ) -> Viewer -> Viewer

Center the viewer at the given image coordinates.

Viewer.centerAtCoordinates ( x, y ) viewer
    |> Viewer.coordinatesAtCenter
    == ( x, y )

translate : ( Basics.Float, Basics.Float ) -> Viewer -> Viewer

Translate the viewer by the given image vector.

.origin (Viewer.translate ( tx, ty ) viewer)
    == (viewer.origin + ( tx, ty ))

pan : ( Basics.Float, Basics.Float ) -> Viewer -> Viewer

Operate the translation on the viewer that would occur if you make a pan gesture (touch hold and move). Let (px, py) be the pan displacement in viewer coordinates, then:

Viewer.pan ( px, py ) viewer
    == Viewer.translate (viewer.scale * ( -px, -py )) viewer

Viewer scaling

fitImage : Basics.Float -> ( Basics.Float, Basics.Float ) -> Viewer -> Viewer

Rescale the viewer such that it fits an image of a given dimension ( width, height ). To get the full image perfectly centered and zoomed to fit in the viewer, you can use:

Viewer.fitImage 1.0 ( width, height ) viewer

If you want to have some margin around the image area, it means that you want the image a bit smaller, so the viewer a bit bigger. For 10% margin, for example, you can use:

Viewer.fitImage 1.1 ( width, height ) viewer

Remarq: This does not resize the viewer or the image, only changes the origin and scale of the viewer.

rescaleCentered : Basics.Float -> Viewer -> Viewer

Rescale the viewer, keeping the center point fix.

zoomIn : Viewer -> Viewer

Zoom in, keeping the center point fix.

zoomOut : Viewer -> Viewer

Zoom out, keeping the center point fix.

rescaleFixPoint : Basics.Float -> ( Basics.Float, Basics.Float ) -> Viewer -> Viewer

Rescale the viewer about a given fix point. Very convenient to keep the point under the mouse fix for example. This is equivalent to rescaleCentered if the fix point is the center point.

Viewer.rescaleFixPoint scale (Viewer.coordinatesAtCenter viewer) viewer
    == Viewer.rescaleCentered scale viewer

zoomToward : ( Basics.Float, Basics.Float ) -> Viewer -> Viewer

Zoom in, keeping a given fix point. Very convenient to keep the point under the mouse fix for example. This is equivalent to zoomIn if the fix point is the center point.

Viewer.zoomToward (Viewer.coordinatesAtCenter viewer) viewer
    == Viewer.zoomIn viewer

zoomAwayFrom : ( Basics.Float, Basics.Float ) -> Viewer -> Viewer

Zoom out, keeping a given fix point. Very convenient to keep the point under the mouse fix for example. This is equivalent to zoomOut if the fix point is the center point.

Viewer.zoomAwayFrom (Viewer.coordinatesAtCenter viewer) viewer
    == Viewer.zoomOut viewer