Array with drawn values, part 2
I did some code updates for the earlier post. The examples over there are already running the updated code. Since the code listings in that post are no longer up-to-date, let's go through the changes.
Better visibility with dark mode - fillRect
with white color instead of clearRect
:
(.clearRect ctx 0 0 width height)
;; replaced with the following two lines
(set! (.-fillStyle ctx) "white")
(.fillRect ctx 0 0 width height)
I also wanted to make it work for touch devices. First, I needed to prevent scrolling when trying to draw with a touch screen; added css property
touch-action: none;
I added (.preventDefault e)
for touchevents as well.
Same drawing behavior for touch events. I decided to implement this by setting the same handlers for touch events as for click events. Some helper functions were needed; "touchstart", "touchend", and "touchmove" event objects don't contain offsetX and offsetY properties. We can calculate these from clientX/Y
of targetTouch
and the getBoundingClientRect()
of the canvas (more info here). Hence:
(defn get-offset-x [e]
(let [bcr (-> e .-target .getBoundingClientRect)
bcr-x (.-x bcr)
x (-> e
.-targetTouches
(aget 0)
.-clientX
(- bcr-x)
int)]
x))
;; this can be used by replacing the let-binding:
(let [x (.-offsetX e)
,,,])
;; with
(let [x (or (.-offsetX e) (get-offset-x e))
,,,])
Same logic works for offset-y
I also made setup-mouse-events
somewhat cleaner:
(defn setup-mouse-events [^js state canvas arr]
(setup-start-draw state canvas arr)
(setup-end-draw state canvas arr)
(setup-draw state canvas arr)
(.addEventListener
canvas "mouseout"
(fn [_]
(aset state "prev-x" nil)
(aset state "prev-y" nil))))
And the implementations:
(defn setup-start-draw [state canvas arr]
(let [start-draw-fn
(fn [e]
(let [x (or (.-offsetX e) (get-offset-x e))
y (or (.-offsetY e) (get-offset-y e))]
(.preventDefault e)
(aset state "drawing?" true)
(aset state "prev-x" x)
(aset state "prev-y" y)
(aset arr x y)
(draw-on-next-frame state "canvas4-draw" canvas arr)))]
(.addEventListener
canvas "touchstart"
start-draw-fn)
(.addEventListener
canvas "mousedown"
start-draw-fn)))
(defn setup-end-draw [state canvas arr]
(let [end-draw-fn
(fn [e]
(aset state "drawing?" false))]
(.addEventListener
js/window "mouseup"
end-draw-fn)
(.addEventListener
js/window "touchend"
end-draw-fn)))
(defn setup-draw [state canvas arr]
(let [draw-fn
(fn [e]
(when (aget state "drawing?")
(let [x (or (.-offsetX e) (get-offset-x e))
y (or (.-offsetY e) (get-offset-y e))
prev-x (aget state "prev-x")
prev-y (aget state "prev-y")]
(aset state "prev-x" x)
(aset state "prev-y" y)
(when (and prev-x prev-y)
(line-to-array arr prev-x prev-y x y))
(draw-on-next-frame state "canvas4-draw" canvas arr))))]
(.addEventListener
canvas "mousemove"
draw-fn)
(.addEventListener
canvas "touchmove"
draw-fn)))
That should be all the changes so far.