folkertdev/one-true-path-experiment/2.0.0

NOTE: this package is not compatible with Elm 0.19.1

Path

Low-level module for constructing svg paths.

This module provides a wrapper around the svg path syntax. A path can be parsed from a string or build up using the svg path primitives, and then converted to a string that can be used in the d attribute to render the path.

Note that this is not the most convenient way of drawing. This package is mainly meant as a primitive to build other packages on top of. If you want to visualize data, have a look at elm-plot and elm-visualization. If you want to draw geometry, check out opensolid.

For more information on svg paths, see the MDN documentation.

Data Layout

A path is a list of subpaths that are drawn in order. A subpath consists of a MoveTo instruction followed by a list of DrawTo instructions.

This package only supports absolute coordinates and instructions, but it is possible to parse strings with relative intructions. When a path is parsed, the first MoveTo instruction is always interpreted as absolute (this is in accordance with the spec), thus making sure that there is always an absolute cursor position.

The constructors are exposed, so if you need an escape hatch it is available. As always though, never reach for it when there are other options.

The vector types are from Zinggi/elm-webgl-math. They are just type aliases for tuples.

Example

-- (Float, Float) is equivalent to Vec2 Float
myPoints : List (Float, Float)

-- connect all the points with a straight line
linear : List (Vec2 Float) -> Path
linear points =
    case points of
        [] ->
            []

        p::ps ->
            [ subpath (moveTo p) [ lineTo ps ] ]


main =
    Svg.svg [ width "400", height "400" ]
        [ Path.element (linear myPoints) [ fill "none" ]
        ]

Data Structures

type alias Path =
List SubPath

A path is a list of subpaths.

Constructing Paths

parse : String -> Result Error (List SubPath)

Parse a path string into a Path

parse "M0,0 l42,73"
    --> Ok [{ moveto = MoveTo Absolute (0,0), drawtos = [ LineTo Relative  [(42, 73)]]}]

Only accepts valid complete subpaths (a sequences of a move followed by zero or more draws). Relative instructions are converted to absolute ones. The types and constructors in the output are described here.

The parser uses elm-tools/parser. The error type is Parser.Error.

Creating SVG

element : Path -> List (Attribute msg) -> Svg msg

Construct an svg path element from a Path with the given attributes

toString : Path -> String

Turn a MixedPath into a String. The result is ready to be used with the d attribute.

Path.toString [ subpath (moveTo (0,0)) [ lineBy ( 42, 73 ) ] ]
    --> "M0,0 l42,73"

Modifying Paths

mapCoordinate : (Vec2 Float -> Vec2 Float) -> Path -> Path

Manipulate the coordinates in your SVG. This can be useful for scaling the svg.

-- make the image twice as big in the x direction
[ subpath (moveTo (10,0)) [ lineTo [ (42, 42) ] ] ]
    |> mapCoordinate (\(x,y) -> (2 * x, y))
         --> [ subpath (moveTo (20,0)) [ lineTo [ (84, 42) ] ] ]
mapWithCursorState : (CursorState -> DrawTo -> b) -> Path -> List b

Map over the DrawTos in a path with access to their starting point.

Many mathematical operations (length, derivative, curvature) are only possible when a segment is fully specified. A DrawTo on its own misses its starting point - the current cursor position. This function makes the cursor position and the start of the current subpath available when mapping.