Simplify stage passepartout control
This commit is contained in:
parent
981bef98f9
commit
ee603a351b
4 changed files with 25 additions and 37 deletions
|
|
@ -164,7 +164,7 @@
|
||||||
:on-click #(rf/dispatch [::set k (stepped k z false)])} "+"]]))
|
:on-click #(rf/dispatch [::set k (stepped k z false)])} "+"]]))
|
||||||
|
|
||||||
|
|
||||||
(rf/reg-sub ::mat (fn [db _] (merge {:margin 100 :opacity 0.55} (get-in db [:ui :passepartout]))))
|
(rf/reg-sub ::mat (fn [db _] (merge {:opacity 0.55} (get-in db [:ui :passepartout]))))
|
||||||
(rf/reg-event-db ::mat (fn [db [_ k v]] (assoc-in db [:ui :passepartout k] v)))
|
(rf/reg-event-db ::mat (fn [db [_ k v]] (assoc-in db [:ui :passepartout k] v)))
|
||||||
|
|
||||||
(defn fit-stage! []
|
(defn fit-stage! []
|
||||||
|
|
@ -177,17 +177,12 @@
|
||||||
(js/requestAnimationFrame #(do (set! (.-scrollLeft area) 0) (set! (.-scrollTop area) 0)))))))
|
(js/requestAnimationFrame #(do (set! (.-scrollLeft area) 0) (set! (.-scrollTop area) 0)))))))
|
||||||
|
|
||||||
(defn stage-controls []
|
(defn stage-controls []
|
||||||
(let [{:keys [margin 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 and surrounding workspace in view"} "fit"]
|
||||||
[:details.passepartout-controls
|
[:details.passepartout-controls
|
||||||
[:summary "passepartout"]
|
[:summary "passepartout"]
|
||||||
[:div.view-popout
|
[:div.view-popout
|
||||||
[:label "Outside margin (px)"
|
[:label "Passepartout"
|
||||||
[:input {:type "number" :min 0 :max 1000 :value margin
|
|
||||||
:on-change #(let [v (js/parseInt (.. % -target -value))]
|
|
||||||
(when (js/Number.isFinite v) (rf/dispatch [::mat :margin (max 0 (min 1000 v))])))}]]
|
|
||||||
[:label "Shade outside export bounds"
|
|
||||||
[:input {:type "range" :min 0 :max 1 :step 0.05 :value opacity
|
[:input {:type "range" :min 0 :max 1 :step 0.05 :value opacity
|
||||||
:on-change #(rf/dispatch [::mat :opacity (js/parseFloat (.. % -target -value))])}]]
|
:on-change #(rf/dispatch [::mat :opacity (js/parseFloat (.. % -target -value))])}]]]]]))
|
||||||
[:p "Draw outside the rectangle. Exports trim to the symbol’s dimensions."]]]]))
|
|
||||||
|
|
|
||||||
|
|
@ -261,14 +261,6 @@
|
||||||
(as-> ops (reduce #(clip/in-layer %1 target (poly (outline/join %2) {:color 0 :knock knock}))
|
(as-> ops (reduce #(clip/in-layer %1 target (poly (outline/join %2) {:color 0 :knock knock}))
|
||||||
ops rings)))))
|
ops rings)))))
|
||||||
|
|
||||||
(defn- shifted-op [op margin]
|
|
||||||
(cond-> op
|
|
||||||
(:pts op) (assoc :pts (let [pts (:pts op) n (* 2 (:n op)) shifted (js/Float64Array. n)]
|
|
||||||
(dotimes [i n] (aset shifted i (+ margin (aget pts i))))
|
|
||||||
shifted))
|
|
||||||
(:cx op) (update :cx + margin)
|
|
||||||
(:cy op) (update :cy + margin)))
|
|
||||||
|
|
||||||
(defn paint!
|
(defn paint!
|
||||||
"Resolve `f` and put it on the canvas. `ops` are consumed here and only here —
|
"Resolve `f` and put it on the canvas. `ops` are consumed here and only here —
|
||||||
the resolver reuses its point buffers between frames, so they have to be
|
the resolver reuses its point buffers between frames, so they have to be
|
||||||
|
|
@ -284,8 +276,7 @@
|
||||||
;; THE STAGE IS THE CLIP'S, not a constant. Project dimensions are
|
;; THE STAGE IS THE CLIP'S, not a constant. Project dimensions are
|
||||||
;; independent of the footage, so the size the frame is rasterised at comes
|
;; independent of the footage, so the size the frame is rasterised at comes
|
||||||
;; out of the document like everything else.
|
;; out of the document like everything else.
|
||||||
(let [margin (:margin mat 100)
|
(let [ras (raster-for width height)
|
||||||
ras (raster-for (+ width (* 2 margin)) (+ height (* 2 margin)))
|
|
||||||
{traces true picture false} (group-by #(= :trace (:kind %)) (resolver f))
|
{traces true picture false} (group-by #(= :trace (:kind %)) (resolver f))
|
||||||
;; A layer switched off, or all of them, is not on the stage at all:
|
;; A layer switched off, or all of them, is not on the stage at all:
|
||||||
;; not painted and not there to be clicked.
|
;; not painted and not there to be clicked.
|
||||||
|
|
@ -296,10 +287,10 @@
|
||||||
(swap! state assoc :ops (into (vec picture) traces))
|
(swap! state assoc :ops (into (vec picture) traces))
|
||||||
(-> ras
|
(-> ras
|
||||||
(raster/clear! bg)
|
(raster/clear! bg)
|
||||||
(raster/draw-ops! (map #(shifted-op % margin) (with-previews picture palette active))))
|
(raster/draw-ops! (with-previews picture palette active)))
|
||||||
(js/performance.mark "arthur/blit:start")
|
(js/performance.mark "arthur/blit:start")
|
||||||
(canvas/blit! canvas ras (pal/effective-ramp palette active))
|
(canvas/blit! canvas ras (pal/effective-ramp palette active))
|
||||||
(tracing/paint! traces (assoc tracing :width (+ width (* 2 margin)) :origin margin :playing? playing?) repaint!))
|
(tracing/paint! traces (assoc tracing :width width :origin 0 :playing? playing?) repaint!))
|
||||||
(js/performance.measure "arthur/resolve+draw" "arthur/paint:start" "arthur/blit:start")
|
(js/performance.measure "arthur/resolve+draw" "arthur/paint:start" "arthur/blit:start")
|
||||||
(js/performance.measure "arthur/paint" "arthur/paint:start")
|
(js/performance.measure "arthur/paint" "arthur/paint:start")
|
||||||
;; User Timing entries otherwise accumulate forever in the browser's
|
;; User Timing entries otherwise accumulate forever in the browser's
|
||||||
|
|
|
||||||
|
|
@ -32,7 +32,7 @@
|
||||||
[re-frame.core :as rf]
|
[re-frame.core :as rf]
|
||||||
[reagent.core :as r]))
|
[reagent.core :as r]))
|
||||||
|
|
||||||
;; Pointer coordinates come from the SVG transform, including the outside margin.
|
;; Pointer coordinates come from the SVG transform, in stage pixels.
|
||||||
|
|
||||||
(defn- event-point [element event]
|
(defn- event-point [element event]
|
||||||
(let [svg (if (= "svg" (.-tagName element)) element (.querySelector element "svg.paint-overlay"))
|
(let [svg (if (= "svg" (.-tagName element)) element (.querySelector element "svg.paint-overlay"))
|
||||||
|
|
@ -415,8 +415,7 @@
|
||||||
(when (and (some? c) (not (symbol/knockout? c)) (or all? (= c start)))
|
(when (and (some? c) (not (symbol/knockout? c)) (or all? (= c start)))
|
||||||
q))))
|
q))))
|
||||||
(get-in document [:symbols sid :nodes]))))
|
(get-in document [:symbols sid :nodes]))))
|
||||||
m (outline/stamp! (let [margin (:margin @(rf/subscribe [::layout/mat]))]
|
m (outline/stamp! (outline/mask (:w ctx) (:h ctx)) p p size)
|
||||||
(assoc (outline/mask (+ (:w ctx) (* 2 margin)) (+ (:h ctx) (* 2 margin))) :origin [(- margin) (- margin)])) p p size)
|
|
||||||
s (cond
|
s (cond
|
||||||
;; The brush's target is the creation target, which the player
|
;; The brush's target is the creation target, which the player
|
||||||
;; reads for itself.
|
;; reads for itself.
|
||||||
|
|
@ -499,7 +498,7 @@
|
||||||
[:circle {:class (str "first" (when (and hover (closes? draft hover)) " closing"))
|
[:circle {:class (str "first" (when (and hover (closes? draft hover)) " closing"))
|
||||||
:cx fx :cy fy :r 1.8}]])))
|
:cx fx :cy fy :r 1.8}]])))
|
||||||
|
|
||||||
(defn- overlay [w h zoom margin opacity]
|
(defn- overlay [w h zoom opacity]
|
||||||
(let [tool @(rf/subscribe [::sub/tool])
|
(let [tool @(rf/subscribe [::sub/tool])
|
||||||
draft @(rf/subscribe [::sub/draft])
|
draft @(rf/subscribe [::sub/draft])
|
||||||
hover @(rf/subscribe [::sub/hover])
|
hover @(rf/subscribe [::sub/hover])
|
||||||
|
|
@ -528,8 +527,8 @@
|
||||||
mark @marquee]
|
mark @marquee]
|
||||||
[:svg {:class (str "paint-overlay tool-" (name tool)
|
[:svg {:class (str "paint-overlay tool-" (name tool)
|
||||||
(when (and pen? hover (closes? draft hover)) " closing"))
|
(when (and pen? hover (closes? draft hover)) " closing"))
|
||||||
:width (* zoom (+ w (* 2 margin))) :height (* zoom (+ h (* 2 margin)))
|
:width (* zoom 3 w) :height (* zoom 3 h)
|
||||||
:view-box (str (- margin) " " (- margin) " " (+ w (* 2 margin)) " " (+ h (* 2 margin)))
|
:view-box (str (- w) " " (- h) " " (* 3 w) " " (* 3 h))
|
||||||
:tab-index -1
|
:tab-index -1
|
||||||
:on-pointer-down
|
:on-pointer-down
|
||||||
(fn [^js event]
|
(fn [^js event]
|
||||||
|
|
@ -615,9 +614,8 @@
|
||||||
(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" (- margin) " " (- margin) "h" (+ w (* 2 margin)) "v" (+ h (* 2 margin)) "h" (- (+ w (* 2 margin))) "z M0 0v" h "h" w "v" (- h) "z")
|
[: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"}]
|
:fill "#000" :fill-rule "evenodd" :opacity opacity :pointer-events "none"}]
|
||||||
[:rect {:x 0 :y 0 :width w :height h :fill "none" :stroke "#aaa" :vector-effect "non-scaling-stroke" :pointer-events "none"}]
|
|
||||||
[ghost]
|
[ghost]
|
||||||
(when (seq selected-pts)
|
(when (seq selected-pts)
|
||||||
[:polygon.selected-paint-outline
|
[:polygon.selected-paint-outline
|
||||||
|
|
@ -723,8 +721,7 @@
|
||||||
destination-name (when-let [sid (:sid destination)]
|
destination-name (when-let [sid (:sid destination)]
|
||||||
(clip/symbol-name clip sid))
|
(clip/symbol-name clip sid))
|
||||||
zoom @(rf/subscribe [::layout/zoom :stage])
|
zoom @(rf/subscribe [::layout/zoom :stage])
|
||||||
{:keys [margin opacity]} @(rf/subscribe [::layout/mat])
|
{:keys [opacity]} @(rf/subscribe [::layout/mat])]
|
||||||
vw (+ w (* 2 margin)) vh (+ h (* 2 margin))]
|
|
||||||
[:div.stage-area
|
[:div.stage-area
|
||||||
(navigation)
|
(navigation)
|
||||||
[:div.stage-wrap
|
[:div.stage-wrap
|
||||||
|
|
@ -733,7 +730,7 @@
|
||||||
;; `dragenter` is cancelled as well as `dragover`: a drop target has to
|
;; `dragenter` is cancelled as well as `dragover`: a drop target has to
|
||||||
;; accept on BOTH, and the element under the pointer changes whenever the
|
;; accept on BOTH, and the element under the pointer changes whenever the
|
||||||
;; preview re-renders beneath it, which fires a fresh `dragenter`.
|
;; preview re-renders beneath it, which fires a fresh `dragenter`.
|
||||||
{:data-width vw :data-height vh
|
{:data-width w :data-height h
|
||||||
:on-drag-enter (fn [^js event] (when (drag/accepts?) (.preventDefault event)))
|
:on-drag-enter (fn [^js event] (when (drag/accepts?) (.preventDefault event)))
|
||||||
:on-drag-over (fn [^js event]
|
:on-drag-over (fn [^js event]
|
||||||
(when (drag/accepts?)
|
(when (drag/accepts?)
|
||||||
|
|
@ -746,12 +743,12 @@
|
||||||
(.preventDefault event)
|
(.preventDefault event)
|
||||||
(drag/land! frame (stage-point event w h)))}
|
(drag/land! frame (stage-point event w h)))}
|
||||||
[:canvas.stage {:ref #(player/set-canvas! %)
|
[:canvas.stage {:ref #(player/set-canvas! %)
|
||||||
:width vw :height vh
|
:width w :height h
|
||||||
:style {:width (str (* zoom vw) "px")
|
:style {:width (str (* zoom w) "px")
|
||||||
:height (str (* zoom vh) "px")}}]
|
:height (str (* zoom h) "px")}}]
|
||||||
[:canvas.tracing {:ref #(tracing/set-canvas! %)
|
[:canvas.tracing {:ref #(tracing/set-canvas! %)
|
||||||
:width (* zoom vw) :height (* zoom vh)}]
|
:width (* zoom w) :height (* zoom h)}]
|
||||||
[overlay w h zoom margin 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]])
|
||||||
[tools/adjust-last]]))
|
[tools/adjust-last]]))
|
||||||
|
|
|
||||||
|
|
@ -874,6 +874,11 @@ button.share-button:hover, button.share-button.on { filter: brightness(1.1); }
|
||||||
.stage { display: block; background: var(--stage); }
|
.stage { display: block; background: var(--stage); }
|
||||||
|
|
||||||
.paint-overlay { position: absolute; inset: 0; touch-action: none; }
|
.paint-overlay { position: absolute; inset: 0; touch-action: none; }
|
||||||
|
.stage-overlay-wrap {
|
||||||
|
position: absolute;
|
||||||
|
left: -100%; top: -100%;
|
||||||
|
width: 300%; height: 300%;
|
||||||
|
}
|
||||||
/* 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