Star

How to draw on a canvas with Klipse and core.async

The cool thing with KLIPSE is that it is 100% client-side.
It means that you can interact freely with the page where the klipse snippets are hosted. As an example, you can draw on a canvas. All you need to do is to add in your html a <canvas> element and refer it from your klipse snippet.

Boring fillRect

Let's start with a simple fillRect manipulation:

(let [canvas (js/document.getElementById "canvas-1")
      ctx (.getContext canvas "2d")
      width (.-width canvas)
      height (.-height canvas)]
  (set! (.-fillStyle  ctx) "red")
  (.clearRect ctx 0 0 width height)
  (.fillRect ctx 0 0 width height))

Random color

(let [canvas (js/document.getElementById "canvas-2")
      ctx (.getContext canvas "2d")
      width (.-width canvas)
      height (.-height canvas)
      colors ["red" "blue" "green" "yellow" "magenta" "purple" "pink"]]
  (set! (.-fillStyle  ctx) (rand-nth colors))
  (.clearRect ctx 0 0 width height)
  (.fillRect ctx 0 0 width height))

Each time you press Ctrl-Enter inside the snippet, the color changes.

Wouldn't it be cool to evaluate the snippet automatically every second or so?

Random color in a loop

Let's run the same klipse snippet in a loop - by setting data-loop-msec="1000" attribute of the DOM element that contains the snippet (look at the page source!):


(let [canvas (js/document.getElementById "canvas-3")
      ctx (.getContext canvas "2d")
      width (.-width canvas)
      height (.-height canvas)
      colors ["red" "blue" "green" "yellow" "magenta" "purple" "pink"]]
  (set! (.-fillStyle  ctx) (rand-nth colors))
  (.clearRect ctx 0 0 width height)
  (.fillRect ctx 0 0 width height))

Core.async

With core.async you can do really cool stuff - like having a progress bar:

First, let's require core.async (It takes a bit of time...):

(ns my.canvas
  (:require-macros [cljs.core.async.macros :refer [go go-loop]])
  (:require [cljs.core.async :refer [put! chan <! >! timeout close!]]))

(let [canvas (js/document.getElementById "canvas-4")
      ctx (.getContext canvas "2d")
      width (.-width canvas)
      height (.-height canvas)]
  (.clearRect ctx 0 0 width height)
  (go-loop [percentage 0]
           (<! (timeout 200))
           (when (<= percentage 100)
               (.fillRect ctx 0 (/ height 2) (/ (* width percentage) 100) 10)
             (recur (+ percentage 10)))))

It's a bit tricky to use core.async inside klipse because once a snippet is evaluated it runs forever. That might cause a lot of confusion if several versions of the snippet run in parallel.

In our core.async snippet, we have set data-eval-idle-msec="10000000" which means that the snippets will run automatically only after 10000 seconds of idleness.

That's it!
Enjoy your interactive drawings...

comments powered by Disqus