Hi Karsten,
interesting question. Canvas seemed to be outside of Reagents scope, or so it
seems. So let me try to bring it in. (And sorry for the late response.) Please
see this as a state of research, and not an "official" tutorial.
First your clock is active, and running at speed. This is not really an
reactive way to go. We need something like this, but I try to reduce its
footprint and to go as reacty as possible.
1. A clock from an atom and one js/setInterval. This is the least non-reacty
way I was able to come up with.
2. A function to repaint the canvas. This, and the way I call it (see below),
are not react at all. Just ClojureScript - it is mainly a copy of your function.
3. The component. This is much simplified now. The dereferencing of the timer
atom will initiate the rerendering each time it changes. Thats the react magic.
I asychroneously start the painting of the canvas by calling js/setTimeout - it
somehow didn't work when I called paint-seconds directly. !This I still don't
completely understand.!
I sprinkled two additional atoms onto the code, to look into it. Just in case
something interesting happens.
Kind regards, Falko
; HELPERS
(defn mappify-time
"Takes a JavaScript date object, and makes it into a map."
[js-date] {:hours (.getHours js-date)
:minutes (.getMinutes js-date)
:seconds (.getSeconds js-date)})
(defn int-to-2digit-str
"I need this three times, so I extract it."
[n]
(let [s (str n)]
(if (> (count s) 1) s (str "0" s))))
; 1. THE CLOCK ATOM AND ITS UPDATE MECHANISM
; one time to rule them all
(defonce timer (atom nil))
; one active point to update time
(defonce time-updater (js/setInterval
#(reset! timer (mappify-time (js/Date.))) 1000))
; JUST A TEST
(defn digital-clock
"A digital clock to look whether time is running."
[timer]
(let [time @timer ; dereferencing makes it re-render when the atom changes
f int-to-2digit-str
time-str (str (f (:hours time)) ":" (f (:minutes time)) ":" (f
(:seconds time)))]
[:div.example-clock
{:style {:color "#f34"}}
time-str]))
; two atoms to monitor our clock component
(defonce clox-render-count (atom 0))
(defonce clox-error (atom "None."))
; THE PAINT METHOD
(defn paint-seconds [canvas-id timer]
(let [canvas-element (.getElementById js/document canvas-id)]
(if canvas-element
(let [ctx (.getContext canvas-element "2d")]
(if ctx
(do
(set! (.-fillStyle ctx) "red")
(set! (.-textAlign ctx) "center")
(let [sec (:seconds @timer)
hpi (/ Math/PI -2)
phi (+ hpi (* (/ sec 60) Math/PI 2))]
(doto ctx
(.clearRect 0 0 200 200)
(.beginPath)
(.arc 100 100 60 hpi phi false)
(.arc 100 100 90 phi hpi true)
(.fill)
(.fillText (int sec) 100 105))))
(reset! clox-error (str "No context found for canvas with id="
canvas-id))))
(reset! clox-error (str "No canvas with id=" canvas-id " found.")))))
; THE COMPONENT
(defn clox
[timer]
(swap! clox-render-count inc)
@timer ; this does the dereferencing & triggers rendering
(js/setTimeout paint-seconds 100 "clox" timer)
[:div
[:canvas {:width 200 :height 200 :id :clox}]])
On Saturday, 4 April 2015 06:26:50 UTC+2, Karsten Schmidt wrote:
> Hi all,
>
> is this component below an idiomatic approach to deal with canvas
> animations in reagent? I tried googling, but couldn't *any* examples
> (which I find hard to believe):
>
> (defn test-canvas
> "Creates animated clock based on seconds only."
> []
> (reagent/create-class
> {:component-did-mount
> #(reagent/next-tick
> (let [ctx (.getContext (reagent/dom-node %) "2d")]
> (fn update []
> (set! (.-fillStyle ctx) "red")
> (set! (.-textAlign ctx) "center")
> (let [now (js/Date.)
> sec (mod (.getTime now) 60000)
> hpi (/ Math/PI -2)
> phi (+ hpi (* (/ sec 60000) Math/PI 2))]
> (doto ctx
> (.clearRect 0 0 200 200)
> (.beginPath)
> (.arc 100 100 60 hpi phi false)
> (.arc 100 100 90 phi hpi true)
> (.fill)
> (.fillText (int (/ sec 1000)) 100 105))
> (reagent/next-tick update)))))
> :display-name "foo"
> :reagent-render (fn [] [:canvas {:width 200 :height 200}])}))
>
> Are there any better solutions?
>
> K.
> --
> Karsten Schmidt
> http://postspectacular.com | http://thi.ng | http://toxiclibs.org
--
Note that posts from new members are moderated - please be patient with your
first post.
---
You received this message because you are subscribed to the Google Groups
"ClojureScript" group.
To unsubscribe from this group and stop receiving emails from it, send an email
to [email protected].
To post to this group, send email to [email protected].
Visit this group at http://groups.google.com/group/clojurescript.