Pan with trackpad scrolling and zoom with pinch gestures
This commit is contained in:
parent
484b4f1698
commit
6df315b73d
1 changed files with 40 additions and 12 deletions
|
|
@ -648,24 +648,52 @@
|
||||||
(.addEventListener js/window "keyup" #(when (= "Space" (.-code %)) (reset! space-held? false)))
|
(.addEventListener js/window "keyup" #(when (= "Space" (.-code %)) (reset! space-held? false)))
|
||||||
(.addEventListener js/window "blur" #(do (reset! space-held? false) (reset! pan nil)))))
|
(.addEventListener js/window "blur" #(do (reset! space-held? false) (reset! pan nil)))))
|
||||||
|
|
||||||
|
(defonce pinch-start-zoom (atom nil))
|
||||||
|
|
||||||
|
(defn- zoom-at! [el client-x client-y scale]
|
||||||
|
(let [z @(rf/subscribe [::layout/zoom :stage])
|
||||||
|
wrap (.querySelector el ".stage-wrap")
|
||||||
|
wb (.getBoundingClientRect wrap)
|
||||||
|
x (- client-x (.-left wb)) y (- client-y (.-top wb))
|
||||||
|
next (max 0.1 (min 16 scale))]
|
||||||
|
(rf/dispatch-sync [::layout/set :stage next])
|
||||||
|
(js/requestAnimationFrame
|
||||||
|
(fn []
|
||||||
|
(let [nb (.getBoundingClientRect wrap)]
|
||||||
|
(set! (.-scrollLeft el) (+ (.-scrollLeft el) (- (+ (.-left nb) (* x (/ next z))) client-x)))
|
||||||
|
(set! (.-scrollTop el) (+ (.-scrollTop el) (- (+ (.-top nb) (* y (/ next z))) client-y))))))))
|
||||||
|
|
||||||
(defn- navigation []
|
(defn- navigation []
|
||||||
{:title "Wheel to zoom · Space-drag or middle-drag to pan"
|
{:title "Two-finger scroll to pan · Pinch or ⌘/Ctrl-wheel to zoom · Space-drag or middle-drag to pan"
|
||||||
:ref (fn [el]
|
:ref (fn [el]
|
||||||
(when el
|
(when el
|
||||||
(set! (.-onwheel el)
|
(set! (.-onwheel el)
|
||||||
(fn [e]
|
(fn [e]
|
||||||
(.preventDefault e)
|
(.preventDefault e)
|
||||||
(let [z @(rf/subscribe [::layout/zoom :stage])
|
;; Chromium and Firefox deliver trackpad pinch as Ctrl-wheel.
|
||||||
wrap (.querySelector el ".stage-wrap")
|
;; Ordinary scrolling pans without guessing the input device.
|
||||||
wb (.getBoundingClientRect wrap)
|
(when-not @pinch-start-zoom
|
||||||
x (- (.-clientX e) (.-left wb)) y (- (.-clientY e) (.-top wb))
|
(let [unit (case (.-deltaMode e) 1 16 2 (.-clientHeight el) 1)
|
||||||
next (max 0.1 (min 16 (* z (js/Math.exp (* -0.002 (.-deltaY e))))))]
|
dx (* unit (.-deltaX e)) dy (* unit (.-deltaY e))]
|
||||||
(rf/dispatch-sync [::layout/set :stage next])
|
(if (or (.-ctrlKey e) (.-metaKey e))
|
||||||
(js/requestAnimationFrame
|
(zoom-at! el (.-clientX e) (.-clientY e)
|
||||||
(fn []
|
(* @(rf/subscribe [::layout/zoom :stage])
|
||||||
(let [nb (.getBoundingClientRect wrap)]
|
(js/Math.exp (* (if (.-ctrlKey e) -0.01 -0.002) dy))))
|
||||||
(set! (.-scrollLeft el) (+ (.-scrollLeft el) (- (+ (.-left nb) (* x (/ next z))) (.-clientX e))))
|
(do
|
||||||
(set! (.-scrollTop el) (+ (.-scrollTop el) (- (+ (.-top nb) (* y (/ next z))) (.-clientY e)))))))))))
|
(set! (.-scrollLeft el) (+ (.-scrollLeft el) dx))
|
||||||
|
(set! (.-scrollTop el) (+ (.-scrollTop el) dy))))))))
|
||||||
|
;; Safari exposes pinch as GestureEvents, with cumulative scale.
|
||||||
|
(set! (.-ongesturestart el)
|
||||||
|
(fn [e]
|
||||||
|
(.preventDefault e)
|
||||||
|
(reset! pinch-start-zoom @(rf/subscribe [::layout/zoom :stage]))))
|
||||||
|
(set! (.-ongesturechange el)
|
||||||
|
(fn [e]
|
||||||
|
(.preventDefault e)
|
||||||
|
(when-let [z @pinch-start-zoom]
|
||||||
|
(zoom-at! el (.-clientX e) (.-clientY e) (* z (.-scale e))))))
|
||||||
|
(set! (.-ongestureend el)
|
||||||
|
(fn [e] (.preventDefault e) (reset! pinch-start-zoom nil))))
|
||||||
nil)
|
nil)
|
||||||
:on-pointer-down-capture
|
:on-pointer-down-capture
|
||||||
(fn [e] (when (or (= 1 (.-button e)) (and (= 0 (.-button e)) @space-held?))
|
(fn [e] (when (or (= 1 (.-button e)) (and (= 0 (.-button e)) @space-held?))
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue