(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) ))))