From 5d5b84a0a11b5ba60f9f4bf6f464b95e2c9eb001 Mon Sep 17 00:00:00 2001 From: Andrey Antukh Date: Sat, 6 Feb 2016 12:29:00 +0200 Subject: [PATCH] Adapt the application to use the new point abstraction. --- src/uxbox/data/workspace.cljs | 4 +- src/uxbox/shapes.cljs | 33 ++++---- src/uxbox/ui/workspace.cljs | 2 +- src/uxbox/ui/workspace/base.cljs | 25 ++---- src/uxbox/ui/workspace/canvas.cljs | 15 ++-- src/uxbox/ui/workspace/canvas/draw.cljs | 20 ++--- src/uxbox/ui/workspace/canvas/ruler.cljs | 95 +++++++++++++++------- src/uxbox/ui/workspace/canvas/selrect.cljs | 14 ++-- src/uxbox/ui/workspace/options.cljs | 23 ++---- 9 files changed, 126 insertions(+), 105 deletions(-) diff --git a/src/uxbox/data/workspace.cljs b/src/uxbox/data/workspace.cljs index ad809961c..a091a7cc1 100644 --- a/src/uxbox/data/workspace.cljs +++ b/src/uxbox/data/workspace.cljs @@ -10,6 +10,7 @@ [uxbox.time :as time] [uxbox.xforms :as xf] [uxbox.shapes :as sh] + [uxbox.util.geom.point :as gpt] [uxbox.util.data :refer (index-of)])) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; @@ -156,7 +157,8 @@ (defn move-shape "Mark a shape selected for drawing in the canvas." - [sid [dx dy :as delta]] + [sid delta] + {:pre [(gpt/point? delta)]} (reify rs/UpdateEvent (-apply-update [_ state] diff --git a/src/uxbox/shapes.cljs b/src/uxbox/shapes.cljs index 450b905af..3c99cac29 100644 --- a/src/uxbox/shapes.cljs +++ b/src/uxbox/shapes.cljs @@ -116,14 +116,16 @@ ;; Resize (defmethod -resize :builtin/line - [shape {:keys [x2 y2] :as pos}] + [shape {:keys [x y] :as pos}] (assoc shape - :x2 x2 :y2 y2)) + :x2 x :y2 x)) (defmethod -resize :builtin/circle - [{:keys [cx cy rx ry] :as shape} {:keys [x2 y2 lock] :as pos}] + [{:keys [cx cy rx ry] :as shape} {:keys [x y lock] :as pos}] (let [x1 (- cx rx) y1 (- cy ry) + x2 x + y2 y width (- x2 x1) height (if lock @@ -140,15 +142,14 @@ (assoc shape :rx rx :ry ry :cx cx :cy cy)))) (defmethod -resize :builtin/rect - [shape {:keys [x2 y2 lock] :as pos}] - (let [{:keys [x y]} shape] - (if lock - (assoc shape - :width (- x2 x) - :height (- x2 x)) - (assoc shape - :width (- x2 x) - :height (- y2 y))))) + [shape {:keys [x y lock] :as pos}] + (if lock + (assoc shape + :width (- x (:x shape)) + :height (- x (:x shape))) + (assoc shape + :width (- x (:x shape)) + :height (- y (:y shape))))) (defmethod -resize :default [shape _] @@ -167,19 +168,19 @@ ;; Move (defmethod -move ::rect - [shape [dx dy]] + [shape {dx :x dy :y}] (assoc shape :x (+ (:x shape) dx) :y (+ (:y shape) dy))) (defmethod -move :builtin/group - [shape [dx dy]] + [shape {dx :x dy :y}] (assoc shape :dx (+ (:dx shape 0) dx) :dy (+ (:dy shape 0) dy))) (defmethod -move :builtin/line - [shape [dx dy]] + [shape {dx :x dy :y}] (assoc shape :x1 (+ (:x1 shape) dx) :y1 (+ (:y1 shape) dy) @@ -187,7 +188,7 @@ :y2 (+ (:y2 shape) dy))) (defmethod -move :builtin/circle - [shape [dx dy]] + [shape {dx :x dy :y}] (assoc shape :cx (+ (:cx shape) dx) :cy (+ (:cy shape) dy))) diff --git a/src/uxbox/ui/workspace.cljs b/src/uxbox/ui/workspace.cljs index 7085d3971..33f860b12 100644 --- a/src/uxbox/ui/workspace.cljs +++ b/src/uxbox/ui/workspace.cljs @@ -25,7 +25,7 @@ (defn- coordenates-render [own] - (let [[x y] (rum/react wb/mouse-position)] + (let [{:keys [x y]} (rum/react wb/mouse-position)] (html [:div {:style {:position "absolute" :left "80px" :top "20px"}} [:table diff --git a/src/uxbox/ui/workspace/base.cljs b/src/uxbox/ui/workspace/base.cljs index 9728f1101..6b65f0ab7 100644 --- a/src/uxbox/ui/workspace/base.cljs +++ b/src/uxbox/ui/workspace/base.cljs @@ -6,6 +6,7 @@ [uxbox.state :as st] [uxbox.data.projects :as dp] [uxbox.data.workspace :as dw] + [uxbox.util.geom.point :as gpt] [uxbox.util.lens :as ul] [goog.events :as events]) (:import goog.events.EventType)) @@ -51,25 +52,15 @@ ;; Scroll Stream ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -(defonce ^:private scroll-b (rx/bus)) +(defonce scroll-b (rx/bus)) (defonce scroll-s (as-> scroll-b $ - (rx/merge $ (rx/of {:top 0 :left 0})) + (rx/merge $ (rx/of (gpt/point))) (rx/dedupe $))) -(defonce scroll-top-s - (->> scroll-s - (rx/map :top) - (rx/dedupe))) - -(defonce scroll-left-s - (->> scroll-s - (rx/map :left) - (rx/dedupe))) - -(defonce scroll-top (rx/to-atom scroll-top-s)) -(defonce scroll-left (rx/to-atom scroll-left-s)) +(defonce scroll + (rx/to-atom scroll-s)) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; Interactions @@ -107,10 +98,7 @@ (defn- coords-delta [[old new]] - (let [[oldx oldy] old - [newx newy] new] - [(- newx oldx) - (- newy oldy)])) + (gpt/subtract new old)) (defonce mouse-delta-s (->> mouse-s @@ -135,4 +123,3 @@ (def document-start-x 50) (def document-start-y 50) - diff --git a/src/uxbox/ui/workspace/canvas.cljs b/src/uxbox/ui/workspace/canvas.cljs index a3bb8891a..52d14b23e 100644 --- a/src/uxbox/ui/workspace/canvas.cljs +++ b/src/uxbox/ui/workspace/canvas.cljs @@ -14,6 +14,7 @@ [uxbox.data.projects :as dp] [uxbox.data.workspace :as dw] [uxbox.ui.mixins :as mx] + [uxbox.util.geom.point :as gpt] [uxbox.util.dom :as dom] [uxbox.ui.keyboard :as kbd] [uxbox.ui.workspace.base :as wb] @@ -109,19 +110,19 @@ (defn- canvas-did-mount [own] - (letfn [(on-mousemove [event page [offset-x offset-y]] - (let [x (.-clientX event) - y (.-clientY event) + (letfn [(on-mousemove [event page offset-pt] + (let [wpt (gpt/point (.-clientX event) (.-clientY event)) + cpt (gpt/subtract wpt offset-pt) event {:id (:id page) :ctrl (kbd/ctrl? event) - :window-coords [x y] - :canvas-coords [(- x offset-x) - (- y offset-y)]}] + :shift (kbd/shift? event) + :window-coords wpt + :canvas-coords cpt}] (rx/push! wb/mouse-b event)))] (let [[page] (:rum/props own) canvas (mx/get-ref-dom own (str "canvas" (:id page))) brect (.getBoundingClientRect canvas) - brect [(.-left brect) (.-top brect)] + brect (gpt/point (.-left brect) (.-top brect)) key (events/listen js/document EventType.MOUSEMOVE #(on-mousemove % page brect))] (swap! wb/bounding-rect assoc (:id page) brect) diff --git a/src/uxbox/ui/workspace/canvas/draw.cljs b/src/uxbox/ui/workspace/canvas/draw.cljs index 0c9b46b86..380b5fa32 100644 --- a/src/uxbox/ui/workspace/canvas/draw.cljs +++ b/src/uxbox/ui/workspace/canvas/draw.cljs @@ -10,6 +10,7 @@ [uxbox.data.workspace :as dw] [uxbox.ui.workspace.base :as wb] [uxbox.ui.mixins :as mx] + [uxbox.util.geom.point :as gpt] [uxbox.util.dom :as dom])) (defonce +drawing-shape+ (atom nil)) @@ -37,13 +38,13 @@ ;; Subscriptions ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; FIXME: this works for now, but should be refactored when advanced rendering +;; is introduced such as polyline, polygon and path. + (define-once :drawing-subscriptions (letfn [(init-shape [shape] - (let [[x y :as mpos] @wb/mouse-position - stop @wb/scroll-top - y (+ stop y) + (let [{:keys [x y]} (gpt/subtract @wb/mouse-position @wb/scroll) shape (sh/-initialize shape {:x1 x :y1 y :x2 x :y2 y})] - (reset! +drawing-shape+ shape) (reset! +drawing-position+ {:x2 x :y2 y :lock false}) @@ -54,10 +55,9 @@ (rx/with-latest-from vector wb/mouse-ctrl-s $) (rx/subscribe $ on-value nil on-complete)))) - (on-value [[[x y :as pos] ctrl?]] - (let [stop @wb/scroll-top] - (reset! +drawing-position+ - {:x2 x :y2 (+ y stop) :lock ctrl?}))) + (on-value [[pos ctrl?]] + (let [{:keys [x y] :as pos} (gpt/subtract pos @wb/scroll)] + (reset! +drawing-position+ {:x2 x :y2 y :lock ctrl?}))) (on-complete [] (let [shape @+drawing-shape+ @@ -69,9 +69,7 @@ (reset! +drawing-shape+ nil))) (init-icon [shape] - (let [[x y] @wb/mouse-position - stop @wb/scroll-top - y (+ stop y) + (let [{:keys [x y]} (gpt/subtract @wb/mouse-position @wb/scroll) props {:x1 x :y1 y :x2 (+ x 100) :y2 (+ y 100)} shape (sh/-initialize shape props)] (rs/emit! (dw/add-shape shape) diff --git a/src/uxbox/ui/workspace/canvas/ruler.cljs b/src/uxbox/ui/workspace/canvas/ruler.cljs index 14c1bd11b..37efb4254 100644 --- a/src/uxbox/ui/workspace/canvas/ruler.cljs +++ b/src/uxbox/ui/workspace/canvas/ruler.cljs @@ -11,6 +11,7 @@ [uxbox.util.math :as mth] [uxbox.ui.workspace.base :as wb] [uxbox.ui.mixins :as mx] + [uxbox.util.geom.point :as gpt] [uxbox.util.dom :as dom])) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; @@ -18,17 +19,17 @@ ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; (defn- resolve-position - [own [x y]] + [own pt] (let [overlay (mx/get-ref-dom own "overlay") - brect (.getBoundingClientRect overlay)] - [(- x (.-left brect)) - (- y (.-top brect))])) + brect (.getBoundingClientRect overlay) + bpt (gpt/point (.-left brect) (.-top brect))] + (gpt/subtract pt bpt))) (defn- get-position [own event] - (let [x (.-clientX event) - y (.-clientY event)] - (resolve-position own [x y]))) + (->> (gpt/point (.-clientX event) + (.-clientY event)) + (resolve-position own))) (defn- on-mouse-down [own local event] @@ -41,41 +42,77 @@ (dom/stop-propagation event) (swap! local assoc :active false)) +(defn- overlay-line-render + [own center pt] + (let [distance (-> (gpt/distance pt center) + (mth/precision 4)) + angle (-> (gpt/angle pt center) + (mth/precision 4)) + {x1 :x y1 :y} center + {x2 :x y2 :y} pt] + (html + [:g + [:line {:x1 x1 :y1 y1 + :x2 x2 :y2 y2 + :style {:cursor "cell"} + :stroke-width "2" + :stroke "red"}] + [:text + {:transform (str "translate(" (+ x2 15) "," (- y2 10) ")")} + [:tspan {:x "0" :dy="1.2em"} + (str "distance=" distance)] + [:tspan {:x "0" :y "20" :dy="1.2em"} + (str "angle=" angle)]]]))) + (defn- overlay-render [own local] - (let [[x1 y1 :as p1] (:pos1 @local) - [x2 y2 :as p2] (:pos2 @local) - distance (mth/distance p1 p2)] + (let [p1 (:pos1 @local) + p2 (:pos2 @local)] (html [:svg {:on-mouse-down #(on-mouse-down own local %) :on-mouse-up #(on-mouse-up own local %) :ref "overlay"} - [:rect {:style {:fill "transparent" :stroke "transparent" :cursor "cell"} + [:rect {:style {:fill "transparent" + :stroke "transparent" + :cursor "cell"} :width wb/viewport-width :height wb/viewport-height}] - (if (and x1 x2) - [:g - [:line {:x1 x1 :y1 y1 :x2 x2 :y2 y2 - :style {:cursor "cell"} - :stroke-width "2" - :stroke "red"}] - [:text {:x (+ x2 15) :y y2} - [:tspan (str distance)]]])]))) + (if (and p1 p2) + (overlay-line-render own p1 p2))]))) + +(def ^:private ^:static +immanted-zones+ + (let [transform #(vector (- % 7) (+ % 7) %)] + (concat + (mapv transform (range 0 181 10)) + (mapv (comp transform -) (range 0 181 10))))) (defn- overlay-will-mount [own local] - (letfn [(on-value [[[x y :as pos] ctrl?]] + (letfn [(align-position [angle pos] + (reduce (fn [pos [a1 a2 v]] + (if (< a1 angle a2) + (reduced (gpt/update-angle pos v)) + pos)) + pos + +immanted-zones+)) + + (on-value-aligned [pos2] + (let [center (:pos1 @local)] + (as-> pos2 $ + (gpt/subtract $ center) + (align-position (gpt/angle $) $) + (gpt/add $ center) + (swap! local assoc :pos2 $)))) + + (on-value-simple [pos2] + (swap! local assoc :pos2 pos2)) + + (on-value [[pos ctrl?]] (if ctrl? - (let [[sx sy] (:pos1 @local) - dx (mth/abs (- x sx)) - dy (mth/abs (- y sy))] - (cond - (> dx dy) (swap! local assoc :pos2 [x sy]) - (> dy dx) (swap! local assoc :pos2 [sx y]) - :else (swap! local assoc :pos2 pos))) - (swap! local assoc :pos2 pos)))] + (on-value-aligned pos) + (on-value-simple pos)))] + (as-> wb/mouse-absolute-s $ - (rx/dedupe $) (rx/filter #(:active @local) $) (rx/map #(resolve-position own %) $) (rx/with-latest-from vector wb/mouse-ctrl-s $) diff --git a/src/uxbox/ui/workspace/canvas/selrect.cljs b/src/uxbox/ui/workspace/canvas/selrect.cljs index 25515bff8..a827b00c2 100644 --- a/src/uxbox/ui/workspace/canvas/selrect.cljs +++ b/src/uxbox/ui/workspace/canvas/selrect.cljs @@ -11,6 +11,7 @@ [uxbox.data.workspace :as dw] [uxbox.ui.workspace.base :as wb] [uxbox.ui.mixins :as mx] + [uxbox.util.geom.point :as gpt] [uxbox.util.dom :as dom])) (defonce selrect-pos (atom nil)) @@ -46,10 +47,10 @@ [data] (let [start (:start data) current (:current data ) - start-x (min (first start) (first current)) - start-y (min (second start) (second current)) - current-x (max (first start) (first current)) - current-y (max (second start) (second current)) + start-x (min (:x start) (:x current)) + start-y (min (:y start) (:y current)) + current-x (max (:x start) (:x current)) + current-y (max (:y start) (:y current)) width (- current-x start-x) height (- current-y start-y)] {:x start-x @@ -58,9 +59,8 @@ :height (- current-y start-y)})) (define-once :selrect-subscriptions - (letfn [(on-value [[x y :as pos]] - (let [scroll (or @wb/scroll-top 0) - pos [x (+ y scroll)]] + (letfn [(on-value [pos] + (let [pos (gpt/subtract pos @wb/scroll)] (if (nil? @selrect-pos) (reset! selrect-pos {:start pos :current pos}) (swap! selrect-pos assoc :current pos)))) diff --git a/src/uxbox/ui/workspace/options.cljs b/src/uxbox/ui/workspace/options.cljs index a333c4972..a0f32e2c1 100644 --- a/src/uxbox/ui/workspace/options.cljs +++ b/src/uxbox/ui/workspace/options.cljs @@ -7,6 +7,7 @@ [uxbox.data.workspace :as dw] [uxbox.ui.icons :as i] [uxbox.ui.mixins :as mx] + [uxbox.util.geom.point :as gpt] [uxbox.util.dom :as dom] [uxbox.ui.colorpicker :refer (colorpicker)] [uxbox.ui.workspace.recent-colors :refer (recent-colors)] @@ -53,19 +54,12 @@ ;; Helpers ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -(defn- viewportcoord->clientcoord - [pageid viewport-x viewport-y] - (let [[offset-x offset-y] (get @wb/bounding-rect pageid) - new-x (+ viewport-x offset-x) - new-y (+ viewport-y offset-y)] - [new-x new-y])) - (defn- get-position [{:keys [page] :as shape}] (let [{:keys [x y width]} (sh/-outer-rect shape) - vx (+ x width 50) - vy (- y 50)] - (viewportcoord->clientcoord page vx vy))) + bpt (get @wb/bounding-rect page) + vpt (gpt/point (+ x width 50) (- y 50))] + (gpt/add vpt bpt))) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; Implementation @@ -496,16 +490,17 @@ (defn element-opts-render [own shape] (let [local (:rum/local own) - shape (rum/react shape) - [popup-x popup-y] (get-position shape) - scroll (or (rum/react wb/scroll-top) 0) zoom 1 + shape (rum/react shape) + scroll (rum/react wb/scroll) + pos (-> (get-position shape) + (gpt/subtract scroll)) ;; and multiply by zoom in future menus (get +menus-map+ (:type shape)) active-menu (:menu @local (first menus))] (when (seq menus) (html [:div#element-options.element-options - {:style {:left (* popup-x zoom) :top (- (* popup-y zoom) scroll)}} + {:style {:left (:x pos) :top (:y pos)}} [:ul.element-icons (for [menu-id (get +menus-map+ (:type shape)) :let [menu (get +menus-by-id+ menu-id)