Skip to content

Instantly share code, notes, and snippets.

@nathanmalishev
Created April 2, 2020 06:52
Show Gist options
  • Save nathanmalishev/bb7e8b90f3280180ddab5304b724aa7c to your computer and use it in GitHub Desktop.
Save nathanmalishev/bb7e8b90f3280180ddab5304b724aa7c to your computer and use it in GitHub Desktop.
-- Show the current time in your time zone.
--
-- Read how it works:
-- https://guide.elm-lang.org/effects/time.html
--
-- For an analog clock, check out this SVG example:
-- https://elm-lang.org/examples/clock
--
import Browser
import Html exposing (Html, br, input, label, p, div ,h1, button)
import Html.Attributes exposing (checked)
import Html.Events exposing (onCheck, onClick)
import Svg exposing (..)
import Svg.Attributes exposing (..)
import Task
import Time as Time exposing (Posix)
-- MAIN
main =
Browser.element
{ init = init
, view = view
, update = update
, subscriptions = subscriptions
}
-- MODEL
type alias Model =
{ time : Posix
, zone : Time.Zone
, state : Bool
}
init : () -> ( Model, Cmd Msg )
init _ =
(
Model (Time.millisToPosix 0) Time.utc False,
Task.perform Zone Time.here )
-- UPDATE
type Msg
= Tick Time.Posix
| Zone Time.Zone
| Toggle
update : Msg -> Model -> (Model, Cmd Msg)
update msg model =
case msg of
Tick newTime ->
( { model | time = newTime }
, Cmd.none
)
Zone newZone ->
( { model | zone = newZone }
, Cmd.none
)
Toggle ->
( toggleState model
, Cmd.none
)
-- UTIL
toggleState : Model -> Model
toggleState model =
{ model | state = not(model.state) }
printWithLeadingZero : Int -> String
printWithLeadingZero number =
if number < 10 then
"0" ++ (String.fromInt number)
else
String.fromInt 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 1000 Tick
False ->
Sub.none
-- VIEW
view : Model -> Html Msg
view model =
let
second =
Time.toSecond model.zone model.time
secondAngle =
minutesToDegrees second
secondHandX =
String.fromFloat(50 + 40 * cos secondAngle)
secondHandY =
String.fromFloat (50 + 40 * sin secondAngle)
minute =
Time.toMinute model.zone model.time
minuteAngle =
minutesToDegrees minute
minuteHandX =
String.fromFloat (50 + 35 * cos minuteAngle)
minuteHandY =
String.fromFloat (50 +35 * sin minuteAngle)
hour =
Time.toHour model.zone model.time
hourAngle =
hoursToDegrees hour
hourHandX =
String.fromFloat (50 + 30 * cos hourAngle)
hourHandY =
String.fromFloat (50 + 30 * sin hourAngle)
currentTime =
(printWithLeadingZero hour) ++ ":" ++ (printWithLeadingZero minute) ++ ":" ++ (printWithLeadingZero second)
in
div []
[
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" ] []
]
, button [onClick Toggle] []
, div [] [ text currentTime ]
]
@nathanmalishev
Copy link
Author

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment