diff --git a/common/uxbox/common/geom/shapes.cljc b/common/uxbox/common/geom/shapes.cljc index f67b65ce3..8655d9560 100644 --- a/common/uxbox/common/geom/shapes.cljc +++ b/common/uxbox/common/geom/shapes.cljc @@ -255,15 +255,17 @@ (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))) + (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))]))] + (->> points + (map #(transform-shape-point % shape (:transform shape (gmt/matrix)))) + (map gpt/round) + (vec)))) (defn points->selrect [points] (let [minx (transduce (map :x) min ##Inf points) @@ -756,8 +758,10 @@ new-shape (as-> shape $ (merge $ rec) - (update $ :x #(mth/precision % 2)) - (update $ :y #(mth/precision % 2)) + (update $ :x #(mth/precision % 0)) + (update $ :y #(mth/precision % 0)) + (update $ :width #(mth/precision % 0)) + (update $ :height #(mth/precision % 0)) (fix-invalid-rect-values $) (update $ :transform #(gmt/multiply (or % (gmt/matrix)) stretch-matrix)) (update $ :transform-inverse #(gmt/multiply stretch-matrix-inverse (or % (gmt/matrix)))) @@ -766,7 +770,6 @@ (update $ :rotation #(mod (+ % (get-in $ [:modifiers :rotation] 0)) 360)) )] - new-shape)) (declare update-path-selrect) diff --git a/common/uxbox/common/math.cljc b/common/uxbox/common/math.cljc index 06e3420c4..d102a845d 100644 --- a/common/uxbox/common/math.cljc +++ b/common/uxbox/common/math.cljc @@ -98,8 +98,8 @@ (defn precision [v n] (when (and (number? v) (number? n)) - #?(:cljs (js/parseFloat (.toFixed v n)) - :clj (.. (BigDecimal/valueOf v) (setScale n java.math.RoundingMode/HALF_UP) (doubleValue))))) + (let [d (pow 10 n)] + (/ (round (* v d)) d)))) (defn radians "Converts degrees to radians." diff --git a/frontend/src/uxbox/main/data/workspace/transforms.cljs b/frontend/src/uxbox/main/data/workspace/transforms.cljs index b08d82765..29531e9ec 100644 --- a/frontend/src/uxbox/main/data/workspace/transforms.cljs +++ b/frontend/src/uxbox/main/data/workspace/transforms.cljs @@ -211,7 +211,7 @@ (rx/filter #(> % 1)) (rx/take 1) (rx/with-latest vector ms/mouse-position-alt) - (rx/flat-map + (rx/mapcat (fn [[_ alt?]] (if alt? ;; When alt is down we start a duplicate+move @@ -242,15 +242,16 @@ (watch [_ state stream] (let [page-id (get state :current-page-id) objects (get-in state [:workspace-data page-id :objects]) - ids (if (nil? ids) (get-in state [:workspace-local :selected]) ids) - shapes (mapv #(get-in state [:workspace-data page-id :objects %]) ids) + ids (if (nil? ids) (get-in state [:workspace-local :selected]) ids) + shapes (mapv #(get objects %) ids) stopper (rx/filter ms/mouse-up? stream) - layout (get state :workspace-layout)] + layout (get state :workspace-layout)] (rx/concat (->> ms/mouse-position (rx/take-until stopper) (rx/map #(gpt/to-vec from-position %)) (rx/switch-map #(snap/closest-snap-move page-id shapes objects layout %)) + (rx/map #(gpt/round % 0)) (rx/map gmt/translate-matrix) (rx/map #(set-modifiers ids {:displacement %}))) diff --git a/frontend/src/uxbox/main/snap.cljs b/frontend/src/uxbox/main/snap.cljs index 41b893aa4..5c2e576f7 100644 --- a/frontend/src/uxbox/main/snap.cljs +++ b/frontend/src/uxbox/main/snap.cljs @@ -23,7 +23,8 @@ (def ^:private snap-accuracy 5) (def ^:private snap-distance-accuracy 10) -(defn- remove-from-snap-points [remove-id?] +(defn- remove-from-snap-points + [remove-id?] (fn [query-result] (->> query-result (map (fn [[value data]] [value (remove (comp remove-id? second) data)])) @@ -57,12 +58,12 @@ :else zero))) (defn get-snap-points [page-id frame-id filter-shapes point coord] - (let [value (coord point)] + (let [value (get point coord)] (->> (uw/ask! {:cmd :snaps/range-query :page-id page-id :frame-id frame-id :coord coord - :ranges [[(- value 1) (+ value 1)]]}) + :ranges [[value value]]}) (rx/first) (rx/map (remove-from-snap-points filter-shapes)) (rx/map flatten-to-points)))) @@ -147,7 +148,8 @@ (if (mth/finite? min-snap) [0 min-snap] nil))))))) -(defn select-shapes-area [page-id shapes objects area-selrect] +(defn select-shapes-area + [page-id shapes objects area-selrect] (->> (uw/ask! {:cmd :selection/query :page-id page-id :frame-id (->> shapes first :frame-id) @@ -155,13 +157,15 @@ (rx/map #(set/difference % (into #{} (map :id shapes)))) (rx/map (fn [ids] (map #(get objects %) ids))))) -(defn closest-distance-snap [page-id shapes objects movev] +(defn closest-distance-snap + [page-id shapes objects movev] (->> (rx/of shapes) (rx/map #(vector (->> % first :frame-id (get objects)) (-> % gsh/selection-rect (gsh/move movev)))) (rx/merge-map (fn [[frame selrect]] - (let [areas (->> (gsh/selrect->areas (or (:selrect frame) (gsh/rect->rect-shape @refs/vbox)) selrect) + (let [areas (->> (gsh/selrect->areas (or (:selrect frame) + (gsh/rect->rect-shape @refs/vbox)) selrect) (d/mapm #(select-shapes-area page-id shapes objects %2))) snap-x (search-snap-distance selrect :x (:left areas) (:right areas)) snap-y (search-snap-distance selrect :y (:top areas) (:bottom areas))] @@ -178,8 +182,7 @@ (not (contains? layout :dynamic-alignment)))))] (->> (closest-snap page-id frame-id [point] filter-shapes) (rx/map #(or % (gpt/point 0 0))) - (rx/map #(gpt/add point %)) -))) + (rx/map #(gpt/add point %))))) (defn closest-snap-move [page-id shapes objects layout movev] @@ -201,4 +204,7 @@ (closest-distance-snap page-id shapes objects movev))) (rx/reduce gpt/min) (rx/map #(or % (gpt/point 0 0))) - (rx/map #(gpt/add movev %))))) + (rx/map #(gpt/add movev %)) + (rx/map #(gpt/round % 0)) + ))) + 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 10605ec25..e1f8a3d55 100644 --- a/frontend/src/uxbox/main/ui/workspace/sidebar/options/measures.cljs +++ b/frontend/src/uxbox/main/ui/workspace/sidebar/options/measures.cljs @@ -73,7 +73,6 @@ on-pos-x-change #(on-position-change % :x) on-pos-y-change #(on-position-change % :y) select-all #(-> % (dom/get-target) (.select))] - [:div.element-set [:div.element-set-content diff --git a/frontend/src/uxbox/main/ui/workspace/snap_distances.cljs b/frontend/src/uxbox/main/ui/workspace/snap_distances.cljs index c3c254540..afd4e22a1 100644 --- a/frontend/src/uxbox/main/ui/workspace/snap_distances.cljs +++ b/frontend/src/uxbox/main/ui/workspace/snap_distances.cljs @@ -53,7 +53,7 @@ (get sr2 (if (= :x coord) :x1 :y1))) distance (- to-c from-c) - distance-str (-> distance (mth/precision 2) str) + distance-str (-> distance (mth/precision 0) str) half-point (half-point coord sr1 sr2) width (-> distance-str count @@ -80,7 +80,7 @@ :font-size (/ pill-text-font-size zoom) :fill "white" :text-anchor "middle"} - (mth/precision distance 2)]]) + (mth/precision distance 0)]]) (let [p1 [(+ from-c (/ segment-gap zoom)) (+ half-point (/ segment-gap-side zoom))] p2 [(+ from-c (/ segment-gap zoom)) (- half-point (/ segment-gap-side zoom))] @@ -110,7 +110,7 @@ pair->distance+pair (fn [[sh1 sh2]] - [(-> (gsh/distance-shapes sh1 sh2) coord (mth/precision 2)) [sh1 sh2]]) + [(-> (gsh/distance-shapes sh1 sh2) coord (mth/precision 0)) [sh1 sh2]]) contains-selected? (fn [selected pairs] @@ -136,7 +136,7 @@ (->> (query-side lt-side) (rx/combine-latest vector (query-side gt-side))))) - + distance-to-selrect (fn [shape] (let [sr (:selrect shape)] @@ -144,11 +144,11 @@ (gsh/distance-selrect sr selrect) (gsh/distance-selrect selrect sr)) coord - (mth/precision 2)))) + (mth/precision 0)))) get-shapes-match (fn [pred? shapes] - (->> shapes + (->> shapes (sort-by coord) (d/map-perm vector) (filter (fn [[sh1 sh2]] (gsh/overlap-coord? coord sh1 sh2))) diff --git a/frontend/src/uxbox/main/ui/workspace/snap_points.cljs b/frontend/src/uxbox/main/ui/workspace/snap_points.cljs index 4ec219936..95f2c3dd9 100644 --- a/frontend/src/uxbox/main/ui/workspace/snap_points.cljs +++ b/frontend/src/uxbox/main/ui/workspace/snap_points.cljs @@ -9,7 +9,8 @@ (def ^:private line-color "#D383DA") -(mf/defc snap-point [{:keys [point zoom]}] +(mf/defc snap-point + [{:keys [point zoom]}] (let [{:keys [x y]} point cross-width (/ 3 zoom)] [:g @@ -24,7 +25,8 @@ :y2 (- y cross-width) :style {:stroke line-color :stroke-width (str (/ 1 zoom))}}]])) -(mf/defc snap-line [{:keys [snap point zoom]}] +(mf/defc snap-line + [{:keys [snap point zoom]}] [:line {:x1 (:x snap) :y1 (:y snap) :x2 (:x point) @@ -32,7 +34,8 @@ :style {:stroke line-color :stroke-width (str (/ 1 zoom))} :opacity 0.4}]) -(defn get-snap [coord {:keys [shapes page-id filter-shapes]}] +(defn get-snap + [coord {:keys [shapes page-id filter-shapes]}] (->> (rx/from shapes) (rx/flat-map (fn [shape] (->> (sp/shape-snap-points shape) @@ -50,10 +53,11 @@ ;; We use sets to store points/lines so there are no points/lines repeated ;; can cause problems with react keys snap-points (into #{} (mapcat (fn [[point snaps coord]] - (when (not-empty snaps) (concat [point] snaps))) @state)) - + (cons point snaps)) + @state)) snap-lines (into #{} (mapcat (fn [[point snaps coord]] (when (not-empty snaps) (map #(vector point %) snaps))) @state))] + (mf/use-effect (fn [] (let [sub @@ -63,7 +67,7 @@ (get-snap :y %) (get-snap :x %))) (rx/subs #(reset! state %)))] - + ;; On unmount callback #(rx/dispose! sub)))) @@ -72,35 +76,36 @@ (fn [] (rx/push! subject props))) - [:g.snap-feedback (for [[from-point to-point] snap-lines] - [:& snap-line {:key (str "line-" (:x from-point) "-" (:y from-point) "-" (:x to-point) "-" (:y to-point) "-") + [:& snap-line {:key (str "line-" (:x from-point) + "-" (:y from-point) + "-" (:x to-point) + "-" (:y to-point) "-") :snap from-point :point to-point :zoom zoom}]) (for [point snap-points] - [:& snap-point {:key (str "point-" (:x point) "-" (:y point)) + [:& snap-point {:key (str "point-" (:x point) + "-" (:y point)) :point point :zoom zoom}])])) -(mf/defc snap-points [{:keys [layout]}] - (let [page-id (mf/deref refs/workspace-page-id) - selected (mf/deref refs/selected-shapes) - selected-shapes (mf/deref (refs/objects-by-id selected)) - drawing (mf/deref refs/current-drawing-shape) +(mf/defc snap-points + {::mf/wrap [mf/memo]} + [{:keys [layout zoom selected page-id drawing transform] :as props}] + (let [shapes (mf/deref (refs/objects-by-id selected)) filter-shapes (mf/deref refs/selected-shapes-with-children) - filter-shapes (fn [id] (if (= id :layout) - (or (not (contains? layout :display-grid)) - (not (contains? layout :snap-grid))) - (or (filter-shapes id) - (not (contains? layout :dynamic-alignment))))) - current-transform (mf/deref refs/current-transform) - snap-data (mf/deref refs/workspace-snap-data) - shapes (if drawing [drawing] selected-shapes) - zoom (mf/deref refs/selected-zoom)] - - (when (or drawing current-transform) + filter-shapes (fn [id] + (if (= id :layout) + (or (not (contains? layout :display-grid)) + (not (contains? layout :snap-grid))) + (or (filter-shapes id) + (not (contains? layout :dynamic-alignment))))) + ;; current-transform (mf/deref refs/current-transform) + ;; snap-data (mf/deref refs/workspace-snap-data) + shapes (if drawing [drawing] shapes)] + (when (or drawing transform) [:& snap-feedback {:shapes shapes :page-id page-id :filter-shapes filter-shapes diff --git a/frontend/src/uxbox/main/ui/workspace/viewport.cljs b/frontend/src/uxbox/main/ui/workspace/viewport.cljs index e7468850f..91fca0e54 100644 --- a/frontend/src/uxbox/main/ui/workspace/viewport.cljs +++ b/frontend/src/uxbox/main/ui/workspace/viewport.cljs @@ -50,7 +50,7 @@ (mf/defc coordinates [] (let [coords (some-> (hooks/use-rxsub ms/mouse-position) - (gpt/round 0))] + (gpt/round))] [:ul.coordinates [:span {:alt "x"} (str "X: " (:x coords "-"))] @@ -290,12 +290,13 @@ ] (-> (gpt/subtract pt brect) (gpt/divide (gpt/point @refs/selected-zoom)) - (gpt/add box)))) + (gpt/add box) + (gpt/round 0)))) on-mouse-move (fn [event] (let [event (.getBrowserEvent event) - pt (gpt/point (.-clientX event) (.-clientY event)) + pt (dom/get-client-position event) pt (translate-point-to-viewport pt) delta (gpt/point (.-movementX event) (.-movementY event))] @@ -457,7 +458,13 @@ (when (contains? layout :display-grid) [:& frame-grid {:zoom zoom}]) - [:& snap-points {:layout layout}] + [:& snap-points {:layout layout + :transform (:transform local) + :drawing (:drawing local) + :zoom zoom + :page-id (:id page) + :selected selected}] + [:& snap-distances {:layout layout}] (when tooltip diff --git a/frontend/src/uxbox/util/geom/snap_points.cljs b/frontend/src/uxbox/util/geom/snap_points.cljs index 25a60746e..3be81b2bc 100644 --- a/frontend/src/uxbox/util/geom/snap_points.cljs +++ b/frontend/src/uxbox/util/geom/snap_points.cljs @@ -28,6 +28,8 @@ [shape] (let [shape (gsh/transform-shape shape) shape-center (gsh/center shape)] - (case (:type shape) - :frame (-> shape gsh/shape->rect-shape frame-snap-points) - (into #{shape-center} (-> shape :points))))) + (if (= :frame (:type shape)) + (-> shape + (gsh/shape->rect-shape) + (frame-snap-points)) + (into #{shape-center} (:points shape))))) diff --git a/frontend/src/uxbox/util/range_tree.js b/frontend/src/uxbox/util/range_tree.js index 076d0ca1c..5e5604766 100644 --- a/frontend/src/uxbox/util/range_tree.js +++ b/frontend/src/uxbox/util/range_tree.js @@ -1,4 +1,4 @@ -/* +/* * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. @@ -10,7 +10,7 @@ */ /* - * Balanced Binary Search Tree based on the red-black BST + * Balanced Binary Search Tree based on the red-black BST * described at "Algorithms" by Robert Sedwick & Kevin Wayne */ "use strict"; @@ -27,7 +27,7 @@ goog.scope(function() { RED: 1, BLACK: 2 } - + class Node { constructor(value, data) { this.value = value; @@ -37,7 +37,7 @@ goog.scope(function() { this.color = Color.BLACK; } } - + // Will store a map from key to list of data // value => [ data ] // The values can be queried in range and the data stored will be retrived whole @@ -46,13 +46,13 @@ goog.scope(function() { constructor() { this.root = null; } - + insert(value, data) { this.root = recInsert(this.root, value, data); this.root.color = Color.BLACK; return this; } - + remove(value, data) { if (!this.root) { return this; @@ -76,16 +76,16 @@ goog.scope(function() { return this; } - + update (value, oldData, newData) { this.root = recUpdate(this.root, value, oldData, newData); return this; } - + get(value) { return recGet(this.root, value); } - + rangeQuery (fromValue, toValue) { return recRangeQuery(this.root, fromValue, toValue, []); } @@ -227,7 +227,7 @@ goog.scope(function() { return recGet(branch.right, value); } } - + function recUpdate(branch, value, oldData, newData) { if (branch === null) { return branch; diff --git a/frontend/src/uxbox/worker/snaps.cljs b/frontend/src/uxbox/worker/snaps.cljs index 4558750bb..2a7bc5d30 100644 --- a/frontend/src/uxbox/worker/snaps.cljs +++ b/frontend/src/uxbox/worker/snaps.cljs @@ -31,9 +31,9 @@ (map #(vector % (:id shape)) points)) ;; The grid points are only added by the "root" of the coord-dat - (if (= (:id shape) frame-id) - (let [points (gg/grid-snap-points shape coord)] - (map #(vector % :layout) points)))))) + (when (= (:id shape) frame-id) + (let [points (gg/grid-snap-points shape coord)] + (map #(vector % :layout) points)))))) into-tree (fn [tree [point _ :as data]] (rt/insert tree (coord point) data))] (->> shapes @@ -48,9 +48,10 @@ (group-by :frame-id)) frame-shapes (->> (cph/select-frames objects) (reduce #(update %1 (:id %2) conj %2) frame-shapes))] + (d/mapm (fn [frame-id shapes] {:x (create-coord-data frame-id shapes :x) - :y (create-coord-data frame-id shapes :y)}) - frame-shapes))) + :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" @@ -74,7 +75,7 @@ (index-page state id objects)))] (swap! state #(reduce process-page % pages))) - #_(log-state) + ;; (log-state) ;; Return nil so the worker will not answer anything back nil) @@ -82,7 +83,7 @@ [{:keys [page-id objects] :as message}] ;; TODO: Check the difference and update the index acordingly (swap! state index-page page-id objects) - #_(log-state) + ;; (log-state) nil) (defmethod impl/handler :snaps/range-query @@ -96,3 +97,4 @@ set ;; unique (into [])))) + diff --git a/package-lock.json b/package-lock.json deleted file mode 100644 index 48e341a09..000000000 --- a/package-lock.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "lockfileVersion": 1 -}