Create a gist now

Instantly share code, notes, and snippets.

Immutable, undoable pixel editor
(def height 10)
(def width 10)
(def pixel-size 10)
(defn ->2D [i]
[(mod i width)
(.floor js/Math (/ i width))])
(def coords (map ->2D, (range (* height width))))
(def colors (repeat "#fff"))
(def pixels (zipmap coords colors))
(defn draw
([x y pixels] (draw x y pixels "#000"))
([x y pixels color]
(assoc pixels [x y] color)))
(defn paint! [ctx pixels]
(let [px pixel-size]
(for [[[x y] color] pixels]
(set! (.-fillStyle ctx) color)
(.fillRect (* x px) (* y px) px px))))
(def canvas (.getElementById js/document "canvas"))
(def undo (.getElementById js/document "undo"))
(def context (.getContext canvas "2d"))
(set! (.width canvas) (* width pixel-size))
(set! (.height canvas) (* height pixel-size))
(paint! context pixels)
(def frames (atom (list)))
(defn handle-click [e]
(let [x (.floor js/Math (/ (.-layerX e) pixel-size))
y (.floor js/Math (/ (.-layerY e) pixel-size))
pixels (draw x y (peek @frames))]
(paint! context pixels)))
(defn handle-undo [e]
(when (> 1 (count frames))
(swap! frames pop)
(paint! context (peek @frames))))
(.addEventListener canvas "click" handle-click)
(.addEventListener undo "click" handle-undo)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment