git.fiddlerwoaroof.com
Browse code

Add PoC, with date selection and elapsed time

fiddlerwoaroof authored on 04/12/2016 09:17:47
Showing 7 changed files
1 1
new file mode 100644
... ...
@@ -0,0 +1,4 @@
1
+/.boot
2
+/target
3
+/.nrepl-port
4
+/.repl-history
0 5
new file mode 100644
... ...
@@ -0,0 +1,42 @@
1
+# history_app
2
+
3
+A [Hoplon][3] project designed to...well, that part is up to you.
4
+
5
+## Dependencies
6
+
7
+- java 1.7+
8
+- [boot][1]
9
+
10
+## Usage
11
+### Development
12
+1. Start the `dev` task. In a terminal run:
13
+    ```bash
14
+    $ boot dev
15
+    ```
16
+    This will give you a  Hoplon development setup with:
17
+    - auto compilation on file changes
18
+    - audible warning for compilation success or failures
19
+    - auto reload the html page on changes
20
+    - Clojurescript REPL
21
+
22
+2. Go to [http://localhost:8000][2] in your browser. You should see "Hello, Hoplon!".
23
+
24
+3. If you edit and save a file, the task will recompile the code and reload the
25
+   browser to show the updated version.
26
+
27
+### Production
28
+1. Run the `prod` task. In a terminal run:
29
+    ```bash
30
+    $ boot prod
31
+    ```
32
+
33
+2. The compiled files will be on the `target/` directory. This will use
34
+   advanced compilation and prerender the html.
35
+
36
+## License
37
+
38
+Copyright © 2016, **Your Name Goes Here**
39
+
40
+[1]: http://boot-clj.com
41
+[2]: http://localhost:8000
42
+[3]: http://hoplon.io
0 43
new file mode 100644
... ...
@@ -0,0 +1,25 @@
1
+* {
2
+    box-sizing: border-box;
3
+}
4
+
5
+body {
6
+    margin: 0;
7
+    padding: 0;
8
+}
9
+
10
+h2 {
11
+    color: blue;
12
+    width: 100%;
13
+    text-align: center;
14
+    margin: 2em;
15
+}
16
+
17
+#container {
18
+    width: 100vw;
19
+    height: 100vh;
20
+    border: thin solid black;
21
+}
22
+
23
+#line {
24
+    height: 3em;
25
+}
0 26
new file mode 100644
... ...
@@ -0,0 +1,4 @@
1
+#https://github.com/boot-clj/boot
2
+BOOT_CLOJURE_VERSION=1.8.0
3
+BOOT_VERSION=2.6.0
4
+BOOT_EMIT_TARGET=no
0 5
new file mode 100644
... ...
@@ -0,0 +1,45 @@
1
+(set-env!
2
+  :dependencies '[[adzerk/boot-cljs          "1.7.228-2"]
3
+                  [adzerk/boot-reload        "0.4.13"]
4
+                  [secretary "1.2.3"]
5
+                  [com.cemerick/url "0.1.1"]
6
+                  [funcool/cuerdas "2.0.1"]
7
+                  [hoplon/hoplon             "6.0.0-alpha17"]
8
+                  [org.clojure/clojure       "1.8.0"]
9
+                  [org.clojure/clojurescript "1.9.293"]
10
+                  [tailrecursion/boot-jetty  "0.1.3"]
11
+                  [adzerk/boot-cljs-repl     "0.3.3"]
12
+                  [com.cemerick/piggieback   "0.2.1"  :scope "test"]
13
+                  [weasel                    "0.7.0"  :scope "test"]
14
+                  [org.clojure/tools.nrepl   "0.2.12" :scope "test"]
15
+                  ]
16
+
17
+  :source-paths #{"src"}
18
+  :asset-paths  #{"assets"})
19
+
20
+(require
21
+  '[adzerk.boot-cljs         :refer [cljs]]
22
+  '[adzerk.boot-cljs-repl    :refer [cljs-repl-env start-repl]]
23
+  '[adzerk.boot-reload       :refer [reload]]
24
+  '[hoplon.boot-hoplon       :refer [hoplon prerender]]
25
+  '[tailrecursion.boot-jetty :refer [serve]])
26
+
27
+(deftask dev
28
+  "Build history_app for local development."
29
+  []
30
+  (comp
31
+    (watch)
32
+    (speak)
33
+    (hoplon)
34
+    (reload)
35
+    (cljs-repl-env)
36
+    (cljs)
37
+    (serve :port 8123)))
38
+
39
+(deftask prod
40
+  "Build history_app for production deployment."
41
+  []
42
+  (comp
43
+    (hoplon)
44
+    (cljs :optimizations :advanced)
45
+    (target :dir #{"target"})))
0 46
new file mode 100644
... ...
@@ -0,0 +1,38 @@
1
+(ns app.route
2
+  (:require [clojure.string]
3
+            [javelin.core :as j]
4
+            [hoplon.core :as h]
5
+            [cuerdas.core]
6
+            [cemerick.url]
7
+            [secretary.core]))
8
+
9
+(def r (h/route-cell))
10
+
11
+(def path
12
+  (j/cell= (-> r
13
+               (cuerdas.core/strip-prefix "#")
14
+               (cuerdas.core/strip-prefix "/")
15
+               (#(str "/" %))
16
+               (#(do (print "The url is: " %)
17
+                     %)))))
18
+
19
+
20
+(defn generate-route
21
+  ([path] (generate-route path nil))
22
+  ([path query]
23
+   {:pre [(sequential? path) (or (nil? query) (map? query))]}
24
+   (str "#/"
25
+        (clojure.string/join "/" path)
26
+        (if query
27
+          (str "?"
28
+               (cemerick.url/map->query query))))))
29
+
30
+(defn set-route!
31
+  "Set the URL hash to work fo the given route."
32
+  ([route]
33
+   (if (string? route)
34
+     (set! (.-hash (.-location js/window))
35
+           route)
36
+     (set-route! (generate-route route))))
37
+  ([path query]
38
+   (set-route! (generate-route path query))))
0 39
new file mode 100644
... ...
@@ -0,0 +1,140 @@
1
+(page "index.html"
2
+  (:require [cuerdas.core :as str]
3
+            [hoplon.svg :as svg]
4
+            [clojure.pprint :refer [cl-format]]))
5
+
6
+(defc state
7
+  {:elapsed-time 0
8
+   :total-time 300
9
+   :date-range [1776 2076]
10
+   :selected-date 1926
11
+   :topics ["American History" "European History"]})
12
+
13
+(defn fraction-to-date [fraction start-date end-date]
14
+  (.floor js/Math
15
+          (+ start-date
16
+             (* fraction
17
+                (- end-date
18
+                   start-date)))))
19
+
20
+
21
+(defc= start-date (get-in state [:date-range 0]))
22
+(defc= end-date (get-in state [:date-range 1]))
23
+(defc= date-range (- end-date start-date))
24
+
25
+(defc hovering nil)
26
+(defc hovered-fraction 0)
27
+(defc= hovered-date
28
+  (fraction-to-date hovered-fraction start-date end-date))
29
+(defc= hovered-date-as-fraction
30
+  (/ (- hovered-date start-date)
31
+     date-range))
32
+
33
+(defc= selected-date
34
+  (:selected-date state)
35
+  (partial swap! state assoc-in [:selected-date]))
36
+
37
+(defc= selected-fraction (/ (- selected-date
38
+                               start-date)
39
+                            date-range))
40
+
41
+(defc= topics
42
+  (:topics state))
43
+
44
+(defc= elapsed-time
45
+  (:elapsed-time state)
46
+  (partial swap! state assoc-in [:elapsed-time]))
47
+
48
+;;; Update total-time with the _difference_ between current and desired;
49
+(defc= total-time
50
+  (:total-time state)
51
+  (partial swap! state update-in [:total-time] +))
52
+
53
+(defc= remaining-time
54
+  (- total-time elapsed-time))
55
+
56
+(defc= time-percentage
57
+  (* 100 (/ elapsed-time total-time)))
58
+
59
+(defn num-to-time [num]
60
+  (cl-format nil "~2d:~2,'0d" (quot num 60) (mod num 60)))
61
+
62
+(defelem time-display [_ _ _]
63
+  (div (div :class "remaining-time" :style "display: inline-block; margin: 0 1em;"
64
+            (cell= (str "Remaining Time: " (num-to-time remaining-time))))
65
+       (div :class "elapsed-time" :style "display: inline-block; margin: 0 1em;"
66
+            (cell= (str "Time Spent:" (num-to-time elapsed-time))))))
67
+
68
+(defelem progress-bar [_ _ _]
69
+  (div {:style (cell= (str "background: hsl(" (- 117 (* 115 (/ time-percentage 100))) ", 75%, 50%); "
70
+                           "height: 0.2em; position: fixed;top:0;left:0;width: "
71
+                           (.floor js/Math (+ 1 (/ (* 99 time-percentage) 100))) "vw;"))}))
72
+
73
+(defmethod do! :viewBox
74
+    [elem _ value]
75
+    (if (= false value)
76
+        (.removeAttribute elem "viewBox")
77
+        (.setAttribute elem "viewBox" value)))
78
+
79
+(defmethod do! :preserveAspectRatio
80
+    [elem _ value]
81
+    (if (= false value)
82
+        (.removeAttribute elem "preserveAspectRatio")
83
+        (.setAttribute elem "preserveAspectRatio" value)))
84
+
85
+(definterval elapsed-update-interval-id 1000
86
+  (swap! elapsed-time inc))
87
+
88
+(cell= (print "The state is:" state))
89
+
90
+(html
91
+ (head
92
+  (link :href "app.css" :rel "stylesheet")
93
+  (style "#line { width: 100%; display: block;}"))
94
+ 
95
+ (body
96
+  (progress-bar)
97
+  (div :id "container"
98
+       (h1 "You're bad at history")
99
+       (time-display)
100
+       (h2 "When did World War 1 start?")
101
+       (div :class "timeline"
102
+            :style "position: relative;"
103
+            (svg/svg :id "line" :height "20"
104
+                     :click #(this-as this
105
+                               (let* [bbox-width (.-width (.getBBox this))
106
+                                      bbox-left (.-x (.getBBox this))
107
+                                      click-x (.-offsetX %)]
108
+                                 (reset! selected-date
109
+                                         (fraction-to-date
110
+                                          (/ (- click-x bbox-left)
111
+                                             bbox-width)
112
+                                          @start-date
113
+                                          @end-date))))
114
+                     :mousemove #(this-as this
115
+                                   (reset! hovering true)
116
+                                   (let* [bbox-width (.-width (.getBBox this))
117
+                                          bbox-left (.-x (.getBBox this))
118
+                                          click-x (.-offsetX %)]
119
+                                     (reset! hovered-fraction
120
+                                             (/ (- click-x bbox-left)
121
+                                                bbox-width))))
122
+                     (svg/line :x1 "0" :y1 "12" :x2 "100%" :y2 "12" :stroke "blue")
123
+                     (when-tpl hovering
124
+                       (let [hovered-percentage (cell= (cl-format nil "~d%" (* 100 hovered-date-as-fraction)))]
125
+                         (svg/g (svg/circle :id "date-cursor"
126
+                                            {:cx hovered-percentage}
127
+                                            :cy "12" :r "10" :fill "transparent" :stroke-width 2 :stroke "red")
128
+                                (svg/text :id "cursor-text" {:x hovered-percentage} :y "32" :dx "-0.75em"
129
+                                          hovered-date ))))
130
+                     (svg/circle :id "date-sel" {:cx (cell= (str (* 100 selected-fraction) "%"))}
131
+                                 :cy "12" :r "9" :fill "#88f")
132
+                     (svg/text :id "cursor-text" {:x (cell= (cl-format nil "~d%" (* 100 selected-fraction)))} :y "32" :dx "-0.75em"
133
+                                          selected-date))
134
+            
135
+            (div :style "position: absolute; display:inline-block; margin-top: 1em;left: 0%" 1776)
136
+            (div :style "position: absolute; display:inline-block; margin-top: 1em; left: 33%" 1876)
137
+            (div :style "position: absolute; display:inline-block; margin-top: 1em; right: 33%" 1976)
138
+            (div :style "position: absolute; display:inline-block; margin-top: 1em; right: 0%" 2076)
139
+
140
+            ))))