mirror of
https://github.com/penpot/penpot.git
synced 2025-06-06 16:01:39 +02:00
♻️ Refactor path-editor component
This commit is contained in:
parent
93199e1a70
commit
3ca76c9ef7
2 changed files with 89 additions and 37 deletions
|
@ -324,6 +324,43 @@
|
||||||
(reduce find-min-point)
|
(reduce find-min-point)
|
||||||
(first))))
|
(first))))
|
||||||
|
|
||||||
|
|
||||||
|
(defn closest-point
|
||||||
|
"Given a path and a position"
|
||||||
|
[content position]
|
||||||
|
|
||||||
|
(let [point+distance
|
||||||
|
(fn [[cur-cmd prev-cmd]]
|
||||||
|
(let [from-p (helpers/command->point prev-cmd)
|
||||||
|
to-p (helpers/command->point cur-cmd)
|
||||||
|
h1 (gpt/point (get-in cur-cmd [:params :c1x])
|
||||||
|
(get-in cur-cmd [:params :c1y]))
|
||||||
|
h2 (gpt/point (get-in cur-cmd [:params :c2x])
|
||||||
|
(get-in cur-cmd [:params :c2y]))
|
||||||
|
point
|
||||||
|
(case (:command cur-cmd)
|
||||||
|
:line-to
|
||||||
|
(line-closest-point position from-p to-p)
|
||||||
|
|
||||||
|
:curve-to
|
||||||
|
(curve-closest-point position from-p to-p h1 h2)
|
||||||
|
|
||||||
|
nil)]
|
||||||
|
(when point
|
||||||
|
[point (gpt/distance point position)])))
|
||||||
|
|
||||||
|
find-min-point
|
||||||
|
(fn [[min-p min-dist :as acc] [cur-p cur-dist :as cur]]
|
||||||
|
(if (and (some? acc) (or (not cur) (<= min-dist cur-dist)))
|
||||||
|
[min-p min-dist]
|
||||||
|
[cur-p cur-dist]))]
|
||||||
|
|
||||||
|
(->> content
|
||||||
|
(d/with-prev)
|
||||||
|
(map point+distance)
|
||||||
|
(reduce find-min-point)
|
||||||
|
(first))))
|
||||||
|
|
||||||
(defn- remove-line-curves
|
(defn- remove-line-curves
|
||||||
"Remove all curves that have both handlers in the same position that the
|
"Remove all curves that have both handlers in the same position that the
|
||||||
beginning and end points. This makes them really line-to commands"
|
beginning and end points. This makes them really line-to commands"
|
||||||
|
|
|
@ -23,8 +23,7 @@
|
||||||
[app.util.path.format :as upf]
|
[app.util.path.format :as upf]
|
||||||
[clojure.set :refer [map-invert]]
|
[clojure.set :refer [map-invert]]
|
||||||
[goog.events :as events]
|
[goog.events :as events]
|
||||||
[rumext.v2 :as mf])
|
[rumext.v2 :as mf]))
|
||||||
(:import goog.events.EventType))
|
|
||||||
|
|
||||||
(def point-radius 5)
|
(def point-radius 5)
|
||||||
(def point-radius-selected 4)
|
(def point-radius-selected 4)
|
||||||
|
@ -257,9 +256,9 @@
|
||||||
(mf/defc path-editor*
|
(mf/defc path-editor*
|
||||||
[{:keys [shape zoom]}]
|
[{:keys [shape zoom]}]
|
||||||
|
|
||||||
(let [editor-ref (mf/use-ref nil)
|
(let [editor-ref (mf/use-ref nil)
|
||||||
edit-path-ref (pc/make-edit-path-ref (:id shape))
|
edit-path-ref (pc/make-edit-path-ref (:id shape))
|
||||||
hover-point (mf/use-state nil)
|
hover-point (mf/use-state nil)
|
||||||
|
|
||||||
{:keys [edit-mode
|
{:keys [edit-mode
|
||||||
drag-handler
|
drag-handler
|
||||||
|
@ -286,7 +285,8 @@
|
||||||
(path.segment/content->points base-content))
|
(path.segment/content->points base-content))
|
||||||
|
|
||||||
content
|
content
|
||||||
(path/apply-content-modifiers base-content content-modifiers)
|
(mf/with-memo [base-content content-modifiers]
|
||||||
|
(path/apply-content-modifiers base-content content-modifiers))
|
||||||
|
|
||||||
content-points
|
content-points
|
||||||
(mf/with-memo [content]
|
(mf/with-memo [content]
|
||||||
|
@ -295,37 +295,37 @@
|
||||||
point->base (->> (map hash-map content-points base-points) (reduce merge))
|
point->base (->> (map hash-map content-points base-points) (reduce merge))
|
||||||
base->point (map-invert point->base)
|
base->point (map-invert point->base)
|
||||||
|
|
||||||
points (into #{} content-points)
|
points
|
||||||
|
(mf/with-memo [content-points]
|
||||||
|
(into #{} content-points))
|
||||||
|
|
||||||
last-p (->> content last path.segment/get-point)
|
last-p (->> content last path.segment/get-point)
|
||||||
handlers (path.segment/content->handlers content)
|
|
||||||
|
|
||||||
is-path-start (not (some? last-point))
|
handlers
|
||||||
|
(mf/with-memo [content]
|
||||||
|
(path.segment/content->handlers content))
|
||||||
|
|
||||||
|
is-path-start
|
||||||
|
(not (some? last-point))
|
||||||
|
|
||||||
show-snap?
|
show-snap?
|
||||||
(and ^boolean snap-toggled
|
(and ^boolean snap-toggled
|
||||||
(or (some? drag-handler)
|
(or (some? drag-handler)
|
||||||
(some? preview)
|
(some? preview)
|
||||||
(some? moving-handler)
|
(some? moving-handler)
|
||||||
moving-nodes))
|
moving-nodes))]
|
||||||
|
|
||||||
handle-double-click-outside
|
(mf/with-layout-effect [edit-mode]
|
||||||
(fn [_]
|
(let [key (events/listen (dom/get-root) "dblclick"
|
||||||
(when (= edit-mode :move)
|
#(when (= edit-mode :move)
|
||||||
(st/emit! :interrupt)))]
|
(st/emit! :interrupt)))]
|
||||||
|
#(events/unlistenByKey key)))
|
||||||
(mf/use-layout-effect
|
|
||||||
(mf/deps edit-mode)
|
|
||||||
(fn []
|
|
||||||
(let [keys [(events/listen (dom/get-root) EventType.DBLCLICK handle-double-click-outside)]]
|
|
||||||
#(doseq [key keys]
|
|
||||||
(events/unlistenByKey key)))))
|
|
||||||
|
|
||||||
(hooks/use-stream
|
(hooks/use-stream
|
||||||
ms/mouse-position
|
ms/mouse-position
|
||||||
(mf/deps shape zoom)
|
(mf/deps base-content zoom)
|
||||||
(fn [position]
|
(fn [position]
|
||||||
(when-let [point (path.segment/path-closest-point shape position)]
|
(when-let [point (path.segment/closest-point base-content position)]
|
||||||
(reset! hover-point (when (< (gpt/distance position point) (/ 10 zoom)) point)))))
|
(reset! hover-point (when (< (gpt/distance position point) (/ 10 zoom)) point)))))
|
||||||
|
|
||||||
[:g.path-editor {:ref editor-ref}
|
[:g.path-editor {:ref editor-ref}
|
||||||
|
@ -353,31 +353,45 @@
|
||||||
:is-start-path is-path-start
|
:is-start-path is-path-start
|
||||||
:zoom zoom}]])
|
:zoom zoom}]])
|
||||||
|
|
||||||
(for [[index position] (d/enumerate points)]
|
(for [position points]
|
||||||
(let [show-handler?
|
(let [pos-x (dm/get-prop position :x)
|
||||||
|
pos-y (dm/get-prop position :y)
|
||||||
|
|
||||||
|
show-handler?
|
||||||
(fn [[index prefix]]
|
(fn [[index prefix]]
|
||||||
|
;; FIXME: handler->point is executed twice for each
|
||||||
|
;; render, this can be optimized
|
||||||
(let [handler-position (path.segment/handler->point content index prefix)]
|
(let [handler-position (path.segment/handler->point content index prefix)]
|
||||||
(not= position handler-position)))
|
(not= position handler-position)))
|
||||||
|
|
||||||
pos-handlers (get handlers position)
|
position-handlers
|
||||||
point-selected? (contains? selected-points (get point->base position))
|
(->> (get handlers position)
|
||||||
point-hover? (contains? hover-points (get point->base position))
|
(filter show-handler?)
|
||||||
is-last (= last-point (get point->base position))
|
(not-empty))
|
||||||
|
|
||||||
pos-handlers (->> pos-handlers (filter show-handler?))
|
point-selected?
|
||||||
is-curve (boolean (seq pos-handlers))]
|
(contains? selected-points (get point->base position))
|
||||||
|
|
||||||
[:g.path-node {:key (dm/str index "-" (:x position) "-" (:y position))}
|
point-hover?
|
||||||
|
(contains? hover-points (get point->base position))
|
||||||
|
|
||||||
|
is-last
|
||||||
|
(= last-point (get point->base position))
|
||||||
|
|
||||||
|
is-curve
|
||||||
|
(boolean position-handlers)]
|
||||||
|
|
||||||
|
[:g.path-node {:key (dm/str pos-x "-" pos-y)}
|
||||||
[:g.point-handlers {:pointer-events (when (= edit-mode :draw) "none")}
|
[:g.point-handlers {:pointer-events (when (= edit-mode :draw) "none")}
|
||||||
(for [[hindex prefix] pos-handlers]
|
(for [[hindex prefix] position-handlers]
|
||||||
(let [handler-position (path.segment/handler->point content hindex prefix)
|
(let [handler-position (path.segment/handler->point content hindex prefix)
|
||||||
handler-hover? (contains? hover-handlers [hindex prefix])
|
handler-hover? (contains? hover-handlers [hindex prefix])
|
||||||
moving-handler? (= handler-position moving-handler)
|
moving-handler? (= handler-position moving-handler)
|
||||||
matching-handler? (matching-handler? content position pos-handlers)]
|
matching-handler? (matching-handler? content position position-handlers)]
|
||||||
|
|
||||||
(when (and position handler-position)
|
(when (and position handler-position)
|
||||||
[:> path-handler*
|
[:> path-handler*
|
||||||
{:key (dm/str (dm/str index "-" (:x position) "-" (:y position)) "-" hindex "-" (d/name prefix))
|
{:key (dm/str hindex "-" (d/name prefix))
|
||||||
:point position
|
:point position
|
||||||
:handler handler-position
|
:handler handler-position
|
||||||
:index hindex
|
:index hindex
|
||||||
|
@ -386,6 +400,7 @@
|
||||||
:is-hover handler-hover?
|
:is-hover handler-hover?
|
||||||
:snap-angle (and moving-handler? matching-handler?)
|
:snap-angle (and moving-handler? matching-handler?)
|
||||||
:edit-mode edit-mode}])))]
|
:edit-mode edit-mode}])))]
|
||||||
|
|
||||||
[:> path-point* {:position position
|
[:> path-point* {:position position
|
||||||
:zoom zoom
|
:zoom zoom
|
||||||
:edit-mode edit-mode
|
:edit-mode edit-mode
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue