mirror of
https://github.com/penpot/penpot.git
synced 2025-02-13 10:38:13 -05:00
✨ Snapping on path elements
This commit is contained in:
parent
2e6dacf539
commit
421b30c1d8
13 changed files with 464 additions and 54 deletions
|
@ -37,3 +37,10 @@
|
|||
;; Path tools
|
||||
(d/export tools/make-curve)
|
||||
(d/export tools/make-corner)
|
||||
(d/export tools/add-node)
|
||||
(d/export tools/remove-node)
|
||||
(d/export tools/merge-nodes)
|
||||
(d/export tools/join-nodes)
|
||||
(d/export tools/separate-nodes)
|
||||
(d/export tools/toggle-snap)
|
||||
|
||||
|
|
|
@ -163,7 +163,7 @@
|
|||
zoom (get-in state [:workspace-local :zoom])
|
||||
mouse-up (->> stream (rx/filter #(or (helpers/end-path-event? %)
|
||||
(ms/mouse-up? %))))
|
||||
drag-events (->> ms/mouse-position
|
||||
drag-events (->> (streams/position-stream)
|
||||
(rx/take-until mouse-up)
|
||||
(rx/map #(drag-handler %)))]
|
||||
|
||||
|
|
|
@ -126,7 +126,7 @@
|
|||
(rx/of (selection/select-node position shift?)))
|
||||
|
||||
;; This stream checks the consecutive mouse positions to do the draging
|
||||
(->> ms/mouse-position
|
||||
(->> (streams/position-stream)
|
||||
(rx/take-until stopper)
|
||||
(rx/map #(move-selected-path-point start-position %)))
|
||||
(rx/of (apply-content-modifiers)))
|
||||
|
@ -135,8 +135,7 @@
|
|||
mouse-click-stream
|
||||
(rx/of (selection/select-node position shift?))]
|
||||
|
||||
(streams/drag-stream mouse-drag-stream
|
||||
mouse-click-stream)))))
|
||||
(streams/drag-stream mouse-drag-stream mouse-click-stream)))))
|
||||
|
||||
(defn start-move-handler
|
||||
[index prefix]
|
||||
|
|
|
@ -14,7 +14,8 @@
|
|||
[app.main.store :as st]
|
||||
[app.main.streams :as ms]
|
||||
[beicon.core :as rx]
|
||||
[potok.core :as ptk]))
|
||||
[potok.core :as ptk]
|
||||
[app.common.math :as mth]))
|
||||
|
||||
(defonce drag-threshold 5)
|
||||
|
||||
|
@ -48,7 +49,15 @@
|
|||
(->> position-stream
|
||||
(rx/merge-map (fn [] to-stream)))))))
|
||||
|
||||
(defn to-dec [num]
|
||||
(let [k 50]
|
||||
(* (mth/floor (/ num k)) k)))
|
||||
|
||||
(defn position-stream []
|
||||
(->> ms/mouse-position
|
||||
;; TODO: Prueba para el snap
|
||||
#_(rx/map #(-> %
|
||||
(update :x to-dec)
|
||||
(update :y to-dec)))
|
||||
(rx/with-latest merge (->> ms/mouse-position-shift (rx/map #(hash-map :shift? %))))
|
||||
(rx/with-latest merge (->> ms/mouse-position-alt (rx/map #(hash-map :alt? %))))))
|
||||
|
|
|
@ -40,3 +40,25 @@
|
|||
new-content (reduce ugp/make-curve-point (:content shape) selected-points)
|
||||
[rch uch] (changes/generate-path-changes page-id shape (:content shape) new-content)]
|
||||
(rx/of (dwc/commit-changes rch uch {:commit-local? true}))))))
|
||||
|
||||
(defn add-node []
|
||||
(ptk/reify ::add-node))
|
||||
|
||||
(defn remove-node []
|
||||
(ptk/reify ::remove-node))
|
||||
|
||||
(defn merge-nodes []
|
||||
(ptk/reify ::merge-nodes))
|
||||
|
||||
(defn join-nodes []
|
||||
(ptk/reify ::join-nodes))
|
||||
|
||||
(defn separate-nodes []
|
||||
(ptk/reify ::separate-nodes))
|
||||
|
||||
(defn toggle-snap []
|
||||
(ptk/reify ::toggle-snap
|
||||
ptk/UpdateEvent
|
||||
(update [_ state]
|
||||
(let [id (st/get-path-id state)]
|
||||
(update-in state [:workspace-local :edit-path id :snap-toggled] not)))))
|
||||
|
|
|
@ -1,44 +0,0 @@
|
|||
;; 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/.
|
||||
;;
|
||||
;; Copyright (c) UXBOX Labs SL
|
||||
|
||||
(ns app.main.ui.workspace.shapes.path.actions
|
||||
(:require
|
||||
[app.main.data.workspace.path :as drp]
|
||||
[app.main.refs :as refs]
|
||||
[app.main.store :as st]
|
||||
[app.main.ui.icons :as i]
|
||||
[app.main.ui.workspace.shapes.path.common :as pc]
|
||||
[rumext.alpha :as mf]))
|
||||
|
||||
(mf/defc path-actions [{:keys [shape]}]
|
||||
(let [id (mf/deref refs/selected-edition)
|
||||
{:keys [edit-mode selected-points snap-toggled] :as all} (mf/deref pc/current-edit-path-ref)]
|
||||
[:div.path-actions
|
||||
[:div.viewport-actions-group
|
||||
[:div.viewport-actions-entry {:class (when (= edit-mode :draw) "is-toggled")
|
||||
:on-click #(st/emit! (drp/change-edit-mode :draw))} i/pen]
|
||||
[:div.viewport-actions-entry {:class (when (= edit-mode :move) "is-toggled")
|
||||
:on-click #(st/emit! (drp/change-edit-mode :move))} i/pointer-inner]]
|
||||
|
||||
[:div.viewport-actions-group
|
||||
[:div.viewport-actions-entry {:class "is-disabled"} i/nodes-add]
|
||||
[:div.viewport-actions-entry {:class "is-disabled"} i/nodes-remove]]
|
||||
|
||||
[:div.viewport-actions-group
|
||||
[:div.viewport-actions-entry {:class "is-disabled"} i/nodes-merge]
|
||||
[:div.viewport-actions-entry {:class "is-disabled"} i/nodes-join]
|
||||
[:div.viewport-actions-entry {:class "is-disabled"} i/nodes-separate]]
|
||||
|
||||
[:div.viewport-actions-group
|
||||
[:div.viewport-actions-entry {:class (when (empty? selected-points) "is-disabled")
|
||||
:on-click #(when-not (empty? selected-points)
|
||||
(st/emit! (drp/make-corner)))} i/nodes-corner]
|
||||
[:div.viewport-actions-entry {:class (when (empty? selected-points) "is-disabled")
|
||||
:on-click #(when-not (empty? selected-points)
|
||||
(st/emit! (drp/make-curve)))} i/nodes-curve]]
|
||||
|
||||
[:div.viewport-actions-group
|
||||
[:div.viewport-actions-entry {:class (when snap-toggled "is-toggled")} i/nodes-snap]]]))
|
|
@ -187,7 +187,7 @@
|
|||
(let [point-selected? (contains? selected-points position)
|
||||
point-hover? (contains? hover-points position)
|
||||
last-p? (= last-point position)
|
||||
start-p? (some? last-point)]
|
||||
start-p? (not (some? last-point))]
|
||||
[:g.path-node
|
||||
[:g.point-handlers {:pointer-events (when (= edit-mode :draw) "none")}
|
||||
(for [[index prefix] (get handlers position)]
|
||||
|
|
|
@ -27,6 +27,7 @@
|
|||
[app.main.ui.workspace.viewport.selection :as selection]
|
||||
[app.main.ui.workspace.viewport.snap-distances :as snap-distances]
|
||||
[app.main.ui.workspace.viewport.snap-points :as snap-points]
|
||||
[app.main.ui.workspace.viewport.snap-path :as snap-path]
|
||||
[app.main.ui.workspace.viewport.utils :as utils]
|
||||
[app.main.ui.workspace.viewport.widgets :as widgets]
|
||||
[beicon.core :as rx]
|
||||
|
@ -282,12 +283,16 @@
|
|||
:selected selected
|
||||
:page-id page-id}])
|
||||
|
||||
[:& snap-path/snap-path
|
||||
{:zoom zoom
|
||||
:edition edition
|
||||
:edit-path edit-path}]
|
||||
|
||||
(when show-cursor-tooltip?
|
||||
[:& widgets/cursor-tooltip
|
||||
{:zoom zoom
|
||||
:tooltip tooltip}])
|
||||
|
||||
|
||||
(when show-presence?
|
||||
[:& presence/active-cursors
|
||||
{:page-id page-id}])
|
||||
|
|
|
@ -45,7 +45,9 @@
|
|||
middle-click? (= 2 (.-which event))
|
||||
|
||||
frame? (= :frame type)
|
||||
selected? (contains? selected id)]
|
||||
selected? (contains? selected id)
|
||||
|
||||
drawing-path? (= :draw (get-in edit-path [edition :edit-mode]))]
|
||||
|
||||
(when middle-click?
|
||||
(dom/prevent-default bevent)
|
||||
|
@ -60,7 +62,8 @@
|
|||
(when (and (or (not edition) (not= edition id)) (not blocked) (not hidden) (not (#{:comments :path} drawing-tool)))
|
||||
(not= edition id))
|
||||
(not blocked)
|
||||
(not hidden))
|
||||
(not hidden)
|
||||
(not drawing-path?))
|
||||
(cond
|
||||
drawing-tool
|
||||
(st/emit! (dd/start-drawing drawing-tool))
|
||||
|
|
174
frontend/src/app/main/ui/workspace/viewport/path_actions.cljs
Normal file
174
frontend/src/app/main/ui/workspace/viewport/path_actions.cljs
Normal file
|
@ -0,0 +1,174 @@
|
|||
;; 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/.
|
||||
;;
|
||||
;; This Source Code Form is "Incompatible With Secondary Licenses", as
|
||||
;; defined by the Mozilla Public License, v. 2.0.
|
||||
;;
|
||||
;; Copyright (c) UXBOX Labs SL
|
||||
|
||||
(ns app.main.ui.workspace.viewport.path-actions
|
||||
(:require
|
||||
[app.main.data.workspace.path :as drp]
|
||||
[app.main.data.workspace.path.helpers :as wph]
|
||||
[app.main.refs :as refs]
|
||||
[app.main.store :as st]
|
||||
[app.main.ui.icons :as i]
|
||||
[app.main.ui.workspace.shapes.path.common :as pc]
|
||||
[app.util.geom.path :as ugp]
|
||||
[rumext.alpha :as mf]))
|
||||
|
||||
(defn check-enabled [content selected-points]
|
||||
(let [segments (ugp/get-segments content selected-points)
|
||||
|
||||
points-selected? (not (empty? selected-points))
|
||||
segments-selected? (not (empty? segments))]
|
||||
{:make-corner points-selected?
|
||||
:make-curve points-selected?
|
||||
:add-node segments-selected?
|
||||
:remove-node points-selected?
|
||||
:merge-nodes segments-selected?
|
||||
:join-nodes segments-selected?
|
||||
:separate-nodes segments-selected?}))
|
||||
|
||||
(mf/defc path-actions [{:keys [shape]}]
|
||||
(let [id (mf/deref refs/selected-edition)
|
||||
{:keys [edit-mode selected-points snap-toggled] :as all} (mf/deref pc/current-edit-path-ref)
|
||||
content (:content shape)
|
||||
|
||||
enabled-buttons
|
||||
(mf/use-memo
|
||||
(mf/deps content selected-points)
|
||||
#(check-enabled content selected-points))
|
||||
|
||||
on-select-draw-mode
|
||||
(mf/use-callback
|
||||
(fn [event]
|
||||
(st/emit! (drp/change-edit-mode :draw))))
|
||||
|
||||
on-select-edit-mode
|
||||
(mf/use-callback
|
||||
(fn [event]
|
||||
(st/emit! (drp/change-edit-mode :move))))
|
||||
|
||||
on-add-node
|
||||
(mf/use-callback
|
||||
(mf/deps (:add-node enabled-buttons))
|
||||
(fn [event]
|
||||
(when (:add-node enabled-buttons)
|
||||
(st/emit! (drp/add-node)))))
|
||||
|
||||
on-remove-node
|
||||
(mf/use-callback
|
||||
(mf/deps (:remove-node enabled-buttons))
|
||||
(fn [event]
|
||||
(when (:remove-node enabled-buttons)
|
||||
(st/emit! (drp/remove-node)))))
|
||||
|
||||
on-merge-nodes
|
||||
(mf/use-callback
|
||||
(mf/deps (:merge-nodes enabled-buttons))
|
||||
(fn [event]
|
||||
(when (:merge-nodes enabled-buttons)
|
||||
(st/emit! (drp/merge-nodes)))))
|
||||
|
||||
on-join-nodes
|
||||
(mf/use-callback
|
||||
(mf/deps (:join-nodes enabled-buttons))
|
||||
(fn [event]
|
||||
(when (:join-nodes enabled-buttons)
|
||||
(st/emit! (drp/join-nodes)))))
|
||||
|
||||
on-separate-nodes
|
||||
(mf/use-callback
|
||||
(mf/deps (:separate-nodes enabled-buttons))
|
||||
(fn [event]
|
||||
(when (:separate-nodes enabled-buttons)
|
||||
(st/emit! (drp/separate-nodes)))))
|
||||
|
||||
on-make-corner
|
||||
(mf/use-callback
|
||||
(mf/deps (:make-corner enabled-buttons))
|
||||
(fn [event]
|
||||
(when (:make-corner enabled-buttons)
|
||||
(st/emit! (drp/make-corner)))))
|
||||
|
||||
on-make-curve
|
||||
(mf/use-callback
|
||||
(mf/deps (:make-curve enabled-buttons))
|
||||
(fn [event]
|
||||
(when (:make-curve enabled-buttons)
|
||||
(st/emit! (drp/make-curve)))))
|
||||
|
||||
on-toggle-snap
|
||||
(mf/use-callback
|
||||
(fn [event]
|
||||
(st/emit! (drp/toggle-snap))))
|
||||
|
||||
]
|
||||
[:div.path-actions
|
||||
[:div.viewport-actions-group
|
||||
|
||||
;; Draw Mode
|
||||
[:div.viewport-actions-entry
|
||||
{:class (when (= edit-mode :draw) "is-toggled")
|
||||
:on-click on-select-draw-mode}
|
||||
i/pen]
|
||||
|
||||
;; Edit mode
|
||||
[:div.viewport-actions-entry
|
||||
{:class (when (= edit-mode :move) "is-toggled")
|
||||
:on-click on-select-edit-mode}
|
||||
i/pointer-inner]]
|
||||
|
||||
[:div.viewport-actions-group
|
||||
;; Add Node
|
||||
[:div.viewport-actions-entry
|
||||
{:class (when-not (:add-node enabled-buttons) "is-disabled")
|
||||
:on-click on-add-node}
|
||||
i/nodes-add]
|
||||
|
||||
;; Remove node
|
||||
[:div.viewport-actions-entry
|
||||
{:class (when-not (:remove-node enabled-buttons) "is-disabled")
|
||||
:on-click on-remove-node}
|
||||
i/nodes-remove]]
|
||||
|
||||
[:div.viewport-actions-group
|
||||
;; Merge Nodes
|
||||
[:div.viewport-actions-entry
|
||||
{:class (when-not (:merge-nodes enabled-buttons) "is-disabled")
|
||||
:on-click on-merge-nodes}
|
||||
i/nodes-merge]
|
||||
|
||||
;; Join Nodes
|
||||
[:div.viewport-actions-entry
|
||||
{:class (when-not (:join-nodes enabled-buttons) "is-disabled")
|
||||
:on-click on-join-nodes}
|
||||
i/nodes-join]
|
||||
|
||||
;; Separate Nodes
|
||||
[:div.viewport-actions-entry
|
||||
{:class (when-not (:separate-nodes enabled-buttons) "is-disabled")
|
||||
:on-click on-separate-nodes}
|
||||
i/nodes-separate]]
|
||||
|
||||
;; Make Corner
|
||||
[:div.viewport-actions-group
|
||||
[:div.viewport-actions-entry
|
||||
{:class (when-not (:make-corner enabled-buttons) "is-disabled")
|
||||
:on-click on-make-corner}
|
||||
i/nodes-corner]
|
||||
|
||||
;; Make Curve
|
||||
[:div.viewport-actions-entry
|
||||
{:class (when-not (:make-curve enabled-buttons) "is-disabled")
|
||||
:on-click on-make-curve}
|
||||
i/nodes-curve]]
|
||||
|
||||
;; Toggle snap
|
||||
[:div.viewport-actions-group
|
||||
[:div.viewport-actions-entry
|
||||
{:class (when snap-toggled "is-toggled")
|
||||
:on-click on-toggle-snap}
|
||||
i/nodes-snap]]]))
|
191
frontend/src/app/main/ui/workspace/viewport/snap_path.cljs
Normal file
191
frontend/src/app/main/ui/workspace/viewport/snap_path.cljs
Normal file
|
@ -0,0 +1,191 @@
|
|||
;; 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/.
|
||||
;;
|
||||
;; This Source Code Form is "Incompatible With Secondary Licenses", as
|
||||
;; defined by the Mozilla Public License, v. 2.0.
|
||||
;;
|
||||
;; Copyright (c) 2020 UXBOX Labs SL
|
||||
|
||||
(ns app.main.ui.workspace.viewport.snap-path
|
||||
(:require
|
||||
#_[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]
|
||||
[app.util.geom.path :as ugp]
|
||||
#_[beicon.core :as rx]
|
||||
[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]}]
|
||||
(let [{:keys [x y]} point
|
||||
x (mth/round x)
|
||||
y (mth/round y)
|
||||
cross-width (/ 3 zoom)]
|
||||
[:g
|
||||
[:line {:x1 (- x cross-width)
|
||||
:y1 (- y cross-width)
|
||||
:x2 (+ x cross-width)
|
||||
:y2 (+ y cross-width)
|
||||
: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 (/ line-width zoom))}}]]))
|
||||
|
||||
#_(mf/defc snap-line
|
||||
[{:keys [snap point zoom]}]
|
||||
[:line {:x1 (mth/round (:x snap))
|
||||
:y1 (mth/round (:y snap))
|
||||
:x2 (mth/round (:x point))
|
||||
:y2 (mth/round (:y point))
|
||||
:style {:stroke line-color :stroke-width (str (/ line-width zoom))}
|
||||
:opacity line-opacity}])
|
||||
|
||||
#_(defn get-snap
|
||||
[coord {:keys [shapes page-id filter-shapes modifiers]}]
|
||||
(let [shape (if (> (count shapes) 1)
|
||||
(->> shapes (map gsh/transform-shape) gsh/selection-rect (gsh/setup {:type :rect}))
|
||||
(->> shapes (first)))
|
||||
|
||||
shape (if modifiers
|
||||
(-> shape (assoc :modifiers modifiers) gsh/transform-shape)
|
||||
shape)
|
||||
|
||||
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 modifiers] :as props}]
|
||||
(let [state (mf/use-state [])
|
||||
subject (mf/use-memo #(rx/subject))
|
||||
|
||||
;; We use sets to store points/lines so there are no points/lines repeated
|
||||
;; can cause problems with react keys
|
||||
snap-points (into #{} (mapcat add-point-to-snaps) @state)
|
||||
|
||||
snap-lines (->> (into (process-snap-lines @state :x)
|
||||
(process-snap-lines @state :y))
|
||||
(into #{}))]
|
||||
|
||||
(mf/use-effect
|
||||
(fn []
|
||||
(let [sub (->> subject
|
||||
(rx/switch-map #(rx/combine-latest
|
||||
d/concat
|
||||
(get-snap :y %)
|
||||
(get-snap :x %)))
|
||||
(rx/subs #(let [rs (filter (fn [[_ snaps _]] (> (count snaps) 0)) %)]
|
||||
(reset! state rs))))]
|
||||
|
||||
;; On unmount callback
|
||||
#(rx/dispose! sub))))
|
||||
|
||||
(mf/use-effect
|
||||
(mf/deps shapes modifiers)
|
||||
(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 from-point
|
||||
:point to-point
|
||||
:zoom zoom}])
|
||||
(for [point snap-points]
|
||||
[:& snap-point {:key (str "point-" (:x point)
|
||||
"-" (:y point))
|
||||
:point point
|
||||
:zoom zoom}])]))
|
||||
|
||||
#_(mf/defc snap-points
|
||||
{::mf/wrap [mf/memo]}
|
||||
[{:keys [layout zoom selected page-id drawing transform modifiers] :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)))))
|
||||
shapes (if drawing [drawing] shapes)]
|
||||
(when (or drawing transform)
|
||||
[:& snap-feedback {:shapes shapes
|
||||
:page-id page-id
|
||||
:filter-shapes filter-shapes
|
||||
:zoom zoom
|
||||
:modifiers modifiers}])))
|
||||
|
||||
(mf/defc snap-feedback [])
|
||||
|
||||
|
||||
(mf/defc snap-path
|
||||
{::mf/wrap [mf/memo]}
|
||||
[{:keys [edition edit-path zoom]}]
|
||||
(let [{:keys [content]} (mf/deref (refs/object-by-id edition))
|
||||
{:keys [drag-handler preview snap-toggled]} (get edit-path edition)
|
||||
|
||||
position (or drag-handler
|
||||
(ugp/command->point preview))]
|
||||
|
||||
(when snap-toggled
|
||||
[:& snap-feedback {:content content
|
||||
:position position
|
||||
:zoom zoom}])))
|
|
@ -14,7 +14,7 @@
|
|||
[app.main.store :as st]
|
||||
[app.main.streams :as ms]
|
||||
[app.main.ui.hooks :as hooks]
|
||||
[app.main.ui.workspace.shapes.path.actions :refer [path-actions]]
|
||||
[app.main.ui.workspace.viewport.path-actions :refer [path-actions]]
|
||||
[app.util.dom :as dom]
|
||||
[app.util.object :as obj]
|
||||
[rumext.alpha :as mf]))
|
||||
|
|
|
@ -604,3 +604,47 @@
|
|||
(as-> content $
|
||||
(reduce redfn $ content-next)
|
||||
(remove-line-curves $))))
|
||||
|
||||
(defn get-segments
|
||||
"Given a content and a set of points return all the segments in the path
|
||||
that uses the points"
|
||||
[content points]
|
||||
(let [point-set (set points)]
|
||||
|
||||
(loop [segments []
|
||||
prev-point nil
|
||||
start-point nil
|
||||
cur-cmd (first content)
|
||||
content (rest content)]
|
||||
|
||||
(let [;; Close-path makes a segment from the last point to the initial path point
|
||||
cur-point (if (= :close-path (:command cur-cmd))
|
||||
start-point
|
||||
(command->point cur-cmd))
|
||||
|
||||
;; If there is a move-to we don't have a segment
|
||||
prev-point (if (= :move-to (:command cur-cmd))
|
||||
nil
|
||||
prev-point)
|
||||
|
||||
;; We update the start point
|
||||
start-point (if (= :move-to (:command cur-cmd))
|
||||
cur-point
|
||||
start-point)
|
||||
|
||||
is-segment? (and (some? prev-point)
|
||||
(contains? point-set prev-point)
|
||||
(contains? point-set cur-point))
|
||||
|
||||
segments (cond-> segments
|
||||
is-segment?
|
||||
(conj [prev-point cur-point]))]
|
||||
|
||||
(if (some? cur-cmd)
|
||||
(recur segments
|
||||
cur-point
|
||||
start-point
|
||||
(first content)
|
||||
(rest content))
|
||||
|
||||
segments)))))
|
||||
|
|
Loading…
Add table
Reference in a new issue