From a5dc634e3530a215bf2d303a2b5f144beed75554 Mon Sep 17 00:00:00 2001 From: Andrey Antukh Date: Mon, 28 Dec 2015 20:06:59 +0200 Subject: [PATCH] Implement shapes moving using mouse. --- frontend/uxbox/data/projects.cljs | 1 + frontend/uxbox/data/workspace.cljs | 38 ++++++++++++-- frontend/uxbox/ui/workspace/base.cljs | 66 +++++++++++++++++++------ frontend/uxbox/ui/workspace/canvas.cljs | 48 +++++++++++++++--- 4 files changed, 126 insertions(+), 27 deletions(-) diff --git a/frontend/uxbox/data/projects.cljs b/frontend/uxbox/data/projects.cljs index 639afd795..e87877252 100644 --- a/frontend/uxbox/data/projects.cljs +++ b/frontend/uxbox/data/projects.cljs @@ -63,6 +63,7 @@ :project project :created (time/now :unix) :shapes [] + :shapes-by-id {} :name name :width width :height height}] diff --git a/frontend/uxbox/data/workspace.cljs b/frontend/uxbox/data/workspace.cljs index 159ead0d9..82a30870e 100644 --- a/frontend/uxbox/data/workspace.cljs +++ b/frontend/uxbox/data/workspace.cljs @@ -74,11 +74,13 @@ (reify rs/UpdateEvent (-apply-update [_ state] - (println "add-shape") - (if-let [pageid (get-in state [:workspace :page])] - (update-in state [:pages-by-id pageid :shapes] conj - (merge shape props)) - state)) + (let [id (random-uuid) + pageid (get-in state [:workspace :page]) + _ (assert pageid) + shape (merge shape props {:id id})] + (as-> state $ + (update-in $ [:pages-by-id pageid :shapes] conj id) + (update-in $ [:pages-by-id pageid :shapes-by-id] assoc id shape)))) IPrintWithWriter (-pr-writer [mv writer _] @@ -101,3 +103,29 @@ (-pr-writer [mv writer _] (-write writer "#")))) +(defn apply-delta + "Mark a shape selected for drawing in the canvas." + [shapeid [dx dy :as delta]] + (reify + rs/UpdateEvent + (-apply-update [_ state] + ;; (println "apply-delta" shapeid delta) + (let [pageid (get-in state [:workspace :page]) + _ (assert pageid) + shape (get-in state [:pages-by-id pageid :shapes-by-id shapeid])] + (update-in state [:pages-by-id pageid :shapes-by-id shapeid] merge + {:x (+ (:x shape) dx) + :y (+ (:y shape) dy)}))))) + + +;; (defn apply-delta' +;; "Mark a shape selected for drawing in the canvas." +;; [shapeid [dx dy :as delta]] +;; (reify +;; rs/UpdateEvent +;; (-apply-update [_ state] +;; ;; (println "apply-delta'" shapeid delta) +;; (let [pageid (get-in state [:workspace :page]) +;; shape (get-in state [:pages-by-id pageid :shapes-by-id shapeid])] +;; (update-in state [:pages-by-id pageid :shapes-by-id shapeid] merge +;; {:x dx :y dy}))))) diff --git a/frontend/uxbox/ui/workspace/base.cljs b/frontend/uxbox/ui/workspace/base.cljs index ae2f184ce..1e99ed9fe 100644 --- a/frontend/uxbox/ui/workspace/base.cljs +++ b/frontend/uxbox/ui/workspace/base.cljs @@ -4,6 +4,7 @@ [uxbox.rstore :as rs] [uxbox.state :as s] [uxbox.data.projects :as dp] + [uxbox.data.workspace :as dw] [uxbox.util.lens :as ul] [uxbox.ui.util :as util] [goog.events :as events]) @@ -54,20 +55,57 @@ ;; Mouse Position Stream ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;; (defn- coords-delta -;; [[old new]] -;; (let [[oldx oldy] old -;; [newx newy] new] -;; [(* 2 (- newx oldx)) -;; (* 2 (- newy oldy))])) +(def immediate-scheduler js/Rx.Scheduler.immediate) +(def current-thread-scheduler js/Rx.Scheduler.currentThread) -;; (def ^{:doc "A stream of mouse coordinate deltas as `[dx dy]` vectors."} -;; delta -;; (s/map coords-delta (s/partition 2 client-position))) +(defn observe-on + [scheduler ob] + (.observeOn ob scheduler)) + +(defn subscribe-on + [scheduler ob] + (.subscribeOn ob scheduler)) + +;; (defn window +;; [n ob] +;; (.windowWithCount ob n)) + +(defonce selected-shape-b (rx/bus)) + +(defonce mouse-b (rx/bus)) +(defonce mouse-s (rx/dedupe mouse-b)) + +;; Deltas + +(defn- coords-delta + [[old new]] + (let [[oldx oldy] old + [newx newy] new] + [(- newx oldx) + (- newy oldy)])) + +(defonce mouse-delta-s + (->> mouse-s + (rx/sample 10) + (rx/buffer 2 1) + (rx/map coords-delta))) + +(defonce _subscription_ + (as-> (rx/with-latest-from vector selected-shape-b mouse-delta-s) $ + (rx/filter #(not= :nothing (second %)) $) + ;; (observe-on current-thread-scheduler $) + (rx/on-value $ (fn [[delta shape]] + (rs/emit! (dw/apply-delta (:id shape) delta)))))) + + ;; (rx/on-value mouse-delta-s + ;; (fn [val] + ;; (println "delta" val)))) + +;; Materialized views + +(defonce mouse-position (rx/to-atom (rx/sample 50 mouse-s))) +;; (defonce mouse-position2 (rx/to-atom mouse-s)) -(defonce mouse-bus (rx/bus)) -(defonce mouse-s (rx/dedupe mouse-bus)) -(defonce mouse-position (rx/to-atom (rx/throttle 50 mouse-s))) (defn- mouse-mixin-did-mount [own] @@ -78,8 +116,8 @@ offset-y (.-top brect) x (.-clientX event) y (.-clientY event)] - (rx/push! mouse-bus [(- x offset-x) - (- y offset-y)])))] + (rx/push! mouse-b [(- x offset-x) + (- y offset-y)])))] (let [key (events/listen js/document EventType.MOUSEMOVE on-mousemove)] (js/console.log "mouse-mixin-did-mount" key) (assoc own ::eventkey key)))) diff --git a/frontend/uxbox/ui/workspace/canvas.cljs b/frontend/uxbox/ui/workspace/canvas.cljs index 6cf387c65..131d25339 100644 --- a/frontend/uxbox/ui/workspace/canvas.cljs +++ b/frontend/uxbox/ui/workspace/canvas.cljs @@ -1,14 +1,16 @@ (ns uxbox.ui.workspace.canvas (:require [sablono.core :as html :refer-macros [html]] [rum.core :as rum] + [beicon.core :as rx] [uxbox.router :as r] [uxbox.rstore :as rs] [uxbox.state :as s] [uxbox.shapes :as shapes] [uxbox.library.icons :as _icons] - [uxbox.ui.mixins :as mx] - [uxbox.ui.util :as util] [uxbox.data.projects :as dp] + [uxbox.ui.mixins :as mx] + [uxbox.ui.dom :as dom] + [uxbox.ui.util :as util] [uxbox.ui.workspace.base :as wb] [uxbox.ui.workspace.rules :as wr] [uxbox.ui.workspace.toolboxes :as toolboxes])) @@ -47,9 +49,33 @@ :stroke "gray"}) (defn- shape-render - [own shape] + [own {:keys [x y] :as shape}] (let [local (:rum/local own)] - (shapes/render shape))) + (html + [:g { + :on-mouse-down + (fn [event] + (println "mouse-down") + (rx/push! wb/selected-shape-b shape)) + + ;; :on-mouse-move + ;; (fn [event] + ;; (when (:drop @local) + ;; (println "mouse-move" @wb/mouse-position2) + ;; (let [target (.-currentTarget event) + ;; [nx ny] @wb/mouse-position2 + ;; svg (aget (.-childNodes target) 0)] + ;; (.setAttribute svg "x" nx) + ;; (.setAttribute svg "y" ny))) + ;; false) + + :on-mouse-up + (fn [event] + (println "mouse-up") + (rx/push! wb/selected-shape-b :nothing) + (dom/stop-propagation event)) + } + (shapes/render shape)]))) ;; (defn- shape-render ;; [own shape] @@ -78,7 +104,7 @@ (util/component {:render shape-render :name "shape" - :mixins [mx/static]})) + :mixins [mx/static (mx/local {})]})) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; Canvas @@ -106,13 +132,19 @@ :ref "canvas" :width page-width :height page-height + :on-mouse-up + (fn [event] + (rx/push! wb/selected-shape-b :nothing) + (dom/stop-propagation event)) + ;; :on-mouse-down cs/on-mouse-down ;; :on-mouse-up cs/on-mouse-up } (background) - [:svg.page-layout - (for [item (:shapes page)] - (shape item))] + [:svg.page-layout {} + (for [shapeid (:shapes page) + :let [item (get-in page [:shapes-by-id shapeid])]] + (rum/with-key (shape item) (str shapeid)))] #_(apply vector :svg#page-layout (map shapes/shape->svg raw-shapes)) #_(when-let [shape (rum/react drawing)] (shapes/shape->drawing-svg shape))