Adds inner shadow filter

This commit is contained in:
alonso.torres 2020-09-24 21:00:25 +02:00
parent 64c0884eb9
commit 215c4fdb56
6 changed files with 144 additions and 42 deletions

View file

@ -24,54 +24,141 @@
(when (seq (:shadow shape))
(str/fmt "url(#$0)" [filter-id])))
(mf/defc color-matrix
[{:keys [color opacity]}]
(let [[r g b a] (color/hex->rgba color opacity)
[r g b] [(/ r 255) (/ g 255) (/ b 255)]]
[:feColorMatrix
{:type "matrix"
:values (str/fmt "0 0 0 0 $0 0 0 0 0 $1 0 0 0 0 $2 0 0 0 $3 0" [r g b a])}]))
(mf/defc drop-shadow-filter
[{:keys [filter-id filter shape]}]
(let [{:keys [x y width height]} (:selrect shape)
{:keys [fid color opacity offset-x offset-y blur spread]} filter
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-x) (* spread 2) (* blur 2) 10)
[r g b a] (color/hex->rgba color opacity)
[r g b] [(/ r 255) (/ g 255) (/ b 255)]
color-matrix (str/fmt "0 0 0 0 $0 0 0 0 0 $1 0 0 0 0 $2 0 0 0 $3 0" [r g b a])]
[:filter {:id filter-id
:x filter-x :y filter-y
:width filter-width :height filter-height
:filterUnits "userSpaceOnUse"
:color-interpolation-filters "sRGB"}
[:feFlood {:flood-opacity 0 :result "BackgroundImageFix"}]
{:keys [id in-filter color opacity offset-x offset-y blur spread]} filter]
[:*
[:feColorMatrix {:in "SourceAlpha" :type "matrix"
:values "0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0"}]
(when (> spread 0)
[:feMorphology {:radius spread
:operator "dilate"
:in "SourceAlpha"
:result "effect1_dropShadow"}])
:result (str "filter" id)}])
[:feOffset {:dx offset-x :dy offset-y}]
[:feGaussianBlur {:stdDeviation (/ blur 2)}]
[:& color-matrix {:color color :opacity opacity}]
[:feBlend {:mode "normal"
:in2 in-filter
:result (str "filter" id)}]]))
(mf/defc inner-shadow-filter
[{:keys [filter-id filter shape]}]
(let [{:keys [x y width height]} (:selrect shape)
{:keys [id in-filter color opacity offset-x offset-y blur spread]} filter]
[:*
[:feColorMatrix {:in "SourceAlpha" :type "matrix"
:values "0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0"
:result "hardAlpha"}]
(when (> spread 0)
[:feMorphology {:radius spread
:operator "erode"
:in "SourceAlpha"
:result (str "filter" id)}])
[:feOffset {:dx offset-x :dy offset-y}]
[:feGaussianBlur {:stdDeviation (/ blur 2)}]
[:feColorMatrix {:type "matrix" :values color-matrix}]
[:feComposite {:in2 "hardAlpha"
:operator "arithmetic"
:k2 "-1"
:k3 "1"}]
[:& color-matrix {:color color :opacity opacity}]
[:feBlend {:mode "normal"
:in2 "BackgroundImageFix"
:result "effect1_dropShadow"}]
:in2 in-filter
:result (str "filter" id)}]]))
[:feBlend {:mode "normal"
:in "SourceGraphic"
:in2 "effect1_dropShadow"
:result "shape"}]]))
(defn filter-bounds [shape filter]
(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}} filter
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-x) (* spread 2) (* blur 2) 10)]
{:x1 filter-x
:y1 filter-y
:x2 (+ filter-x filter-width)
:y2 (+ filter-y filter-height)}))
(defn get-filters-bounds
[shape filters]
(let [filter-bounds (->>
filters
(filter #(= :drop-shadow (:type %)))
(map (partial filter-bounds shape) ))
x1 (apply min (:x1 filter-bounds))
y1 (apply min (:y1 filter-bounds))
x2 (apply max (:x2 filter-bounds))
y2 (apply max (:y2 filter-bounds))]
[x1 y1 (- x2 x1) (- y2 y1)]))
(mf/defc filters
[{:keys [filter-id shape]}]
[:defs
(for [{:keys [id type hidden] :as filter} (:shadow shape)]
(when (not hidden)
[:& drop-shadow-filter {:key id
:filter-id filter-id
:filter filter
:shape shape}]))])
(let [add-in-filter
(fn [filter in-filter]
(assoc filter :in-filter in-filter))
filters (->> shape :shadow (filter (comp not :hidden)))
[filter-x filter-y filter-width filter-height] (get-filters-bounds shape filters)]
(when (seq filters)
[:defs
[:filter {:id filter-id
:x filter-x :y filter-y
:width filter-width :height filter-height
:filterUnits "userSpaceOnUse"
:color-interpolation-filters "sRGB"}
(let [;; Add as a paramter the input filter
drop-shadow-filters (->> filters (filter #(= :drop-shadow (:style %))))
drop-shadow-filters (->> drop-shadow-filters
(map #(str "filter" (:id %)))
(concat ["BackgroundImageFix"])
(map add-in-filter drop-shadow-filters))
inner-shadow-filters (->> filters (filter #(= :inner-shadow (:style %))))
inner-shadow-filters (->> inner-shadow-filters
(map #(str "filter" (:id %)))
(concat ["shape"])
(map add-in-filter inner-shadow-filters))]
[:*
[:feFlood {:flood-opacity 0 :result "BackgroundImageFix"}]
(for [{:keys [id type] :as filter} drop-shadow-filters]
[:& drop-shadow-filter {:key id
:filter-id filter-id
:filter filter
:shape shape}])
[:feBlend {:mode "normal"
:in "SourceGraphic"
:in2 (if (seq drop-shadow-filters)
(str "filter" (:id (last drop-shadow-filters)))
"BackgroundImageFix")
:result "shape"}]
(for [{:keys [id type] :as filter} inner-shadow-filters]
[:& inner-shadow-filter {:key id
:filter-id filter-id
:filter filter
:shape shape}])
])
]])))