From 0c4c52d6f424f7c12f1cb3967bd3ca885949536b Mon Sep 17 00:00:00 2001
From: simon <simon@journeyman.cc>
Date: Sun, 9 Jul 2017 16:01:58 +0100
Subject: [PATCH 1/7] Very initial start of a pen trace meter

Nothing even begins to work yet.
---
 .../pen_trace_meter.cljs                      | 43 +++++++++++++++++++
 1 file changed, 43 insertions(+)
 create mode 100644 src/cljs/swinging_needle_meter/pen_trace_meter.cljs

diff --git a/src/cljs/swinging_needle_meter/pen_trace_meter.cljs b/src/cljs/swinging_needle_meter/pen_trace_meter.cljs
new file mode 100644
index 0000000..661ec6f
--- /dev/null
+++ b/src/cljs/swinging_needle_meter/pen_trace_meter.cljs
@@ -0,0 +1,43 @@
+(ns swinging-needle-meter.pen-trace-meter
+  (:require [re-com.core     :refer [h-box v-box box gap line label title slider checkbox p]]
+            [re-com.box      :refer [flex-child-style]]
+            [re-com.util     :refer [deref-or-value]]
+            [re-com.validate :refer [number-or-string? css-style? html-attr? validate-args-macro]]
+            [reagent.core    :as    reagent]))
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;;;
+;;;; pen-trace-meter: an experiment in animating SVG from re-frame.
+;;;; Draws heavily on re-com..
+;;;;
+;;;; This program is free software; you can redistribute it and/or
+;;;; modify it under the terms of the GNU General Public License
+;;;; as published by the Free Software Foundation; either version 2
+;;;; of the License, or (at your option) any later version.
+;;;;
+;;;; This program is distributed in the hope that it will be useful,
+;;;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;;;; GNU General Public License for more details.
+;;;;
+;;;; You should have received a copy of the GNU General Public License
+;;;; along with this program; if not, write to the Free Software
+;;;; Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301,
+;;;; USA.
+;;;;
+;;;; Copyright (C) 2014 Simon Brooke
+;;;;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+;; ------------------------------------------------------------------------------------
+;;  Component: pen-trace-meter
+;; ------------------------------------------------------------------------------------
+
+(defn pen-trace-meter
+  [& {:keys [model width height min-value max-value]
+      :or {width          "100%"
+             height         "100%"
+             min-value      0
+             max-value      100
+             }}]
+   )

From 6dca39ce91749e1d8a39477de1404870fb89b6fd Mon Sep 17 00:00:00 2001
From: simon <simon@journeyman.cc>
Date: Tue, 11 Jul 2017 16:46:35 +0100
Subject: [PATCH 2/7] All angles now depend on the deflection function

This is preparatory to making the deflection function pluggable.
---
 .../swinging_needle_meter.cljs                | 76 ++++++++++---------
 src/cljs/swinging_needle_meter/views.cljs     |  1 +
 2 files changed, 40 insertions(+), 37 deletions(-)

diff --git a/src/cljs/swinging_needle_meter/swinging_needle_meter.cljs b/src/cljs/swinging_needle_meter/swinging_needle_meter.cljs
index 54beb1b..30482ca 100644
--- a/src/cljs/swinging_needle_meter/swinging_needle_meter.cljs
+++ b/src/cljs/swinging_needle_meter/swinging_needle_meter.cljs
@@ -82,6 +82,7 @@
    {:name :attr          :required false :type "HTML attr map"
     :validate-fn html-attr?        :description [:span "HTML attributes, like " [:code ":on-mouse-move"] [:br] "No " [:code ":class"] " or " [:code ":style"] "allowed"]}])
 
+
 (defn abs
   "Return the absolute value of the (numeric) argument."
   [n] (max n (- n)))
@@ -90,21 +91,22 @@
 ;; from the left end of the scale to right end, in degrees.
 (def full-scale-deflection 140)
 
+
 ;; ultimately this should be resizeable, and radius should be a function of
 ;; size...
 (def scale-radius 75)
 
+
 (defn deflection
-  "Return the deflection of a needle given this `value` on the
+  "Return the linear deflection of a needle given this `value` on the
   range `min-value`...`max-value`."
   [value min-value max-value]
   (let [range (- max-value min-value)
-        deflection (/ value range)
         zero-offset (/ (- 0 min-value) range)
-        limited (min (max (+ zero-offset deflection) 0) 1)]
-    (js/console.log (str "zero-offset: " zero-offset))
+        limited (min (max (+ zero-offset (/ value range)) 0) 1)]
     (* (- limited 0.5) full-scale-deflection)))
 
+
 (defn polar-to-cartesian
   "Return, as a map with keys :x. :y, the cartesian coordinates at the point
    `radius` distance at `theta` (degrees) angle from a point at
@@ -115,6 +117,7 @@
     {:x (+ cx (* radius (.cos js/Math in-radians)))
      :y (+ cy (* radius (.sin js/Math in-radians)))}))
 
+
 (defn describe-arc
   "Return as a string an SVG path definition describing an arc centred
    at `cx`, cy` starting at `start-angle` and ending at `end-angle` (both
@@ -141,18 +144,21 @@
   "Return as a string an SVG path definition describing a radial stroke from a center
   at `cx`, cy` starting at `min-radius` and extending to `max-radius`."
   [cx cy min-radius max-radius angle label]
-  (let
-    [start (polar-to-cartesian cx cy min-radius angle)
-     mid (polar-to-cartesian cx cy (+ min-radius
-                                      (* (- max-radius min-radius) 0.333))
-                             angle)
-     end (polar-to-cartesian cx cy max-radius angle)]
-    [:g {:class "snm-gradation"}
-     [:path {:d (string/join " " ["M" (:x mid) (:y mid) "L"  (:x end) (:y end)])}]
-     [:text {:text-anchor "middle"
-             :x (:x start)
-             :y (:y start)
-             :transform (string/join " " ["rotate(" angle (:x start) (:y start) ")"])} (as-label label)]]))
+  [:g {:class "snm-gradation"
+       :transform (string/join " " ["rotate(" angle cx cy ")"])}
+   [:path {:d (string/join
+                " "
+                ["M"
+                 cx
+                 (- cy
+                    (+ min-radius
+                       (* (- max-radius min-radius) 0.333)))
+                 "L"
+                 cx
+                 (- cy max-radius)])}]
+   [:text {:text-anchor "middle"
+           :x cx
+           :y (- cy min-radius)} (as-label label)]])
 
 
 (defn swinging-needle-meter
@@ -178,12 +184,7 @@
   {:pre [(validate-args-macro swinging-needle-args-desc args "swinging-needle")]}
   (let [model (deref-or-value model)
         setpoint (deref-or-value setpoint)
-        mid-point-deflection (/ full-scale-deflection 2)
-        ;; if warn-value is greater than max-value, we don't want a red-zone at all.
-        red-zone-deflection (if
-                              (< warn-value max-value)
-                              (* full-scale-deflection (/ warn-value max-value))
-                              full-scale-deflection)]
+        mid-point-deflection (/ full-scale-deflection 2)]
     [box
      :align :start
      :child [:div
@@ -197,9 +198,7 @@
                               {:width width :height height}
                               style)}
                attr)
-             [:svg {:xmlns:svg "http://www.w3.org/2000/svg"
-                    :xmlns "http://www.w3.org/2000/svg"
-                    :xml:space "preserve"
+             [:svg {:xmlSpace "preserve"
                     :overflow "visible"
                     :viewBox "0 0 180 120"
                     :y "0px"
@@ -216,11 +215,14 @@
                 :class "snm-value"}[:tspan (str (as-label model) (if unit " ") unit)]]
               [:path {:class scale-class
                       :id (str id "-scale")
-                      :d (describe-arc 80 100 scale-radius (- 0 mid-point-deflection) mid-point-deflection)}]
+                      :d (describe-arc 80 100 scale-radius
+                                       (deflection min-value min-value max-value)
+                                       (deflection max-value min-value max-value))}]
               [:path {:class redzone-class
                       :id (str id "-redzone")
-                      :d (describe-arc 80 100 scale-radius (- red-zone-deflection mid-point-deflection) mid-point-deflection)}]
-
+                      :d (describe-arc 80 100 scale-radius
+                                       (deflection warn-value min-value max-value)
+                                       (deflection max-value min-value max-value))}]
               [:path {:class cursor-class
                       :id (str id "-cursor")
                       :d "M 80,20 80,100"
@@ -230,15 +232,15 @@
                       :id (str id "-needle")
                       :d "M 80,20 80,100"
                       :transform (str "rotate( " (deflection model min-value max-value) ", 80, 100)") }]
-              (apply vector (cons :g (map #(gradation 80 100 60 82
-                                                      (- (* %
-                                                            (/ full-scale-deflection gradations))
-                                                         mid-point-deflection)
-                                                      (+ min-value
-                                                         (*
-                                                           (/
-                                                             (- max-value min-value)
-                                                             gradations) %)))
+              (apply vector (cons :g (map #(let
+                                             [value (+ min-value
+                                                       (*
+                                                         (/
+                                                           (- max-value min-value)
+                                                           gradations) %))]
+                                             (gradation 80 100 60 82
+                                                        (deflection value min-value max-value)
+                                                        value))
                                           (range 0 (+ gradations 1)))))
               [:rect {:class frame-class
                       :id (str id "-frame")
diff --git a/src/cljs/swinging_needle_meter/views.cljs b/src/cljs/swinging_needle_meter/views.cljs
index 729d191..167dc69 100644
--- a/src/cljs/swinging_needle_meter/views.cljs
+++ b/src/cljs/swinging_needle_meter/views.cljs
@@ -63,6 +63,7 @@
 ;;                                                        :max-value (aget js/Math "PI")
                                                        :tolerance 2
                                                        :alarm-class "snm-warning"
+                                                       :gradations 5
                                                        :width     "350px"]
                                                       [title :level :level3 :label "Parameters"]
                                                       [h-box

From 6f611ec122bcd28cea2ad6a328d876e5b9077ae2 Mon Sep 17 00:00:00 2001
From: simon <simon@journeyman.cc>
Date: Tue, 11 Jul 2017 17:51:17 +0100
Subject: [PATCH 3/7] Entirely resizeable

---
 .../public/css/swinging-needle-meter.css      | 16 +++---
 .../swinging_needle_meter.cljs                | 49 ++++++++++---------
 src/cljs/swinging_needle_meter/views.cljs     |  3 +-
 3 files changed, 33 insertions(+), 35 deletions(-)

diff --git a/resources/public/css/swinging-needle-meter.css b/resources/public/css/swinging-needle-meter.css
index 26f1909..b7664f0 100644
--- a/resources/public/css/swinging-needle-meter.css
+++ b/resources/public/css/swinging-needle-meter.css
@@ -8,13 +8,13 @@
 
 .snm-cursor {
 	stroke:#ff8500;
-	stroke-width:5;
+	stroke-width: 3%;
 	stroke-opacity: 0.5;
 }
 
 .snm-frame {
 	fill: none;
-	stroke-width: 10;
+	stroke-width: 5%;
 	stroke-linejoin: round;
 	stroke: #444444;
 }
@@ -25,7 +25,7 @@
 }
 
 .snm-gradation text {
-  font-size: 50%;
+  font-size: 150%;
   font-weight: lighter;
 }
 
@@ -33,11 +33,6 @@
 	fill: #444444;
 }
 
-.snm-limit {
-  text-align: center;
-  font-size: 66%;
-}
-
 .snm-meter {
 	height: 50%;
 	width: auto;
@@ -51,13 +46,13 @@
 .snm-redzone {
 	fill:none;
 	stroke: maroon;
-	stroke-width: 15;
+	stroke-width: 10%;
 }
 
 .snm-scale {
 	fill: none;
 	stroke: green;
-	stroke-width: 15;
+	stroke-width: 10%;
 }
 
 .snm-target .snm-frame {
@@ -65,6 +60,7 @@
 }
 
 .snm-value {
+  font-size: 200%;
   text-align: center;
 }
 
diff --git a/src/cljs/swinging_needle_meter/swinging_needle_meter.cljs b/src/cljs/swinging_needle_meter/swinging_needle_meter.cljs
index 30482ca..dd8e98b 100644
--- a/src/cljs/swinging_needle_meter/swinging_needle_meter.cljs
+++ b/src/cljs/swinging_needle_meter/swinging_needle_meter.cljs
@@ -41,10 +41,10 @@
     :validate-fn number-or-string? :description "current value of the variable being watched. A number between 0 and 100"}
    {:name :setpoint      :required false :type "double | atom"
     :validate-fn number-or-string? :description "current setpoint for the variable being watched, if any. A number between 0 and 100"}
-   {:name :width         :required false :type "string"                 :default "100%"
-    :validate-fn string?           :description "a CSS width"}
-   {:name :height        :required false :type "string"                 :default "100%"
-    :validate-fn string?           :description "a CSS height"}
+   {:name :width         :required false :type "integer"                 :default "300"
+    :validate-fn integer?          :description "a CSS width"}
+   {:name :height        :required false :type "integer"                 :default "200"
+    :validate-fn integer?          :description "a CSS height"}
    {:name :min-value     :required false :type "double"                 :default 0
     :validate-fn number?           :description "the minimum value model can take"}
    {:name :max-value     :required false :type "double"                 :default 100
@@ -92,11 +92,6 @@
 (def full-scale-deflection 140)
 
 
-;; ultimately this should be resizeable, and radius should be a function of
-;; size...
-(def scale-radius 75)
-
-
 (defn deflection
   "Return the linear deflection of a needle given this `value` on the
   range `min-value`...`max-value`."
@@ -164,8 +159,8 @@
 (defn swinging-needle-meter
   "Render an SVG swinging needle meter"
   [& {:keys [model setpoint width height min-value max-value warn-value tolerance class gradations alarm-class cursor-class frame-class hub-class needle-class redzone-class scale-class target-class unit id style attr]
-      :or   {width          "100%"
-             height         "100%"
+      :or   {width          300
+             height         200
              min-value      0
              max-value      100
              warn-value     80
@@ -184,7 +179,12 @@
   {:pre [(validate-args-macro swinging-needle-args-desc args "swinging-needle")]}
   (let [model (deref-or-value model)
         setpoint (deref-or-value setpoint)
-        mid-point-deflection (/ full-scale-deflection 2)]
+        mid-point-deflection (/ full-scale-deflection 2)
+        cx (/ width 2)
+        cy (* height 0.90)
+        needle-length (* height 0.75)
+        scale-radius (* height 0.7)
+        gradation-inner (* height 0.55)]
     [box
      :align :start
      :child [:div
@@ -200,52 +200,53 @@
                attr)
              [:svg {:xmlSpace "preserve"
                     :overflow "visible"
-                    :viewBox "0 0 180 120"
+                    :viewBox (string/join " " [0 0 width height])
                     :y "0px"
                     :x "0px"
                     :version "1.1"
                     :id id
                     :class (str "snm-meter " class)}
+
               [:text
                {:text-anchor "middle"
-                :x 80
-                :y 70
+                :x (/ width 2)
+                :y (/ height 2)
                 :width "100"
                 :id (str id "-current-value")
                 :class "snm-value"}[:tspan (str (as-label model) (if unit " ") unit)]]
               [:path {:class scale-class
                       :id (str id "-scale")
-                      :d (describe-arc 80 100 scale-radius
+                      :d (describe-arc cx cy scale-radius
                                        (deflection min-value min-value max-value)
                                        (deflection max-value min-value max-value))}]
               [:path {:class redzone-class
                       :id (str id "-redzone")
-                      :d (describe-arc 80 100 scale-radius
+                      :d (describe-arc cx cy scale-radius
                                        (deflection warn-value min-value max-value)
                                        (deflection max-value min-value max-value))}]
               [:path {:class cursor-class
                       :id (str id "-cursor")
-                      :d "M 80,20 80,100"
+                      :d (str "M " cx  "," (- cy needle-length) " " cx "," cy) ;; "M cx,20 cx,100"
                       :visibility (if (and (number? setpoint) (> setpoint min-value)) "visible" "hidden")
-                      :transform (str "rotate( " (deflection setpoint min-value max-value) ", 80, 100)")}]
+                      :transform (str "rotate( " (deflection setpoint min-value max-value) "," cx "," cy ")")}]
               [:path {:class needle-class
                       :id (str id "-needle")
-                      :d "M 80,20 80,100"
-                      :transform (str "rotate( " (deflection model min-value max-value) ", 80, 100)") }]
+                      :d (str "M " cx "," (- cy needle-length) " " cx "," cy) ;; "M cx,20 cx,100"
+                      :transform (str "rotate( " (deflection model min-value max-value) "," cx "," cy ")") }]
               (apply vector (cons :g (map #(let
                                              [value (+ min-value
                                                        (*
                                                          (/
                                                            (- max-value min-value)
                                                            gradations) %))]
-                                             (gradation 80 100 60 82
+                                             (gradation cx cy gradation-inner needle-length
                                                         (deflection value min-value max-value)
                                                         value))
                                           (range 0 (+ gradations 1)))))
               [:rect {:class frame-class
                       :id (str id "-frame")
-                      :x "5" :y "5" :height "100" :width "150"}]
+                      :x (* width 0.05) :y (* height .05) :height cy :width (* width 0.9)}]
               [:circle {:class hub-class
                         :id (str id "-hub")
-                        :r "10" :cx "80" :cy "100"}]]
+                        :r (/ height 10) :cx cx :cy cy}]]
              ]]))
