diff --git a/frontend/src/uxbox/main/data/shapes.cljs b/frontend/src/uxbox/main/data/shapes.cljs index 4827d6d7b..3c9fd535d 100644 --- a/frontend/src/uxbox/main/data/shapes.cljs +++ b/frontend/src/uxbox/main/data/shapes.cljs @@ -5,21 +5,31 @@ ;; Copyright (c) 2015-2016 Andrey Antukh (ns uxbox.main.data.shapes - (:require [beicon.core :as rx] + (:require [cljs.spec :as s :include-macros true] + [beicon.core :as rx] [uxbox.util.uuid :as uuid] [potok.core :as ptk] [uxbox.store :as st] - [uxbox.util.forms :as sc] - [uxbox.util.geom.point :as gpt] - [uxbox.util.geom.matrix :as gmt] - [uxbox.util.router :as r] - [uxbox.util.rlocks :as rlocks] - [uxbox.util.workers :as uw] [uxbox.main.constants :as c] [uxbox.main.geom :as geom] [uxbox.main.data.core :refer (worker)] [uxbox.main.data.shapes-impl :as impl] - [uxbox.main.data.pages :as udp])) + [uxbox.main.data.pages :as udp] + [uxbox.util.forms :as sc] + [uxbox.util.spec :as us] + [uxbox.util.geom.point :as gpt] + [uxbox.util.geom.matrix :as gmt] + [uxbox.util.router :as r] + [uxbox.util.rlocks :as rlocks] + [uxbox.util.workers :as uw])) + +(s/def ::x1 number?) +(s/def ::y1 number?) +(s/def ::x2 number?) +(s/def ::y2 number?) +(s/def ::type keyword?) + +(s/def ::rect-shape (s/keys :req-un [::x1 ::y1 ::x2 ::y2 ::type])) ;; --- Shapes CRUD @@ -56,16 +66,6 @@ ;; --- Shape Transformations -(defn move-shape - "Move shape using relative position (delta)." - [sid delta] - (reify - udp/IPageUpdate - ptk/UpdateEvent - (update [_ state] - (let [shape (get-in state [:shapes sid])] - (update-in state [:shapes sid] geom/move delta))))) - (declare align-point) (def ^:private canvas-coords @@ -126,11 +126,23 @@ ;; --- Apply Temporal Displacement +(defn rotate + [{:keys [x1 y1 x2 y2 rotation] :as shape}] + (let [x-center (+ x1 (/ (- x2 x1) 2)) + y-center (+ y1 (/ (- y2 y1) 2))] + (-> (gmt/matrix) + #_(gmt/translate x-center y-center) + (gmt/rotate 15) + #_(gmt/translate (- x-center) (- y-center))))) + (deftype ApplyTemporalDisplacement [id delta] + udp/IPageUpdate ptk/UpdateEvent (update [_ state] - (let [current-delta (get-in state [:shapes id :tmp-displacement] (gpt/point 0 0)) - delta (gpt/add current-delta delta)] + (let [shape (get-in state [:shapes id]) + displ (:tmp-displacement shape (gpt/point 0 0)) + ;; delta (gpt/transform delta (rotate shape)) + delta (gpt/add displ delta)] (assoc-in state [:shapes id :tmp-displacement] delta)))) (defn apply-temporal-displacement @@ -141,6 +153,7 @@ ;; --- Apply Displacement (deftype ApplyDisplacement [id] + udp/IPageUpdate ptk/UpdateEvent (update [_ state] (let [{:keys [tmp-displacement type] :as shape} (get-in state [:shapes id]) @@ -170,6 +183,7 @@ ;; --- Apply Temporal Resize Matrix (deftype ApplyTemporalResizeMatrix [id mx] + udp/IPageUpdate ptk/UpdateEvent (update [_ state] (assoc-in state [:shapes id :tmp-resize-xform] mx))) @@ -184,6 +198,7 @@ (declare apply-resize-matrix) (deftype ApplyResizeMatrix [id] + udp/IPageUpdate ptk/UpdateEvent (update [_ state] (let [{:keys [type tmp-resize-xform] @@ -210,26 +225,6 @@ {:pre [(uuid? id)]} (ApplyResizeMatrix. id)) -(defn update-vertex-position - [id {:keys [vid delta]}] - (reify - udp/IPageUpdate - ptk/UpdateEvent - (update [_ state] - (update-in state [:shapes id] geom/move-vertex vid delta)))) - -(defn initial-vertext-align - [id vid] - (reify - ptk/WatchEvent - (watch [_ state s] - (let [shape (get-in state [:shapes id]) - point (geom/get-vertex-point shape vid) - point (gpt/add point canvas-coords)] - (->> (align-point point) - (rx/map #(gpt/subtract % point)) - (rx/map #(update-vertex-position id {:vid vid :delta %}))))))) - (defn update-position "Update the start position coordenate of the shape." [sid {:keys [x y] :as opts}] @@ -481,21 +476,23 @@ (defn select-shape "Mark a shape selected for drawing in the canvas." [id] + {:pre [(uuid? id)]} (SelectShape. id)) ;; --- Select Shapes -(defrecord SelectShapes [selrect] +(deftype SelectShapesBySelrect [selrect] ptk/UpdateEvent (update [_ state] (let [page (get-in state [:workspace :page]) shapes (impl/match-by-selrect state page selrect)] (assoc-in state [:workspace :selected] shapes)))) -(defn select-shapes +(defn select-shapes-by-selrect "Select shapes that matches the select rect." [selrect] - (SelectShapes. selrect)) + {:pre [(us/valid? ::rect-shape selrect)]} + (SelectShapesBySelrect. selrect)) ;; --- Update Interaction @@ -636,23 +633,6 @@ (rx/from-coll (into [(deselect-all)] (map #(delete-shape %) selected))))))) -(defn move-selected - "Move a minimal position unit the selected shapes." - ([dir] (move-selected dir 1)) - ([dir n] - {:pre [(contains? #{:up :down :right :left} dir)]} - (reify - ptk/WatchEvent - (watch [_ state s] - (let [selected (get-in state [:workspace :selected]) - delta (case dir - :up (gpt/point 0 (- n)) - :down (gpt/point 0 n) - :right (gpt/point n 0) - :left (gpt/point (- n) 0))] - (rx/from-coll - (map #(move-shape % delta) selected))))))) - (defn update-selected-shapes-fill "Update the fill related attributed on selected shapes." diff --git a/frontend/src/uxbox/main/data/shapes_impl.cljs b/frontend/src/uxbox/main/data/shapes_impl.cljs index 337c59c47..e9cef89ea 100644 --- a/frontend/src/uxbox/main/data/shapes_impl.cljs +++ b/frontend/src/uxbox/main/data/shapes_impl.cljs @@ -276,7 +276,7 @@ (let [xf (comp (map #(get-in state [:shapes %])) (remove :hidden) (remove :blocked) - (map geom/outer-rect)) + (map geom/selection-rect)) match (partial try-match-shape xf selrect) shapes (get-in state [:pages page :shapes])] (reduce match #{} (sequence xf shapes)))) diff --git a/frontend/src/uxbox/main/ui/shapes/circle.cljs b/frontend/src/uxbox/main/ui/shapes/circle.cljs index 7c4e3e7e4..37e086062 100644 --- a/frontend/src/uxbox/main/ui/shapes/circle.cljs +++ b/frontend/src/uxbox/main/ui/shapes/circle.cljs @@ -32,11 +32,18 @@ (mx/defc circle-shape {:mixins [mx/static]} - [{:keys [id tmp-resize-xform tmp-displacement] :as shape}] - (let [xfmt (cond-> (or tmp-resize-xform (gmt/matrix)) - tmp-displacement (gmt/translate tmp-displacement)) + [{:keys [id tmp-resize-xform tmp-displacement rotation cx cy] :as shape}] + (let [shape (cond-> shape + tmp-displacement (geom/transform (gmt/translate-matrix tmp-displacement)) + tmp-resize-xform (geom/transform tmp-resize-xform)) + center (gpt/point (:cx shape) + (:cy shape)) + rotation (or rotation 0) - props {:transform (str xfmt) :id (str id)} + xfmt (-> (gmt/matrix) + (gmt/rotate* rotation center)) + + props {:id (str id) :transform (str xfmt)} attrs (merge props (attrs/extract-style-attrs shape) (select-keys shape [:cx :cy :rx :ry]))] diff --git a/frontend/src/uxbox/main/ui/shapes/group.cljs b/frontend/src/uxbox/main/ui/shapes/group.cljs index 8c873add7..9bb2df9bb 100644 --- a/frontend/src/uxbox/main/ui/shapes/group.cljs +++ b/frontend/src/uxbox/main/ui/shapes/group.cljs @@ -19,7 +19,6 @@ [uxbox.util.geom.matrix :as gmt] [uxbox.util.mixins :as mx :include-macros true])) - ;; --- Helpers (declare group-component) @@ -70,8 +69,7 @@ (let [xfmt (cond-> (or tmp-resize-xform (gmt/matrix)) tmp-displacement (gmt/translate tmp-displacement)) - props {:id (str id) - :transform (str xfmt)} + props {:id (str id) :transform (str xfmt)} attrs (merge props (attrs/extract-style-attrs shape))] [:g attrs diff --git a/frontend/src/uxbox/main/ui/shapes/icon.cljs b/frontend/src/uxbox/main/ui/shapes/icon.cljs index cd161d0e2..7f6170dd6 100644 --- a/frontend/src/uxbox/main/ui/shapes/icon.cljs +++ b/frontend/src/uxbox/main/ui/shapes/icon.cljs @@ -9,7 +9,8 @@ [uxbox.main.ui.shapes.attrs :as attrs] [uxbox.main.geom :as geom] [uxbox.util.mixins :as mx :include-macros true] - [uxbox.util.geom.matrix :as gmt])) + [uxbox.util.geom.matrix :as gmt] + [uxbox.util.geom.point :as gpt])) ;; --- Icon Component @@ -31,28 +32,27 @@ {:mixins [mx/static]} [shape] (let [{:keys [x1 y1 content id metadata - width height + width height rotation tmp-resize-xform tmp-displacement]} (geom/size shape) - [_ _ orw orh] (:view-box metadata) - scalex (/ width orw) - scaley (/ height orh) - view-box (apply str (interpose " " (:view-box metadata))) - xfmt (cond-> (or tmp-resize-xform (gmt/matrix)) + xfmt (cond-> (gmt/matrix) + tmp-resize-xform (gmt/multiply tmp-resize-xform) tmp-displacement (gmt/translate tmp-displacement) - true (gmt/translate x1 y1) - true (gmt/scale scalex scaley)) + rotation (gmt/rotate* rotation (gpt/point (+ x1 (/ width 2)) + (+ y1 (/ height 2))))) props {:id (str id) + :x x1 :y y1 :view-box view-box + :width width :height height :preserve-aspect-ratio "none" - :dangerouslySetInnerHTML {:__html content} - :transform (str xfmt)} + :dangerouslySetInnerHTML {:__html content}} attrs (merge props (attrs/extract-style-attrs shape))] - [:g attrs])) + [:g {:transform (str xfmt)} + [:svg attrs]])) ;; --- Icon SVG diff --git a/frontend/src/uxbox/main/ui/shapes/path.cljs b/frontend/src/uxbox/main/ui/shapes/path.cljs index 4143c4b89..a90c747a1 100644 --- a/frontend/src/uxbox/main/ui/shapes/path.cljs +++ b/frontend/src/uxbox/main/ui/shapes/path.cljs @@ -12,6 +12,7 @@ [uxbox.main.data.shapes :as uds] [uxbox.main.geom :as geom] [uxbox.util.geom.matrix :as gmt] + [uxbox.util.geom.point :as gpt] [uxbox.util.mixins :as mx :include-macros true])) ;; --- Path Component @@ -46,11 +47,13 @@ (mx/defc path-shape {:mixins [mx/static]} - [{:keys [id tmp-resize-xform tmp-displacement] :as shape}] - (let [xfmt (cond-> (or tmp-resize-xform (gmt/matrix)) - tmp-displacement (gmt/translate tmp-displacement)) - props {:transform (str xfmt) - :id (str id) + [{:keys [id tmp-resize-xform tmp-displacement rotation] :as shape}] + (let [shape (cond-> shape + tmp-displacement (geom/transform (gmt/translate-matrix tmp-displacement)) + tmp-resize-xform (geom/transform tmp-resize-xform) + (pos? rotation) (geom/rotate-shape)) + + props {:id (str id) :d (render-path shape)} attrs (merge props (attrs/extract-style-attrs shape))] [:path attrs])) diff --git a/frontend/src/uxbox/main/ui/shapes/rect.cljs b/frontend/src/uxbox/main/ui/shapes/rect.cljs index 598d85ced..b8dacf10d 100644 --- a/frontend/src/uxbox/main/ui/shapes/rect.cljs +++ b/frontend/src/uxbox/main/ui/shapes/rect.cljs @@ -25,21 +25,30 @@ selected? (contains? selected id) on-mouse-down #(common/on-mouse-down % shape selected)] [:g.shape {:class (when selected? "selected") - :on-mouse-down on-mouse-down - } + :on-mouse-down on-mouse-down} (rect-shape shape identity)])) ;; --- Rect Shape +(defn- rotate + [mt {:keys [x1 y1 x2 y2 width height rotation] :as shape}] + (let [x-center (+ x1 (/ width 2)) + y-center (+ y1 (/ height 2)) + center (gpt/point x-center y-center)] + (gmt/rotate* mt rotation center))) + (mx/defc rect-shape {:mixins [mx/static]} - [shape] - (let [{:keys [id x1 y1 width height - tmp-resize-xform - tmp-displacement]} (geom/size shape) + [{:keys [id tmp-displacement tmp-resize-xform rotation] :as shape}] + (let [xfmt (cond-> (gmt/matrix) + tmp-displacement (gmt/translate tmp-displacement) + tmp-resize-xform (gmt/multiply tmp-resize-xform)) - xfmt (cond-> (or tmp-resize-xform (gmt/matrix)) - tmp-displacement (gmt/translate tmp-displacement)) + {:keys [x1 y1 width height] :as shape} (-> (geom/transform shape xfmt) + (geom/size)) + + xfmt (cond-> (gmt/matrix) + (pos? rotation) (rotate shape)) props {:x x1 :y y1 :id id :width width diff --git a/frontend/src/uxbox/main/ui/shapes/selection.cljs b/frontend/src/uxbox/main/ui/shapes/selection.cljs index cd4d5b723..cd721a6b5 100644 --- a/frontend/src/uxbox/main/ui/shapes/selection.cljs +++ b/frontend/src/uxbox/main/ui/shapes/selection.cljs @@ -43,95 +43,163 @@ (def edition-ref scommon/edition-ref) -(defn transform-rect - [{:keys [x1 y1 x2 y2] :as shape} xfmt] - (if xfmt - (let [tl (gpt/transform [x1 y1] xfmt) - tr (gpt/transform [x2 y1] xfmt) - bl (gpt/transform [x1 y2] xfmt) - br (gpt/transform [x2 y2] xfmt) - minx (apply min (map :x [tl tr bl br])) - maxx (apply max (map :x [tl tr bl br])) - miny (apply min (map :y [tl tr bl br])) - maxy (apply max (map :y [tl tr bl br]))] - (assoc shape - :x1 minx - :y1 miny - :x2 maxx - :y2 maxy)) - shape)) - ;; --- Resize Implementation +(defn- rotate + [shape] + (let [{:keys [x1 y1 width height rotation]} (-> (geom/shape->rect-shape shape) + (assoc :type :rect) + (geom/size)) + x-center (+ x1 (/ width 2)) + y-center (+ y1 (/ height 2)) + mt (-> (gmt/matrix) + (gmt/translate x-center y-center) + (gmt/rotate rotation) + (gmt/translate (- x-center) (- y-center)))] + (geom/transform shape mt))) + (defn- start-resize [vid ids shape] (letfn [(gen-matrix [shape {scalex :x scaley :y}] + (let [shape shape #_(rotate shape)] + (case vid + :top-left + (-> (gmt/matrix) + (gmt/translate (+ (:x2 shape)) + (+ (:y2 shape))) + (gmt/scale scalex scaley) + (gmt/translate (- (:x2 shape)) + (- (:y2 shape)))) + + :top-right + (-> (gmt/matrix) + (gmt/translate (+ (:x1 shape)) + (+ (:y2 shape))) + (gmt/scale scalex scaley) + (gmt/translate (- (:x1 shape)) + (- (:y2 shape)))) + + :top + (-> (gmt/matrix) + (gmt/translate (+ (:x1 shape)) + (+ (:y2 shape))) + (gmt/scale scalex scaley) + (gmt/translate (- (:x1 shape)) + (- (:y2 shape)))) + + :bottom-left + (-> (gmt/matrix) + (gmt/translate (+ (:x2 shape)) + (+ (:y1 shape))) + (gmt/scale scalex scaley) + (gmt/translate (- (:x2 shape)) + (- (:y1 shape)))) + + :bottom-right + (-> (gmt/matrix) + (gmt/translate (+ (:x1 shape)) + (+ (:y1 shape))) + (gmt/scale scalex scaley) + (gmt/translate (- (:x1 shape)) + (- (:y1 shape)))) + + :bottom + (-> (gmt/matrix) + (gmt/translate (+ (:x1 shape)) + (+ (:y1 shape))) + (gmt/scale scalex scaley) + (gmt/translate (- (:x1 shape)) + (- (:y1 shape)))) + + :right + (-> (gmt/matrix) + (gmt/translate (+ (:x1 shape)) + (+ (:y1 shape))) + (gmt/scale scalex scaley) + (gmt/translate (- (:x1 shape)) + (- (:y1 shape)))) + + :left + (-> (gmt/matrix) + (gmt/translate (+ (:x2 shape)) + (+ (:y1 shape))) + (gmt/scale scalex scaley) + (gmt/translate (- (:x2 shape)) + (- (:y1 shape)))) + ))) + + (calculate-ratio [orig-shape {:keys [width height] :as shape}] + (let [result {:x (/ width (:width orig-shape)) + :y (/ height (:height orig-shape))}] + result)) + + (accumulate-width [shape [{:keys [x y] :as point} ctrl?]] (case vid :top-left - (-> (gmt/matrix) - (gmt/translate (+ (:x2 shape)) - (+ (:y2 shape))) - (gmt/scale scalex scaley) - (gmt/translate (- (:x2 shape)) - (- (:y2 shape)))) + (let [width (- (:x2 shape) x) + height (- (:y2 shape) y) + proportion (:proportion shape)] + (assoc shape + :width width + :height (if ctrl? (/ width proportion) height))) :top-right - (-> (gmt/matrix) - (gmt/translate (+ (:x1 shape)) - (+ (:y2 shape))) - (gmt/scale scalex scaley) - (gmt/translate (- (:x1 shape)) - (- (:y2 shape)))) + (let [width (- x (:x1 shape)) + height (- (:y2 shape) y) + proportion (:proportion shape)] + (assoc shape + :width width + :height (if ctrl? (/ width proportion) height))) :top - (-> (gmt/matrix) - (gmt/translate (+ (:x1 shape)) - (+ (:y2 shape))) - (gmt/scale scalex scaley) - (gmt/translate (- (:x1 shape)) - (- (:y2 shape)))) + (let [width (- (:x2 shape) (:x1 shape)) + height (- (:y2 shape) y) + proportion (:proportion shape)] + (assoc shape + :width width + :height (if ctrl? (/ width proportion) height))) :bottom-left - (-> (gmt/matrix) - (gmt/translate (+ (:x2 shape)) - (+ (:y1 shape))) - (gmt/scale scalex scaley) - (gmt/translate (- (:x2 shape)) - (- (:y1 shape)))) + (let [width (- (:x2 shape) x) + height (- y (:y1 shape)) + proportion (:proportion shape)] + (assoc shape + :width width + :height (if ctrl? (/ width proportion) height))) :bottom-right - (-> (gmt/matrix) - (gmt/translate (+ (:x1 shape)) - (+ (:y1 shape))) - (gmt/scale scalex scaley) - (gmt/translate (- (:x1 shape)) - (- (:y1 shape)))) + (let [width (- x (:x1 shape)) + height (- y (:y1 shape)) + proportion (:proportion shape)] + (assoc shape + :width width + :height (if ctrl? (/ width proportion) height))) :bottom - (-> (gmt/matrix) - (gmt/translate (+ (:x1 shape)) - (+ (:y1 shape))) - (gmt/scale scalex scaley) - (gmt/translate (- (:x1 shape)) - (- (:y1 shape)))) - - :right - (-> (gmt/matrix) - (gmt/translate (+ (:x1 shape)) - (+ (:y1 shape))) - (gmt/scale scalex scaley) - (gmt/translate (- (:x1 shape)) - (- (:y1 shape)))) + (let [width (- (:x2 shape) (:x1 shape)) + height (- y (:y1 shape)) + proportion (:proportion shape)] + (assoc shape + :width width + :height (if ctrl? (/ width proportion) height))) :left - (-> (gmt/matrix) - (gmt/translate (+ (:x2 shape)) - (+ (:y1 shape))) - (gmt/scale scalex scaley) - (gmt/translate (- (:x2 shape)) - (- (:y1 shape)))) - )) + (let [width (- (:x2 shape) x) + height (- (:y2 shape) (:y1 shape)) + proportion (:proportion shape)] + (assoc shape + :width width + :height (if ctrl? (/ width proportion) height))) + :right + (let [width (- x (:x1 shape)) + height (- (:y2 shape) (:y1 shape)) + proportion (:proportion shape)] + (assoc shape + :width width + :height (if ctrl? (/ width proportion) height))) + + )) (on-resize [shape scale] (let [mt (gen-matrix shape scale) xf (map #(uds/apply-temporal-resize-matrix % mt))] @@ -139,79 +207,11 @@ (on-end [] (apply st/emit! (map uds/apply-resize-matrix ids)) - (rlocks/release! :shape/resize)) - (calculate-ratio [orig-shape {:keys [width height] :as shape}] - {:x (/ width (:width orig-shape)) - :y (/ height (:height orig-shape))}) - (apply-delta [shape [{:keys [x y] :as point} ctrl?]] - (case vid - :top-left - (let [width (- (:x2 shape) x) - height (- (:y2 shape) y) - proportion (:proportion shape)] - (assoc shape - :width width - :height (if ctrl? (/ width proportion) height))) + (rlocks/release! :shape/resize))] - :top-right - (let [width (- x (:x1 shape)) - height (- (:y2 shape) y) - proportion (:proportion shape)] - (assoc shape - :width width - :height (if ctrl? (/ width proportion) height))) - - :top - (let [width (- (:x2 shape) (:x1 shape)) - height (- (:y2 shape) y) - proportion (:proportion shape)] - (assoc shape - :width width - :height (if ctrl? (/ width proportion) height))) - - :bottom-left - (let [width (- (:x2 shape) x) - height (- y (:y1 shape)) - proportion (:proportion shape)] - (assoc shape - :width width - :height (if ctrl? (/ width proportion) height))) - - :bottom-right - (let [width (- x (:x1 shape)) - height (- y (:y1 shape)) - proportion (:proportion shape)] - (assoc shape - :width width - :height (if ctrl? (/ width proportion) height))) - - :bottom - (let [width (- (:x2 shape) (:x1 shape)) - height (- y (:y1 shape)) - proportion (:proportion shape)] - (assoc shape - :width width - :height (if ctrl? (/ width proportion) height))) - - :left - (let [width (- (:x2 shape) x) - height (- (:y2 shape) (:y1 shape)) - proportion (:proportion shape)] - (assoc shape - :width width - :height (if ctrl? (/ width proportion) height))) - - :right - (let [width (- x (:x1 shape)) - height (- (:y2 shape) (:y1 shape)) - proportion (:proportion shape)] - (assoc shape - :width width - :height (if ctrl? (/ width proportion) height))) - - ))] - - (let [stoper (->> wb/events-s + (let [shape (->> (geom/shape->rect-shape shape) + (geom/size)) + stoper (->> wb/events-s (rx/map first) (rx/filter #(= % :mouse/up)) (rx/take 1)) @@ -223,7 +223,7 @@ (rx/of point)))) (rx/take-until stoper) (rx/with-latest-from vector wb/mouse-ctrl-s) - (rx/scan apply-delta shape) + (rx/scan accumulate-width shape) (rx/map (partial calculate-ratio shape)))] (rlocks/acquire! :shape/resize) (rx/subscribe stream @@ -233,9 +233,27 @@ ;; --- Controls (Component) +(defn selection-rect + [{:keys [x1 y1 x2 y2 width height rotation] :as shape}] + {:x x1 + :y y1 + :rotation rotation + :width width + :height height}) + +(defn- render-path + [points] + {:pre [(pos? (count points))]} + (let [start (first points) + close? false + init (str "M " (:x start) " " (:y start)) + path (reduce #(str %1 " L" (:x %2) " " (:y %2)) init points)] + (cond-> path + close? (str " Z")))) + (mx/defc controls {:mixins [mx/static]} - [{:keys [width height x1 y1]} zoom on-mouse-down] + [{:keys [x1 y1 width height] :as shape} zoom on-mouse-down] [:g.controls [:rect.main {:x x1 :y y1 :width width @@ -328,39 +346,21 @@ (mx/defc multiple-selection-handlers {:mixins [mx/static]} [[shape & rest :as shapes] zoom] - (let [resize-xf (:tmp-resize-xform shape (gmt/matrix)) - displc-xf (-> (:tmp-displacement shape (gpt/point 0 0)) - (gmt/translate-matrix)) - selection (-> (geom/shapes->rect-shape shapes) - (assoc :type :rect) - (geom/transform resize-xf) - (geom/transform displc-xf) - (geom/size)) + (let [selection (-> (map #(geom/selection-rect %) shapes) + (geom/shapes->rect-shape) + (geom/selection-rect)) + shape (geom/shapes->rect-shape shapes) on-click #(do (dom/stop-propagation %2) - (start-resize %1 (map :id shapes) selection))] - ;; (println "single-selection-handlers" displc-xf) - ;; (println "single-selection-handlers" (select-keys selection [:x1 :y1 :x2 :y2])) - ;; (println "single-selection-handlers" (select-keys selection [:x1 :y1 :width :height])) + (start-resize %1 (map :id shapes) shape))] (controls selection zoom on-click))) (mx/defc single-selection-handlers {:mixins [mx/static]} [{:keys [id] :as shape} zoom] - (let [resize-xf (:tmp-resize-xform shape (gmt/matrix)) - displc-xf (-> (:tmp-displacement shape (gpt/point 0 0)) - (gmt/translate-matrix)) - selection (-> (geom/shape->rect-shape shape) - ;; (transform-rect resize-xf) - (assoc :type :rect) - (geom/transform resize-xf) - (geom/transform displc-xf) - (geom/size)) - on-click #(do (dom/stop-propagation %2) - (start-resize %1 #{id} selection))] - ;; (println "single-selection-handlers" displc-xf) - ;; (println "single-selection-handlers" (select-keys selection [:x1 :y1 :x2 :y2])) - ;; (println "single-selection-handlers" (select-keys selection [:x1 :y1 :width :height])) - (controls selection zoom on-click))) + (let [on-click #(do (dom/stop-propagation %2) + (start-resize %1 #{id} shape)) + shape (geom/selection-rect shape)] + (controls shape zoom on-click))) (mx/defc selection-handlers {:mixins [mx/reactive mx/static]} diff --git a/frontend/src/uxbox/main/ui/workspace/selrect.cljs b/frontend/src/uxbox/main/ui/workspace/selrect.cljs index 1dfab0a31..6dbb0acd5 100644 --- a/frontend/src/uxbox/main/ui/workspace/selrect.cljs +++ b/frontend/src/uxbox/main/ui/workspace/selrect.cljs @@ -15,6 +15,7 @@ [uxbox.main.data.workspace :as dw] [uxbox.main.data.shapes :as uds] [uxbox.main.ui.workspace.base :as wb] + [uxbox.main.geom :as geom] [uxbox.util.rlocks :as rlocks])) (defonce position (atom nil)) @@ -39,29 +40,26 @@ :mixins [mx/static mx/reactive]} [] (when-let [data (mx/react position)] - (let [{:keys [x y width height]} (selrect->rect data)] + (let [{:keys [x1 y1 width height]} (geom/size (selrect->rect data))] [:rect.selection-rect - {:x x - :y y + {:x x1 + :y y1 :width width :height height}]))) ;; --- Interaction (defn- selrect->rect - [data] - (let [start (:start data) - current (:current data) - start-x (min (:x start) (:x current)) + [{:keys [start current] :as data}] + (let [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 - :y start-y - :width (- current-x start-x) - :height (- current-y start-y)})) + end-x (max (:x start) (:x current)) + end-y (max (:y start) (:y current))] + {:x1 start-x + :y1 start-y + :x2 end-x + :y2 end-y + :type :rect})) (defn- translate-to-canvas "Translate the given rect to the canvas coordinates system." @@ -70,10 +68,10 @@ startx (* c/canvas-start-x zoom) starty (* c/canvas-start-y zoom)] (assoc rect - :x (/ (- (:x rect) startx) zoom) - :y (/ (- (:y rect) starty) zoom) - :width (/ (:width rect) zoom) - :height (/ (:height rect) zoom)))) + :x1 (/ (- (:x1 rect) startx) zoom) + :y1 (/ (- (:y1 rect) starty) zoom) + :x2 (/ (- (:x2 rect) startx) zoom) + :y2 (/ (- (:y2 rect) starty) zoom)))) (declare on-start) @@ -96,7 +94,7 @@ (let [rect (-> (selrect->rect @position) (translate-to-canvas))] (st/emit! (uds/deselect-all) - (uds/select-shapes rect)) + (uds/select-shapes-by-selrect rect)) (rlocks/release! :ui/selrect) (reset! position nil)))