Skip to content

Commit

Permalink
Separate graph into its own module
Browse files Browse the repository at this point in the history
  • Loading branch information
TimOrme committed Mar 29, 2023
1 parent 48ebac0 commit 956cb00
Show file tree
Hide file tree
Showing 2 changed files with 141 additions and 105 deletions.
137 changes: 137 additions & 0 deletions elm/src/Graph.elm
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
module Graph exposing (..)

import Chart as C
import Chart.Attributes as CA
import Chart.Events as CE
import Chart.Item as CI
import Html exposing (Attribute, Html)
import Html.Attributes exposing (style)
import Time exposing (..)


{-| A graph model, including all data for the graph, as well as the current hover state.
-}
type alias GraphModel =
{ graphData : List GraphData
, currentHover : List (CI.One GraphData CI.Dot)
}


{-| Graph data, representing a point on the graph.
-}
type alias GraphData =
{ time : Float
, epa : Float
, pm25 : Float
, pm10 : Float
}


{-| Get a chart of read data.
Accepts a model of graph data, and an event that occurs on graph hover.
-}
getChart : GraphModel -> (List (CI.One GraphData CI.Dot) -> msg) -> Html msg
getChart graphModel onHover =
C.chart
[ CA.height 300
, CA.width 1000
, CE.onMouseMove onHover (CE.getNearest CI.dots)
, CE.onMouseLeave (onHover [])
]
[ C.xLabels [ CA.moveDown 25, CA.withGrid, CA.rotate 60, CA.format formatTime ]
, C.yLabels [ CA.withGrid ]
, C.series .time
[ C.interpolated .epa [ CA.monotone, CA.color CA.blue ] [ CA.circle, CA.size 3 ] |> C.named "EPA"
, C.interpolated .pm25 [ CA.monotone, CA.color CA.yellow ] [ CA.circle, CA.size 3 ] |> C.named "PM2.5"
, C.interpolated .pm10 [ CA.monotone, CA.color CA.red ] [ CA.circle, CA.size 3 ] |> C.named "PM10"
]
graphModel.graphData
, C.each graphModel.currentHover <|
\p item ->
[ C.tooltip item [] [] [] ]
, C.legendsAt .min
.max
[ CA.row -- Appear as column instead of row
, CA.alignLeft -- Anchor legends to the right
, CA.spacing 5 -- Spacing between legends
, CA.background "Azure" -- Color background
, CA.border "gray" -- Add border
, CA.borderWidth 1 -- Set border width
, CA.htmlAttrs [ style "padding" "0px 4px" ]
]
[ CA.fontSize 12 -- Change font size
]
]


{-| Format a unix timestamp as a string like MM/DD HH:MM:SS
-}
formatTime : Float -> String
formatTime time =
let
milliTime =
Time.millisToPosix (floor time * 1000)

year =
String.fromInt (toYear utc milliTime)

month =
monthToString (toMonth utc milliTime)

day =
String.fromInt (toDay utc milliTime)

hour =
String.fromInt (toHour utc milliTime)

minute =
String.fromInt (toMinute utc milliTime)

second =
String.fromInt (toSecond utc milliTime)
in
month ++ "/" ++ day ++ " " ++ hour ++ ":" ++ minute ++ ":" ++ second


{-| Convert a month to a string value. In this case, to a 2 digit numeric representation
-}
monthToString : Month -> String
monthToString month =
case month of
Jan ->
"01"

Feb ->
"02"

Mar ->
"03"

Apr ->
"04"

May ->
"05"

Jun ->
"06"

Jul ->
"07"

Aug ->
"08"

Sep ->
"09"

Oct ->
"10"

Nov ->
"11"

Dec ->
"12"
109 changes: 4 additions & 105 deletions elm/src/Main.elm
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,9 @@ import Bootstrap.Grid.Col as Col
import Bootstrap.Grid.Row as Row
import Bootstrap.Text as Text
import Browser
import Chart as C
import Chart.Attributes as CA
import Chart.Events as CE
import Chart.Item as CI
import DeviceStatus as DS exposing (..)
import Graph as G exposing (..)
import Html exposing (Attribute, Html, div, h1, h5, text)
import Html.Attributes exposing (class, style)
import Http
Expand Down Expand Up @@ -228,37 +226,7 @@ view model =
, Grid.row [ Row.attrs [ style "padding-top" "1em" ], Row.centerMd ]
[ Grid.col [ Col.lg ]
[ div [ style "height" "400px" ]
[ C.chart
[ CA.height 300
, CA.width 1000
, CE.onMouseMove OnHover (CE.getNearest CI.dots)
, CE.onMouseLeave (OnHover [])
]
[ C.xLabels [ CA.moveDown 25, CA.withGrid, CA.rotate 60, CA.format formatTime ]
, C.yLabels [ CA.withGrid ]
, C.series .time
[ C.interpolated .epa [ CA.monotone, CA.color CA.blue ] [ CA.circle, CA.size 3 ] |> C.named "EPA"
, C.interpolated .pm25 [ CA.monotone, CA.color CA.yellow ] [ CA.circle, CA.size 3 ] |> C.named "PM2.5"
, C.interpolated .pm10 [ CA.monotone, CA.color CA.red ] [ CA.circle, CA.size 3 ] |> C.named "PM10"
]
model.allReads
, C.each model.hovering <|
\p item ->
[ C.tooltip item [] [] [] ]
, C.legendsAt .min
.max
[ CA.row -- Appear as column instead of row
, CA.alignLeft -- Anchor legends to the right
, CA.spacing 5 -- Spacing between legends
, CA.background "Azure" -- Color background
, CA.border "gray" -- Add border
, CA.borderWidth 1 -- Set border width
, CA.htmlAttrs [ style "padding" "0px 4px" ]
]
[ CA.fontSize 12 -- Change font size
]
]
]
[ G.getChart { graphData = model.allReads, currentHover = model.hovering } OnHover ]
]
]
]
Expand Down Expand Up @@ -329,6 +297,8 @@ statusDecoder =
(maybe (field "reader_exception" string))


{-| JSON decoder to convert a device state to its type.
-}
stateDecoder : Decoder DS.DeviceState
stateDecoder =
string
Expand All @@ -349,77 +319,6 @@ stateDecoder =
)


{-| Format a unix timestamp as a string like MM/DD HH:MM:SS
-}
formatTime : Float -> String
formatTime time =
let
milliTime =
Time.millisToPosix (floor time * 1000)

year =
String.fromInt (toYear utc milliTime)

month =
monthToString (toMonth utc milliTime)

day =
String.fromInt (toDay utc milliTime)

hour =
String.fromInt (toHour utc milliTime)

minute =
String.fromInt (toMinute utc milliTime)

second =
String.fromInt (toSecond utc milliTime)
in
month ++ "/" ++ day ++ " " ++ hour ++ ":" ++ minute ++ ":" ++ second


{-| Convert a month to a string value. In this case, to a 2 digit numeric representation
-}
monthToString : Month -> String
monthToString month =
case month of
Jan ->
"01"

Feb ->
"02"

Mar ->
"03"

Apr ->
"04"

May ->
"05"

Jun ->
"06"

Jul ->
"07"

Aug ->
"08"

Sep ->
"09"

Oct ->
"10"

Nov ->
"11"

Dec ->
"12"


{-| Given a list of read data, retrieve the last item from that list.
Useful for grabbing the most recent read from the device.
If the list is empty, a read with all 0 values is returned.
Expand Down

0 comments on commit 956cb00

Please sign in to comment.