diff --git a/src/cljs/swinging_needle_meter/views.cljs b/src/cljs/swinging_needle_meter/views.cljs
index 167dc69..f877727 100644
--- a/src/cljs/swinging_needle_meter/views.cljs
+++ b/src/cljs/swinging_needle_meter/views.cljs
@@ -64,7 +64,8 @@
                                                        :tolerance 2
                                                        :alarm-class "snm-warning"
                                                        :gradations 5
-                                                       :width     "350px"]
+                                                       :height 300
+                                                       :width     500]
                                                       [title :level :level3 :label "Parameters"]
                                                       [h-box
                                                        :gap "10px"

From 3ebc2612fa8cd31086d32327f9805dfa5fee49a9 Mon Sep 17 00:00:00 2001
From: simon <simon@journeyman.cc>
Date: Tue, 11 Jul 2017 21:44:16 +0100
Subject: [PATCH 4/7] Lots of prettiness.

---
 resources/public/css/chosen-sprite.png        | Bin 0 -> 646 bytes
 .../swinging_needle_meter.cljs                |  29 ++++--
 src/cljs/swinging_needle_meter/views.cljs     |  93 +++++++++++++++---
 3 files changed, 99 insertions(+), 23 deletions(-)
 create mode 100644 resources/public/css/chosen-sprite.png

diff --git a/resources/public/css/chosen-sprite.png b/resources/public/css/chosen-sprite.png
new file mode 100644
index 0000000000000000000000000000000000000000..3611ae4ace1c4b1cbeacd6145b5a79cbc72e0bdc
GIT binary patch
literal 646
zcmV;10(t$3P)<h;3K|Lk000e1NJLTq001-q001Qj1^@s64f4v>0006_Nkl<Zc-rmO
zziSh57=ZCp!No$b5DZk@+)pBbK$lj?l1Z>&pbAC0n?)s%2x5M$#UgGxI1~gymp~v;
zh<`zGaTJP5BybQY4tlRo;SIcmE0t>ueW3>*u6N;@_u;;|BoL8PuhZ#FWY9$(fl<H!
zS#Lpo2qF_z)MG*4ThJ;FOw@*n86tEQq?R#;AlCf|Ap&<nY7?=Es!U!p7aS|a8z(wx
zQ1OU6l%Ge?!i<A#OoVkrHp*V`8j|3B%AhR1;@S*@dM2iz=kgjO7}yIIu@5mu$fXQ=
z2SIO!K^gQWF-C}8<fbnuLyUVVm)sqQ@!%vurBdmi*+Hh4-iMT*p+yWKMueq#2ibx4
zu#_@r2a=#WgP;t$$WMh7FhDlN(`l}c?dhOC1d)j<>an1oVvxDBL8~}0Q5z;^2p>Ov
z7}Q$E7=l>$BZLUt1*uKMCaQwKYf$lsJCyerWMd+%BeGH6f_f&Vpy%=$BN%uK%Ahxi
zF+%Jj=Pc-WXF;djS<ruDw`Q|>iJw|m4>cN%^Fi|FBZ!E{_yJLS?RI<3U696XLkQSs
z{{&kQJ$K(#5CgC1;GbA>mjm56zJZ^-Hg2_ASKI_K@CybPh7Rq}8ud``)NM~eZx}qT
z)oK?Lf>t!B;%Uh}*P+)Ef?jbx#w|BNEVb(l{2LK}m#fw4xx>ddF;&j}!S{N-e!<&Q
z?k<D~VgCi+AjX!fAYEQJ@s{B~>vzyI_AT@H-u4tUz1h&GCh8>?TnA~?BZ7WGP<9`r
gQ6DuZO!_~60ju@{TzXF%TmS$707*qoM6N<$g2#CqL;wH)

literal 0
HcmV?d00001

diff --git a/src/cljs/swinging_needle_meter/swinging_needle_meter.cljs b/src/cljs/swinging_needle_meter/swinging_needle_meter.cljs
index dd8e98b..6152f90 100644
--- a/src/cljs/swinging_needle_meter/swinging_needle_meter.cljs
+++ b/src/cljs/swinging_needle_meter/swinging_needle_meter.cljs
@@ -156,6 +156,12 @@
            :y (- cy min-radius)} (as-label label)]])
 
 
