Fix shadows in frames for dashboard and viewer

This commit is contained in:
alonso.torres 2022-06-21 22:18:18 +02:00
parent e1d6cded62
commit 8e60834292
11 changed files with 215 additions and 258 deletions

View file

@ -98,13 +98,6 @@
(defn distance-shapes [shape other] (defn distance-shapes [shape other]
(distance-selrect (:selrect shape) (:selrect other))) (distance-selrect (:selrect shape) (:selrect other)))
(defn shape-stroke-margin
[shape stroke-width]
(if (= (:type shape) :path)
;; TODO: Calculate with the stroke offset (not implemented yet
(mth/sqrt (* 2 stroke-width stroke-width))
(- (mth/sqrt (* 2 stroke-width stroke-width)) stroke-width)))
(defn close-attrs? (defn close-attrs?
"Compares two shapes attributes to see if they are equal or almost "Compares two shapes attributes to see if they are equal or almost
equal (in case of numeric). Takes into account attributes that are equal (in case of numeric). Takes into account attributes that are

View file

@ -0,0 +1,151 @@
(ns app.common.geom.shapes.bounds
(:require
[app.common.data :as d]
[app.common.geom.shapes.rect :as gsr]
[app.common.math :as mth]
[app.common.pages.helpers :as cph]))
(defn shape-stroke-margin
[shape stroke-width]
(if (= (:type shape) :path)
;; TODO: Calculate with the stroke offset (not implemented yet
(mth/sqrt (* 2 stroke-width stroke-width))
(- (mth/sqrt (* 2 stroke-width stroke-width)) stroke-width)))
(defn blur-filters [type value]
(->> [value]
(remove :hidden)
(filter #(= (:type %) type))
(map #(hash-map :id (str "filter_" (:id %))
:type (:type %)
:params %))))
(defn shadow-filters [type filters]
(->> filters
(remove :hidden)
(filter #(= (:style %) type))
(map #(hash-map :id (str "filter_" (:id %))
:type (:style %)
:params %))))
(defn shape->filters
[shape]
(d/concat-vec
[{:id "BackgroundImageFix" :type :image-fix}]
;; Background blur won't work in current SVG specification
;; We can revisit this in the future
#_(->> shape :blur (blur-filters :background-blur))
(->> shape :shadow (shadow-filters :drop-shadow))
[{:id "shape" :type :blend-filters}]
(->> shape :shadow (shadow-filters :inner-shadow))
(->> shape :blur (blur-filters :layer-blur))))
(defn calculate-filter-bounds [{:keys [x y width height]} filter-entry]
(let [{:keys [offset-x offset-y blur spread] :or {offset-x 0 offset-y 0 blur 0 spread 0}} (:params filter-entry)
filter-x (min x (+ x offset-x (- spread) (- blur) -5))
filter-y (min y (+ y offset-y (- spread) (- blur) -5))
filter-width (+ width (mth/abs offset-x) (* spread 2) (* blur 2) 10)
filter-height (+ height (mth/abs offset-y) (* spread 2) (* blur 2) 10)]
(gsr/make-selrect filter-x filter-y filter-width filter-height)))
(defn get-rect-filter-bounds
[selrect filters blur-value]
(let [filter-bounds (->> filters
(filter #(= :drop-shadow (:type %)))
(map (partial calculate-filter-bounds selrect))
(concat [selrect])
(gsr/join-selrects))
delta-blur (* blur-value 2)
result
(-> filter-bounds
(update :x - delta-blur)
(update :y - delta-blur)
(update :x1 - delta-blur)
(update :x1 - delta-blur)
(update :x2 + delta-blur)
(update :y2 + delta-blur)
(update :width + (* delta-blur 2))
(update :height + (* delta-blur 2)))]
result))
(defn get-shape-filter-bounds
([shape]
(let [svg-root? (and (= :svg-raw (:type shape)) (not= :svg (get-in shape [:content :tag])))]
(if svg-root?
(:selrect shape)
(let [filters (shape->filters shape)
blur-value (or (-> shape :blur :value) 0)]
(get-rect-filter-bounds (-> shape :points gsr/points->selrect) filters blur-value))))))
(defn calculate-padding
([shape]
(calculate-padding shape false))
([shape ignore-margin?]
(let [stroke-width (apply max 0 (map #(case (:stroke-alignment % :center)
:center (/ (:stroke-width % 0) 2)
:outer (:stroke-width % 0)
0) (:strokes shape)))
margin (if ignore-margin?
0
(apply max 0 (map #(shape-stroke-margin % stroke-width) (:strokes shape))))
shadow-width (apply max 0 (map #(case (:style % :drop-shadow)
:drop-shadow (+ (mth/abs (:offset-x %)) (* (:spread %) 2) (* (:blur %) 2) 10)
0) (:shadow shape)))
shadow-height (apply max 0 (map #(case (:style % :drop-shadow)
:drop-shadow (+ (mth/abs (:offset-y %)) (* (:spread %) 2) (* (:blur %) 2) 10)
0) (:shadow shape)))]
{:horizontal (+ stroke-width margin shadow-width)
:vertical (+ stroke-width margin shadow-height)})))
(defn- add-padding
[bounds padding]
(-> bounds
(update :x - (:horizontal padding))
(update :y - (:vertical padding))
(update :width + (* 2 (:horizontal padding)))
(update :height + (* 2 (:vertical padding)))))
(defn get-object-bounds
[objects shape]
(let [calculate-base-bounds
(fn [shape]
(-> (get-shape-filter-bounds shape)
(add-padding (calculate-padding shape true))))
bounds
(cph/reduce-objects
objects
(fn [shape]
(and (d/not-empty? (:shapes shape))
(or (not (cph/frame-shape? shape))
(:show-content shape))
(or (not (cph/group-shape? shape))
(not (:masked-group? shape)))))
(:id shape)
(fn [result shape]
(conj result (get-object-bounds objects shape)))
[(calculate-base-bounds shape)])
children-bounds (or (:children-bounds shape) (gsr/join-selrects bounds))
filters (shape->filters shape)
blur-value (or (-> shape :blur :value) 0)]
(get-rect-filter-bounds children-bounds filters blur-value)))

View file

@ -657,7 +657,10 @@
(reduce-objects objects nil reducer-fn init-val)) (reduce-objects objects nil reducer-fn init-val))
([objects check-children? reducer-fn init-val] ([objects check-children? reducer-fn init-val]
(let [root-children (get-in objects [uuid/zero :shapes])] (reduce-objects objects check-children? uuid/zero reducer-fn init-val))
([objects check-children? root-id reducer-fn init-val]
(let [root-children (get-in objects [root-id :shapes])]
(if (empty? root-children) (if (empty? root-children)
init-val init-val

View file

@ -359,7 +359,6 @@
(p/let [params {:file-id file-id (p/let [params {:file-id file-id
:page-id page-id :page-id page-id
:render-texts true
:render-embed true :render-embed true
:object-id (mapv :id objects) :object-id (mapv :id objects)
:route "objects"} :route "objects"}

View file

@ -147,6 +147,7 @@
height: 120px; height: 120px;
border: 1px solid $color-gray-20; border: 1px solid $color-gray-20;
border-radius: 2px; border-radius: 2px;
padding: 4px;
display: flex; display: flex;
justify-content: center; justify-content: center;

View file

@ -14,11 +14,11 @@
(:require (:require
["react-dom/server" :as rds] ["react-dom/server" :as rds]
[app.common.colors :as clr] [app.common.colors :as clr]
[app.common.data :as d]
[app.common.data.macros :as dm] [app.common.data.macros :as dm]
[app.common.geom.matrix :as gmt] [app.common.geom.matrix :as gmt]
[app.common.geom.point :as gpt] [app.common.geom.point :as gpt]
[app.common.geom.shapes :as gsh] [app.common.geom.shapes :as gsh]
[app.common.geom.shapes.bounds :as gsb]
[app.common.math :as mth] [app.common.math :as mth]
[app.common.pages.helpers :as cph] [app.common.pages.helpers :as cph]
[app.config :as cfg] [app.config :as cfg]
@ -28,7 +28,6 @@
[app.main.ui.shapes.circle :as circle] [app.main.ui.shapes.circle :as circle]
[app.main.ui.shapes.embed :as embed] [app.main.ui.shapes.embed :as embed]
[app.main.ui.shapes.export :as export] [app.main.ui.shapes.export :as export]
[app.main.ui.shapes.filters :as filters]
[app.main.ui.shapes.frame :as frame] [app.main.ui.shapes.frame :as frame]
[app.main.ui.shapes.group :as group] [app.main.ui.shapes.group :as group]
[app.main.ui.shapes.image :as image] [app.main.ui.shapes.image :as image]
@ -61,13 +60,11 @@
(defn- calculate-dimensions (defn- calculate-dimensions
[objects] [objects]
(let [rect (let [bounds
(->> (cph/get-root-objects objects) (->> (cph/get-root-objects objects)
(map #(if (some? (:children-bounds %)) (map (partial gsb/get-object-bounds objects))
(:children-bounds %) (gsh/join-rects))]
(gsh/points->selrect (:points %)))) (-> bounds
(gsh/join-selrects))]
(-> rect
(update :x mth/finite 0) (update :x mth/finite 0)
(update :y mth/finite 0) (update :y mth/finite 0)
(update :width mth/finite 100000) (update :width mth/finite 100000)
@ -193,36 +190,12 @@
(reduce updt-fn objects mod-ids))) (reduce updt-fn objects mod-ids)))
(defn get-object-bounds
[objects object-id]
(let [object (get objects object-id)
padding (filters/calculate-padding object true)
bounds (-> (filters/get-filters-bounds object)
(update :x - (:horizontal padding))
(update :y - (:vertical padding))
(update :width + (* 2 (:horizontal padding)))
(update :height + (* 2 (:vertical padding))))]
(cond
(and (cph/group-shape? object) (:masked-group? object))
(get-object-bounds objects (-> object :shapes first))
(or (cph/group-shape? object)
(and (cph/frame-shape? object) (:show-content object)))
(->> (:shapes object)
(into [bounds] (map (partial get-object-bounds objects)))
(gsh/join-rects))
:else
bounds)))
(mf/defc page-svg (mf/defc page-svg
{::mf/wrap [mf/memo]} {::mf/wrap [mf/memo]}
[{:keys [data thumbnails? render-embed? include-metadata?] :as props [{:keys [data thumbnails? render-embed? include-metadata?] :as props
:or {render-embed? false include-metadata? false}}] :or {render-embed? false include-metadata? false}}]
(let [objects (:objects data) (let [objects (:objects data)
shapes (cph/get-immediate-children objects) shapes (cph/get-immediate-children objects)
dim (calculate-dimensions objects) dim (calculate-dimensions objects)
vbox (format-viewbox dim) vbox (format-viewbox dim)
bgcolor (dm/get-in data [:options :background] default-color) bgcolor (dm/get-in data [:options :background] default-color)
@ -248,7 +221,6 @@
(when include-metadata? (when include-metadata?
[:& export/export-page {:options (:options data)}]) [:& export/export-page {:options (:options data)}])
(let [shapes (->> shapes (let [shapes (->> shapes
(remove cph/frame-shape?) (remove cph/frame-shape?)
(mapcat #(cph/get-children-with-self objects (:id %)))) (mapcat #(cph/get-children-with-self objects (:id %))))
@ -262,20 +234,20 @@
;; Component that serves for render frame thumbnails, mainly used in ;; Component that serves for render frame thumbnails, mainly used in
;; the viewer and handoff ;; the viewer and handoff
(mf/defc frame-svg (mf/defc frame-svg
{::mf/wrap [mf/memo]} {::mf/wrap [mf/memo]}
[{:keys [objects frame zoom show-thumbnails?] :or {zoom 1} :as props}] [{:keys [objects frame zoom show-thumbnails?] :or {zoom 1} :as props}]
(let [frame-id (:id frame) (let [frame-id (:id frame)
include-metadata? (mf/use-ctx export/include-metadata-ctx) include-metadata? (mf/use-ctx export/include-metadata-ctx)
bounds (or (:children-bounds frame) (gsh/points->rect (:points frame))) bounds (gsb/get-object-bounds objects frame)
modifier ;; Bounds without shadows/blur will be the bounds of the thumbnail
(mf/with-memo [(:x bounds) (:y bounds)] bounds2 (gsb/get-object-bounds objects (dissoc frame :shadow :blur))
(-> (gpt/point (:x bounds) (:y bounds))
(gpt/negate) delta-bounds (gpt/point (:x bounds) (:y bounds))
(gmt/translate-matrix)))
modifier (gmt/translate-matrix (gpt/negate delta-bounds))
children-ids children-ids
(cph/get-children-ids objects frame-id) (cph/get-children-ids objects frame-id)
@ -293,19 +265,19 @@
(assoc-in [:modifiers :displacement] modifier) (assoc-in [:modifiers :displacement] modifier)
(gsh/transform-shape))) (gsh/transform-shape)))
bounds
(if (:show-content frame)
(gsh/selection-rect (concat [frame] (->> children-ids (map (d/getf objects)))))
(-> frame :points gsh/points->rect))
frame frame
(cond-> frame (cond-> frame
(and (some? bounds) (nil? (:children-bounds bounds))) (and (some? bounds) (nil? (:children-bounds bounds)))
(assoc :children-bounds bounds)) (assoc :children-bounds bounds2))
frame-wrapper frame (-> frame
(mf/with-memo [objects] (update-in [:children-bounds :x] - (:x delta-bounds))
(frame-wrapper-factory objects)) (update-in [:children-bounds :y] - (:y delta-bounds)))
shape-wrapper
(mf/use-memo
(mf/deps objects)
#(shape-wrapper-factory objects))
width (* (:width bounds) zoom) width (* (:width bounds) zoom)
height (* (:height bounds) zoom) height (* (:height bounds) zoom)
@ -321,13 +293,11 @@
:xmlns:penpot (when include-metadata? "https://penpot.app/xmlns") :xmlns:penpot (when include-metadata? "https://penpot.app/xmlns")
:fill "none"} :fill "none"}
[:> shape-container {:shape frame} [:& shape-wrapper {:shape frame}]]]))
[:& frame-wrapper {:shape frame :view-box vbox}]]]]))
;; Component for rendering a thumbnail of a single componenent. Mainly ;; Component for rendering a thumbnail of a single componenent. Mainly
;; used to render thumbnails on assets panel. ;; used to render thumbnails on assets panel.
(mf/defc component-svg (mf/defc component-svg
{::mf/wrap [mf/memo #(mf/deferred % ts/idle-then-raf)]} {::mf/wrap [mf/memo #(mf/deferred % ts/idle-then-raf)]}
[{:keys [objects group zoom] :or {zoom 1} :as props}] [{:keys [objects group zoom] :or {zoom 1} :as props}]
@ -375,7 +345,7 @@
(mf/defc object-svg (mf/defc object-svg
{::mf/wrap [mf/memo]} {::mf/wrap [mf/memo]}
[{:keys [objects object-id render-texts? render-embed?] [{:keys [objects object-id render-embed?]
:or {render-embed? false} :or {render-embed? false}
:as props}] :as props}]
(let [object (get objects object-id) (let [object (get objects object-id)
@ -383,30 +353,21 @@
(:hide-fill-on-export object) (:hide-fill-on-export object)
(assoc :fills [])) (assoc :fills []))
{:keys [x y width height]} (get-object-bounds objects object-id)
vbox (dm/str x " " y " " width " " height)
frame-wrapper bounds (gsb/get-object-bounds objects object)
(mf/with-memo [objects] vbox (format-viewbox bounds)
(frame-wrapper-factory objects)) fonts (ff/shape->fonts object objects)
group-wrapper
(mf/with-memo [objects]
(group-wrapper-factory objects))
shape-wrapper shape-wrapper
(mf/with-memo [objects] (mf/with-memo [objects]
(shape-wrapper-factory objects)) (shape-wrapper-factory objects))]
text-shapes (sequence (filter cph/text-shape?) (vals objects))
render-texts? (and render-texts? (d/seek (comp nil? :position-data) text-shapes))]
[:& (mf/provider export/include-metadata-ctx) {:value false} [:& (mf/provider export/include-metadata-ctx) {:value false}
[:& (mf/provider embed/context) {:value render-embed?} [:& (mf/provider embed/context) {:value render-embed?}
[:svg {:id (dm/str "screenshot-" object-id) [:svg {:id (dm/str "screenshot-" object-id)
:view-box vbox :view-box vbox
:width width :width (:width bounds)
:height height :height (:height bounds)
:version "1.1" :version "1.1"
:xmlns "http://www.w3.org/2000/svg" :xmlns "http://www.w3.org/2000/svg"
:xmlnsXlink "http://www.w3.org/1999/xlink" :xmlnsXlink "http://www.w3.org/1999/xlink"
@ -415,30 +376,8 @@
:style {:-webkit-print-color-adjust :exact} :style {:-webkit-print-color-adjust :exact}
:fill "none"} :fill "none"}
(let [fonts (ff/shape->fonts object objects)] [:& ff/fontfaces-style {:fonts fonts}]
[:& ff/fontfaces-style {:fonts fonts}]) [:& shape-wrapper {:shape object}]]]]))
(case (:type object)
:frame [:> shape-container {:shape object}
[:& frame-wrapper {:shape object :view-box vbox}]]
:group [:> shape-container {:shape object}
[:& group-wrapper {:shape object}]]
[:& shape-wrapper {:shape object}])]
;; Auxiliary SVG for rendering text-shapes
(when render-texts?
(for [object text-shapes]
[:& (mf/provider muc/text-plain-colors-ctx) {:value true}
[:svg
{:id (dm/str "screenshot-text-" (:id object))
:view-box (dm/str "0 0 " (:width object) " " (:height object))
:width (:width object)
:height (:height object)
:version "1.1"
:xmlns "http://www.w3.org/2000/svg"
:xmlnsXlink "http://www.w3.org/1999/xlink"
:fill "none"}
[:& shape-wrapper {:shape (assoc object :x 0 :y 0)}]]]))]]))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; SPRITES (DEBUG) ;; SPRITES (DEBUG)

View file

@ -9,6 +9,7 @@
[app.common.data :as d] [app.common.data :as d]
[app.common.data.macros :as dm] [app.common.data.macros :as dm]
[app.common.geom.shapes :as gsh] [app.common.geom.shapes :as gsh]
[app.common.geom.shapes.bounds :as gsb]
[app.common.pages.helpers :as cph] [app.common.pages.helpers :as cph]
[app.main.ui.context :as muc] [app.main.ui.context :as muc]
[app.main.ui.shapes.attrs :as attrs] [app.main.ui.shapes.attrs :as attrs]
@ -45,7 +46,7 @@
:center (/ (:stroke-width shape 0) 2) :center (/ (:stroke-width shape 0) 2)
:outer (:stroke-width shape 0) :outer (:stroke-width shape 0)
0) 0)
margin (gsh/shape-stroke-margin shape stroke-width) margin (gsb/shape-stroke-margin shape stroke-width)
bounding-box (-> (gsh/points->selrect (:points shape)) bounding-box (-> (gsh/points->selrect (:points shape))
(update :x - (+ stroke-width margin)) (update :x - (+ stroke-width margin))
(update :y - (+ stroke-width margin)) (update :y - (+ stroke-width margin))

View file

@ -8,8 +8,7 @@
(:require (:require
[app.common.data :as d] [app.common.data :as d]
[app.common.data.macros :as dm] [app.common.data.macros :as dm]
[app.common.geom.shapes :as gsh] [app.common.geom.shapes.bounds :as gsb]
[app.common.math :as mth]
[app.common.uuid :as uuid] [app.common.uuid :as uuid]
[app.util.color :as color] [app.util.color :as color]
[cuerdas.core :as str] [cuerdas.core :as str]
@ -108,34 +107,6 @@
:in2 filter-in :in2 filter-in
:result filter-id}]) :result filter-id}])
(defn filter-bounds [shape filter-entry]
(let [{:keys [x y width height]} (:selrect shape)
{:keys [offset-x offset-y blur spread] :or {offset-x 0 offset-y 0 blur 0 spread 0}} (:params filter-entry)
filter-x (min x (+ x offset-x (- spread) (- blur) -5))
filter-y (min y (+ y offset-y (- spread) (- blur) -5))
filter-width (+ width (mth/abs offset-x) (* spread 2) (* blur 2) 10)
filter-height (+ height (mth/abs offset-y) (* spread 2) (* blur 2) 10)]
{:x1 filter-x
:y1 filter-y
:x2 (+ filter-x filter-width)
:y2 (+ filter-y filter-height)}))
(defn blur-filters [type value]
(->> [value]
(remove :hidden)
(filter #(= (:type %) type))
(map #(hash-map :id (str "filter_" (:id %))
:type (:type %)
:params %))))
(defn shadow-filters [type filters]
(->> filters
(remove :hidden)
(filter #(= (:style %) type))
(map #(hash-map :id (str "filter_" (:id %))
:type (:style %)
:params %))))
(mf/defc filter-entry [{:keys [entry]}] (mf/defc filter-entry [{:keys [entry]}]
(let [props #js {:filter-id (:id entry) (let [props #js {:filter-id (:id entry)
:filter-in (:filter-in entry) :filter-in (:filter-in entry)
@ -148,84 +119,6 @@
:image-fix [:> image-fix-filter props] :image-fix [:> image-fix-filter props]
:blend-filters [:> blend-filters props]))) :blend-filters [:> blend-filters props])))
(defn shape->filters
[shape]
(d/concat-vec
[{:id "BackgroundImageFix" :type :image-fix}]
;; Background blur won't work in current SVG specification
;; We can revisit this in the future
#_(->> shape :blur (blur-filters :background-blur))
(->> shape :shadow (shadow-filters :drop-shadow))
[{:id "shape" :type :blend-filters}]
(->> shape :shadow (shadow-filters :inner-shadow))
(->> shape :blur (blur-filters :layer-blur))))
(defn get-filters-bounds
([shape]
(let [filters (shape->filters shape)
blur-value (or (-> shape :blur :value) 0)]
(get-filters-bounds shape filters blur-value)))
([shape filters blur-value]
(let [svg-root? (and (= :svg-raw (:type shape)) (not= :svg (get-in shape [:content :tag])))
{:keys [x y width height]} (:selrect shape)]
(if svg-root?
;; When is a raw-svg but not the root we use the whole svg as bound for the filter. Is the maximum
;; we're allowed to display
{:x x :y y :width width :height height}
;; Otherwise we calculate the bound
(let [filter-bounds (->> filters
(filter #(= :drop-shadow (:type %)))
(map (partial filter-bounds shape)))
;; We add the selrect so the minimum size will be the selrect
filter-bounds (conj filter-bounds (-> shape :points gsh/points->selrect))
x1 (apply min (map :x1 filter-bounds))
y1 (apply min (map :y1 filter-bounds))
x2 (apply max (map :x2 filter-bounds))
y2 (apply max (map :y2 filter-bounds))
x1 (- x1 (* blur-value 2))
x2 (+ x2 (* blur-value 2))
y1 (- y1 (* blur-value 2))
y2 (+ y2 (* blur-value 2))]
;; We should move the frame filter coordinates because they should be
;; relative with the frame. By default they come as absolute
{:x x1
:y y1
:width (- x2 x1)
:height (- y2 y1)})))))
(defn calculate-padding
([shape]
(calculate-padding shape false))
([shape ignore-margin?]
(let [stroke-width (apply max 0 (map #(case (:stroke-alignment % :center)
:center (/ (:stroke-width % 0) 2)
:outer (:stroke-width % 0)
0) (:strokes shape)))
margin (if ignore-margin?
0
(apply max 0 (map #(gsh/shape-stroke-margin % stroke-width) (:strokes shape))))
shadow-width (apply max 0 (map #(case (:style % :drop-shadow)
:drop-shadow (+ (mth/abs (:offset-x %)) (* (:spread %) 2) (* (:blur %) 2) 10)
0) (:shadow shape)))
shadow-height (apply max 0 (map #(case (:style % :drop-shadow)
:drop-shadow (+ (mth/abs (:offset-y %)) (* (:spread %) 2) (* (:blur %) 2) 10)
0) (:shadow shape)))]
{:horizontal (+ stroke-width margin shadow-width)
:vertical (+ stroke-width margin shadow-height)})))
(defn change-filter-in (defn change-filter-in
"Adds the previous filter as `filter-in` parameter" "Adds the previous filter as `filter-in` parameter"
[filters] [filters]
@ -234,9 +127,9 @@
(mf/defc filters (mf/defc filters
[{:keys [filter-id shape]}] [{:keys [filter-id shape]}]
(let [filters (-> shape shape->filters change-filter-in) (let [filters (-> shape gsb/shape->filters change-filter-in)
bounds (get-filters-bounds shape filters (or (-> shape :blur :value) 0)) bounds (gsb/get-rect-filter-bounds (:selrect shape) filters (or (-> shape :blur :value) 0))
padding (calculate-padding shape) padding (gsb/calculate-padding shape)
selrect (:selrect shape) selrect (:selrect shape)
filter-x (/ (- (:x bounds) (:x selrect) (:horizontal padding)) (:width selrect)) filter-x (/ (- (:x bounds) (:x selrect) (:horizontal padding)) (:width selrect))
filter-y (/ (- (:y bounds) (:y selrect) (:vertical padding)) (:height selrect)) filter-y (/ (- (:y bounds) (:y selrect) (:vertical padding)) (:height selrect))

View file

@ -10,7 +10,7 @@
[app.common.data.macros :as dm] [app.common.data.macros :as dm]
[app.common.geom.matrix :as gmt] [app.common.geom.matrix :as gmt]
[app.common.geom.shapes :as gsh] [app.common.geom.shapes :as gsh]
[app.main.ui.shapes.filters :as f] [app.common.geom.shapes.bounds :as gsb]
[app.util.svg :as usvg] [app.util.svg :as usvg]
[rumext.alpha :as mf])) [rumext.alpha :as mf]))
@ -87,7 +87,7 @@
(d/parse-double (get-in svg-def [:attrs :width])) (d/parse-double (get-in svg-def [:attrs :width]))
(d/parse-double (get-in svg-def [:attrs :height]))) (d/parse-double (get-in svg-def [:attrs :height])))
(gsh/transform-rect transform)) (gsh/transform-rect transform))
(f/get-filters-bounds shape)))) (gsb/get-shape-filter-bounds shape))))
(mf/defc svg-defs [{:keys [shape render-id]}] (mf/defc svg-defs [{:keys [shape render-id]}]
(let [svg-defs (:svg-defs shape) (let [svg-defs (:svg-defs shape)

View file

@ -11,7 +11,7 @@
[app.common.data.macros :as dm] [app.common.data.macros :as dm]
[app.common.exceptions :as ex] [app.common.exceptions :as ex]
[app.common.geom.point :as gpt] [app.common.geom.point :as gpt]
[app.common.geom.shapes :as gsh] [app.common.geom.shapes.bounds :as gsb]
[app.common.pages.helpers :as cph] [app.common.pages.helpers :as cph]
[app.common.text :as txt] [app.common.text :as txt]
[app.main.data.comments :as dcm] [app.main.data.comments :as dcm]
@ -23,7 +23,6 @@
[app.main.ui.context :as ctx] [app.main.ui.context :as ctx]
[app.main.ui.hooks :as hooks] [app.main.ui.hooks :as hooks]
[app.main.ui.icons :as i] [app.main.ui.icons :as i]
[app.main.ui.shapes.filters :as filters]
[app.main.ui.share-link] [app.main.ui.share-link]
[app.main.ui.static :as static] [app.main.ui.static :as static]
[app.main.ui.viewer.comments :refer [comments-layer comments-sidebar]] [app.main.ui.viewer.comments :refer [comments-layer comments-sidebar]]
@ -39,16 +38,8 @@
[rumext.alpha :as mf])) [rumext.alpha :as mf]))
(defn- calculate-size (defn- calculate-size
[frame zoom bounds] [objects frame zoom]
(let [frame-bounds (filters/get-filters-bounds frame) (let [{:keys [x y width height]} (gsb/get-object-bounds objects frame)]
{:keys [x y width height]} (if (:show-content frame)
(gsh/join-rects [bounds frame-bounds])
frame-bounds)
padding (filters/calculate-padding frame)
x (- x (:horizontal padding))
y (- y (:vertical padding))
width (+ width (* 2 (:horizontal padding)))
height (+ height (* 2 (:vertical padding)))]
{:base-width width {:base-width width
:base-height height :base-height height
:x x :x x
@ -83,10 +74,9 @@
[:div.counter (str/join " / " [(+ index 1) num-frames])] [:div.counter (str/join " / " [(+ index 1) num-frames])]
[:span]]]) [:span]]])
(mf/defc viewer-wrapper (mf/defc viewer-wrapper
[{:keys [wrapper-size scroll orig-frame orig-viewport-ref orig-size page file users current-viewport-ref [{:keys [wrapper-size scroll orig-frame orig-viewport-ref orig-size page file users current-viewport-ref
size frame interactions-mode overlays zoom close-overlay section index children-bounds] :as props}] size frame interactions-mode overlays zoom close-overlay section index] :as props}]
(let [{clist :list} (mf/deref refs/comments-local) (let [{clist :list} (mf/deref refs/comments-local)
show-comments-list (and (= section :comments) (= :show clist))] show-comments-list (and (= section :comments) (= :show clist))]
[:* [:*
@ -135,7 +125,7 @@
:interactions-mode interactions-mode}] :interactions-mode interactions-mode}]
(for [overlay overlays] (for [overlay overlays]
(let [size-over (calculate-size (:frame overlay) zoom children-bounds)] (let [size-over (calculate-size (:objects page) (:frame overlay) zoom)]
[:* [:*
(when (or (:close-click-outside overlay) (when (or (:close-click-outside overlay)
(:background-overlay overlay)) (:background-overlay overlay))
@ -204,12 +194,6 @@
frames (:frames page) frames (:frames page)
frame (get frames index) frame (get frames index)
children-bounds
(mf/use-memo
(mf/deps page (:id frame))
#(-> (cph/get-children (:objects page) (:id frame))
(gsh/selection-rect)))
fullscreen? (mf/deref refs/viewer-fullscreen?) fullscreen? (mf/deref refs/viewer-fullscreen?)
overlays (:overlays local) overlays (:overlays local)
scroll (mf/use-state nil) scroll (mf/use-state nil)
@ -219,13 +203,13 @@
(d/seek #(= (:id %) (:orig-frame-id current-animation)) frames)) (d/seek #(= (:id %) (:orig-frame-id current-animation)) frames))
size (mf/use-memo size (mf/use-memo
(mf/deps frame zoom children-bounds) (mf/deps frame zoom)
(fn [] (calculate-size frame zoom children-bounds))) (fn [] (calculate-size (:objects page) frame zoom)))
orig-size (mf/use-memo orig-size (mf/use-memo
(mf/deps orig-frame zoom) (mf/deps orig-frame zoom)
(fn [] (when orig-frame (fn [] (when orig-frame
(calculate-size orig-frame zoom children-bounds)))) (calculate-size (:objects page) orig-frame zoom))))
wrapper-size (mf/use-memo wrapper-size (mf/use-memo
(mf/deps size orig-size zoom) (mf/deps size orig-size zoom)
@ -318,7 +302,7 @@
wrapper-size))))) wrapper-size)))))
(mf/use-layout-effect (mf/use-layout-effect
(mf/deps current-animation children-bounds) (mf/deps current-animation)
(fn [] (fn []
;; Overlay animations may be started when needed. ;; Overlay animations may be started when needed.
(when current-animation (when current-animation
@ -328,7 +312,7 @@
(let [overlay-viewport (dom/get-element (str "overlay-" (str (:overlay-id current-animation)))) (let [overlay-viewport (dom/get-element (str "overlay-" (str (:overlay-id current-animation))))
overlay (d/seek #(= (:id (:frame %)) (:overlay-id current-animation)) overlay (d/seek #(= (:id (:frame %)) (:overlay-id current-animation))
overlays) overlays)
overlay-size (calculate-size (:frame overlay) zoom children-bounds) overlay-size (calculate-size (:objects page) (:frame overlay) zoom)
overlay-position {:x (* (:x (:position overlay)) zoom) overlay-position {:x (* (:x (:position overlay)) zoom)
:y (* (:y (:position overlay)) zoom)}] :y (* (:y (:position overlay)) zoom)}]
(interactions/animate-open-overlay (interactions/animate-open-overlay
@ -342,7 +326,7 @@
(let [overlay-viewport (dom/get-element (str "overlay-" (str (:overlay-id current-animation)))) (let [overlay-viewport (dom/get-element (str "overlay-" (str (:overlay-id current-animation))))
overlay (d/seek #(= (:id (:frame %)) (:overlay-id current-animation)) overlay (d/seek #(= (:id (:frame %)) (:overlay-id current-animation))
overlays) overlays)
overlay-size (calculate-size (:frame overlay) zoom children-bounds) overlay-size (calculate-size (:objects page) (:frame overlay) zoom)
overlay-position {:x (* (:x (:position overlay)) zoom) overlay-position {:x (* (:x (:position overlay)) zoom)
:y (* (:y (:position overlay)) zoom)}] :y (* (:y (:position overlay)) zoom)}]
(interactions/animate-close-overlay (interactions/animate-close-overlay
@ -427,8 +411,7 @@
:overlays overlays :overlays overlays
:zoom zoom :zoom zoom
:section section :section section
:index index :index index}]))]]]))
:children-bounds children-bounds}]))]]]))
;; --- Component: Viewer Page ;; --- Component: Viewer Page

View file

@ -98,7 +98,7 @@
state)) state))
(mf/defc object-svg (mf/defc object-svg
[{:keys [page-id file-id object-id render-embed? render-texts?]}] [{:keys [page-id file-id object-id render-embed?]}]
(let [fetch-state (mf/use-fn (let [fetch-state (mf/use-fn
(mf/deps file-id page-id object-id) (mf/deps file-id page-id object-id)
(fn [] (fn []
@ -131,11 +131,10 @@
[:& render/object-svg [:& render/object-svg
{:objects objects {:objects objects
:object-id object-id :object-id object-id
:render-embed? render-embed? :render-embed? render-embed?}])))
:render-texts? render-texts?}])))
(mf/defc objects-svg (mf/defc objects-svg
[{:keys [page-id file-id object-ids render-embed? render-texts?]}] [{:keys [page-id file-id object-ids render-embed?]}]
(let [fetch-state (mf/use-fn (let [fetch-state (mf/use-fn
(mf/deps file-id page-id) (mf/deps file-id page-id)
(fn [] (fn []
@ -157,27 +156,24 @@
{:objects objects {:objects objects
:key (str object-id) :key (str object-id)
:object-id object-id :object-id object-id
:render-embed? render-embed? :render-embed? render-embed?}])))))
:render-texts? render-texts?}])))))
(s/def ::page-id ::us/uuid) (s/def ::page-id ::us/uuid)
(s/def ::file-id ::us/uuid) (s/def ::file-id ::us/uuid)
(s/def ::object-id (s/def ::object-id
(s/or :single ::us/uuid (s/or :single ::us/uuid
:multiple (s/coll-of ::us/uuid))) :multiple (s/coll-of ::us/uuid)))
(s/def ::render-text ::us/boolean)
(s/def ::embed ::us/boolean) (s/def ::embed ::us/boolean)
(s/def ::render-objects (s/def ::render-objects
(s/keys :req-un [::file-id ::page-id ::object-id] (s/keys :req-un [::file-id ::page-id ::object-id]
:opt-un [::render-text ::render-embed])) :opt-un [::render-embed]))
(defn- render-objects (defn- render-objects
[params] [params]
(let [{:keys [file-id (let [{:keys [file-id
page-id page-id
render-embed render-embed]
render-texts]
:as params} :as params}
(us/conform ::render-objects params) (us/conform ::render-objects params)
@ -190,8 +186,7 @@
{:file-id file-id {:file-id file-id
:page-id page-id :page-id page-id
:object-id object-id :object-id object-id
:render-embed? render-embed :render-embed? render-embed}])
:render-texts? render-texts}])
:multiple :multiple
(mf/html (mf/html
@ -199,8 +194,7 @@
{:file-id file-id {:file-id file-id
:page-id page-id :page-id page-id
:object-ids (into #{} object-id) :object-ids (into #{} object-id)
:render-embed? render-embed :render-embed? render-embed}]))))
:render-texts? render-texts}]))))
;; ---- COMPONENTS SPRITE ;; ---- COMPONENTS SPRITE