From 215c4fdb569bf91ab36c5e632465fdd4c5a42aaf Mon Sep 17 00:00:00 2001 From: "alonso.torres" Date: Thu, 24 Sep 2020 21:00:25 +0200 Subject: [PATCH] :sparkles: Adds inner shadow filter --- frontend/src/app/main/ui/shapes/filters.cljs | 149 ++++++++++++++---- .../app/main/ui/workspace/shapes/common.cljs | 6 +- .../app/main/ui/workspace/shapes/frame.cljs | 8 +- .../ui/workspace/sidebar/options/circle.cljs | 8 +- .../ui/workspace/sidebar/options/frame.cljs | 6 +- .../ui/workspace/sidebar/options/shadow.cljs | 9 +- 6 files changed, 144 insertions(+), 42 deletions(-) diff --git a/frontend/src/app/main/ui/shapes/filters.cljs b/frontend/src/app/main/ui/shapes/filters.cljs index d07db2cf7..8b5a537d1 100644 --- a/frontend/src/app/main/ui/shapes/filters.cljs +++ b/frontend/src/app/main/ui/shapes/filters.cljs @@ -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}]) + ]) + ]]))) diff --git a/frontend/src/app/main/ui/workspace/shapes/common.cljs b/frontend/src/app/main/ui/workspace/shapes/common.cljs index 662e89805..9aeaaacd4 100644 --- a/frontend/src/app/main/ui/workspace/shapes/common.cljs +++ b/frontend/src/app/main/ui/workspace/shapes/common.cljs @@ -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}]]))) diff --git a/frontend/src/app/main/ui/workspace/shapes/frame.cljs b/frontend/src/app/main/ui/workspace/shapes/frame.cljs index 19defafca..1e6702795 100644 --- a/frontend/src/app/main/ui/workspace/shapes/frame.cljs +++ b/frontend/src/app/main/ui/workspace/shapes/frame.cljs @@ -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}]]]))))) diff --git a/frontend/src/app/main/ui/workspace/sidebar/options/circle.cljs b/frontend/src/app/main/ui/workspace/sidebar/options/circle.cljs index 287c2d9c2..3986c025c 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/options/circle.cljs +++ b/frontend/src/app/main/ui/workspace/sidebar/options/circle.cljs @@ -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])}]])) diff --git a/frontend/src/app/main/ui/workspace/sidebar/options/frame.cljs b/frontend/src/app/main/ui/workspace/sidebar/options/frame.cljs index afb6e0e48..78642b1b9 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/options/frame.cljs +++ b/frontend/src/app/main/ui/workspace/sidebar/options/frame.cljs @@ -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}]])) diff --git a/frontend/src/app/main/ui/workspace/sidebar/options/shadow.cljs b/frontend/src/app/main/ui/workspace/sidebar/options/shadow.cljs index 47ff7ef24..b3ef6ee70 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/options/shadow.cljs +++ b/frontend/src/app/main/ui/workspace/sidebar/options/shadow.cljs @@ -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)) )))]