+(defn as-mm
+  "return the argument, as a string, with 'mm' appended"
+  [arg]
+  (str arg "mm"))
+
+
 (defn swinging-needle-meter
   "Render an SVG swinging needle meter"
   [& {:keys [model setpoint width height min-value max-value warn-value tolerance class gradations alarm-class cursor-class frame-class hub-class needle-class redzone-class scale-class target-class unit id style attr]
@@ -201,6 +207,8 @@
              [:svg {:xmlSpace "preserve"
                     :overflow "visible"
                     :viewBox (string/join " " [0 0 width height])
+                    :width (str width "px")
+                    :height (str height "px")
                     :y "0px"
                     :x "0px"
                     :version "1.1"
@@ -233,16 +241,17 @@
                       :id (str id "-needle")
                       :d (str "M " cx "," (- cy needle-length) " " cx "," cy) ;; "M cx,20 cx,100"
                       :transform (str "rotate( " (deflection model min-value max-value) "," cx "," cy ")") }]
-              (apply vector (cons :g (map #(let
-                                             [value (+ min-value
-                                                       (*
-                                                         (/
-                                                           (- max-value min-value)
-                                                           gradations) %))]
-                                             (gradation cx cy gradation-inner needle-length
-                                                        (deflection value min-value max-value)
-                                                        value))
-                                          (range 0 (+ gradations 1)))))
+              (if (> gradations 0)
+                (apply vector (cons :g (map #(let
+                                               [value (+ min-value
+                                                         (*
+                                                           (/
+                                                             (- max-value min-value)
+                                                             gradations) %))]
+                                               (gradation cx cy gradation-inner needle-length
+                                                          (deflection value min-value max-value)
+                                                          value))
+                                            (range 0 (+ gradations 1))))))
               [:rect {:class frame-class
                       :id (str id "-frame")
                       :x (* width 0.05) :y (* height .05) :height cy :width (* width 0.9)}]
diff --git a/src/cljs/swinging_needle_meter/views.cljs b/src/cljs/swinging_needle_meter/views.cljs
index f877727..a4cb1b5 100644
--- a/src/cljs/swinging_needle_meter/views.cljs
+++ b/src/cljs/swinging_needle_meter/views.cljs
@@ -1,6 +1,7 @@
 (ns swinging-needle-meter.views
   (:require [re-frame.core :as    re-frame]
-            [re-com.core   :refer [h-box v-box box gap line label title progress-bar slider checkbox p]]
+            [re-com.core   :refer [h-box v-box box gap line label title progress-bar slider checkbox p single-dropdown]]
+            [re-com.util   :refer [deref-or-value]]
             [swinging-needle-meter.swinging-needle-meter :refer [swinging-needle-meter  swinging-needle-args-desc]]
             [swinging-needle-meter.utils   :refer [panel-title title2 args-table github-hyperlink status-text]]
             [reagent.core  :as    reagent]))
@@ -11,8 +12,14 @@
 
 (defn swinging-needle-demo
   []
-  (let [value (reagent/atom 75)
-        setpoint (reagent/atom 75)]
+  (let [value (reagent/atom 60)
+        setpoint (reagent/atom 75)
+        gradations (reagent/atom 5)
+        size (reagent/atom 70)
+        min-val (reagent/atom 0)
+        max-val (reagent/atom 100)
+        warn-val (reagent/atom 80)
+        unit (reagent/atom "Mw")]
     (fn
       []
       [v-box
@@ -56,23 +63,22 @@
                                            :children [[swinging-needle-meter
                                                        :model     value
                                                        :setpoint  setpoint
-                                                       :unit      "Mw"
-;;                                                        :min-value 20
-;;                                                        :warn-value 35
-;;                                                        :max-value 40
-;;                                                        :max-value (aget js/Math "PI")
+                                                       :unit      (deref-or-value unit)
+                                                       :min-value (deref-or-value min-val)
+                                                       :warn-value (deref-or-value warn-val)
+                                                       :max-value (deref-or-value max-val)
                                                        :tolerance 2
                                                        :alarm-class "snm-warning"
-                                                       :gradations 5
-                                                       :height 300
-                                                       :width     500]
+                                                       :gradations (deref-or-value gradations)
+                                                       :height    (int (* (deref-or-value size) 6))
+                                                       :width     (int (* (deref-or-value size) 10))]
                                                       [title :level :level3 :label "Parameters"]
                                                       [h-box
                                                        :gap "10px"
                                                        :children [[box :align :start :child [:code ":model"]]
                                                                   [slider
                                                                    :model     value
-                                                                   :min       0
+                                                                   :min       -100
                                                                    :max       100
                                                                    :width     "200px"
                                                                    :on-change #(reset! value %)]
@@ -82,11 +88,72 @@
                                                        :children [[box :align :start :child [:code ":setpoint"]]
                                                                   [slider
                                                                    :model     setpoint
-                                                                   :min       0
+                                                                   :min       -100
                                                                    :max       100
                                                                    :width     "200px"
                                                                    :on-change #(reset! setpoint %)]
                                                                   [label :label @setpoint]]]
+                                                      [h-box
+                                                       :gap "10px"
+                                                       :children [[box :align :start :child [:code ":min-val"]]
+                                                                  [slider
+                                                                   :model     min-val
+                                                                   :min       -100
+                                                                   :max       100
+                                                                   :width     "200px"
+                                                                   :on-change #(reset! min-val %)]
+                                                                  [label :label @min-val]]]
+                                                      [h-box
+                                                       :gap "10px"
+                                                       :children [[box :align :start :child [:code ":max-val"]]
+                                                                  [slider
+                                                                   :model     max-val
+                                                                   :min       -100
+                                                                   :max       100
+                                                                   :width     "200px"
+                                                                   :on-change #(reset! max-val %)]
+                                                                  [label :label @max-val]]]
+                                                      [h-box
+                                                       :gap "10px"
+                                                       :children [[box :align :start :child [:code ":warn-val"]]
+                                                                  [slider
+                                                                   :model     warn-val
+                                                                   :min       -100
+                                                                   :max       100
+                                                                   :width     "200px"
+                                                                   :on-change #(reset! warn-val %)]
+                                                                  [label :label @warn-val]]]
+                                                      [h-box
+                                                       :gap "10px"
+                                                       :children [[box :align :start :child [:code ":gradations"]]
+                                                                  [slider
+                                                                   :model     gradations
+                                                                   :min       0
+                                                                   :max       10
+                                                                   :width     "200px"
+                                                                   :on-change #(reset! gradations %)]
+                                                                  [label :label @gradations]]]
+                                                      [h-box
+                                                       :gap "10px"
+                                                       :children [[box :align :start :child [:code ":unit"]]
+                                                                  [single-dropdown
+                                                                   :model     unit
+                                                                   :choices [{:id "Mw" :label "Megawatts" :group "Electrical"}
+                                                                             {:id "M/s" :label "Metres per second" :group "Motion"}
+                                                                             {:id "F/f" :label "Furlongs per fortnight" :group "Motion"}
+                                                                             {:id "°C" :label "Degrees Celsius" :group "Temperature"}]
+                                                                   :width     "200px"
+                                                                   :on-change #(reset! unit %)]]]
+                                                      [h-box
+                                                       :gap "10px"
+                                                       :children [[box :align :start :child [:code ":size"]]
+                                                                  [slider
+                                                                   :model     size
+                                                                   :min       25
+                                                                   :max       100
+                                                                   :width     "200px"
+                                                                   :on-change #(reset! size %)]
+                                                                  [label :label @size]]]
                                                       ]]]]]]]])))
 
 

From b3c624eb5c56369f9fb8cd207eb94caa44755d68 Mon Sep 17 00:00:00 2001
From: simon <simon@journeyman.cc>
Date: Tue, 18 Jul 2017 13:33:52 +0100
Subject: [PATCH 5/7] Now working correctly with publish/subscribe model

---
 project.clj                                   | 13 +--
 resources/public/index.html                   |  1 +
 src/cljs/swinging_needle_meter/db.cljs        |  4 -
 src/cljs/swinging_needle_meter/events.cljs    | 55 +++++++++++-
 .../pen_trace_meter.cljs                      | 43 ----------
 src/cljs/swinging_needle_meter/state.cljs     | 14 ++++
 src/cljs/swinging_needle_meter/subs.cljs      | 48 ++++++++++-
 .../swinging_needle_meter.cljs                |  8 +-
 src/cljs/swinging_needle_meter/utils.cljs     |  8 +-
 src/cljs/swinging_needle_meter/views.cljs     | 84 ++++++++++---------
 10 files changed, 171 insertions(+), 107 deletions(-)
 delete mode 100644 src/cljs/swinging_needle_meter/db.cljs
 delete mode 100644 src/cljs/swinging_needle_meter/pen_trace_meter.cljs
 create mode 100644 src/cljs/swinging_needle_meter/state.cljs

diff --git a/project.clj b/project.clj
index 2e37dc6..dd955a5 100644
--- a/project.clj
+++ b/project.clj
@@ -5,7 +5,8 @@
                  [reagent "0.6.0"]
                  [re-frame "0.9.4"]
                  [org.clojure/core.async "0.2.391"]
-                 [re-com "2.0.0"]]
+                 [re-com "2.0.0"]
+                 [org.webjars.bower/snap.svg "0.4.1"]]
 
   :plugins [[lein-cljsbuild "1.1.4"]]
 
@@ -20,9 +21,7 @@
   :profiles
   {:dev
    {:dependencies [[binaryage/devtools "0.8.2"]]
-
-    :plugins      [[lein-figwheel "0.5.9"]]
-    }}
+    :plugins      [[lein-figwheel "0.5.9"]]}}
 
   :cljsbuild
   {:builds
@@ -44,8 +43,4 @@
                     :output-to       "resources/public/js/compiled/app.js"
                     :optimizations   :advanced
                     :closure-defines {goog.DEBUG false}
-                    :pretty-print    false}}
-
-
-    ]}
-  )
+                    :pretty-print    false}}]})
diff --git a/resources/public/index.html b/resources/public/index.html
index 91a5ada..f6f63a4 100644
--- a/resources/public/index.html
+++ b/resources/public/index.html
@@ -14,6 +14,7 @@
   </head>
   <body>
     <div id="app"></div>
