🎉 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:
Alejandro Alonso 2026-05-04 17:57:00 +02:00 committed by GitHub
parent e948020886
commit c794e0ed73
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
7 changed files with 66 additions and 53 deletions

View File

@ -177,12 +177,12 @@
(rx/of #(-> % (assoc-in [:workspace-local :panning] true)))
(->> stream
(rx/filter mse/pointer-event?)
(rx/filter #(= :delta (:source %)))
(rx/filter #(some? (mse/get-pointer-movement %)))
(rx/take-until stopper)
;; Some events are executed in synchronous way like panning with backspace pressed
(rx/observe-on :af)
(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))
:y #(- % (/ (:y delta) zoom))})))))))))))

View File

@ -160,8 +160,8 @@
(rx/of #(-> % (assoc-in [:workspace-local :zooming] true)))
(->> stream
(rx/filter mse/pointer-event?)
(rx/filter #(= :delta (:source %)))
(rx/map :pt)
(rx/filter #(some? (mse/get-pointer-movement %)))
(rx/map mse/get-pointer-movement)
(rx/take-until stopper)
(rx/map (fn [delta]
(let [scale (+ 1 (/ (:y delta) 100))] ;; this number may be adjusted after user testing

View File

@ -93,23 +93,12 @@
(rx/take 1)
(rx/map (remove-from-snap-points remove-snap?)))))
(defn- search-snap
[page-id frame-id points coord remove-snap? zoom]
(let [snap-accuracy (/ snap-accuracy zoom)
ranges (->> points
(map coord)
(mapv #(vector (- % snap-accuracy)
(+ % 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-accuracy-ranges
[points coord zoom]
(let [acc (/ snap-accuracy zoom)]
(->> points
(map coord)
(mapv #(vector (- % acc) (+ % acc))))))
(defn snap->vector [[[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
[page-id frame-id points remove-snap? zoom]
(let [snap-x (search-snap page-id frame-id points :x remove-snap? zoom)
snap-y (search-snap page-id frame-id points :y remove-snap? zoom)]
(->> (rx/combine-latest snap-x snap-y)
(rx/map snap->vector))))
(let [vbox @refs/vbox
x-ranges (snap-accuracy-ranges points :x zoom)
y-ranges (snap-accuracy-ranges points :y zoom)
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]
(let [c1 (if (= coord :x) :x1 :y1)

View File

@ -360,16 +360,14 @@
(rx/push! move-stream pt)
(reset! last-position raw-pt)
(st/emit! (mse/->PointerEvent :delta delta
(kbd/ctrl? event)
(kbd/shift? event)
(kbd/alt? event)
(kbd/meta? event)))
;; Single store emit per move: viewport `pt` + `movement` (old :delta `pt`) avoids
;; doubling Potok + `st/stream` work on every pointermove.
(st/emit! (mse/->PointerEvent :viewport pt
(kbd/ctrl? event)
(kbd/shift? event)
(kbd/alt? event)
(kbd/meta? event))))))))
(kbd/meta? event)
delta)))))))
(defn- schedule-zoom!
"Accumulate a compound zoom scale and a cursor point into `state`, scheduling

View File

@ -181,7 +181,6 @@
(let [;; We use ref so we don't recreate the stream on a change
zoom-ref (mf/use-ref zoom)
mod-ref (mf/use-ref @mod?)
transform-ref (mf/use-ref nil)
selected-ref (mf/use-ref selected)
hover-disabled-ref (mf/use-ref hover-disabled?)
focus-ref (mf/use-ref focus)
@ -191,13 +190,15 @@
query-point
(mf/use-callback
(mf/deps page-id)
(mf/deps page-id transform)
(fn [point]
(let [zoom (mf/ref-val zoom-ref)
rect (grc/center->rect point (/ 5 zoom))]
(if (mf/ref-val hover-disabled-ref)
(rx/of nil)
(if (or (mf/ref-val hover-disabled-ref)
(some? transform))
;; No index query while dragging/transforming: snap already hits the worker.
(rx/of [])
(->> (mw/ask-buffered!
{:cmd :index/query-selection
:page-id page-id
@ -222,7 +223,6 @@
(->> move-stream
(rx/tap #(reset! last-point-ref %))
;; When transforming shapes we stop querying the worker
(rx/merge-map query-point)))
(rx/share)))
@ -231,10 +231,6 @@
(->> over-shapes-stream (rx/debounce 50))]
;; Refresh the refs on a value change
(mf/use-effect
(mf/deps transform)
#(mf/set-ref-val! transform-ref transform))
(mf/use-effect
(mf/deps zoom)
#(mf/set-ref-val! zoom-ref zoom))

View File

@ -9,7 +9,10 @@
[beicon.v2.core :as rx]))
(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 BlurEvent [])
@ -53,6 +56,10 @@
[^PointerEvent ev]
(.-pt ev))
(defn get-pointer-movement
[^PointerEvent ev]
(.-movement ev))
(defn get-pointer-ctrl-mod
[^PointerEvent ev]
(.-ctrl ev))

View File

@ -63,23 +63,35 @@
(log/dbg :hint "page index updated" :id page-id :elapsed elapsed ::log/sync? true))))
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
(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)]
(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))
(run-query-snap index page-id frame-id axis ranges bounds)
[]))
;; 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
(defmethod impl/handler :index/query-selection