redraw only on state change

49 views
Skip to first unread message

Shaun Williams

unread,
Oct 28, 2017, 10:19:32 AM10/28/17
to clj-processing
My sketches only need to be redrawn when the user interacts with them, and it would be nice to not overheat the user's computer when I have multiple such sketches on the page :)

I was going to use `q/no-loop` then call `q/redraw` when my state atom changes.

is there a way to do this in `fun-mode`?

Nikita Beloglazov

unread,
Oct 28, 2017, 4:12:39 PM10/28/17
to clj-pro...@googlegroups.com
Hi Shaun

Yes, there are no built-in support for "redraw-only-when-changed" functionality. Using no-loop/redraw is certainly an option. Another option would be to check inside draw whether the state has changed and it hasn't - don't draw anything. There are multiple ways to achieve that. One approach can be to on each state update store hash of *old* state and then inside draw check if that hash doesn't match hash of current state then redraw. Pseudo-code:

(defn update-state [old-state]
  (-> old-state
    real-update-state
    (:prev-state-hash (hash old-state)))

(defn draw [state]
  (when-not (= (hash state) (:prev-state-hash state))
      ; do drawing here))

Idea is that if real-update-state doesn't change the state then prev-state-hash becomes equal to hash of the current state. Even easier (but less functionall-y) approach is to keep hash of last drawn state in an atom and check/update it from draw. 

It would be great to have such option as part of functional mode. 

Nikita

--
You received this message because you are subscribed to the Google Groups "clj-processing" group.
To unsubscribe from this group and stop receiving emails from it, send an email to clj-processin...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

John Lynch

unread,
Oct 29, 2017, 4:30:50 PM10/29/17
to clj-processing
Hi Shaun -

Here's another way you could do it:  maintain a boolean flag in the state map that you set to true when the user interacts, to tell the draw function whether to draw or not.   The difficulty is that draw does not return a value, so you need to set it to false in update and set a second, temporary flag that tells draw to draw.   Here's an example I've made:

core.clj:
----------
(ns drawtest.core
 
(:require [quil.core :as q])
 
(:require [drawtest.dynamic :as dyn])
 
(:require [quil.middleware :as m])
)
   
(q/defsketch drawtest
 
:title "Draw Test"              
 
:setup dyn/setup
 
:update dyn/update-state          
 
:draw dyn/draw
 
:mouse-clicked dyn/mouse-clicked            
 
:size [768 768]
 
:features [:exit-on-close]
 
:middleware [m/fun-mode])



dynamic.clj:
----------------
(ns drawtest.dynamic
 
(:require [quil.core :as q]
           
[clojure.string :as str]))
(def width 768)
(def height 768)

(defn setup []
 
(q/no-stroke)
 
(q/smooth)
 
(q/frame-rate 64)
 
(q/background 0)
 
(q/fill (q/color 255 0 255))
 
{:x (/ width 2) :y (/ height 2) :draw true})

(defn update-state [state]  
 
(if (:draw state) ; want to draw, so set :draw-now true and reset :draw to false
   
(assoc state :draw false :draw-now true)  
   
(assoc state :draw-now false)))


(defn draw [state]
 
(let [{:keys [x y draw-now]} state]
   
(when (:draw-now state) ; only draw if update has set :draw-now to true
   
(q/ellipse x y 64 64))))


(defn mouse-clicked
 
[state event]
 
(q/background 0)
 
(let [px    (:x event)
        py    
(:y event)]
   
(assoc state :x px :y py :draw true)))

Hope this helps.
John

marco.molte...@gmail.com

unread,
May 24, 2018, 4:23:31 PM5/24/18
to clj-processing
Hello,

I think I found a way that uses fun-mode, is simpler than the other proposed and in addition it really stops the loop and restarts it if an event happens: 

; Marco Molteni, May 2018
; Show how to draw only on state change using functional mode.

(ns game-of-life.state-change
  (:require [quil.core :as q]
            [quil.middleware :as m]))

(defn setup []
  (q/frame-rate 15)
  {})

(defn update-state [state]
  state)

(defn draw [state]
  (let [x    (q/random (q/width))
        y    (q/random (q/width))
        r    (q/random (/ (q/width) 2))
        grey (q/random 50 200)]
    (q/fill grey)
    (q/ellipse x y r r)))

(defn key-pressed [state event]
  (if (:stop state)
    (do (q/start-loop)
        (assoc state :stop false))
    (do (q/no-loop)
        (assoc state :stop true))))

(q/defsketch state-change
  :size [400 400]
  :setup setup
  :update update-state
  :draw draw
  :key-pressed key-pressed
  :features [:keep-on-top :no-safe-fns]
  :middleware [m/fun-mode])



Reply all
Reply to author
Forward
0 new messages