+    <script src="https://cdnjs.cloudflare.com/ajax/libs/snap.svg/0.5.1/snap.svg-min.js"></script>
     <script src="js/compiled/app.js"></script>
     <script>swinging_needle_meter.core.init();</script>
   </body>
diff --git a/src/cljs/swinging_needle_meter/db.cljs b/src/cljs/swinging_needle_meter/db.cljs
deleted file mode 100644
index a71f237..0000000
--- a/src/cljs/swinging_needle_meter/db.cljs
+++ /dev/null
@@ -1,4 +0,0 @@
-(ns swinging-needle-meter.db)
-
-(def default-db
-  {:name "re-frame"})
diff --git a/src/cljs/swinging_needle_meter/events.cljs b/src/cljs/swinging_needle_meter/events.cljs
index d1183e6..b474e3f 100644
--- a/src/cljs/swinging_needle_meter/events.cljs
+++ b/src/cljs/swinging_needle_meter/events.cljs
@@ -1,10 +1,57 @@
 (ns swinging-needle-meter.events
   (:require [re-frame.core :as re-frame]
-            [swinging-needle-meter.db :as db]))
-
-;;; This file is unchanged (except this line) from the leiningen recom template
+            [swinging-needle-meter.state :as state]))
 
+;; Reset.
 (re-frame/reg-event-db
  :initialize-db
  (fn  [_ _]
-   db/default-db))
+   state/default-state))
+
+;; The clock ticked.
+(re-frame/reg-event-db
+ :timer
+ (fn [db _]
+   db))
+
+(re-frame/reg-event-db
+ :set-value
+ (fn [db [x value]]
+   (js/console.log (str :set-value " " x " " value))
+   (assoc db :value value)))
+
+(re-frame/reg-event-db
+ :set-setpoint
+ (fn [db [_ value]]
+   (assoc db :setpoint value)))
+
+(re-frame/reg-event-db
+ :set-gradations
+ (fn [db [_ value]]
+   (assoc db :gradations value)))
+
+(re-frame/reg-event-db
+ :set-size
+ (fn [db [_ value]]
+   (assoc db :size value)))
+
+(re-frame/reg-event-db
+ :set-min-value
+ (fn [db [_ value]]
+   (assoc db :min-val value)))
+
+(re-frame/reg-event-db
+ :set-max-value
+ (fn [db [_ value]]
+   (assoc db :max-val value)))
+
+(re-frame/reg-event-db
+ :set-warning-value
+ (fn [db [_ value]]
+   (assoc db :warn-val value)))
+
+(re-frame/reg-event-db
+ :set-unit
+ (fn [db [_ value]]
+   (assoc db :unit value)))
+
diff --git a/src/cljs/swinging_needle_meter/pen_trace_meter.cljs b/src/cljs/swinging_needle_meter/pen_trace_meter.cljs
deleted file mode 100644
index 661ec6f..0000000
--- a/src/cljs/swinging_needle_meter/pen_trace_meter.cljs
+++ /dev/null
@@ -1,43 +0,0 @@
-(ns swinging-needle-meter.pen-trace-meter
-  (:require [re-com.core     :refer [h-box v-box box gap line label title slider checkbox p]]
-            [re-com.box      :refer [flex-child-style]]
-            [re-com.util     :refer [deref-or-value]]
-            [re-com.validate :refer [number-or-string? css-style? html-attr? validate-args-macro]]
-            [reagent.core    :as    reagent]))
-
-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-;;;;
-;;;; pen-trace-meter: an experiment in animating SVG from re-frame.
-;;;; Draws heavily on re-com..
-;;;;
-;;;; This program is free software; you can redistribute it and/or
-;;;; modify it under the terms of the GNU General Public License
-;;;; as published by the Free Software Foundation; either version 2
-;;;; of the License, or (at your option) any later version.
-;;;;
-;;;; This program is distributed in the hope that it will be useful,
-;;;; but WITHOUT ANY WARRANTY; without even the implied warranty of
-;;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-;;;; GNU General Public License for more details.
-;;;;
-;;;; You should have received a copy of the GNU General Public License
-;;;; along with this program; if not, write to the Free Software
-;;;; Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301,
-;;;; USA.
-;;;;
-;;;; Copyright (C) 2014 Simon Brooke
-;;;;
-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-
-;; ------------------------------------------------------------------------------------
-;;  Component: pen-trace-meter
-;; ------------------------------------------------------------------------------------
-
-(defn pen-trace-meter
-  [& {:keys [model width height min-value max-value]
-      :or {width          "100%"
-             height         "100%"
-             min-value      0
-             max-value      100
-             }}]
-   )
diff --git a/src/cljs/swinging_needle_meter/state.cljs b/src/cljs/swinging_needle_meter/state.cljs
new file mode 100644
index 0000000..0ea97f2
--- /dev/null
+++ b/src/cljs/swinging_needle_meter/state.cljs
@@ -0,0 +1,14 @@
+(ns ^{:doc "Client state."
+      :author "Simon Brooke"}
+  swinging-needle-meter.state)
+
+(def default-state
+  {:timer (js/Date.)
+   :value 60
+   :setpoint 75
+   :gradations 5
+   :size 70
+   :min-val 0
+   :max-val 100
+   :warn-val 80
+   :unit "Mw"})
diff --git a/src/cljs/swinging_needle_meter/subs.cljs b/src/cljs/swinging_needle_meter/subs.cljs
index f1844c7..0e488c4 100644
--- a/src/cljs/swinging_needle_meter/subs.cljs
+++ b/src/cljs/swinging_needle_meter/subs.cljs
@@ -2,9 +2,53 @@
   (:require-macros [reagent.ratom :refer [reaction]])
   (:require [re-frame.core :as re-frame]))
 
