(page "index.html"
(:require [cuerdas.core :as str]
[hoplon.svg :as svg]
[clojure.pprint :refer [cl-format]]))
(defc state
{:elapsed-time 0
:total-time 300
:date-range [1776 2076]
:selected-date 1926
:topics ["American History" "European History"]})
(defn fraction-to-date [fraction start-date end-date]
(.floor js/Math
(+ start-date
(* fraction
(- end-date
start-date)))))
(defc= start-date (get-in state [:date-range 0]))
(defc= end-date (get-in state [:date-range 1]))
(defc= date-range (- end-date start-date))
(defc hovering nil)
(defc hovered-fraction 0)
(defc= hovered-date
(fraction-to-date hovered-fraction start-date end-date))
(defc= hovered-date-as-fraction
(/ (- hovered-date start-date)
date-range))
(defc= selected-date
(:selected-date state)
(partial swap! state assoc-in [:selected-date]))
(defc= selected-fraction (/ (- selected-date
start-date)
date-range))
(defc= topics
(:topics state))
(defc= elapsed-time
(:elapsed-time state)
(partial swap! state assoc-in [:elapsed-time]))
;;; Update total-time with the _difference_ between current and desired;
(defc= total-time
(:total-time state)
(partial swap! state update-in [:total-time] +))
(defc= remaining-time
(- total-time elapsed-time))
(defc= time-percentage
(* 100 (/ elapsed-time total-time)))
(defn num-to-time [num]
(cl-format nil "~2d:~2,'0d" (quot num 60) (mod num 60)))
(defelem time-display [_ _ _]
(div (div :class "remaining-time" :style "display: inline-block; margin: 0 1em;"
(cell= (str "Remaining Time: " (num-to-time remaining-time))))
(div :class "elapsed-time" :style "display: inline-block; margin: 0 1em;"
(cell= (str "Time Spent:" (num-to-time elapsed-time))))))
(defelem progress-bar [_ _ _]
(div {:style (cell= (str "background: hsl(" (- 117 (* 115 (/ time-percentage 100))) ", 75%, 50%); "
"height: 0.2em; position: fixed;top:0;left:0;width: "
(.floor js/Math (+ 1 (/ (* 99 time-percentage) 100))) "vw;"))}))
(defmethod do! :viewBox
[elem _ value]
(if (= false value)
(.removeAttribute elem "viewBox")
(.setAttribute elem "viewBox" value)))
(defmethod do! :preserveAspectRatio
[elem _ value]
(if (= false value)
(.removeAttribute elem "preserveAspectRatio")
(.setAttribute elem "preserveAspectRatio" value)))
(definterval elapsed-update-interval-id 1000
(swap! elapsed-time inc))
(cell= (print "The state is:" state))
(html
(head
(link :href "app.css" :rel "stylesheet")
(style "#line { width: 100%; display: block;}"))
(body
(progress-bar)
(div :id "container"
(h1 "You're bad at history")
(time-display)
(h2 "When did World War 1 start?")
(div :class "timeline"
:style "position: relative;"
(svg/svg :id "line" :height "20"
:click #(this-as this
(let* [bbox-width (.-width (.getBBox this))
bbox-left (.-x (.getBBox this))
click-x (.-offsetX %)]
(reset! selected-date
(fraction-to-date
(/ (- click-x bbox-left)
bbox-width)
@start-date
@end-date))))
:mousemove #(this-as this
(reset! hovering true)
(let* [bbox-width (.-width (.getBBox this))
bbox-left (.-x (.getBBox this))
click-x (.-offsetX %)]
(reset! hovered-fraction
(/ (- click-x bbox-left)
bbox-width))))
(svg/line :x1 "0" :y1 "12" :x2 "100%" :y2 "12" :stroke "blue")
(when-tpl hovering
(let [hovered-percentage (cell= (cl-format nil "~d%" (* 100 hovered-date-as-fraction)))]
(svg/g (svg/circle :id "date-cursor"
{:cx hovered-percentage}
:cy "12" :r "10" :fill "transparent" :stroke-width 2 :stroke "red")
(svg/text :id "cursor-text" {:x hovered-percentage} :y "32" :dx "-0.75em"
hovered-date ))))
(svg/circle :id "date-sel" {:cx (cell= (str (* 100 selected-fraction) "%"))}
:cy "12" :r "9" :fill "#88f")
(svg/text :id "cursor-text" {:x (cell= (cl-format nil "~d%" (* 100 selected-fraction)))} :y "32" :dx "-0.75em"
selected-date))
(div :style "position: absolute; display:inline-block; margin-top: 1em;left: 0%" 1776)
(div :style "position: absolute; display:inline-block; margin-top: 1em; left: 33%" 1876)
(div :style "position: absolute; display:inline-block; margin-top: 1em; right: 33%" 1976)
(div :style "position: absolute; display:inline-block; margin-top: 1em; right: 0%" 2076)
))))