mirror of
https://github.com/penpot/penpot.git
synced 2025-02-10 00:58:26 -05:00
✨ Adds inner shadow filter
This commit is contained in:
parent
64c0884eb9
commit
215c4fdb56
6 changed files with 144 additions and 42 deletions
|
@ -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}])
|
||||
])
|
||||
]])))
|
||||
|
|
|
@ -71,11 +71,11 @@
|
|||
on-context-menu (mf/use-callback
|
||||
(mf/deps shape)
|
||||
#(on-context-menu % shape))
|
||||
filter-id (filters/get-filter-id)]
|
||||
filter-id (mf/use-var (filters/get-filter-id))]
|
||||
[:g.shape {:on-mouse-down on-mouse-down
|
||||
:on-context-menu on-context-menu
|
||||
:filter (filters/filter-str filter-id shape)}
|
||||
[:& filters/filters {:filter-id filter-id :shape shape}]
|
||||
:filter (filters/filter-str @filter-id shape)}
|
||||
[:& filters/filters {:filter-id @filter-id :shape shape}]
|
||||
[:& component {:shape shape}]])))
|
||||
|
||||
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
[app.main.ui.workspace.shapes.common :as common]
|
||||
[app.main.data.workspace.selection :as dws]
|
||||
[app.main.ui.shapes.frame :as frame]
|
||||
[app.main.ui.shapes.filters :as filters]
|
||||
[app.common.geom.matrix :as gmt]
|
||||
[app.common.geom.point :as gpt]
|
||||
[app.common.geom.shapes :as geom]
|
||||
|
@ -96,7 +97,9 @@
|
|||
(mf/use-callback
|
||||
(mf/deps (:id shape))
|
||||
(fn []
|
||||
(st/emit! (dws/change-hover-state (:id shape) false))))]
|
||||
(st/emit! (dws/change-hover-state (:id shape) false))))
|
||||
|
||||
filter-id (filters/get-filter-id)]
|
||||
|
||||
(when-not (:hidden shape)
|
||||
[:g {:class (when selected? "selected")
|
||||
|
@ -121,7 +124,8 @@
|
|||
:on-mouse-over on-mouse-over
|
||||
:on-mouse-out on-mouse-out}
|
||||
(:name shape)]
|
||||
[:*
|
||||
[:g.frame {:filter (filters/filter-str filter-id shape)}
|
||||
[:& filters/filters {:filter-id filter-id :shape shape}]
|
||||
[:& frame-shape
|
||||
{:shape shape
|
||||
:childs children}]]])))))
|
||||
|
|
|
@ -12,7 +12,8 @@
|
|||
[rumext.alpha :as mf]
|
||||
[app.main.ui.workspace.sidebar.options.measures :refer [measure-attrs measures-menu]]
|
||||
[app.main.ui.workspace.sidebar.options.fill :refer [fill-attrs fill-menu]]
|
||||
[app.main.ui.workspace.sidebar.options.stroke :refer [stroke-attrs stroke-menu]]))
|
||||
[app.main.ui.workspace.sidebar.options.stroke :refer [stroke-attrs stroke-menu]]
|
||||
[app.main.ui.workspace.sidebar.options.shadow :refer [shadow-menu]]))
|
||||
|
||||
(mf/defc options
|
||||
[{:keys [shape] :as props}]
|
||||
|
@ -30,4 +31,7 @@
|
|||
:values (select-keys shape fill-attrs)}]
|
||||
[:& stroke-menu {:ids ids
|
||||
:type type
|
||||
:values stroke-values}]]))
|
||||
:values stroke-values}]
|
||||
[:& shadow-menu {:ids ids
|
||||
:type type
|
||||
:values (select-keys shape [:shadow])}]]))
|
||||
|
|
|
@ -22,7 +22,8 @@
|
|||
[app.main.ui.components.dropdown :refer [dropdown]]
|
||||
[app.main.ui.workspace.sidebar.options.fill :refer [fill-attrs fill-menu]]
|
||||
[app.main.ui.workspace.sidebar.options.stroke :refer [stroke-attrs stroke-menu]]
|
||||
[app.main.ui.workspace.sidebar.options.frame-grid :refer [frame-grid]]))
|
||||
[app.main.ui.workspace.sidebar.options.frame-grid :refer [frame-grid]]
|
||||
[app.main.ui.workspace.sidebar.options.shadow :refer [shadow-menu]]))
|
||||
|
||||
(declare +size-presets+)
|
||||
|
||||
|
@ -211,5 +212,8 @@
|
|||
[:& stroke-menu {:ids ids
|
||||
:type type
|
||||
:values stroke-values}]
|
||||
[:& shadow-menu {:ids ids
|
||||
:type type
|
||||
:values (select-keys shape [:shadow])}]
|
||||
[:& frame-grid {:shape shape}]]))
|
||||
|
||||
|
|
|
@ -121,9 +121,13 @@
|
|||
[:& advanced-options {:visible? @open-shadow
|
||||
:on-close #(reset! open-shadow false)}
|
||||
[:div.row-grid-2
|
||||
[:select.input-select
|
||||
[:select.input-select
|
||||
{:default-value (str (:style value))
|
||||
:on-change (fn [event]
|
||||
(let [value (-> event dom/get-target dom/get-value d/read-string)]
|
||||
(st/emit! (dwc/update-shapes ids #(assoc-in % [:shadow index :style] value)))))}
|
||||
[:option {:value ":drop-shadow"} "Drop shadow"]
|
||||
#_[:option {:value ":inner-shadow"} "Inner shadow"]]]
|
||||
[:option {:value ":inner-shadow"} "Inner shadow"]]]
|
||||
|
||||
[:div.row-grid-2
|
||||
[:div.input-element
|
||||
|
@ -177,7 +181,6 @@
|
|||
(mf/defc shadow-menu
|
||||
[{:keys [ids type values] :as props}]
|
||||
|
||||
(.log js/console "values" (clj->js values))
|
||||
(let [on-add-shadow
|
||||
(fn []
|
||||
(st/emit! (dwc/update-shapes ids #(update % :shadow (fnil conj []) (create-shadow)) )))]
|
||||
|
|
Loading…
Add table
Reference in a new issue