Skip to content

Instantly share code, notes, and snippets.

@saolsen
Last active June 22, 2021 06:45
Show Gist options
  • Save saolsen/7799063 to your computer and use it in GitHub Desktop.
Save saolsen/7799063 to your computer and use it in GitHub Desktop.
2d canvas drawing in clojurescript
(ns saolsen.draw-2d)
;; Draw stuff (and never care about ie ever)
;; There's obviously a ton this lib doesn't do, just adding what
;; I need when I need it.
(def request-animation-frame
(or js/requestAnimationFrame
js/webkitRequestAnimationFrame))
(defn get-canvas-context-from-id
"Gets the drawing context from the id of the canvas element.
Actual context is in a map with the canvas element and some
other info."
[id]
(let [canvas (.getElementById js/document id)]
{:canvas canvas
:width (.-width canvas)
:height (.-height canvas)
:ctx (.getContext canvas "2d")}))
(defn to-color [& rgbas]
(let [csv (apply str (interpose ", " rgbas))]
(str "rgb(" csv ")")))
(defmulti draw-object :type)
(defmethod draw-object :rectangle [{:keys [color pos size]} ctx]
(let [[x y] pos
[w h] size]
(aset ctx "fillStyle" (apply to-color color))
(.fillRect ctx x y w h)))
(def twopi (* 2 (.-PI js/Math)))
(defmethod draw-object :circle [{:keys [color pos size]} ctx]
(let [[x y] pos]
(aset ctx "fillStyle" (apply to-color color))
(.beginPath ctx)
(.arc ctx x y size 0 twopi)
(.closePath ctx)
(.fill ctx)))
(defmethod draw-object :line [{:keys [color width posns]} ctx]
(let [[startx starty] (first posns)]
(.beginPath ctx)
(.moveTo ctx startx starty)
(doseq [[x y] (rest posns)]
(.lineTo ctx x y))
(.closePath ctx)
(aset ctx "lineWidth" width)
(.stroke ctx)))
(defn clear-canvas
"Clears the canvas"
[ctx width height]
(.save ctx)
(.setTransform ctx 1 0 0 1 0 0)
(.clearRect ctx 0 0 width height)
(.restore ctx))
(defn draw-scene
"Draws a sequence of objects to the screen.
Object must contain various keys depending on their type.
{:type :rectangle :color [r g b a] :pos [x y] :size [w h]}
{:type :circle :color [r g b a] :pos [x y] :size r}
{:type :line :color [r g b a] :posns [x y ...]}
Objects are drawn in the order received and the pos coordinate
specifies the upper left corner."
[objs {:keys [width height ctx]}]
(clear-canvas ctx width height)
;; clear screen first?
(doseq [obj objs]
(draw-object obj ctx)))
(comment
(def context (get-canvas-context-from-id "draw"))
(print context)
(draw-scene [{:type :rectangle :color [200 0 0] :pos [50 50] :size [100 20]}
{:type :rectangle :color [0 0 200] :pos [55 55] :size [2 10]}
{:type :line :color [0 200 0] :width 1 :posns [[10 10] [50 10] [10 50]]}
] context)
)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment