8

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

 3 years ago
source link: https://blog.klipse.tech/clojure/2020/09/09/core-async-canvas.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

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:

xxxxxxxxxx
(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))
the evaluation will appear here (soon)...

Random color

xxxxxxxxxx
(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))
xxxxxxxxxx
the evaluation will appear here (soon)...

Each time you press Ctrl-Enter inside the snippet, the color is randomly picked.

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!):

xxxxxxxxxx
(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))
xxxxxxxxxx
the evaluation will appear here (soon)...

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…):

xxxxxxxxxx
(ns my.canvas
  (:require [cljs.core.async :refer [go go-loop <! timeout]]))
xxxxxxxxxx
the evaluation will appear here (soon)...
xxxxxxxxxx
(let [canvas (js/document.getElementById "canvas-4")
      ctx (.getContext canvas "2d")
      width (.-width canvas)
      height (.-height canvas)]
  (.clearRect ctx 0 0 width height)
  (set! (.-fillStyle  ctx) "green")
  (go-loop [percentage 0]
           (when (<= percentage 100)
             (<! (timeout 200))
             (.fillRect ctx 0 (/ height 2) (/ (* width percentage) 100) 10)
             (recur (+ percentage 10)))))
xxxxxxxxxx
the evaluation will appear here (soon)...

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 or when you press Ctrl-Enter.

That’s it! Enjoy your interactive drawings…


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK