Fix stage zoom anchoring and continuous passepartout shading
This commit is contained in:
parent
e5b61bfcdd
commit
f2fc261221
3 changed files with 40 additions and 16 deletions
|
|
@ -179,7 +179,7 @@
|
||||||
(defn stage-controls []
|
(defn stage-controls []
|
||||||
(let [{:keys [opacity]} @(rf/subscribe [::mat])]
|
(let [{:keys [opacity]} @(rf/subscribe [::mat])]
|
||||||
[:<>
|
[:<>
|
||||||
[:button {:on-click fit-stage! :title "Fit stage and surrounding workspace in view"} "fit"]
|
[:button {:on-click fit-stage! :title "Fit stage in view"} "fit"]
|
||||||
[:details.passepartout-controls
|
[:details.passepartout-controls
|
||||||
[:summary "passepartout"]
|
[:summary "passepartout"]
|
||||||
[:div.view-popout
|
[:div.view-popout
|
||||||
|
|
|
||||||
|
|
@ -614,8 +614,6 @@
|
||||||
(reset! dragging nil) (reset! marquee nil)
|
(reset! dragging nil) (reset! marquee nil)
|
||||||
(reset! painting nil) (player/stroke! nil)
|
(reset! painting nil) (player/stroke! nil)
|
||||||
(let-go! false))}
|
(let-go! false))}
|
||||||
[:path {:d (str "M" (- w) " " (- h) "h" (* 3 w) "v" (* 3 h) "h" (* -3 w) "z M0 0v" h "h" w "v" (- h) "z")
|
|
||||||
:fill "#000" :fill-rule "evenodd" :opacity opacity :pointer-events "none"}]
|
|
||||||
[ghost]
|
[ghost]
|
||||||
(when (seq selected-pts)
|
(when (seq selected-pts)
|
||||||
[:polygon.selected-paint-outline
|
[:polygon.selected-paint-outline
|
||||||
|
|
@ -637,29 +635,48 @@
|
||||||
|
|
||||||
(defonce space-held? (atom false))
|
(defonce space-held? (atom false))
|
||||||
(defonce pan (atom nil))
|
(defonce pan (atom nil))
|
||||||
|
(defn- stage-key-target? [target]
|
||||||
|
(and (.closest target ".stage-area")
|
||||||
|
(not (.closest target "input, textarea, select, button, a, summary, [role='button']"))
|
||||||
|
(not (.-isContentEditable target))))
|
||||||
|
|
||||||
(defonce navigation-keys
|
(defonce navigation-keys
|
||||||
(when (exists? js/window)
|
(when (exists? js/window)
|
||||||
(.addEventListener js/window "keydown"
|
(.addEventListener js/window "keydown"
|
||||||
(fn [e] (when (and (= "Space" (.-code e))
|
(fn [e]
|
||||||
(not (#{"INPUT" "TEXTAREA" "SELECT"} (.-tagName (.-target e)))) )
|
(when (and (= "Space" (.-code e))
|
||||||
(.preventDefault e) (reset! space-held? true))))
|
(not (or (.-ctrlKey e) (.-metaKey e) (.-altKey e)))
|
||||||
|
(stage-key-target? (.-target e)))
|
||||||
|
(.preventDefault e)
|
||||||
|
(reset! space-held? true))))
|
||||||
(.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))
|
(defonce pinch-start-zoom (atom nil))
|
||||||
|
(defonce pending-zoom (atom nil))
|
||||||
|
|
||||||
(defn- zoom-at! [el client-x client-y scale]
|
(defn- zoom-at! [el client-x client-y scale]
|
||||||
|
(let [wrap (.querySelector el ".stage-wrap")
|
||||||
|
next (max 0.1 (min 16 scale))
|
||||||
|
pending @pending-zoom]
|
||||||
|
;; Retain the anchor from the layout before this batch of events. React
|
||||||
|
;; may not have committed the new dimensions until the animation frame.
|
||||||
|
(when-not pending
|
||||||
(let [z @(rf/subscribe [::layout/zoom :stage])
|
(let [z @(rf/subscribe [::layout/zoom :stage])
|
||||||
wrap (.querySelector el ".stage-wrap")
|
box (.getBoundingClientRect wrap)]
|
||||||
wb (.getBoundingClientRect wrap)
|
(reset! pending-zoom {:x (/ (- client-x (.-left box)) z)
|
||||||
x (- client-x (.-left wb)) y (- client-y (.-top wb))
|
:y (/ (- client-y (.-top box)) z)})))
|
||||||
next (max 0.1 (min 16 scale))]
|
(swap! pending-zoom assoc :scale next :client-x client-x :client-y client-y)
|
||||||
(rf/dispatch-sync [::layout/set :stage next])
|
(rf/dispatch-sync [::layout/set :stage next])
|
||||||
|
(when-not pending
|
||||||
(js/requestAnimationFrame
|
(js/requestAnimationFrame
|
||||||
(fn []
|
(fn []
|
||||||
(let [nb (.getBoundingClientRect wrap)]
|
(r/flush)
|
||||||
(set! (.-scrollLeft el) (+ (.-scrollLeft el) (- (+ (.-left nb) (* x (/ next z))) client-x)))
|
(let [{:keys [x y scale client-x client-y]} @pending-zoom
|
||||||
(set! (.-scrollTop el) (+ (.-scrollTop el) (- (+ (.-top nb) (* y (/ next z))) client-y))))))))
|
box (.getBoundingClientRect wrap)]
|
||||||
|
(reset! pending-zoom nil)
|
||||||
|
(set! (.-scrollLeft el) (+ (.-scrollLeft el) (- (+ (.-left box) (* x scale)) client-x)))
|
||||||
|
(set! (.-scrollTop el) (+ (.-scrollTop el) (- (+ (.-top box) (* y scale)) client-y)))))))))
|
||||||
|
|
||||||
(defn- navigation []
|
(defn- navigation []
|
||||||
{:title "Two-finger scroll to pan · Pinch or ⌘/Ctrl-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"
|
||||||
|
|
@ -748,6 +765,7 @@
|
||||||
:height (str (* zoom h) "px")}}]
|
:height (str (* zoom h) "px")}}]
|
||||||
[:canvas.tracing {:ref #(tracing/set-canvas! %)
|
[:canvas.tracing {:ref #(tracing/set-canvas! %)
|
||||||
:width (* zoom w) :height (* zoom h)}]
|
:width (* zoom w) :height (* zoom h)}]
|
||||||
|
[:div.stage-shade {:style {:box-shadow (str "0 0 0 100vmax rgba(0,0,0," opacity ")")}}]
|
||||||
[:div.stage-overlay-wrap [overlay w h zoom opacity]]]
|
[:div.stage-overlay-wrap [overlay w h zoom opacity]]]
|
||||||
(when destination-name
|
(when destination-name
|
||||||
[:div.stage-target "creating in " [:strong destination-name]])
|
[:div.stage-target "creating in " [:strong destination-name]])
|
||||||
|
|
|
||||||
|
|
@ -879,6 +879,12 @@ button.share-button:hover, button.share-button.on { filter: brightness(1.1); }
|
||||||
left: -100%; top: -100%;
|
left: -100%; top: -100%;
|
||||||
width: 300%; height: 300%;
|
width: 300%; height: 300%;
|
||||||
}
|
}
|
||||||
|
.stage-shade {
|
||||||
|
position: absolute;
|
||||||
|
inset: 0;
|
||||||
|
pointer-events: none;
|
||||||
|
outline: 1px solid #aaa;
|
||||||
|
}
|
||||||
/* The footage traced over: a reference above the picture, never part of it. */
|
/* The footage traced over: a reference above the picture, never part of it. */
|
||||||
.tracing { position: absolute; inset: 0; pointer-events: none; }
|
.tracing { position: absolute; inset: 0; pointer-events: none; }
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue