mirror of
https://github.com/penpot/penpot.git
synced 2026-09-13 15:38:38 +00:00
🎉 Events enhancements (#9310)
* 🎉 Coalesce viewport pointermove into one PointerEvent * 🎉 Skip worker hover selection query during transform * 🎉 Coalesce snap X/Y into one worker query-snap-xy
This commit is contained in:
parent
e948020886
commit
c794e0ed73
@ -177,12 +177,12 @@
|
|||||||
(rx/of #(-> % (assoc-in [:workspace-local :panning] true)))
|
(rx/of #(-> % (assoc-in [:workspace-local :panning] true)))
|
||||||
(->> stream
|
(->> stream
|
||||||
(rx/filter mse/pointer-event?)
|
(rx/filter mse/pointer-event?)
|
||||||
(rx/filter #(= :delta (:source %)))
|
(rx/filter #(some? (mse/get-pointer-movement %)))
|
||||||
(rx/take-until stopper)
|
(rx/take-until stopper)
|
||||||
;; Some events are executed in synchronous way like panning with backspace pressed
|
;; Some events are executed in synchronous way like panning with backspace pressed
|
||||||
(rx/observe-on :af)
|
(rx/observe-on :af)
|
||||||
(rx/map (fn [event]
|
(rx/map (fn [event]
|
||||||
(let [delta (dm/get-prop event :pt)]
|
(let [delta (mse/get-pointer-movement event)]
|
||||||
(update-viewport-position {:x #(- % (/ (:x delta) zoom))
|
(update-viewport-position {:x #(- % (/ (:x delta) zoom))
|
||||||
:y #(- % (/ (:y delta) zoom))})))))))))))
|
:y #(- % (/ (:y delta) zoom))})))))))))))
|
||||||
|
|
||||||
|
|||||||
@ -160,8 +160,8 @@
|
|||||||
(rx/of #(-> % (assoc-in [:workspace-local :zooming] true)))
|
(rx/of #(-> % (assoc-in [:workspace-local :zooming] true)))
|
||||||
(->> stream
|
(->> stream
|
||||||
(rx/filter mse/pointer-event?)
|
(rx/filter mse/pointer-event?)
|
||||||
(rx/filter #(= :delta (:source %)))
|
(rx/filter #(some? (mse/get-pointer-movement %)))
|
||||||
(rx/map :pt)
|
(rx/map mse/get-pointer-movement)
|
||||||
(rx/take-until stopper)
|
(rx/take-until stopper)
|
||||||
(rx/map (fn [delta]
|
(rx/map (fn [delta]
|
||||||
(let [scale (+ 1 (/ (:y delta) 100))] ;; this number may be adjusted after user testing
|
(let [scale (+ 1 (/ (:y delta) 100))] ;; this number may be adjusted after user testing
|
||||||
|
|||||||
@ -93,23 +93,12 @@
|
|||||||
(rx/take 1)
|
(rx/take 1)
|
||||||
(rx/map (remove-from-snap-points remove-snap?)))))
|
(rx/map (remove-from-snap-points remove-snap?)))))
|
||||||
|
|
||||||
(defn- search-snap
|
(defn- snap-accuracy-ranges
|
||||||
[page-id frame-id points coord remove-snap? zoom]
|
[points coord zoom]
|
||||||
(let [snap-accuracy (/ snap-accuracy zoom)
|
(let [acc (/ snap-accuracy zoom)]
|
||||||
ranges (->> points
|
(->> points
|
||||||
(map coord)
|
(map coord)
|
||||||
(mapv #(vector (- % snap-accuracy)
|
(mapv #(vector (- % acc) (+ % acc))))))
|
||||||
(+ % snap-accuracy))))
|
|
||||||
vbox @refs/vbox]
|
|
||||||
(->> (mw/ask! {:cmd :index/query-snap
|
|
||||||
:page-id page-id
|
|
||||||
:frame-id frame-id
|
|
||||||
:axis coord
|
|
||||||
:bounds vbox
|
|
||||||
:ranges ranges})
|
|
||||||
(rx/take 1)
|
|
||||||
(rx/map (remove-from-snap-points remove-snap?))
|
|
||||||
(rx/map (get-min-distance-snap points coord)))))
|
|
||||||
|
|
||||||
(defn snap->vector [[[from-x to-x] [from-y to-y]]]
|
(defn snap->vector [[[from-x to-x] [from-y to-y]]]
|
||||||
(when (or from-x to-x from-y to-y)
|
(when (or from-x to-x from-y to-y)
|
||||||
@ -119,10 +108,21 @@
|
|||||||
|
|
||||||
(defn- closest-snap
|
(defn- closest-snap
|
||||||
[page-id frame-id points remove-snap? zoom]
|
[page-id frame-id points remove-snap? zoom]
|
||||||
(let [snap-x (search-snap page-id frame-id points :x remove-snap? zoom)
|
(let [vbox @refs/vbox
|
||||||
snap-y (search-snap page-id frame-id points :y remove-snap? zoom)]
|
x-ranges (snap-accuracy-ranges points :x zoom)
|
||||||
(->> (rx/combine-latest snap-x snap-y)
|
y-ranges (snap-accuracy-ranges points :y zoom)
|
||||||
(rx/map snap->vector))))
|
rm (remove-from-snap-points remove-snap?)
|
||||||
|
gmx (get-min-distance-snap points :x)
|
||||||
|
gmy (get-min-distance-snap points :y)]
|
||||||
|
(->> (mw/ask! {:cmd :index/query-snap-xy
|
||||||
|
:page-id page-id
|
||||||
|
:frame-id frame-id
|
||||||
|
:bounds vbox
|
||||||
|
:x-ranges x-ranges
|
||||||
|
:y-ranges y-ranges})
|
||||||
|
(rx/take 1)
|
||||||
|
(rx/map (fn [{:keys [x y]}]
|
||||||
|
(snap->vector [(gmx (rm x)) (gmy (rm y))]))))))
|
||||||
|
|
||||||
(defn sr-distance [coord sr1 sr2]
|
(defn sr-distance [coord sr1 sr2]
|
||||||
(let [c1 (if (= coord :x) :x1 :y1)
|
(let [c1 (if (= coord :x) :x1 :y1)
|
||||||
|
|||||||
@ -360,16 +360,14 @@
|
|||||||
|
|
||||||
(rx/push! move-stream pt)
|
(rx/push! move-stream pt)
|
||||||
(reset! last-position raw-pt)
|
(reset! last-position raw-pt)
|
||||||
(st/emit! (mse/->PointerEvent :delta delta
|
;; Single store emit per move: viewport `pt` + `movement` (old :delta `pt`) avoids
|
||||||
(kbd/ctrl? event)
|
;; doubling Potok + `st/stream` work on every pointermove.
|
||||||
(kbd/shift? event)
|
|
||||||
(kbd/alt? event)
|
|
||||||
(kbd/meta? event)))
|
|
||||||
(st/emit! (mse/->PointerEvent :viewport pt
|
(st/emit! (mse/->PointerEvent :viewport pt
|
||||||
(kbd/ctrl? event)
|
(kbd/ctrl? event)
|
||||||
(kbd/shift? event)
|
(kbd/shift? event)
|
||||||
(kbd/alt? event)
|
(kbd/alt? event)
|
||||||
(kbd/meta? event))))))))
|
(kbd/meta? event)
|
||||||
|
delta)))))))
|
||||||
|
|
||||||
(defn- schedule-zoom!
|
(defn- schedule-zoom!
|
||||||
"Accumulate a compound zoom scale and a cursor point into `state`, scheduling
|
"Accumulate a compound zoom scale and a cursor point into `state`, scheduling
|
||||||
|
|||||||
@ -181,7 +181,6 @@
|
|||||||
(let [;; We use ref so we don't recreate the stream on a change
|
(let [;; We use ref so we don't recreate the stream on a change
|
||||||
zoom-ref (mf/use-ref zoom)
|
zoom-ref (mf/use-ref zoom)
|
||||||
mod-ref (mf/use-ref @mod?)
|
mod-ref (mf/use-ref @mod?)
|
||||||
transform-ref (mf/use-ref nil)
|
|
||||||
selected-ref (mf/use-ref selected)
|
selected-ref (mf/use-ref selected)
|
||||||
hover-disabled-ref (mf/use-ref hover-disabled?)
|
hover-disabled-ref (mf/use-ref hover-disabled?)
|
||||||
focus-ref (mf/use-ref focus)
|
focus-ref (mf/use-ref focus)
|
||||||
@ -191,13 +190,15 @@
|
|||||||
|
|
||||||
query-point
|
query-point
|
||||||
(mf/use-callback
|
(mf/use-callback
|
||||||
(mf/deps page-id)
|
(mf/deps page-id transform)
|
||||||
(fn [point]
|
(fn [point]
|
||||||
(let [zoom (mf/ref-val zoom-ref)
|
(let [zoom (mf/ref-val zoom-ref)
|
||||||
rect (grc/center->rect point (/ 5 zoom))]
|
rect (grc/center->rect point (/ 5 zoom))]
|
||||||
|
|
||||||
(if (mf/ref-val hover-disabled-ref)
|
(if (or (mf/ref-val hover-disabled-ref)
|
||||||
(rx/of nil)
|
(some? transform))
|
||||||
|
;; No index query while dragging/transforming: snap already hits the worker.
|
||||||
|
(rx/of [])
|
||||||
(->> (mw/ask-buffered!
|
(->> (mw/ask-buffered!
|
||||||
{:cmd :index/query-selection
|
{:cmd :index/query-selection
|
||||||
:page-id page-id
|
:page-id page-id
|
||||||
@ -222,7 +223,6 @@
|
|||||||
|
|
||||||
(->> move-stream
|
(->> move-stream
|
||||||
(rx/tap #(reset! last-point-ref %))
|
(rx/tap #(reset! last-point-ref %))
|
||||||
;; When transforming shapes we stop querying the worker
|
|
||||||
(rx/merge-map query-point)))
|
(rx/merge-map query-point)))
|
||||||
|
|
||||||
(rx/share)))
|
(rx/share)))
|
||||||
@ -231,10 +231,6 @@
|
|||||||
(->> over-shapes-stream (rx/debounce 50))]
|
(->> over-shapes-stream (rx/debounce 50))]
|
||||||
|
|
||||||
;; Refresh the refs on a value change
|
;; Refresh the refs on a value change
|
||||||
(mf/use-effect
|
|
||||||
(mf/deps transform)
|
|
||||||
#(mf/set-ref-val! transform-ref transform))
|
|
||||||
|
|
||||||
(mf/use-effect
|
(mf/use-effect
|
||||||
(mf/deps zoom)
|
(mf/deps zoom)
|
||||||
#(mf/set-ref-val! zoom-ref zoom))
|
#(mf/set-ref-val! zoom-ref zoom))
|
||||||
|
|||||||
@ -9,7 +9,10 @@
|
|||||||
[beicon.v2.core :as rx]))
|
[beicon.v2.core :as rx]))
|
||||||
|
|
||||||
(defrecord MouseEvent [type ctrl shift alt meta])
|
(defrecord MouseEvent [type ctrl shift alt meta])
|
||||||
(defrecord PointerEvent [source pt ctrl shift alt meta])
|
;; `movement` — optional delta (client/window space) for the same tick as `pt`.
|
||||||
|
;; Used so viewport `pointermove` can emit once (`source` :viewport) while pan/zoom
|
||||||
|
;; still observe displacement without a second Potok emit.
|
||||||
|
(defrecord PointerEvent [source pt ctrl shift alt meta movement])
|
||||||
(defrecord ScrollEvent [point])
|
(defrecord ScrollEvent [point])
|
||||||
(defrecord BlurEvent [])
|
(defrecord BlurEvent [])
|
||||||
|
|
||||||
@ -53,6 +56,10 @@
|
|||||||
[^PointerEvent ev]
|
[^PointerEvent ev]
|
||||||
(.-pt ev))
|
(.-pt ev))
|
||||||
|
|
||||||
|
(defn get-pointer-movement
|
||||||
|
[^PointerEvent ev]
|
||||||
|
(.-movement ev))
|
||||||
|
|
||||||
(defn get-pointer-ctrl-mod
|
(defn get-pointer-ctrl-mod
|
||||||
[^PointerEvent ev]
|
[^PointerEvent ev]
|
||||||
(.-ctrl ev))
|
(.-ctrl ev))
|
||||||
|
|||||||
@ -63,23 +63,35 @@
|
|||||||
(log/dbg :hint "page index updated" :id page-id :elapsed elapsed ::log/sync? true))))
|
(log/dbg :hint "page index updated" :id page-id :elapsed elapsed ::log/sync? true))))
|
||||||
nil))
|
nil))
|
||||||
|
|
||||||
|
(defn- run-query-snap
|
||||||
|
[index page-id frame-id axis ranges bounds]
|
||||||
|
(let [match-bounds?
|
||||||
|
(fn [[_ data]]
|
||||||
|
(some #(or (= :guide (:type %))
|
||||||
|
(= :layout (:type %))
|
||||||
|
(grc/contains-point? bounds (:pt %))) data))
|
||||||
|
|
||||||
|
xform
|
||||||
|
(comp (mapcat #(snap/query index page-id frame-id axis %))
|
||||||
|
(distinct)
|
||||||
|
(filter match-bounds?))]
|
||||||
|
(into [] xform ranges)))
|
||||||
|
|
||||||
;; FIXME: schema
|
;; FIXME: schema
|
||||||
(defmethod impl/handler :index/query-snap
|
(defmethod impl/handler :index/query-snap
|
||||||
[{:keys [page-id frame-id axis ranges bounds] :as message}]
|
[{:keys [page-id frame-id axis ranges bounds]}]
|
||||||
(if-let [index (get @state ::snap)]
|
(if-let [index (get @state ::snap)]
|
||||||
(let [match-bounds?
|
(run-query-snap index page-id frame-id axis ranges bounds)
|
||||||
(fn [[_ data]]
|
|
||||||
(some #(or (= :guide (:type %))
|
|
||||||
(= :layout (:type %))
|
|
||||||
(grc/contains-point? bounds (:pt %))) data))
|
|
||||||
|
|
||||||
xform
|
|
||||||
(comp (mapcat #(snap/query index page-id frame-id axis %))
|
|
||||||
(distinct)
|
|
||||||
(filter match-bounds?))]
|
|
||||||
(into [] xform ranges))
|
|
||||||
[]))
|
[]))
|
||||||
|
|
||||||
|
;; Single round-trip for X+Y snap used by `app.main.snap/closest-snap` (e.g. shape drag).
|
||||||
|
(defmethod impl/handler :index/query-snap-xy
|
||||||
|
[{:keys [page-id frame-id bounds x-ranges y-ranges]}]
|
||||||
|
(if-let [index (get @state ::snap)]
|
||||||
|
{:x (run-query-snap index page-id frame-id :x x-ranges bounds)
|
||||||
|
:y (run-query-snap index page-id frame-id :y y-ranges bounds)}
|
||||||
|
{:x [] :y []}))
|
||||||
|
|
||||||
;; FIXME: schema
|
;; FIXME: schema
|
||||||
|
|
||||||
(defmethod impl/handler :index/query-selection
|
(defmethod impl/handler :index/query-selection
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user