diff --git a/r_place_backend/src/r_place_backend/core.clj b/r_place_backend/src/r_place_backend/core.clj index 2b647a3..a83b363 100644 --- a/r_place_backend/src/r_place_backend/core.clj +++ b/r_place_backend/src/r_place_backend/core.clj @@ -4,19 +4,46 @@ [compojure.route :refer [files not-found]] [compojure.core :refer [defroutes GET POST DELETE ANY context]])) +(def sample-data {:column 4 + :row 4 + :color "green"}) + +(def colors ["#8967B3" "#4F75FF" "#8FD14F" + "#FF6500" "#73EC8B" "#243642"]) + +(defn random-data + [] + (map (fn [i] + {:column i + :row i + :color (rand-nth colors)}) + (range 20))) + +(defonce state (atom [])) + +(defn on-receive-handler + [channel data] + (let [{:keys [column row color] :as pixel-data} + (read-string data)] + (swap! state conj pixel-data))) + (defn chat-handler [req] - (http-kit/with-channel req channel ; get the channel + (http-kit/with-channel req channel ; get the channel ;; communicate with client using method defined above (http-kit/on-close channel (fn [status] - (println "channel closed"))) + (println "channel closed"))) (if (http-kit/websocket? channel) (println "WebSocket channel") (println "HTTP channel")) - (http-kit/on-receive channel (fn [data] ; data received from client - ;; An optional param can pass to send!: close-after-send? - ;; When unspecified, `close-after-send?` defaults to true for HTTP channels - ;; and false for WebSocket. (send! channel data close-after-send?) - (http-kit/send! channel data))))) ; data is sent directly to the client + + (doseq [pixel-update @state] + (http-kit/send! channel + (pr-str pixel-update))) + (http-kit/on-receive channel (fn [data] ; data received from client + ;; An optional param can pass to send!: close-after-send? + ;; When unspecified, `close-after-send?` defaults to true for HTTP channels + ;; and false for WebSocket. (send! channel data close-after-send?) + (on-receive-handler channel data))))) ; data is sent directly to the client (defn show-landing-page [req] ;; ordinary clojure function, accepts a request map, returns a response map ;; return landing page's html string. Using template library is a good idea: diff --git a/r_place_ui/src/place/core.cljs b/r_place_ui/src/place/core.cljs index a763664..989d6a6 100644 --- a/r_place_ui/src/place/core.cljs +++ b/r_place_ui/src/place/core.cljs @@ -1,5 +1,6 @@ (ns place.core - (:require [goog.dom :as dom] + (:require [cljs.reader :as cljsr] + [goog.dom :as dom] [goog.events :as events] [goog.style :as style])) @@ -39,13 +40,24 @@ (set! (.-fillStyle ctx) color) (.fillRect ctx grid-x grid-y grid-size grid-size))) +(defn canvas-coord->grid-coord + [coord grid-size] + (* (Math/floor (/ coord grid-size)) grid-size)) + (defn draw-pixel [x y color] - (let [grid-x (* (Math/floor (/ x grid-size)) grid-size) - grid-y (* (Math/floor (/ y grid-size)) grid-size)] + (let [grid-x (canvas-coord->grid-coord x grid-size) + grid-y (canvas-coord->grid-coord y grid-size)] (def l* [grid-x grid-y]) (set! (.-fillStyle ctx) color) (.fillRect ctx grid-x grid-y grid-size grid-size))) + +(defn send-pixel! + [x y color] + (.send socket* (pr-str {:column x + :row y + :color color}))) + (defn handle-canvas-click [e] (let [rect (.getBoundingClientRect canvas) scale (:scale @app-state) @@ -55,23 +67,19 @@ "#FFFFFF" (:current-color @app-state))] (draw-pixel x y color) + (send-pixel! (Math/floor (/ x grid-size)) + (Math/floor (/ y grid-size)) + color) (draw-grid))) -(comment - (events/listen canvas "click" handle-canvas-click) +(events/listen canvas "click" handle-canvas-click) - (events/listen canvas "touchstart" - (fn [e] - (.preventDefault e) - (handle-canvas-click (aget (.-touches e) 0)))) - - (events/listen (:brush tools) "click" #(swap! app-state assoc :current-tool :brush)) - (events/listen (:eraser tools) "click" #(swap! app-state assoc :current-tool :eraser)) - (events/listen (:color-picker tools) "change" - #(swap! app-state assoc :current-color (.. % -target -value))) - ) +(defn websocket-message-handler + [data] + (let [{:keys [column row color]} (cljsr/read-string data)] + (draw-grid-pixel column row color))) -(comment +(do (set! (.-width canvas) 500) (set! (.-height canvas) 500) @@ -88,12 +96,24 @@ ;; Draw initial grid (draw-grid) - ) + + + + (def socket* (setup-ws "ws://localhost:8080/ws" + (fn [] + (js/console.log "Socket connected")) + (fn [e] + (js/console.log e.data) + (websocket-message-handler e.data))))) (comment (draw-grid-pixel 2 1 "red") (draw-grid-pixel 0 0 "red") + + (def data {:column 0 + :row 1 + :color "red"}) ) (defn setup-ws @@ -105,11 +125,28 @@ on-message-fn) socket)) + +(def sample-data {:column 0 + :row 1 + :color "red"}) + + + + (comment - (def socket* (setup-ws "ws://localhost:8080/ws" - (fn [] - (js/console.log "Socket connected")) - (fn [e] - (js/console.log e.data)))) + (websocket-message-handler (pr-str sample-data)) + + + + (.send socket* "pong") + (events/listen canvas "touchstart" + (fn [e] + (.preventDefault e) + (handle-canvas-click (aget (.-touches e) 0)))) + + (events/listen (:brush tools) "click" #(swap! app-state assoc :current-tool :brush)) + (events/listen (:eraser tools) "click" #(swap! app-state assoc :current-tool :eraser)) + (events/listen (:color-picker tools) "change" + #(swap! app-state assoc :current-color (.. % -target -value))) + ) - (.send socket* "pong"))