Line Chart
This module shows how to build a simple line and area chart using some of the primitives provided in this library.
Specifically we define scales, use these to create shapes, then transform those into SVG.
module LineChart exposing (main)
import Axis
import Color
import Path exposing (Path)
import Scale exposing (ContinuousScale)
import Shape
import Time
import TypedSvg exposing (g, svg)
import TypedSvg.Attributes exposing (class, fill, stroke, transform, viewBox)
import TypedSvg.Attributes.InPx exposing (strokeWidth)
import TypedSvg.Core exposing (Svg)
import TypedSvg.Types exposing (Paint(..), Transform(..))
w : Float
w =
900
h : Float
h =
450
padding : Float
padding =
30
xScale : ContinuousScale Time.Posix
xScale =
Scale.time Time.utc ( 0, w - 2 * padding ) ( Time.millisToPosix 1448928000000, Time.millisToPosix 1456790400000 )
yScale : ContinuousScale Float
yScale =
Scale.linear ( h - 2 * padding, 0 ) ( 0, 5 )
xAxis : List ( Time.Posix, Float ) -> Svg msg
xAxis model =
Axis.bottom [ Axis.tickCount (List.length model) ] xScale
yAxis : Svg msg
yAxis =
Axis.left [ Axis.tickCount 5 ] yScale
transformToLineData : ( Time.Posix, Float ) -> Maybe ( Float, Float )
transformToLineData ( x, y ) =
Just ( Scale.convert xScale x, Scale.convert yScale y )
tranfromToAreaData : ( Time.Posix, Float ) -> Maybe ( ( Float, Float ), ( Float, Float ) )
tranfromToAreaData ( x, y ) =
Just
( ( Scale.convert xScale x, Tuple.first (Scale.rangeExtent yScale) )
, ( Scale.convert xScale x, Scale.convert yScale y )
)
line : List ( Time.Posix, Float ) -> Path
line model =
List.map transformToLineData model
|> Shape.line Shape.monotoneInXCurve
area : List ( Time.Posix, Float ) -> Path
area model =
List.map tranfromToAreaData model
|> Shape.area Shape.monotoneInXCurve
view : List ( Time.Posix, Float ) -> Svg msg
view model =
svg [ viewBox 0 0 w h ]
[ g [ transform [ Translate (padding - 1) (h - padding) ] ]
[ xAxis model ]
, g [ transform [ Translate (padding - 1) padding ] ]
[ yAxis ]
, g [ transform [ Translate padding padding ], class [ "series" ] ]
[ Path.element (area model) [ strokeWidth 3, fill <| Paint <| Color.rgba 1 0 0 0.54 ]
, Path.element (line model) [ stroke <| Paint <| Color.rgb 1 0 0, strokeWidth 3, fill PaintNone ]
]
]
-- From here onwards this is simply example boilerplate.
-- In a real app you would load the data from a server and parse it, perhaps in
-- a separate module.
main : Svg msg
main =
view timeSeries
timeSeries : List ( Time.Posix, Float )
timeSeries =
[ ( Time.millisToPosix 1448928000000, 2.5 )
, ( Time.millisToPosix 1451606400000, 2 )
, ( Time.millisToPosix 1452211200000, 3.5 )
, ( Time.millisToPosix 1452816000000, 2 )
, ( Time.millisToPosix 1453420800000, 3 )
, ( Time.millisToPosix 1454284800000, 1 )
, ( Time.millisToPosix 1456790400000, 1.2 )
]