-;;; This file is unchanged (except this line) from the leiningen recom template
-
 (re-frame/reg-sub
  :name
  (fn [db]
    (:name db)))
+
+(re-frame/reg-sub
+ :value
+ (fn [db]
+   (:value db)))
+
+(re-frame/reg-sub
+ :setpoint
+ (fn [db]
+   (:setpoint db)))
+
+(re-frame/reg-sub
+ :unit
+ (fn [db]
+   (:unit db)))
+
+(re-frame/reg-sub
+ :min-val
+ (fn [db]
+   (:min-val db)))
+
+(re-frame/reg-sub
+ :max-val
+ (fn [db]
+   (:max-val db)))
+
+(re-frame/reg-sub
+ :gradations
+ (fn [db]
+   (:gradations db)))
+
+(re-frame/reg-sub
+ :warn-val
+ (fn [db]
+   (:warn-val db)))
+
+(re-frame/reg-sub
+ :size
+ (fn [db]
+   (:size db)))
+
+(re-frame/reg-sub
+ :timer
+ (fn [db]
+   (:timer db)))
+
diff --git a/src/cljs/swinging_needle_meter/swinging_needle_meter.cljs b/src/cljs/swinging_needle_meter/swinging_needle_meter.cljs
index 6152f90..3044805 100644
--- a/src/cljs/swinging_needle_meter/swinging_needle_meter.cljs
+++ b/src/cljs/swinging_needle_meter/swinging_needle_meter.cljs
@@ -4,7 +4,8 @@
             [re-com.box      :refer [flex-child-style]]
             [re-com.util     :refer [deref-or-value]]
             [re-com.validate :refer [number-or-string? css-style? html-attr? validate-args-macro]]
-            [reagent.core    :as    reagent]))
+            [reagent.core    :as    reagent]
+            [swinging-needle-meter.utils :refer [abs]]))
 
 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 ;;;;
@@ -82,11 +83,6 @@
    {:name :attr          :required false :type "HTML attr map"
     :validate-fn html-attr?        :description [:span "HTML attributes, like " [:code ":on-mouse-move"] [:br] "No " [:code ":class"] " or " [:code ":style"] "allowed"]}])
 
-
-(defn abs
-  "Return the absolute value of the (numeric) argument."
-  [n] (max n (- n)))
-
 ;; the constant 140 represents the full sweep of the needle
 ;; from the left end of the scale to right end, in degrees.
 (def full-scale-deflection 140)
diff --git a/src/cljs/swinging_needle_meter/utils.cljs b/src/cljs/swinging_needle_meter/utils.cljs
index b85df97..9b5de77 100644
--- a/src/cljs/swinging_needle_meter/utils.cljs
+++ b/src/cljs/swinging_needle_meter/utils.cljs
@@ -1,9 +1,15 @@
 (ns swinging-needle-meter.utils
   (:require [re-com.core :refer [h-box v-box box gap title line label hyperlink-href align-style]]))
 
-;;;; This file is just stolen wholesale from re-demo in the re-com package;
+;;;; This file is mostly stolen wholesale from re-demo in the re-com package;
 ;;;; I claim no credit for it.
 
+
+(defn abs
+  "Return the absolute value of the (numeric) argument."
+  [n] (max n (- n)))
+
+
 (defn github-hyperlink
   "given a label and a relative path, return a component which hyperlinks to the GitHub URL in a new tab"
   [label src-path]
diff --git a/src/cljs/swinging_needle_meter/views.cljs b/src/cljs/swinging_needle_meter/views.cljs
index a4cb1b5..8fac950 100644
--- a/src/cljs/swinging_needle_meter/views.cljs
+++ b/src/cljs/swinging_needle_meter/views.cljs
@@ -1,25 +1,33 @@
 (ns swinging-needle-meter.views
-  (:require [re-frame.core :as    re-frame]
+  (:require [re-frame.core :as    rf]
             [re-com.core   :refer [h-box v-box box gap line label title progress-bar slider checkbox p single-dropdown]]
             [re-com.util   :refer [deref-or-value]]
             [swinging-needle-meter.swinging-needle-meter :refer [swinging-needle-meter  swinging-needle-args-desc]]
             [swinging-needle-meter.utils   :refer [panel-title title2 args-table github-hyperlink status-text]]
-            [reagent.core  :as    reagent]))
+            [reagent.core  :as    reagent]
+            [swinging-needle-meter.utils :refer [abs]]))
 
 ;; ------------------------------------------------------------------------------------
 ;;  Demo: swinging-needle-meter
 ;; ------------------------------------------------------------------------------------
 
