clojurescriptreagentquil

Quil sketch on a Reagent canvas


I have an html canvas and would like to display a Quil sketch on it. Most of the Quil examples use defsketch to draw onto a canvas defined on a static html page. I would like to do it onto the canvas within this Reagent component:

(defn my-component []      
  (reagent/create-class
    {:component-did-mount (fn [this]
                            (let [canvas (reagent/dom-node this)
                                  width (.-width canvas)
                                  height (.-height canvas)]
                              (u/log (str "On canvas with width, height: " width " " height))))
     :component-will-mount #(u/log "component-will-mount")
     :display-name "my-component"
     :reagent-render (fn [] [:canvas {:width 400}])}))

(defn graph-panel []
  [v-box
   :gap "1em"
   :children [[my-component]]])

The best documentation I've found for doing this sort of thing is here, but I can't quite work out how to go to the next level and apply it to the canvas above. Actual code for say drawing a line on the above canvas would be great.

In fact a static and always running defsketch would be fine - the difficulty would be having it access this dynamic kind of canvas.

If it can't be done then that would be nice to know, and I'll use Processing.js directly, assuming that's the next best idea.


Solution

  • You should look into Quil's source code and find out how it works. defsketch is just a macro that creates a function, that calls to quil.sketch/sketch, which eventually returns js/Processing.Sketch object. That's the thing you can use with quil.sketch/with-sketch macro, that just uses binding. That means, most of Quil's drawing functions use the quil.sketch/*applet* var.

    I suggest the following: Use defsketch as you would normally do in Quil app, but use :no-start true option. Also, use some fixed :host element ID, that you will use in your reagent component, ie. :canvas#wathever

    Example repo here: https://github.com/skrat/quil-reagent-test Run with: lein figwheel dev then open http://localhost:3449/

    (ns ^:figwheel-always kil.core
      (:require [reagent.core :as reagent :refer [atom]]
                [quil.core :as q :include-macros true]
                [quil.middleware :as m]))
    
    (enable-console-print!)
    
    (def w 400)
    (def h 400)
    
    (defn setup []
      {:t 1})
    
    (defn update [state]
      (update-in state [:t] inc))
    
    (defn draw [state]
      (q/background 255)
      (q/fill 0)
      (q/ellipse (rem (:t state) w) 46 55 55))
    
    (q/defsketch foo
      :setup  setup
      :update update
      :draw   draw
      :host "foo"
      :no-start true
      :middleware [m/fun-mode]
      :size [w h])
    
    (defn hello-world []
      (reagent/create-class
        {:reagent-render (fn [] [:canvas#foo {:width w :height h}])
         :component-did-mount foo}))
    
    (reagent/render-component
      [hello-world]
      (. js/document (getElementById "app")))