gampleman/evg/1.0.0

NOTE: the latest version is 1.0.1

Evg.Performance

Tools for optimizing rendering performance.

Most of the time you won't need these, since the default rendering is fast enough for typical use. Reach for this module when you have:

  • A very large number of repeated shapes (hundreds or thousands)
  • Complex shapes that are identical in structure (only position changes)
  • Heavy computations producing shapes that rarely change

Lazy Evaluation

On every update Elm re-runs your view and works out what changed. lazy skips that work for a shape whose inputs haven't changed since last time: if the arguments are the same values as before, the previous result is reused without re-rendering anything.

lazy : String -> (a -> Evg msg) -> a -> Evg msg

Skips re-rendering the shape when the argument is unchanged since the last update. Works like Html.Lazy.lazy but for Evg graphics, and comes with the same caveats: both the function and the argument are compared by reference, so pass a top-level function (not a lambda) and a value straight out of your model rather than a record or list built fresh on every call.

The first argument is a name for this piece of the drawing, unique within your whole scene. The library cannot look inside a lazy shape without defeating its purpose, so the name stands in for the content when the library needs to tell shapes apart (for example when a lazy shape is used as a clip stencil). Two different lazy shapes with the same name can get mixed up, so name them uniquely.

Evg.Performance.lazy "sales-chart"
    viewExpensiveChart
    model.chartData
lazy2 : String -> (a -> b -> Evg msg) -> a -> b -> Evg msg

Like lazy but checks two arguments.

lazy3 : String -> (a -> b -> c -> Evg msg) -> a -> b -> c -> Evg msg

Like lazy but checks three arguments.

Reusable Definitions

Draw a complex shape once, then stamp out cheap copies of it wherever you need them.

Evg msg
-> List
(Attribute
{ fill : Supported
, stroke : Supported
, opacity : Supported
, filter : Supported
, transform : Supported
, events : Supported
}
msg
)
-> { x : Float
, y : Float
, width : Float
, height : Float
}
-> Evg msg

Turns a shape into a reusable definition. Returns a function that stamps out lightweight copies, working just like the shape constructors in Evg: it takes a list of attributes and then the position and size of the copy.

This is useful when you have the same complex shape repeated many times. The shape is drawn once as a hidden definition, and each visible copy is just a cheap reference to it, so the browser does the expensive work only once. The definition itself travels with the copies, so simply placing the stamped shapes in your scene is enough.

useIcon =
    Evg.Performance.asDef myComplexIcon


scene =
    Evg.svg []
        { width = 200, height = 200 }
        [ useIcon []
            { x = 10
            , y = 10
            , width = 24
            , height = 24
            }
        , useIcon [ Evg.opacity 0.5 ]
            { x = 50
            , y = 10
            , width = 24
            , height = 24
            }
        ]

Attributes vary each copy individually: fade one out with opacity, listen for clicks with an event handler, or move it with a transform.

Colors work by ordinary inheritance: fill and stroke set on a copy flow into the parts of the original shape that left those unset, while parts that picked explicit colors keep them. So if you design the original without colors, every stamp can be tinted differently; if you color the original fully, stamps always look identical.

(There is also an explicit opt-in mechanism: parts of the original painted with Evg.Paint.contextFill or contextStroke take their color from the copy even alongside other explicit colors. Be aware that browser support for context colors on copies is uneven; they are reliable for markers, less so here.)