+(defn dispatch-timer-event
+  []
+  (let [now (js/Date.)]
+    (rf/dispatch [:timer now])))  ;; <-- dispatch used
+
+;; call the dispatching function every tenth of a second
+(defonce do-timer (js/setInterval dispatch-timer-event 100))
+
+
 (defn swinging-needle-demo
   []
-  (let [value (reagent/atom 60)
-        setpoint (reagent/atom 75)
-        gradations (reagent/atom 5)
-        size (reagent/atom 70)
-        min-val (reagent/atom 0)
-        max-val (reagent/atom 100)
-        warn-val (reagent/atom 80)
-        unit (reagent/atom "Mw")]
+  (let [unit @(rf/subscribe [:unit])
+        min-val @(rf/subscribe [:min-val])
+        max-val @(rf/subscribe [:max-val])
+        warn-val @(rf/subscribe [:warn-val])
+        gradations @(rf/subscribe [:gradations])
+        size @(rf/subscribe [:size])]
     (fn
       []
       [v-box
@@ -61,48 +69,48 @@
                                           [v-box
                                            :gap      "20px"
                                            :children [[swinging-needle-meter
-                                                       :model     value
-                                                       :setpoint  setpoint
-                                                       :unit      (deref-or-value unit)
-                                                       :min-value (deref-or-value min-val)
-                                                       :warn-value (deref-or-value warn-val)
-                                                       :max-value (deref-or-value max-val)
+                                                       :model     @(rf/subscribe [:value])
+                                                       :setpoint  @(rf/subscribe [:setpoint])
+                                                       :unit      @(rf/subscribe [:unit])
+                                                       :min-value @(rf/subscribe [:min-val])
+                                                       :warn-value @(rf/subscribe [:warn-val])
+                                                       :max-value @(rf/subscribe [:max-val])
                                                        :tolerance 2
                                                        :alarm-class "snm-warning"
-                                                       :gradations (deref-or-value gradations)
-                                                       :height    (int (* (deref-or-value size) 6))
-                                                       :width     (int (* (deref-or-value size) 10))]
+                                                       :gradations @(rf/subscribe [:gradations])
+                                                       :height    (int (* @(rf/subscribe [:size]) 6))
+                                                       :width     (int (* @(rf/subscribe [:size]) 10))]
                                                       [title :level :level3 :label "Parameters"]
                                                       [h-box
                                                        :gap "10px"
                                                        :children [[box :align :start :child [:code ":model"]]
                                                                   [slider
-                                                                   :model     value
+                                                                   :model     @(rf/subscribe [:value])
                                                                    :min       -100
                                                                    :max       100
                                                                    :width     "200px"
-                                                                   :on-change #(reset! value %)]
-                                                                  [label :label @value]]]
+                                                                   :on-change #(rf/dispatch [:set-value %])]
+                                                                  [label :label @(rf/subscribe [:value])]]]
                                                       [h-box
                                                        :gap "10px"
                                                        :children [[box :align :start :child [:code ":setpoint"]]
                                                                   [slider
-                                                                   :model     setpoint
+                                                                   :model     @(rf/subscribe [:setpoint])
                                                                    :min       -100
                                                                    :max       100
                                                                    :width     "200px"
-                                                                   :on-change #(reset! setpoint %)]
-                                                                  [label :label @setpoint]]]
+                                                                   :on-change #(rf/dispatch [:set-setpoint %])]
+                                                                  [label :label @(rf/subscribe [:setpoint])]]]
                                                       [h-box
                                                        :gap "10px"
                                                        :children [[box :align :start :child [:code ":min-val"]]
                                                                   [slider
-                                                                   :model     min-val
+                                                                   :model     @(rf/subscribe [:min-val])
                                                                    :min       -100
                                                                    :max       100
                                                                    :width     "200px"
-                                                                   :on-change #(reset! min-val %)]
-                                                                  [label :label @min-val]]]
+                                                                   :on-change #(rf/dispatch [:set-min-value %])]
+                                                                  [label :label @(rf/subscribe [:min-val])]]]
                                                       [h-box
                                                        :gap "10px"
                                                        :children [[box :align :start :child [:code ":max-val"]]
@@ -111,8 +119,8 @@
                                                                    :min       -100
                                                                    :max       100
                                                                    :width     "200px"
-                                                                   :on-change #(reset! max-val %)]
-                                                                  [label :label @max-val]]]
+                                                                   :on-change #(rf/dispatch [:set-max-value %])]
+                                                                  [label :label max-val]]]
                                                       [h-box
                                                        :gap "10px"
                                                        :children [[box :align :start :child [:code ":warn-val"]]
@@ -121,8 +129,8 @@
                                                                    :min       -100
                                                                    :max       100
                                                                    :width     "200px"
-                                                                   :on-change #(reset! warn-val %)]
-                                                                  [label :label @warn-val]]]
+                                                                   :on-change #(rf/dispatch [:set-warning-value %])]
+                                                                  [label :label warn-val]]]
                                                       [h-box
                                                        :gap "10px"
                                                        :children [[box :align :start :child [:code ":gradations"]]
@@ -131,19 +139,19 @@
                                                                    :min       0
                                                                    :max       10
                                                                    :width     "200px"
-                                                                   :on-change #(reset! gradations %)]
-                                                                  [label :label @gradations]]]
+                                                                   :on-change #(rf/dispatch [:set-gradations %])]
+                                                                  [label :label gradations]]]
                                                       [h-box
                                                        :gap "10px"
                                                        :children [[box :align :start :child [:code ":unit"]]
                                                                   [single-dropdown
-                                                                   :model     unit
+                                                                   :model     @(rf/subscribe [:unit])
                                                                    :choices [{:id "Mw" :label "Megawatts" :group "Electrical"}
                                                                              {:id "M/s" :label "Metres per second" :group "Motion"}
                                                                              {:id "F/f" :label "Furlongs per fortnight" :group "Motion"}
                                                                              {:id "°C" :label "Degrees Celsius" :group "Temperature"}]
                                                                    :width     "200px"
-                                                                   :on-change #(reset! unit %)]]]
+                                                                   :on-change #(rf/dispatch [:set-unit %])]]]
                                                       [h-box
                                                        :gap "10px"
                                                        :children [[box :align :start :child [:code ":size"]]
@@ -152,8 +160,8 @@
                                                                    :min       25
                                                                    :max       100
                                                                    :width     "200px"
-                                                                   :on-change #(reset! size %)]
-                                                                  [label :label @size]]]
+                                                                   :on-change #(rf/dispatch [:set-size %])]
+                                                                  [label :label size]]]
                                                       ]]]]]]]])))
 
 

From c83b557d418e81fffd2b8861cf15648273aa9f7c Mon Sep 17 00:00:00 2001
From: simon <simon@journeyman.cc>
Date: Tue, 18 Jul 2017 13:49:32 +0100
Subject: [PATCH 6/7] And now with inertia

---
 src/cljs/swinging_needle_meter/core.cljs   | 14 +++++++++++---
 src/cljs/swinging_needle_meter/events.cljs | 15 ++++++++++-----
 src/cljs/swinging_needle_meter/state.cljs  |  1 +
 src/cljs/swinging_needle_meter/subs.cljs   |  5 +++++
 src/cljs/swinging_needle_meter/views.cljs  | 10 +---------
 5 files changed, 28 insertions(+), 17 deletions(-)

diff --git a/src/cljs/swinging_needle_meter/core.cljs b/src/cljs/swinging_needle_meter/core.cljs
index ea96433..04ceafc 100644
--- a/src/cljs/swinging_needle_meter/core.cljs
+++ b/src/cljs/swinging_needle_meter/core.cljs
@@ -1,6 +1,6 @@
 (ns swinging-needle-meter.core
   (:require [reagent.core :as reagent]
-            [re-frame.core :as re-frame]
+            [re-frame.core :as rf]
             [swinging-needle-meter.events]
             [swinging-needle-meter.subs]
             [swinging-needle-meter.views :as views]
@@ -14,12 +14,20 @@
     (enable-console-print!)
     (println "dev mode")))
 
