diff --git a/common/app/common/geom/shapes.cljc b/common/app/common/geom/shapes.cljc index 83fbd9791..1f77a7d15 100644 --- a/common/app/common/geom/shapes.cljc +++ b/common/app/common/geom/shapes.cljc @@ -406,6 +406,10 @@ :y miny :width (- maxx minx) :height (- maxy miny) + :points [(gpt/point minx miny) + (gpt/point maxx miny) + (gpt/point maxx maxy) + (gpt/point minx maxy)] :type :rect})) (defn translate-to-frame @@ -674,7 +678,7 @@ resize-transform (:resize-transform modifiers (gmt/matrix)) resize-transform-inverse (:resize-transform-inverse modifiers (gmt/matrix)) - rt-modif (:rotation modifiers 0) + rt-modif (or (:rotation modifiers) 0) shape (-> shape (transform ds-modifier)) @@ -792,8 +796,8 @@ (assoc $ :points (shape->points $)) (assoc $ :selrect (points->selrect (:points $))) (update $ :selrect fix-invalid-rect-values) - (update $ :rotation #(mod (+ (or % 0) (get-in $ [:modifiers :rotation] 0)) 360)) - )] + (update $ :rotation #(mod (+ (or % 0) + (or (get-in $ [:modifiers :rotation]) 0)) 360)))] new-shape)) (declare update-path-selrect) diff --git a/frontend/src/app/main/snap.cljs b/frontend/src/app/main/snap.cljs index ca62522ff..4dcc3b000 100644 --- a/frontend/src/app/main/snap.cljs +++ b/frontend/src/app/main/snap.cljs @@ -193,10 +193,12 @@ (not (contains? layout :snap-grid))) (or (filter-shapes id) (not (contains? layout :dynamic-alignment))))) - shapes-points (->> shapes - ;; Unroll all the possible snap-points - (mapcat (partial sp/shape-snap-points)) + shape (if (> (count shapes) 1) + (->> shapes (map gsh/transform-shape) gsh/selection-rect) + (->> shapes (first))) + shapes-points (->> shape + (sp/shape-snap-points) ;; Move the points in the translation vector (map #(gpt/add % movev)))] (->> (rx/merge (closest-snap page-id frame-id shapes-points filter-shapes) @@ -205,6 +207,5 @@ (rx/reduce gpt/min) (rx/map #(or % (gpt/point 0 0))) (rx/map #(gpt/add movev %)) - (rx/map #(gpt/round % 0)) - ))) + (rx/map #(gpt/round % 0))))) diff --git a/frontend/src/app/main/ui/workspace/snap_distances.cljs b/frontend/src/app/main/ui/workspace/snap_distances.cljs index bc425057a..bc4dc1f8e 100644 --- a/frontend/src/app/main/ui/workspace/snap_distances.cljs +++ b/frontend/src/app/main/ui/workspace/snap_distances.cljs @@ -172,7 +172,7 @@ (map pair->distance+pair) (filter (comp pred? first)))) - ;; Checks if the value is in a set of numbers with an error margin of 0.1 + ;; Checks if the value is in a set of numbers with an error margin check-in-set (fn [value number-set] (->> number-set diff --git a/frontend/src/app/main/ui/workspace/snap_points.cljs b/frontend/src/app/main/ui/workspace/snap_points.cljs index 429491aa4..594c81401 100644 --- a/frontend/src/app/main/ui/workspace/snap_points.cljs +++ b/frontend/src/app/main/ui/workspace/snap_points.cljs @@ -12,6 +12,7 @@ [app.common.math :as mth] [app.common.data :as d] [app.common.geom.point :as gpt] + [app.common.geom.shapes :as gsh] [app.main.refs :as refs] [app.main.snap :as snap] [app.util.geom.snap-points :as sp] @@ -19,6 +20,13 @@ [rumext.alpha :as mf])) (def ^:private line-color "#D383DA") +(def ^:private line-opacity 0.6) +(def ^:private line-width 1) + +;; Configuration for debug +;; (def ^:private line-color "red") +;; (def ^:private line-opacity 1 ) +;; (def ^:private line-width 2) (mf/defc snap-point [{:keys [point zoom]}] @@ -31,12 +39,12 @@ :y1 (- y cross-width) :x2 (+ x cross-width) :y2 (+ y cross-width) - :style {:stroke line-color :stroke-width (str (/ 1 zoom))}}] + :style {:stroke line-color :stroke-width (str (/ line-width zoom))}}] [:line {:x1 (- x cross-width) :y1 (+ y cross-width) :x2 (+ x cross-width) :y2 (- y cross-width) - :style {:stroke line-color :stroke-width (str (/ 1 zoom))}}]])) + :style {:stroke line-color :stroke-width (str (/ line-width zoom))}}]])) (mf/defc snap-line [{:keys [snap point zoom]}] @@ -44,19 +52,56 @@ :y1 (mth/round (:y snap)) :x2 (mth/round (:x point)) :y2 (mth/round (:y point)) - :style {:stroke line-color :stroke-width (str (/ 1 zoom))} - :opacity 0.4}]) + :style {:stroke line-color :stroke-width (str (/ line-width zoom))} + :opacity line-opacity}]) (defn get-snap [coord {:keys [shapes page-id filter-shapes]}] - (->> (rx/from shapes) - (rx/flat-map (fn [shape] - (->> (sp/shape-snap-points shape) - (map #(vector (:frame-id shape) %))))) - (rx/flat-map (fn [[frame-id point]] - (->> (snap/get-snap-points page-id frame-id filter-shapes point coord) - (rx/map #(vector point % coord))))) - (rx/reduce conj []))) + (let [shape (if (> (count shapes) 1) + (->> shapes (map gsh/transform-shape) gsh/selection-rect) + (->> shapes (first))) + + frame-id (snap/snap-frame-id shapes)] + + (->> (rx/of shape) + (rx/flat-map (fn [shape] + (->> (sp/shape-snap-points shape) + (map #(vector frame-id %))))) + (rx/flat-map (fn [[frame-id point]] + (->> (snap/get-snap-points page-id frame-id filter-shapes point coord) + (rx/map #(vector point % coord))))) + (rx/reduce conj [])))) + +(defn- flip + "Function that reverses the x/y coordinates to their counterpart" + [coord] + (if (= coord :x) :y :x)) + +(defn add-point-to-snaps + [[point snaps coord]] + (let [normalize-coord #(assoc % coord (get point coord))] + (cons point (map normalize-coord snaps)))) + + +(defn- process-snap-lines + "Gets the snaps for a coordinate and creates lines with a fixed coordinate" + [snaps coord] + (->> snaps + ;; only snap on the `coord` coordinate + (filter #(= (nth % 2) coord)) + ;; we add the point so the line goes from the point to the snap + (mapcat add-point-to-snaps) + ;; We flatten because it's a list of from-to points + (flatten) + ;; Put together the points of the coordinate + (group-by coord) + ;; Keep only the other coordinate + (d/mapm #(map (flip coord) %2)) + ;; Finally get the max/min and this will define the line to draw + (d/mapm #(vector (apply min %2) (apply max %2))) + ;; Change the structure to retrieve a list of lines from/todo + (map (fn [[fixedv [minv maxv]]] [(hash-map coord fixedv (flip coord) minv) + (hash-map coord fixedv (flip coord) maxv)])))) (mf/defc snap-feedback [{:keys [shapes page-id filter-shapes zoom] :as props}] @@ -65,11 +110,12 @@ ;; 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]] - (cons point snaps)) - @state)) - snap-lines (into #{} (mapcat (fn [[point snaps coord]] - (when (not-empty snaps) (map #(vector point %) snaps))) @state))] + snap-points (->> @state + (mapcat add-point-to-snaps) + (into #{})) + + snap-lines (into (process-snap-lines @state :x) + (process-snap-lines @state :y))] (mf/use-effect (fn [] @@ -78,7 +124,8 @@ d/concat (get-snap :y %) (get-snap :x %))) - (rx/subs #(reset! state %)))] + (rx/subs #(let [rs (filter (fn [[_ snaps _]] (> (count snaps) 0)) %)] + (reset! state rs))))] ;; On unmount callback #(rx/dispose! sub))))