mirror of
https://github.com/penpot/penpot.git
synced 2025-01-23 06:58:58 -05:00
🐛 Fix shadows when exporting groups
This commit is contained in:
parent
a14890f163
commit
0f6ce233bd
3 changed files with 85 additions and 66 deletions
|
@ -63,6 +63,7 @@
|
||||||
- Fix issue when promoting to owner [Taiga #1494](https://tree.taiga.io/project/penpot/issue/1494)
|
- Fix issue when promoting to owner [Taiga #1494](https://tree.taiga.io/project/penpot/issue/1494)
|
||||||
- Fix cannot click on blocked elements in viewer [Taiga #1430](https://tree.taiga.io/project/penpot/issue/1430)
|
- Fix cannot click on blocked elements in viewer [Taiga #1430](https://tree.taiga.io/project/penpot/issue/1430)
|
||||||
- Fix SVG not showing properties at code [Taiga #1437](https://tree.taiga.io/project/penpot/issue/1437)
|
- Fix SVG not showing properties at code [Taiga #1437](https://tree.taiga.io/project/penpot/issue/1437)
|
||||||
|
- Fix shadows when exporting groups [Taiga #1495](https://tree.taiga.io/project/penpot/issue/1495)
|
||||||
|
|
||||||
|
|
||||||
### :arrow_up: Deps updates
|
### :arrow_up: Deps updates
|
||||||
|
|
|
@ -9,18 +9,21 @@
|
||||||
|
|
||||||
(ns app.main.ui.render
|
(ns app.main.ui.render
|
||||||
(:require
|
(:require
|
||||||
[cljs.spec.alpha :as s]
|
|
||||||
[beicon.core :as rx]
|
|
||||||
[rumext.alpha :as mf]
|
|
||||||
[app.common.uuid :as uuid]
|
|
||||||
[app.common.pages :as cp]
|
|
||||||
[app.common.math :as mth]
|
|
||||||
[app.common.geom.shapes :as geom]
|
|
||||||
[app.common.geom.point :as gpt]
|
|
||||||
[app.common.geom.matrix :as gmt]
|
[app.common.geom.matrix :as gmt]
|
||||||
[app.main.ui.context :as muc]
|
[app.common.geom.point :as gpt]
|
||||||
|
[app.common.geom.shapes :as gsh]
|
||||||
|
[app.common.math :as mth]
|
||||||
|
[app.common.pages :as cp]
|
||||||
|
[app.common.uuid :as uuid]
|
||||||
[app.main.exports :as exports]
|
[app.main.exports :as exports]
|
||||||
[app.main.repo :as repo]))
|
[app.main.repo :as repo]
|
||||||
|
[app.main.ui.context :as muc]
|
||||||
|
[app.main.ui.shapes.filters :as filters]
|
||||||
|
[app.main.ui.shapes.shape :refer [shape-container]]
|
||||||
|
[beicon.core :as rx]
|
||||||
|
[cljs.spec.alpha :as s]
|
||||||
|
[cuerdas.core :as str]
|
||||||
|
[rumext.alpha :as mf]))
|
||||||
|
|
||||||
(mf/defc object-svg
|
(mf/defc object-svg
|
||||||
{::mf/wrap [mf/memo]}
|
{::mf/wrap [mf/memo]}
|
||||||
|
@ -37,18 +40,23 @@
|
||||||
mod-ids (cons frame-id (cp/get-children frame-id objects))
|
mod-ids (cons frame-id (cp/get-children frame-id objects))
|
||||||
updt-fn #(-> %1
|
updt-fn #(-> %1
|
||||||
(assoc-in [%2 :modifiers :displacement] modifier)
|
(assoc-in [%2 :modifiers :displacement] modifier)
|
||||||
(update %2 geom/transform-shape))
|
(update %2 gsh/transform-shape))
|
||||||
|
|
||||||
objects (reduce updt-fn objects mod-ids)
|
objects (reduce updt-fn objects mod-ids)
|
||||||
object (get objects object-id)
|
object (get objects object-id)
|
||||||
|
|
||||||
width (* (get-in object [:selrect :width]) zoom)
|
|
||||||
height (* (get-in object [:selrect :height]) zoom)
|
|
||||||
|
|
||||||
vbox (str (get-in object [:selrect :x]) " "
|
{:keys [width height]} (gsh/points->selrect (:points object))
|
||||||
(get-in object [:selrect :y]) " "
|
|
||||||
(get-in object [:selrect :width]) " "
|
;; We need to get the shadows/blurs paddings to create the viewbox properly
|
||||||
(get-in object [:selrect :height]))
|
{:keys [x y width height]} (filters/get-filters-bounds object)
|
||||||
|
|
||||||
|
x (* x zoom)
|
||||||
|
y (* y zoom)
|
||||||
|
width (* width zoom)
|
||||||
|
height (* height zoom)
|
||||||
|
|
||||||
|
vbox (str/join " " [x y width height])
|
||||||
|
|
||||||
frame-wrapper
|
frame-wrapper
|
||||||
(mf/use-memo
|
(mf/use-memo
|
||||||
|
@ -76,7 +84,8 @@
|
||||||
:xmlns "http://www.w3.org/2000/svg"}
|
:xmlns "http://www.w3.org/2000/svg"}
|
||||||
(case (:type object)
|
(case (:type object)
|
||||||
:frame [:& frame-wrapper {:shape object :view-box vbox}]
|
:frame [:& frame-wrapper {:shape object :view-box vbox}]
|
||||||
:group [:& group-wrapper {:shape object}]
|
:group [:> shape-container {:shape object}
|
||||||
|
[:& group-wrapper {:shape object}]]
|
||||||
[:& shape-wrapper {:shape object}])]]))
|
[:& shape-wrapper {:shape object}])]]))
|
||||||
|
|
||||||
(defn- adapt-root-frame
|
(defn- adapt-root-frame
|
||||||
|
@ -84,9 +93,9 @@
|
||||||
(if (uuid/zero? object-id)
|
(if (uuid/zero? object-id)
|
||||||
(let [object (get objects object-id)
|
(let [object (get objects object-id)
|
||||||
shapes (cp/select-toplevel-shapes objects {:include-frames? true})
|
shapes (cp/select-toplevel-shapes objects {:include-frames? true})
|
||||||
srect (geom/selection-rect shapes)
|
srect (gsh/selection-rect shapes)
|
||||||
object (merge object (select-keys srect [:x :y :width :height]))
|
object (merge object (select-keys srect [:x :y :width :height]))
|
||||||
object (geom/transform-shape object)
|
object (gsh/transform-shape object)
|
||||||
object (assoc object :fill-color "#f0f0f0")]
|
object (assoc object :fill-color "#f0f0f0")]
|
||||||
(assoc objects (:id object) object))
|
(assoc objects (:id object) object))
|
||||||
objects))
|
objects))
|
||||||
|
|
|
@ -122,40 +122,6 @@
|
||||||
:x2 (+ filter-x filter-width)
|
:x2 (+ filter-x filter-width)
|
||||||
:y2 (+ filter-y filter-height)}))
|
:y2 (+ filter-y filter-height)}))
|
||||||
|
|
||||||
(defn get-filters-bounds
|
|
||||||
[shape filters blur-value]
|
|
||||||
|
|
||||||
(let [svg-root? (and (= :svg-raw (:type shape)) (not= :svg (get-in shape [:content :tag])))
|
|
||||||
frame? (= :frame (:type shape))
|
|
||||||
{: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 0 :y 0 :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 (if frame? (- x1 x) x1)
|
|
||||||
:y (if frame? (- y1 y) y1)
|
|
||||||
:width (- x2 x1)
|
|
||||||
:height (- y2 y1)}))))
|
|
||||||
|
|
||||||
(defn blur-filters [type value]
|
(defn blur-filters [type value]
|
||||||
(->> [value]
|
(->> [value]
|
||||||
(remove :hidden)
|
(remove :hidden)
|
||||||
|
@ -184,21 +150,64 @@
|
||||||
: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
|
||||||
|
[]
|
||||||
|
[{: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])))
|
||||||
|
frame? (= :frame (:type shape))
|
||||||
|
{: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 0 :y 0 :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 (if frame? (- x1 x) x1)
|
||||||
|
:y (if frame? (- y1 y) y1)
|
||||||
|
:width (- x2 x1)
|
||||||
|
:height (- y2 y1)})))))
|
||||||
|
|
||||||
(mf/defc filters
|
(mf/defc filters
|
||||||
[{:keys [filter-id shape]}]
|
[{:keys [filter-id shape]}]
|
||||||
|
|
||||||
(let [filters (d/concat
|
(let [filters (shape->filters shape)
|
||||||
[]
|
|
||||||
[{: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)))
|
|
||||||
|
|
||||||
;; Adds the previous filter as `filter-in` parameter
|
;; Adds the previous filter as `filter-in` parameter
|
||||||
filters (map #(assoc %1 :filter-in %2) filters (cons nil (map :id filters)))
|
filters (map #(assoc %1 :filter-in %2) filters (cons nil (map :id filters)))
|
||||||
|
|
Loading…
Add table
Reference in a new issue