+(defn dispatch-timer-event
+  []
+  (let [now (js/Date.)]
+    (rf/dispatch [:timer now])))  ;; <-- dispatch used
+
+;; call the dispatching function every tenth of a second
+(defonce do-timer (js/setInterval dispatch-timer-event 100))
+
 (defn mount-root []
-  (re-frame/clear-subscription-cache!)
+  (rf/clear-subscription-cache!)
   (reagent/render [views/main-panel]
                   (.getElementById js/document "app")))
 
 (defn ^:export init []
-  (re-frame/dispatch-sync [:initialize-db])
+  (rf/dispatch-sync [:initialize-db])
   (dev-setup)
   (mount-root))
diff --git a/src/cljs/swinging_needle_meter/events.cljs b/src/cljs/swinging_needle_meter/events.cljs
index b474e3f..b35980c 100644
--- a/src/cljs/swinging_needle_meter/events.cljs
+++ b/src/cljs/swinging_needle_meter/events.cljs
@@ -8,17 +8,22 @@
  (fn  [_ _]
    state/default-state))
 
-;; The clock ticked.
+;; The clock ticked. Implement a mechanical swing.
 (re-frame/reg-event-db
  :timer
- (fn [db _]
-   db))
+ (fn [db [x value]]
+   (let [old-value (:old-value db)
+         target (:value db)
+         new-value (+ old-value (/ (- target old-value) 10))]
+   (assoc db :old-value new-value))))
 
 (re-frame/reg-event-db
  :set-value
  (fn [db [x value]]
-   (js/console.log (str :set-value " " x " " value))
-   (assoc db :value value)))
+   (assoc
+     (assoc db :old-value (:value db))
+     :value
+     value)))
 
 (re-frame/reg-event-db
  :set-setpoint
diff --git a/src/cljs/swinging_needle_meter/state.cljs b/src/cljs/swinging_needle_meter/state.cljs
index 0ea97f2..b69bed9 100644
--- a/src/cljs/swinging_needle_meter/state.cljs
+++ b/src/cljs/swinging_needle_meter/state.cljs
@@ -5,6 +5,7 @@
 (def default-state
   {:timer (js/Date.)
    :value 60
+   :old-value 0
    :setpoint 75
    :gradations 5
    :size 70
diff --git a/src/cljs/swinging_needle_meter/subs.cljs b/src/cljs/swinging_needle_meter/subs.cljs
index 0e488c4..8414bdf 100644
--- a/src/cljs/swinging_needle_meter/subs.cljs
+++ b/src/cljs/swinging_needle_meter/subs.cljs
@@ -12,6 +12,11 @@
  (fn [db]
    (:value db)))
 
+(re-frame/reg-sub
+ :old-value
+ (fn [db]
+   (:old-value db)))
+
 (re-frame/reg-sub
  :setpoint
  (fn [db]
diff --git a/src/cljs/swinging_needle_meter/views.cljs b/src/cljs/swinging_needle_meter/views.cljs
index 8fac950..688eaa9 100644
--- a/src/cljs/swinging_needle_meter/views.cljs
+++ b/src/cljs/swinging_needle_meter/views.cljs
@@ -11,14 +11,6 @@
 ;;  Demo: swinging-needle-meter
 ;; ------------------------------------------------------------------------------------
 
-(defn dispatch-timer-event
-  []
-  (let [now (js/Date.)]
-    (rf/dispatch [:timer now])))  ;; <-- dispatch used
-
-;; call the dispatching function every tenth of a second
-(defonce do-timer (js/setInterval dispatch-timer-event 100))
-
 
 (defn swinging-needle-demo
   []
@@ -69,7 +61,7 @@
                                           [v-box
                                            :gap      "20px"
                                            :children [[swinging-needle-meter
-                                                       :model     @(rf/subscribe [:value])
+                                                       :model     @(rf/subscribe [:old-value])
                                                        :setpoint  @(rf/subscribe [:setpoint])
                                                        :unit      @(rf/subscribe [:unit])
                                                        :min-value @(rf/subscribe [:min-val])

From ef4653e3b25377dcb70a560e8539dea165170ff0 Mon Sep 17 00:00:00 2001
From: simon <simon@journeyman.cc>
Date: Tue, 18 Jul 2017 13:56:41 +0100
Subject: [PATCH 7/7] Minor fix.

---
 project.clj                               |  2 +-
 src/cljs/swinging_needle_meter/views.cljs | 12 ++++++------
 2 files changed, 7 insertions(+), 7 deletions(-)

diff --git a/project.clj b/project.clj
index dd955a5..4a37b04 100644
--- a/project.clj
+++ b/project.clj
@@ -1,4 +1,4 @@
-(defproject swinging-needle-meter "1.0.0"
+(defproject swinging-needle-meter "1.0.1"
   :description "A swinging needle meter, as an experiment in animating SVG from re-frame. Draws heavily on re-com."
   :dependencies [[org.clojure/clojure "1.8.0"]
                  [org.clojure/clojurescript "1.9.229"]
diff --git a/src/cljs/swinging_needle_meter/views.cljs b/src/cljs/swinging_needle_meter/views.cljs
index 688eaa9..d89bd40 100644
--- a/src/cljs/swinging_needle_meter/views.cljs
+++ b/src/cljs/swinging_needle_meter/views.cljs
@@ -107,32 +107,32 @@
                                                        :gap "10px"
                                                        :children [[box :align :start :child [:code ":max-val"]]
                                                                   [slider
-                                                                   :model     max-val
+                                                                   :model     @(rf/subscribe [:max-val])
                                                                    :min       -100
                                                                    :max       100
                                                                    :width     "200px"
                                                                    :on-change #(rf/dispatch [:set-max-value %])]
-                                                                  [label :label max-val]]]
+                                                                  [label :label @(rf/subscribe [:max-val])]]]
                                                       [h-box
                                                        :gap "10px"
                                                        :children [[box :align :start :child [:code ":warn-val"]]
                                                                   [slider
-                                                                   :model     warn-val
+                                                                   :model     @(rf/subscribe [:warn-val])
                                                                    :min       -100
                                                                    :max       100
                                                                    :width     "200px"
                                                                    :on-change #(rf/dispatch [:set-warning-value %])]
-                                                                  [label :label warn-val]]]
+                                                                  [label :label @(rf/subscribe [:warn-val])]]]
                                                       [h-box
                                                        :gap "10px"
                                                        :children [[box :align :start :child [:code ":gradations"]]
                                                                   [slider
-                                                                   :model     gradations
+                                                                   :model     @(rf/subscribe [:gradations])
                                                                    :min       0
                                                                    :max       10
                                                                    :width     "200px"
                                                                    :on-change #(rf/dispatch [:set-gradations %])]
-                                                                  [label :label gradations]]]
+                                                                  [label :label @(rf/subscribe [:gradations])]]]
                                                       [h-box
                                                        :gap "10px"
                                                        :children [[box :align :start :child [:code ":unit"]]