From e06d8e754f5da03b40bccf03e556e8df3f205af5 Mon Sep 17 00:00:00 2001 From: "alonso.torres" Date: Fri, 22 May 2020 16:45:39 +0200 Subject: [PATCH] :recycle: Adds new properties to shapes --- backend/src/uxbox/util/migrations.clj | 1 - common/uxbox/common/data.cljc | 5 + common/uxbox/common/geom/point.cljc | 4 + common/uxbox/common/geom/shapes.cljc | 177 +++++++++++------- common/uxbox/common/migrations.cljc | 63 +++++++ common/uxbox/common/pages.cljc | 27 ++- frontend/src/uxbox/main/data/workspace.cljs | 3 + .../src/uxbox/main/data/workspace/common.cljs | 5 +- .../main/data/workspace/persistence.cljs | 3 +- .../uxbox/main/data/workspace/transforms.cljs | 4 +- frontend/src/uxbox/main/ui/viewer/shapes.cljs | 3 +- .../src/uxbox/main/ui/workspace/drawarea.cljs | 34 ++-- .../uxbox/main/ui/workspace/selection.cljs | 3 +- .../src/uxbox/main/ui/workspace/shapes.cljs | 5 +- .../shapes/{bbox.cljs => bounding_box.cljs} | 42 ++++- .../ui/workspace/shapes/interactions.cljs | 8 +- .../workspace/sidebar/options/measures.cljs | 12 +- frontend/src/uxbox/util/debug.cljs | 2 +- frontend/src/uxbox/util/geom/snap_points.cljs | 9 +- frontend/src/uxbox/worker/snaps.cljs | 14 +- 20 files changed, 288 insertions(+), 136 deletions(-) create mode 100644 common/uxbox/common/migrations.cljc rename frontend/src/uxbox/main/ui/workspace/shapes/{bbox.cljs => bounding_box.cljs} (53%) diff --git a/backend/src/uxbox/util/migrations.clj b/backend/src/uxbox/util/migrations.clj index 2f2fdf652..965360159 100644 --- a/backend/src/uxbox/util/migrations.clj +++ b/backend/src/uxbox/util/migrations.clj @@ -12,7 +12,6 @@ [cuerdas.core :as str] [next.jdbc :as jdbc])) - (s/def ::name string?) (s/def ::step (s/keys :req-un [::name ::desc ::fn])) (s/def ::steps (s/every ::step :kind vector?)) diff --git a/common/uxbox/common/data.cljc b/common/uxbox/common/data.cljc index dd39982ca..d49dc238e 100644 --- a/common/uxbox/common/data.cljc +++ b/common/uxbox/common/data.cljc @@ -105,6 +105,11 @@ (defn zip [col1 col2] (map vector col1 col2)) +(defn mapm + "Map over the values of a map" + [mfn coll] + (into {} (map (fn [[key val]] [key (mfn key val)]) coll))) + ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; Data Parsing / Conversion ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; diff --git a/common/uxbox/common/geom/point.cljc b/common/uxbox/common/geom/point.cljc index 1265221d2..fea614018 100644 --- a/common/uxbox/common/geom/point.cljc +++ b/common/uxbox/common/geom/point.cljc @@ -182,3 +182,7 @@ (multiply v2-unit (point scalar-projection scalar-projection)))) + +(defn center-points [points] + (let [k (point (count points))] + (reduce #(add %1 (divide %2 k)) (point) points))) diff --git a/common/uxbox/common/geom/shapes.cljc b/common/uxbox/common/geom/shapes.cljc index 7a0f2b803..4c0976578 100644 --- a/common/uxbox/common/geom/shapes.cljc +++ b/common/uxbox/common/geom/shapes.cljc @@ -17,6 +17,15 @@ [uxbox.common.math :as mth] [uxbox.common.data :as d])) +(defn- nilf + "Returns a new function that if you pass nil as any argument will + return nil" + [f] + (fn [& args] + (if (some nil? args) + nil + (apply f args)))) + ;; --- Relative Movement (declare move-rect) @@ -31,29 +40,23 @@ (defn move "Move the shape relativelly to its current position applying the provided delta." - [shape dpoint] - (case (:type shape) - :curve (move-path shape dpoint) - :path (move-path shape dpoint) - (move-rect shape dpoint))) - -(defn- move-rect - "A specialized function for relative movement - for rect-like shapes." [shape {dx :x dy :y}] - (assoc shape - :x (+ (-chk (:x shape)) (-chk dx)) - :y (+ (-chk (:y shape)) (-chk dy)))) - -(defn- move-path - "A specialized function for relative movement - for path shapes." - [shape {dx :x dy :y}] - (let [segments (:segments shape) - xf (comp - (map #(update % :x + dx)) - (map #(update % :y + dy)))] - (assoc shape :segments (into [] xf segments)))) + (let [inc-x (nilf (fn [x] (+ (-chk x) (-chk dx)))) + inc-y (nilf (fn [y] (+ (-chk y) (-chk dy)))) + inc-point (nilf (fn [p] (-> p + (update :x inc-x) + (update :y inc-y))))] + (-> shape + (update :x inc-x) + (update :y inc-y) + (update-in [:selrect :x] inc-x) + (update-in [:selrect :x1] inc-x) + (update-in [:selrect :x2] inc-x) + (update-in [:selrect :y] inc-y) + (update-in [:selrect :y1] inc-y) + (update-in [:selrect :y2] inc-y) + (update :points #(mapv inc-point %)) + (update :segments #(mapv inc-point %))))) (defn recursive-move "Move the shape and all its recursive children." @@ -70,8 +73,7 @@ "Move the shape to the exactly specified position." [shape position] (case (:type shape) - :path shape - :curve shape + (:curve :path) shape (absolute-move-rect shape position))) (defn- absolute-move-rect @@ -198,14 +200,19 @@ :image (setup-image shape props) (setup-rect shape props))) +(declare shape->points) +(declare points->selrect) + (defn- setup-rect "A specialized function for setup rect-like shapes." [shape {:keys [x y width height]}] - (assoc shape - :x x - :y y - :width width - :height height)) + (as-> shape $ + (assoc $ :x x + :y y + :width width + :height height) + (assoc $ :points (shape->points $)) + (assoc $ :selrect (points->selrect (:points $))))) (defn- setup-image [{:keys [metadata] :as shape} {:keys [x y width height] :as props}] @@ -228,8 +235,7 @@ "Coerce shape to rect like shape." [{:keys [type] :as shape}] (case type - :path (path->rect-shape shape) - :curve (path->rect-shape shape) + (:curve :path) (path->rect-shape shape) (rect->rect-shape shape))) (defn shapes->rect-shape @@ -249,13 +255,43 @@ :height (- maxy miny) :type :rect})) +;; -- Points + +(declare transform-shape-point) +(defn shape->points [shape] + (let [points + (case (:type shape) + (:curve :path) (:segments shape) + (let [{:keys [x y width height]} shape] + [(gpt/point x y) + (gpt/point (+ x width) y) + (gpt/point (+ x width) (+ y height)) + (gpt/point x (+ y height))]))] + (mapv #(transform-shape-point % shape (:transform shape (gmt/matrix))) points))) + +(defn points->selrect [points] + (let [minx (transduce (map :x) min points) + miny (transduce (map :y) min points) + maxx (transduce (map :x) max points) + maxy (transduce (map :y) max points)] + {:x1 minx + :y1 miny + :x2 maxx + :y2 maxy + :x minx + :y miny + :width (- maxx minx) + :height (- maxy miny) + :type :rect})) + +;; Shape->PATH + (declare rect->path) (defn shape->path [shape] (case (:type shape) - :path shape - :curve shape + (:curve :path) shape (rect->path shape))) (defn rect->path @@ -282,20 +318,9 @@ (defn- path->rect-shape [{:keys [segments] :as shape}] - (let [minx (transduce (map :x) min segments) - miny (transduce (map :y) min segments) - maxx (transduce (map :x) max segments) - maxy (transduce (map :y) max segments)] - (assoc shape - :type :rect - :x1 minx - :y1 miny - :x2 maxx - :y2 maxy - :x minx - :y miny - :width (- maxx minx) - :height (- maxy miny)))) + (merge shape + {:type :rect} + (:selrect shape))) ;; --- Resolve Shape @@ -365,19 +390,11 @@ ;; --- Outer Rect -(declare transform-apply-modifiers) - -(defn selection-rect-shape - [shape] - (-> shape - (transform-apply-modifiers) - (shape->rect-shape))) - (defn selection-rect "Returns a rect that contains all the shapes and is aware of the rotation of each shape. Mainly used for multiple selection." [shapes] - (let [xf-resolve-shape (map selection-rect-shape) + (let [xf-resolve-shape (map :selrect) shapes (into [] xf-resolve-shape shapes) minx (transduce (map :x1) min shapes) miny (transduce (map :y1) min shapes) @@ -685,19 +702,27 @@ (gmt/skew (- skew-angle) 0) (gmt/rotate (- rotation-angle))) - new-shape (-> shape - (merge rec) - (update :x #(mth/precision % 2)) - (update :y #(mth/precision % 2)) - (fix-invalid-rect-values) - (update :transform #(gmt/multiply (or % (gmt/matrix)) stretch-matrix)) - (update :transform-inverse #(gmt/multiply stretch-matrix-inverse (or % (gmt/matrix)))))] + new-shape (as-> shape $ + (merge $ rec) + (update $ :x #(mth/precision % 2)) + (update $ :y #(mth/precision % 2)) + (fix-invalid-rect-values $) + (update $ :transform #(gmt/multiply (or % (gmt/matrix)) stretch-matrix)) + (update $ :transform-inverse #(gmt/multiply stretch-matrix-inverse (or % (gmt/matrix)))) + (assoc $ :points (shape->points $)) + (assoc $ :selrect (points->selrect (:points $))) + (update $ :rotation #(mod (+ % (get-in $ [:modifiers :rotation] 0)) 360)) + + )] new-shape)) +(declare update-path-selrect) (defn transform-path-shape [shape] - (transform-apply-modifiers shape) + (-> shape + transform-apply-modifiers + update-path-selrect) ;; TODO: Addapt for paths is not working #_(let [shape-path (transform-apply-modifiers shape) shape-path-center (center shape-path) @@ -715,14 +740,15 @@ "Transform the shape properties given the modifiers" ([shape] (transform-shape nil shape)) ([frame shape] - (let [new-shape (case (:type shape) - :path (transform-path-shape shape) - :curve (transform-path-shape shape) - (transform-rect-shape shape))] + (let [new-shape + (if (:modifiers shape) + (as-> (case (:type shape) + (:curve :path) (transform-path-shape shape) + (transform-rect-shape shape)) $ + (dissoc $ :modifiers)) + shape)] (-> new-shape - (translate-to-frame frame) - (update :rotation #(mod (+ % (get-in shape [:modifiers :rotation] 0)) 360)) - (dissoc :modifiers))))) + (translate-to-frame frame))))) (defn transform-matrix @@ -735,6 +761,15 @@ (gmt/multiply (:transform shape (gmt/matrix))) (gmt/translate (gpt/negate shape-center)))))) +(defn update-path-selrect [shape] + (as-> shape $ + (assoc $ :points (shape->points $)) + (assoc $ :selrect (points->selrect (:points $))) + (assoc $ :x (get-in $ [:selrect :x])) + (assoc $ :y (get-in $ [:selrect :y])) + (assoc $ :width (get-in $ [:selrect :width])) + (assoc $ :height (get-in $ [:selrect :height])))) + (defn adjust-to-viewport ([viewport srect] (adjust-to-viewport viewport srect nil)) ([viewport srect {:keys [padding] :or {padding 0}}] diff --git a/common/uxbox/common/migrations.cljc b/common/uxbox/common/migrations.cljc new file mode 100644 index 000000000..feda32aa9 --- /dev/null +++ b/common/uxbox/common/migrations.cljc @@ -0,0 +1,63 @@ +(ns uxbox.common.migrations + (:require + [uxbox.common.pages :as p] + [uxbox.common.geom.shapes :as gsh] + [uxbox.common.geom.point :as gpt] + [uxbox.common.geom.matrix :as gmt] + [uxbox.common.uuid :as uuid] + [uxbox.common.data :as d])) + +(defmulti migrate :version) + +(defn migrate-page + ([page from-version to-version] + (-> page + (assoc :version to-version) + (migrate))) + + ([{:keys [version] :as page}] + (reduce #(migrate-page % (:version %1) %2) + page + (range version (inc p/page-version))))) + +;; Default handler, noop +(defmethod migrate :default [page] page) + +;; -- MIGRATIONS -- + +(defmethod migrate 4 [page] + (prn "Migrate " (:id page)) + ;; We changed the internal model of the shapes so they have their selection rect + ;; and the vertices + + (letfn [;; Creates a new property `points` that stores the transformed points inside the shape + ;; this will be used for the snaps and the selection rect + (calculate-shape-points [objects] + (->> objects + (d/mapm + (fn [id shape] + (if (= (:id shape) uuid/zero) + shape + (assoc shape :points (gsh/shape->points shape))))))) + + ;; Creates a new property `selrect` that stores the selection rect for the shape + (calculate-shape-selrects [objects] + (->> objects + (d/mapm + (fn [id shape] + (if (= (:id shape) uuid/zero) + shape + (assoc shape :selrect (gsh/points->selrect (:points shape))))))))] + (-> page + + ;; We only store the version in the page data + (update :data dissoc :version ) + + ;; Adds vertices to shapes + (update-in [:data :objects] calculate-shape-points) + + ;; Creates selection rects for shapes + (update-in [:data :objects] calculate-shape-selrects)))) + + + diff --git a/common/uxbox/common/pages.cljc b/common/uxbox/common/pages.cljc index db454761d..b289743e0 100644 --- a/common/uxbox/common/pages.cljc +++ b/common/uxbox/common/pages.cljc @@ -16,6 +16,8 @@ [uxbox.common.exceptions :as ex] [uxbox.common.spec :as us])) +(def page-version 4) + ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; Page Data Structure Helpers ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; @@ -184,6 +186,22 @@ (s/def ::width number?) (s/def ::height number?) (s/def ::index integer?) +(s/def ::x1 number?) +(s/def ::y1 number?) +(s/def ::x2 number?) +(s/def ::y2 number?) + +(s/def ::selrect (s/keys :req-un [::x + ::y + ::x1 + ::y1 + ::x2 + ::y2 + ::width + ::height])) + +(s/def ::point (s/keys :req-un [::x ::y])) +(s/def ::points (s/coll-of ::point :kind vector?)) (s/def ::shape-attrs (s/keys :opt-un [::blocked @@ -211,7 +229,9 @@ ::stroke-alignment ::text-align ::width ::height - ::interactions])) + ::interactions + ::selrect + ::points])) (s/def ::minimal-shape (s/keys :req-un [::type ::name] @@ -282,8 +302,7 @@ (def default-page-data "A reference value of the empty page data." - {:version 3 - :options {} + {:options {} :objects {root {:id root @@ -469,5 +488,3 @@ [shape op] (ex/raise :type :operation-not-implemented :context {:type (:type op)})) - - diff --git a/frontend/src/uxbox/main/data/workspace.cljs b/frontend/src/uxbox/main/data/workspace.cljs index 17fdad5d8..fbd42075a 100644 --- a/frontend/src/uxbox/main/data/workspace.cljs +++ b/frontend/src/uxbox/main/data/workspace.cljs @@ -9,6 +9,7 @@ (ns uxbox.main.data.workspace (:require + [uxbox.util.debug :refer [logjs]] [beicon.core :as rx] [cljs.spec.alpha :as s] [clojure.set :as set] @@ -16,6 +17,7 @@ [uxbox.common.data :as d] [uxbox.common.exceptions :as ex] [uxbox.common.pages :as cp] + [uxbox.common.migrations :as mg] [uxbox.common.spec :as us] [uxbox.common.uuid :as uuid] [uxbox.config :as cfg] @@ -149,6 +151,7 @@ ptk/UpdateEvent (update [_ state] (let [page (get-in state [:workspace-pages page-id]) + page (mg/migrate-page page) local (get-in state [:workspace-cache page-id] workspace-default)] (-> state (assoc :current-page-id page-id ; mainly used by events diff --git a/frontend/src/uxbox/main/data/workspace/common.cljs b/frontend/src/uxbox/main/data/workspace/common.cljs index fdbba4760..66e2843f2 100644 --- a/frontend/src/uxbox/main/data/workspace/common.cljs +++ b/frontend/src/uxbox/main/data/workspace/common.cljs @@ -165,9 +165,8 @@ (defn- calculate-frame-overlap [frames shape] - (let [shape (geom/shape->rect-shape shape) - xf (comp - (filter #(geom/overlaps? % shape)) + (let [xf (comp + (filter #(geom/overlaps? % (:selrect shape))) (take 1)) frame (first (into [] xf frames))] (or (:id frame) uuid/zero))) diff --git a/frontend/src/uxbox/main/data/workspace/persistence.cljs b/frontend/src/uxbox/main/data/workspace/persistence.cljs index 9a54ccd3d..ccaf6a151 100644 --- a/frontend/src/uxbox/main/data/workspace/persistence.cljs +++ b/frontend/src/uxbox/main/data/workspace/persistence.cljs @@ -210,7 +210,8 @@ params {:name name :file-id file-id :ordering ordering - :data cp/default-page-data}] + :data cp/default-page-data + :version cp/page-version}] (->> (rp/mutation :create-page params) (rx/map page-created)))))) diff --git a/frontend/src/uxbox/main/data/workspace/transforms.cljs b/frontend/src/uxbox/main/data/workspace/transforms.cljs index 81f506b64..c2e8895eb 100644 --- a/frontend/src/uxbox/main/data/workspace/transforms.cljs +++ b/frontend/src/uxbox/main/data/workspace/transforms.cljs @@ -80,6 +80,8 @@ (let [{:keys [width height rotation]} shape shapev (-> (gpt/point width height)) + rotation (if (#{:curve :path} (:type shape)) 0 rotation) + ;; Vector modifiers depending on the handler handler-modif (let [[x y] (handler-modifiers handler)] (gpt/point x y)) @@ -129,7 +131,7 @@ ptk/WatchEvent (watch [_ state stream] - (let [shape (gsh/shape->rect-shape shape) + (let [;;shape (gsh/shape->rect-shape shape) initial @ms/mouse-position stoper (rx/filter ms/mouse-up? stream) page-id (get state :current-page-id) diff --git a/frontend/src/uxbox/main/ui/viewer/shapes.cljs b/frontend/src/uxbox/main/ui/viewer/shapes.cljs index 91db8caf8..6e291b665 100644 --- a/frontend/src/uxbox/main/ui/viewer/shapes.cljs +++ b/frontend/src/uxbox/main/ui/viewer/shapes.cljs @@ -44,8 +44,7 @@ {::mf/wrap-props false} [props] (let [{:keys [x y width height] - :as shape} (->> (unchecked-get props "shape") - (geom/selection-rect-shape)) + :as shape} (->> (unchecked-get props "shape") :selrect) childs (unchecked-get props "childs") frame (unchecked-get props "frame") diff --git a/frontend/src/uxbox/main/ui/workspace/drawarea.cljs b/frontend/src/uxbox/main/ui/workspace/drawarea.cljs index 4bc3d5c40..b45744fa1 100644 --- a/frontend/src/uxbox/main/ui/workspace/drawarea.cljs +++ b/frontend/src/uxbox/main/ui/workspace/drawarea.cljs @@ -196,7 +196,8 @@ (assoc-in [:workspace-local :drawing ::initialized?] true))) (insert-point-segment [state point] - (update-in state [:workspace-local :drawing :segments] (fnil conj []) point)) + (-> state + (update-in [:workspace-local :drawing :segments] (fnil conj []) point))) (update-point-segment [state index point] (let [segments (count (get-in state [:workspace-local :drawing :segments])) @@ -204,8 +205,12 @@ (cond-> state exists? (assoc-in [:workspace-local :drawing :segments index] point)))) - (remove-dangling-segmnet [state] - (update-in state [:workspace-local :drawing :segments] #(vec (butlast %))))] + (finish-drawing-path [state] + (update-in + state [:workspace-local :drawing] + (fn [shape] (-> shape + (update :segments #(vec (butlast %))) + (geom/update-path-selrect)))))] (ptk/reify ::handle-drawing-path ptk/WatchEvent @@ -263,9 +268,11 @@ point)] #(update-point-segment % index point)))) (rx/take-until stoper)) - (rx/of remove-dangling-segmnet + (rx/of finish-drawing-path handle-finish-drawing)))))))) +(def simplify-tolerance 0.3) + (def handle-drawing-curve (letfn [(stoper-event? [{:keys [type shift] :as event}] (ms/mouse-event? event) (= type :up)) @@ -276,8 +283,13 @@ (insert-point-segment [state point] (update-in state [:workspace-local :drawing :segments] (fnil conj []) point)) - (simplify-drawing-path [state tolerance] - (update-in state [:workspace-local :drawing :segments] path/simplify tolerance))] + (finish-drawing-curve [state] + (update-in + state [:workspace-local :drawing] + (fn [shape] + (-> shape + (update :segments #(path/simplify % simplify-tolerance)) + (geom/update-path-selrect)))))] (ptk/reify ::handle-drawing-curve ptk/WatchEvent @@ -290,7 +302,7 @@ (->> mouse (rx/map (fn [pt] #(insert-point-segment % pt))) (rx/take-until stoper)) - (rx/of #(simplify-drawing-path % 0.3) + (rx/of finish-drawing-curve handle-finish-drawing))))))) (def handle-finish-drawing @@ -308,10 +320,8 @@ :text 16 5) shape (-> shape - (geom/transform-shape) - (update :width #(max shape-min-width %)) - (update :height #(max shape-min-height %)) - (dissoc shape ::initialized?))] + geom/transform-shape + (dissoc ::initialized?)) ] ;; Add & select the created shape to the workspace (rx/of dw/deselect-all (dw/add-shape shape))))))))) @@ -336,7 +346,7 @@ (mf/defc generic-draw-area [{:keys [shape zoom]}] - (let [{:keys [x y width height]} (geom/selection-rect-shape shape)] + (let [{:keys [x y width height]} (:selrect shape)] (when (and x y) [:g [:& shapes/shape-wrapper {:shape shape}] diff --git a/frontend/src/uxbox/main/ui/workspace/selection.cljs b/frontend/src/uxbox/main/ui/workspace/selection.cljs index 0f26b1362..902fc9f11 100644 --- a/frontend/src/uxbox/main/ui/workspace/selection.cljs +++ b/frontend/src/uxbox/main/ui/workspace/selection.cljs @@ -187,7 +187,7 @@ [:g.controls ;; Selection rect - [:& selection-rect {:rect shape + [:& selection-rect {:rect selrect :transform transform :zoom zoom}] @@ -283,7 +283,6 @@ (let [shape-id (:id shape) shape (geom/transform-shape shape) shape' (if (debug? :simple-selection) (geom/selection-rect [shape]) shape) - on-resize #(do (dom/stop-propagation %2) (st/emit! (dw/start-resize %1 #{shape-id} shape'))) diff --git a/frontend/src/uxbox/main/ui/workspace/shapes.cljs b/frontend/src/uxbox/main/ui/workspace/shapes.cljs index 0d81d6f7e..022cc4e39 100644 --- a/frontend/src/uxbox/main/ui/workspace/shapes.cljs +++ b/frontend/src/uxbox/main/ui/workspace/shapes.cljs @@ -20,7 +20,7 @@ ;; namespace under uxbox.ui.workspace.shapes.* prefix, all the ;; others are defined using a generic wrapper implemented in ;; common. - [uxbox.main.ui.workspace.shapes.bbox :as bbox] + [uxbox.main.ui.workspace.shapes.bounding-box :refer [bounding-box]] [uxbox.main.ui.workspace.shapes.common :as common] [uxbox.main.ui.workspace.shapes.frame :as frame] [uxbox.main.ui.workspace.shapes.group :as group] @@ -71,7 +71,8 @@ ;; Only used when drawing a new frame. :frame [:> frame-wrapper {:shape shape}] nil) - [:& bbox/bounding-box {:shape shape :frame frame}]]))) + [:& bounding-box {:shape (->> shape (geom/transform-shape frame)) :frame frame}]]))) (def group-wrapper (group/group-wrapper-factory shape-wrapper)) (def frame-wrapper (frame/frame-wrapper-factory shape-wrapper)) + diff --git a/frontend/src/uxbox/main/ui/workspace/shapes/bbox.cljs b/frontend/src/uxbox/main/ui/workspace/shapes/bounding_box.cljs similarity index 53% rename from frontend/src/uxbox/main/ui/workspace/shapes/bbox.cljs rename to frontend/src/uxbox/main/ui/workspace/shapes/bounding_box.cljs index 6ddb5fa94..f3ac9059f 100644 --- a/frontend/src/uxbox/main/ui/workspace/shapes/bbox.cljs +++ b/frontend/src/uxbox/main/ui/workspace/shapes/bounding_box.cljs @@ -4,7 +4,7 @@ ;; ;; Copyright (c) 2020 UXBOX Labs SL -(ns uxbox.main.ui.workspace.shapes.bbox +(ns uxbox.main.ui.workspace.shapes.bounding-box (:require [cuerdas.core :as str] [rumext.alpha :as mf] @@ -13,37 +13,61 @@ [uxbox.common.geom.matrix :as gmt] [uxbox.common.geom.point :as gpt] [uxbox.util.debug :refer [debug?]] + [uxbox.main.refs :as refs] ["randomcolor" :as rdcolor])) (defn fixed [num] (when num (.toFixed num 2))) +(mf/defc cross-point [{:keys [point zoom color]}] + (let [width (/ 10 zoom)] + [:g.point + [:line {:x1 (- (:x point) 10) :y1 (- (:y point) 10) + :x2 (+ (:x point) 10) :y2 (+ (:y point) 10) + :stroke color + :stroke-width "1px" + :stroke-opacity 0.5}] + + [:line {:x1 (+ (:x point) 10) :y1 (- (:y point) 10) + :x2 (- (:x point) 10) :y2 (+ (:y point) 10) + :stroke color + :stroke-width "1px" + :stroke-opacity 0.5}]])) + (mf/defc bounding-box {::mf/wrap-props false} [props] (when (debug? :bounding-boxes) (let [shape (unchecked-get props "shape") frame (unchecked-get props "frame") - selrect (-> shape - (geom/selection-rect-shape) - (geom/translate-to-frame frame)) - shape-center (geom/center selrect) - line-color (rdcolor #js {:seed (str (:id shape))})] - [:g + selrect (-> shape :selrect) + shape-center (geom/center shape) + line-color (rdcolor #js {:seed (str (:id shape))}) + zoom (mf/deref refs/selected-zoom)] + [:g.bounding-box [:text {:x (:x selrect) :y (- (:y selrect) 5) :font-size 10 - :fill "red" + :fill line-color :stroke "white" :stroke-width 0.1} (str/format "%s - (%s, %s)" (str/slice (str (:id shape)) 0 8) (fixed (:x shape)) (fixed (:y shape)))] + [:& cross-point {:point shape-center + :zoom zoom + :color line-color}] + + (for [point (:points shape)] + [:& cross-point {:point point + :zoom zoom + :color line-color}]) + [:rect {:x (:x selrect) :y (:y selrect) :width (:width selrect) :height (:height selrect) - :style {:stroke "red" + :style {:stroke line-color :fill "transparent" :stroke-width "1px" :stroke-opacity 0.5 diff --git a/frontend/src/uxbox/main/ui/workspace/shapes/interactions.cljs b/frontend/src/uxbox/main/ui/workspace/shapes/interactions.cljs index 279cb27b4..a042c2f7d 100644 --- a/frontend/src/uxbox/main/ui/workspace/shapes/interactions.cljs +++ b/frontend/src/uxbox/main/ui/workspace/shapes/interactions.cljs @@ -40,8 +40,8 @@ "Calculate the best position to draw an interaction line between two shapes" [orig-shape dest-shape] - (let [orig-rect (geom/selection-rect-shape orig-shape) - dest-rect (geom/selection-rect-shape dest-shape) + (let [orig-rect (:selrect orig-shape) + dest-rect (:selrect dest-shape) orig-x-left (:x orig-rect) orig-x-right (+ orig-x-left (:width orig-rect)) @@ -71,7 +71,7 @@ "Calculate the best position to draw an interaction line between one shape and one point" [orig-shape dest-point] - (let [orig-rect (geom/selection-rect-shape orig-shape) + (let [orig-rect (:selrect orig-shape) orig-x-left (:x orig-rect) orig-x-right (+ orig-x-left (:width orig-rect)) @@ -159,7 +159,7 @@ (mf/defc interaction-handle [{:keys [shape selected zoom] :as props}] - (let [shape-rect (geom/selection-rect-shape shape) + (let [shape-rect (:selrect shape) handle-x (+ (:x shape-rect) (:width shape-rect)) handle-y (+ (:y shape-rect) (/ (:height shape-rect) 2))] [:g {:on-mouse-down #(on-mouse-down % shape selected)} diff --git a/frontend/src/uxbox/main/ui/workspace/sidebar/options/measures.cljs b/frontend/src/uxbox/main/ui/workspace/sidebar/options/measures.cljs index 66b649f77..9cca409b2 100644 --- a/frontend/src/uxbox/main/ui/workspace/sidebar/options/measures.cljs +++ b/frontend/src/uxbox/main/ui/workspace/sidebar/options/measures.cljs @@ -25,13 +25,9 @@ (defn user-coords-vector [shape] - (let [{sel-x :x sel-y :y :as selrect} - (-> shape - gsh/shape->path - (gsh/center-transform (:transform shape)) - gsh/shape->rect-shape) + (let [oldselrec (-> shape gsh/shape->path (gsh/center-transform (:transform shape)) gsh/shape->rect-shape) + {sel-x :x sel-y :y :as selrec} #_(:selrect shape) oldselrec {rec-x :x rec-y :y} (-> shape gsh/shape->rect-shape) - dx (- rec-x sel-x) dy (- rec-y sel-y)] (-> (gpt/point dx dy) @@ -141,13 +137,13 @@ :type "number" :no-validate true :on-change on-pos-x-change - :value (:x shape)}]] + :value (-> shape :x (math/precision 2))}]] [:div.input-element.Yaxis [:input.input-text {:placeholder "y" :type "number" :no-validate true :on-change on-pos-y-change - :value (:y shape)}]]]) + :value (-> shape :y (math/precision 2))}]]]) (when (options :rotation) [:div.row-flex diff --git a/frontend/src/uxbox/util/debug.cljs b/frontend/src/uxbox/util/debug.cljs index a6eae4df4..3f0712f2f 100644 --- a/frontend/src/uxbox/util/debug.cljs +++ b/frontend/src/uxbox/util/debug.cljs @@ -3,7 +3,7 @@ (def debug-options #{:bounding-boxes :group :events :rotation-handler :resize-handler :selection-center #_:simple-selection }) -(defonce ^:dynamic *debug* (atom #{})) +(defonce ^:dynamic *debug* (atom #{:bounding-boxes})) (defn debug-all! [] (reset! *debug* debug-options)) (defn debug-none! [] (reset! *debug* #{})) diff --git a/frontend/src/uxbox/util/geom/snap_points.cljs b/frontend/src/uxbox/util/geom/snap_points.cljs index 593e327ae..25a60746e 100644 --- a/frontend/src/uxbox/util/geom/snap_points.cljs +++ b/frontend/src/uxbox/util/geom/snap_points.cljs @@ -26,9 +26,8 @@ (defn shape-snap-points [shape] - (let [modified-path (gsh/transform-apply-modifiers shape) - shape-center (gsh/center modified-path)] + (let [shape (gsh/transform-shape shape) + shape-center (gsh/center shape)] (case (:type shape) - :frame (-> modified-path gsh/shape->rect-shape frame-snap-points) - (:path :curve) (into #{shape-center} (-> modified-path gsh/shape->rect-shape :segments)) - (into #{shape-center} (-> modified-path :segments))))) + :frame (-> shape gsh/shape->rect-shape frame-snap-points) + (into #{shape-center} (-> shape :points))))) diff --git a/frontend/src/uxbox/worker/snaps.cljs b/frontend/src/uxbox/worker/snaps.cljs index e314acda0..0d41634df 100644 --- a/frontend/src/uxbox/worker/snaps.cljs +++ b/frontend/src/uxbox/worker/snaps.cljs @@ -12,6 +12,7 @@ [okulary.core :as l] [uxbox.common.uuid :as uuid] [uxbox.common.pages :as cp] + [uxbox.common.data :as d] [uxbox.worker.impl :as impl] [uxbox.util.range-tree :as rt] [uxbox.util.geom.snap-points :as snap] @@ -38,11 +39,6 @@ (mapcat (process-shape coord)) (reduce into-tree (rt/make-tree))))) -(defn- mapm - "Map over the values of a map" - [mfn coll] - (into {} (map (fn [[key val]] [key (mfn key val)]) coll))) - (defn- initialize-snap-data "Initialize the snap information with the current workspace information" [objects] @@ -51,16 +47,16 @@ (group-by :frame-id)) frame-shapes (->> (cp/select-frames objects) (reduce #(update %1 (:id %2) conj %2) frame-shapes))] - (mapm (fn [frame-id shapes] {:x (create-coord-data frame-id shapes :x) + (d/mapm (fn [frame-id shapes] {:x (create-coord-data frame-id shapes :x) :y (create-coord-data frame-id shapes :y)}) frame-shapes))) (defn- log-state "Helper function to print a friendly version of the snap tree. Debugging purposes" [] - (let [process-frame-data #(mapm rt/as-map %) - process-page-data #(mapm process-frame-data %)] - (js/console.log "STATE" (clj->js (mapm process-page-data @state))))) + (let [process-frame-data #(d/mapm rt/as-map %) + process-page-data #(d/mapm process-frame-data %)] + (js/console.log "STATE" (clj->js (d/mapm process-page-data @state))))) (defn- index-page [state page-id objects] (let [snap-data (initialize-snap-data objects)]