From d3345c0fa613d06d98cf30fbb20e63a0501cceee Mon Sep 17 00:00:00 2001 From: "alonso.torres" Date: Tue, 2 Mar 2021 15:19:54 +0100 Subject: [PATCH] :sparkles: Clip-paths, polylines, polygons and fixes --- .../app/main/data/workspace/svg_upload.cljs | 7 ++- frontend/src/app/main/ui/shapes/attrs.cljs | 13 +++-- frontend/src/app/main/ui/shapes/svg_defs.cljs | 11 +++-- frontend/src/app/util/svg.cljs | 47 +++++++++++++++++-- 4 files changed, 64 insertions(+), 14 deletions(-) diff --git a/frontend/src/app/main/data/workspace/svg_upload.cljs b/frontend/src/app/main/data/workspace/svg_upload.cljs index f33cf7861..b945855f1 100644 --- a/frontend/src/app/main/data/workspace/svg_upload.cljs +++ b/frontend/src/app/main/data/workspace/svg_upload.cljs @@ -273,7 +273,7 @@ (defn parse-svg-element [frame-id svg-data element-data unames] (let [{:keys [tag attrs]} element-data - attrs (cond-> attrs (contains? attrs :style) usvg/format-styles) + attrs (usvg/format-styles attrs) element-data (cond-> element-data (map? element-data) (assoc :attrs attrs)) name (dwc/generate-unique-name unames (or (:id attrs) (tag->name tag)) true) att-refs (usvg/find-attr-references attrs) @@ -290,7 +290,8 @@ translate (gpt/point (:x attrs 0) (:y attrs 0)) attrs' (dissoc attrs :x :y :width :height :href :xlink:href) ;; TODO: If the child is a symbol we've to take the width/height into account - use-data (update use-data :attrs #(d/deep-merge attrs' %)) + use-data (update use-data :attrs #(let [attrs (usvg/format-styles %)] + (d/deep-merge attrs' attrs))) [shape children] (parse-svg-element frame-id svg-data use-data unames)] [(-> shape (gsh/move translate)) children]) @@ -302,6 +303,8 @@ (:circle :ellipse) (create-circle-shape name frame-id svg-data element-data) :path (create-path-shape name frame-id svg-data element-data) + :polyline (create-path-shape name frame-id svg-data (-> element-data usvg/polyline->path)) + :polygon (create-path-shape name frame-id svg-data (-> element-data usvg/polygon->path)) #_other (create-raw-svg name frame-id svg-data element-data)) (assoc :svg-defs (select-keys (:defs svg-data) references)) diff --git a/frontend/src/app/main/ui/shapes/attrs.cljs b/frontend/src/app/main/ui/shapes/attrs.cljs index b94cf0dce..9d61e85a0 100644 --- a/frontend/src/app/main/ui/shapes/attrs.cljs +++ b/frontend/src/app/main/ui/shapes/attrs.cljs @@ -107,9 +107,13 @@ (:stroke-color-gradient shape) (assoc :stroke (str/format "url(#%s)" stroke-color-gradient-id)) - (not (:stroke-color-gradient shape)) - (assoc :stroke (:stroke-color shape nil) - :strokeOpacity (:stroke-opacity shape nil)) + (and (not (:stroke-color-gradient shape)) + (:stroke-color shape nil)) + (assoc :stroke (:stroke-color shape nil)) + + (and (not (:stroke-color-gradient shape)) + (:stroke-opacity shape nil)) + (assoc :strokeOpacity (:stroke-opacity shape nil)) (not= stroke-style :svg) (assoc :strokeDasharray (stroke-type->dasharray stroke-style)))] @@ -124,8 +128,7 @@ id)) svg-attrs (-> svg-attrs (usvg/clean-attrs) - (usvg/update-attr-ids replace-id) - ) + (usvg/update-attr-ids replace-id)) attrs (-> svg-attrs (dissoc :style) (clj->js)) styles (-> svg-attrs (:style {}) (clj->js))] diff --git a/frontend/src/app/main/ui/shapes/svg_defs.cljs b/frontend/src/app/main/ui/shapes/svg_defs.cljs index 1c4cb2f62..36d05b5a7 100644 --- a/frontend/src/app/main/ui/shapes/svg_defs.cljs +++ b/frontend/src/app/main/ui/shapes/svg_defs.cljs @@ -55,6 +55,9 @@ (every? d/num-string? [(:x attrs "0") (:y attrs "0") (:width attrs "0") (:height attrs "0")]) (= "userSpaceOnUse" (get attrs :patternUnits "userSpaceOnUse"))) + transform-clippath? (and (= :clipPath tag) + (= "userSpaceOnUse" (get attrs :clipPathUnits "userSpaceOnUse"))) + transform-filter? (and (= #{:filter ;; Filter primitives. We need to remap subregions :feBlend :feColorMatrix :feComponentTransfer :feComposite :feConvolveMatrix @@ -70,6 +73,7 @@ (cond-> transform-gradient? (add-matrix :gradientTransform transform) transform-pattern? (add-matrix :patternTransform transform) + transform-clippath? (add-matrix :transform transform) transform-filter? (transform-region transform))) [wrapper wrapper-props] (if (= tag :mask) @@ -93,9 +97,10 @@ (gmt/matrix) (usvg/svg-transform-matrix shape))) - transform (gmt/multiply - transform - (or (:svg-transform shape) (gmt/matrix))) + ;; Paths doesn't have transform so we have to transform its gradients + transform (if (and (= :path (:type shape)) (contains? shape :svg-transform)) + (gmt/multiply transform (or (:svg-transform shape) (gmt/matrix))) + transform) prefix-id (fn [id] diff --git a/frontend/src/app/util/svg.cljs b/frontend/src/app/util/svg.cljs index 0c09d78e7..5aaf65e37 100644 --- a/frontend/src/app/util/svg.cljs +++ b/frontend/src/app/util/svg.cljs @@ -49,7 +49,9 @@ (into {})) style-str))] - (update attrs :style format-styles))) + (cond-> attrs + (contains? attrs :style) + (update :style format-styles)))) (defn clean-attrs "Transforms attributes to their react equivalent" @@ -166,7 +168,8 @@ :else (let [node (get defs to-check) - new-refs (find-node-references node)] + new-refs (find-node-references node) + pending (concat pending new-refs)] (recur (d/concat result new-refs) (conj checked? to-check) (first pending) @@ -185,7 +188,12 @@ (gmt/multiply (gmt/matrix) - (gsh/transform-matrix shape) + + ;; Paths doesn't have transform so we have to transform its gradients + (if (= :path (:type shape)) + (gsh/transform-matrix shape) + (gmt/matrix)) + (gmt/translate-matrix (gpt/point (- x (* scale-x svg-x)) (- y (* scale-y svg-y)))) (gmt/scale-matrix (gpt/point scale-x scale-y)))) @@ -204,7 +212,7 @@ (defn format-translate-params [params] (assert (or (= (count params) 1) (= (count params) 2))) (if (= (count params) 1) - [(gpt/point (nth params 0))] + [(gpt/point (nth params 0) 0)] [(gpt/point (nth params 0) (nth params 1))])) (defn format-scale-params [params] @@ -252,3 +260,34 @@ (reduce gmt/multiply (gmt/matrix) matrices)) (gmt/matrix))) +(def points-regex #"[^\s\,]+") + +(defn format-move [[x y]] (str "M" x " " y)) +(defn format-line [[x y]] (str "L" x " " y)) + +(defn points->path [points-str] + (let [points (->> points-str + (re-seq points-regex) + (mapv d/parse-double) + (partition 2)) + + head (first points) + other (rest points)] + + (str (format-move head) + (->> other (map format-line) (str/join " "))))) + +(defn polyline->path [{:keys [attrs tag] :as node}] + (let [tag :path + attrs (-> attrs + (dissoc :points) + (assoc :d (points->path (:points attrs))))] + + (assoc node :attrs attrs :tag tag))) + +(defn polygon->path [{:keys [attrs tag] :as node}] + (let [tag :path + attrs (-> attrs + (dissoc :points) + (assoc :d (str (points->path (:points attrs)) "Z")))] + (assoc node :attrs attrs :tag tag)))