Created
September 28, 2018 05:02
-
-
Save wat-aro/c8e8f58effb66028815e1176aa02cc3c to your computer and use it in GitHub Desktop.
SVG Clock
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
module Main exposing (Model, init, main) | |
import Browser | |
import Html exposing (..) | |
import Html.Attributes as Attributes | |
import Html.Events exposing (onClick) | |
import Svg | |
import Svg.Attributes | |
import Task | |
import Time | |
main = | |
Browser.element | |
{ init = init | |
, view = view | |
, update = update | |
, subscriptions = subscriptions | |
} | |
type TimeStreaming | |
= Streaming | |
| Stop | |
type alias Model = | |
{ zone : Time.Zone | |
, time : Time.Posix | |
, timeStreaming : TimeStreaming | |
} | |
init : () -> ( Model, Cmd Msg ) | |
init _ = | |
( Model Time.utc (Time.millisToPosix 0) Streaming | |
, Task.perform AdjustTimeZone Time.here | |
) | |
type Msg | |
= Tick Time.Posix | |
| AdjustTimeZone Time.Zone | |
| StartStreaming | |
| StopStreaming | |
update : Msg -> Model -> ( Model, Cmd Msg ) | |
update msg model = | |
case msg of | |
Tick newTime -> | |
( { model | time = newTime } | |
, Cmd.none | |
) | |
AdjustTimeZone newZone -> | |
( { model | zone = newZone } | |
, Cmd.none | |
) | |
StopStreaming -> | |
( { model | timeStreaming = Stop } | |
, Cmd.none | |
) | |
StartStreaming -> | |
( { model | timeStreaming = Streaming } | |
, Cmd.none | |
) | |
subscriptions : Model -> Sub Msg | |
subscriptions model = | |
case model.timeStreaming of | |
Streaming -> | |
Time.every 1000 Tick | |
Stop -> | |
Sub.none | |
radius : Int | |
radius = | |
120 | |
radiusString : String | |
radiusString = | |
String.fromInt radius | |
radiusFloat : Float | |
radiusFloat = | |
toFloat radius | |
diameterString : String | |
diameterString = | |
2 * radius |> String.fromInt | |
view : Model -> Html Msg | |
view model = | |
h1 [] | |
[ Svg.svg | |
[ Svg.Attributes.width diameterString | |
, Svg.Attributes.height diameterString | |
, Svg.Attributes.viewBox <| "0 0 " ++ diameterString ++ " " ++ diameterString | |
] | |
[ outerCircle | |
, innerCircle | |
, hand model Hour | |
, hand model Minute | |
, hand model Second | |
] | |
, div [] [ streamingButton model ] | |
] | |
type HandType | |
= Hour | |
| Minute | |
| Second | |
strokeHand : HandType -> String | |
strokeHand handType = | |
case handType of | |
Hour -> | |
"3" | |
Minute -> | |
"3" | |
Second -> | |
"1" | |
handLength : HandType -> Float | |
handLength handType = | |
case handType of | |
Hour -> | |
35.0 * radiusFloat / 60.0 | |
Minute -> | |
55.0 * radiusFloat / 60.0 | |
Second -> | |
55.0 * radiusFloat / 60.0 | |
handAngle : Model -> HandType -> Float | |
handAngle model handType = | |
case handType of | |
Hour -> | |
2 * pi * toFloat (modBy 12 (hour model)) / 12.0 + (toFloat (minute model) / 60.0 * pi / 6.0) - pi / 2 | |
Minute -> | |
2 * pi * toFloat (minute model) / 60.0 - pi / 2 | |
Second -> | |
2 * pi * toFloat (second model) / 60.0 - pi / 2 | |
hour : Model -> Int | |
hour model = | |
Time.toHour model.zone model.time | |
minute : Model -> Int | |
minute model = | |
Time.toMinute model.zone model.time | |
second : Model -> Int | |
second model = | |
Time.toSecond model.zone model.time | |
outerCircle : Svg.Svg Msg | |
outerCircle = | |
Svg.circle | |
[ Svg.Attributes.cx radiusString | |
, Svg.Attributes.cy radiusString | |
, Svg.Attributes.r radiusString | |
, Svg.Attributes.fill "black" | |
] | |
[] | |
innerCircle : Svg.Svg Msg | |
innerCircle = | |
Svg.circle | |
[ Svg.Attributes.cx radiusString | |
, Svg.Attributes.cy radiusString | |
, radius - 1 |> String.fromInt |> Svg.Attributes.r | |
, Svg.Attributes.fill "white" | |
] | |
[] | |
hand : Model -> HandType -> Svg.Svg Msg | |
hand model handType = | |
Svg.line | |
[ Svg.Attributes.x1 radiusString | |
, Svg.Attributes.y1 radiusString | |
, cos (handAngle model handType) * handLength handType + radiusFloat |> String.fromFloat |> Svg.Attributes.x2 | |
, sin (handAngle model handType) * handLength handType + radiusFloat |> String.fromFloat |> Svg.Attributes.y2 | |
, strokeHand handType |> Svg.Attributes.strokeWidth | |
, Svg.Attributes.stroke "black" | |
] | |
[] | |
streamingButton : Model -> Html Msg | |
streamingButton { timeStreaming } = | |
case timeStreaming of | |
Streaming -> | |
button [ onClick StopStreaming ] [ text "Stop" ] | |
Stop -> | |
button [ onClick StartStreaming ] [ text "Start" ] |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment