In http://guide.elm-lang.org/architecture/effects/time.html, we are given an application that resembles a clock and we are asked to add a button to pause it and add additional hands.
What we did in the following code is:
- We created a normal clock that shows the time in UTC
- A toggle button that pauses/resumes it was added
- We added the second, minute and hour hands. Which we gave them different lengths and colors
- We created utilities to convert time to angle in degrees both for minutes/seconds and for hours
- A new function that adds the leading zero to values when we print the time in digital format was created
import Html exposing (Html, br, div, button) import Html.Events exposing (onClick) import Html.App as Html import Svg exposing (..) import Svg.Attributes exposing (..) import Time exposing (Time, second) main = Html.program { init = init , view = view , update = update , subscriptions = subscriptions } -- MODEL type alias Model = { time : Time , state : Bool } init : (Model, Cmd Msg) init = (Model 0 True, Cmd.none) -- UPDATE type Msg = Tick Time | Toggle update : Msg -> Model -> (Model, Cmd Msg) update msg model = case msg of Tick newTime -> ({ model | time = newTime }, Cmd.none) Toggle -> (toggleState model, Cmd.none) -- UTILITIES toggleState : Model -> Model toggleState model = {model | state = not(model.state)} printWithLeadingZero : Int -> String printWithLeadingZero number = if number < 10 then "0" ++ (toString number) else toString number degressCorrection : Float degressCorrection = 90.0 -- The correction we must do on our analog clock to show 12 pointing up instead to the right degressForHour : Float degressForHour = 360.0 / 12.0 -- We divide the total degrees of a full circle by the full hours of the day to get the degrees per hour degreesForMinute : Float degreesForMinute = 360.0 / 60.0 -- We divide the total degrees of a full circle by the full minutes of the hour to get the degrees per minute convertToDegrees : Int -> Float -> Float convertToDegrees value degreesPerPoint = degrees (((toFloat value) * degreesPerPoint) - degressCorrection) minutesToDegrees : Int -> Float minutesToDegrees minutes = convertToDegrees minutes degreesForMinute hoursToDegrees : Int -> Float hoursToDegrees hours = convertToDegrees hours degressForHour -- SUBSCRIPTIONS subscriptions : Model -> Sub Msg subscriptions model = case model.state of True -> Time.every second Tick False -> Sub.none -- VIEW view : Model -> Html Msg view model = let second' = Time.inSeconds model.time secondOfMinute = truncate second' `rem` 60 secondAngle = minutesToDegrees secondOfMinute secondHandX = toString (50 + 40 * cos secondAngle) secondHandY = toString (50 + 40 * sin secondAngle) minute' = Time.inMinutes model.time minuteOfHour = truncate minute' `rem` 60 minuteAngle = minutesToDegrees minuteOfHour minuteHandX = toString (50 + 35 * cos minuteAngle) minuteHandY = toString (50 +35 * sin minuteAngle) hour' = Time.inHours model.time hourOfDay = truncate hour' `rem` 24 hourAngle = hoursToDegrees hourOfDay hourHandX = toString (50 + 30 * cos hourAngle) hourHandY = toString (50 + 30 * sin hourAngle) currentTime = (printWithLeadingZero hourOfDay) ++ ":" ++ (printWithLeadingZero minuteOfHour) ++ ":" ++ (printWithLeadingZero secondOfMinute) in div [] [ div [] [text currentTime] , svg [ viewBox "0 0 100 100", width "300px" ] [ circle [ cx "50", cy "50", r "45", fill "#0B79CE" ] [] , line [ x1 "50", y1 "50", x2 secondHandX, y2 secondHandY, stroke "#ee0000" ] [] , line [ x1 "50", y1 "50", x2 minuteHandX, y2 minuteHandY, stroke "#0000ee" ] [] , line [ x1 "50", y1 "50", x2 hourHandX, y2 hourHandY, stroke "#023963" ] [] ] , br [] [] , button [onClick Toggle] [text "Toggle Clock Status"] ]
You can download the solution from here [download id=”1816″]
This post is also available in: Αγγλικα