mirror of
https://github.com/penpot/penpot.git
synced 2025-08-06 13:38:30 +02:00
✨ Improve svg shapes attrs handling
And collaterally it improves performance since now the attrs processing is done in the import and not in the render.
This commit is contained in:
parent
807f475a2d
commit
4f23852bca
8 changed files with 292 additions and 225 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -1,4 +1,5 @@
|
||||||
*-init.clj
|
*-init.clj
|
||||||
|
*.css.json
|
||||||
*.jar
|
*.jar
|
||||||
*.orig
|
*.orig
|
||||||
*.penpot
|
*.penpot
|
||||||
|
|
|
@ -6,4 +6,4 @@
|
||||||
|
|
||||||
(ns app.common.files.defaults)
|
(ns app.common.files.defaults)
|
||||||
|
|
||||||
(def version 31)
|
(def version 32)
|
||||||
|
|
|
@ -18,6 +18,7 @@
|
||||||
[app.common.math :as mth]
|
[app.common.math :as mth]
|
||||||
[app.common.pages.changes :as cpc]
|
[app.common.pages.changes :as cpc]
|
||||||
[app.common.pages.helpers :as cph]
|
[app.common.pages.helpers :as cph]
|
||||||
|
[app.common.svg :as csvg]
|
||||||
[app.common.text :as txt]
|
[app.common.text :as txt]
|
||||||
[app.common.types.shape :as cts]
|
[app.common.types.shape :as cts]
|
||||||
[app.common.uuid :as uuid]
|
[app.common.uuid :as uuid]
|
||||||
|
@ -587,7 +588,23 @@
|
||||||
|
|
||||||
(update-container [container]
|
(update-container [container]
|
||||||
(d/update-when container :objects update-vals update-object))]
|
(d/update-when container :objects update-vals update-object))]
|
||||||
|
(-> data
|
||||||
|
(update :pages-index update-vals update-container)
|
||||||
|
(update :components update-vals update-container))))
|
||||||
|
|
||||||
|
(defmethod migrate 32
|
||||||
|
[data]
|
||||||
|
(letfn [(update-object [object]
|
||||||
|
(as-> object object
|
||||||
|
(if (contains? object :svg-attrs)
|
||||||
|
(update object :svg-attrs csvg/attrs->props)
|
||||||
|
object)
|
||||||
|
(if (contains? object :svg-viewbox)
|
||||||
|
(update object :svg-viewbox grc/make-rect)
|
||||||
|
object)))
|
||||||
|
|
||||||
|
(update-container [container]
|
||||||
|
(update container :objects update-vals update-object))]
|
||||||
(-> data
|
(-> data
|
||||||
(update :pages-index update-vals update-container)
|
(update :pages-index update-vals update-container)
|
||||||
(update :components update-vals update-container))))
|
(update :components update-vals update-container))))
|
||||||
|
|
|
@ -6,10 +6,9 @@
|
||||||
|
|
||||||
(ns app.common.svg
|
(ns app.common.svg
|
||||||
(:require
|
(:require
|
||||||
#?(:cljs ["./svg_optimizer.js" :as svgo])
|
#?(:cljs ["./svg_optimizer.js" :as svgo])
|
||||||
|
|
||||||
|
|
||||||
[app.common.data :as d]
|
[app.common.data :as d]
|
||||||
|
[app.common.data.macros :as dm]
|
||||||
[app.common.geom.matrix :as gmt]
|
[app.common.geom.matrix :as gmt]
|
||||||
[app.common.geom.point :as gpt]
|
[app.common.geom.point :as gpt]
|
||||||
[app.common.geom.shapes :as gsh]
|
[app.common.geom.shapes :as gsh]
|
||||||
|
@ -548,34 +547,74 @@
|
||||||
[num-str]
|
[num-str]
|
||||||
(cond
|
(cond
|
||||||
(str/starts-with? num-str ".")
|
(str/starts-with? num-str ".")
|
||||||
(str "0" num-str)
|
(dm/str "0" num-str)
|
||||||
|
|
||||||
(str/starts-with? num-str "-.")
|
(str/starts-with? num-str "-.")
|
||||||
(str "-0" (subs num-str 1))
|
(dm/str "-0" (subs num-str 1))
|
||||||
|
|
||||||
:else
|
:else
|
||||||
num-str))
|
num-str))
|
||||||
|
|
||||||
(defn format-styles
|
(defn- camelize
|
||||||
"Transforms attributes to their react equivalent"
|
[s]
|
||||||
[attrs]
|
(when (string? s)
|
||||||
(letfn [(format-styles [style-str]
|
#?(:cljs (js* "~{}.replace(\":\", \"-\").replace(/-./g, x=>x[1].toUpperCase())", s)
|
||||||
(if (string? style-str)
|
:clj (str/camel s))))
|
||||||
(->> (str/split style-str ";")
|
|
||||||
(map str/trim)
|
|
||||||
(map #(str/split % ":"))
|
|
||||||
(group-by first)
|
|
||||||
(map (fn [[key val]]
|
|
||||||
(vector (keyword key) (second (first val)))))
|
|
||||||
(into {}))
|
|
||||||
style-str))]
|
|
||||||
|
|
||||||
(cond-> attrs
|
(defn parse-style
|
||||||
(contains? attrs :style)
|
[style]
|
||||||
(update :style format-styles))))
|
(reduce (fn [res item]
|
||||||
|
(let [[k v] (-> (str/trim item) (str/split ":" 2))
|
||||||
|
k (keyword k)]
|
||||||
|
(if (contains? res k)
|
||||||
|
res
|
||||||
|
(assoc res (keyword k) v))))
|
||||||
|
{}
|
||||||
|
(str/split style ";")))
|
||||||
|
|
||||||
|
;; FIXME: rename to `format-style` or directly use parse-style on code...
|
||||||
|
(defn format-styles
|
||||||
|
"Transform string based styles found on attrs map to key-value map."
|
||||||
|
[attrs]
|
||||||
|
(if (contains? attrs :style)
|
||||||
|
(update attrs :style
|
||||||
|
(fn [style]
|
||||||
|
(if (string? style)
|
||||||
|
(parse-style style)
|
||||||
|
style)))
|
||||||
|
attrs))
|
||||||
|
|
||||||
|
(defn attrs->props
|
||||||
|
"Transforms and cleans svg attributes to react compatible props"
|
||||||
|
([attrs]
|
||||||
|
(attrs->props attrs true))
|
||||||
|
|
||||||
|
([attrs whitelist?]
|
||||||
|
(reduce-kv (fn [res k v]
|
||||||
|
(if (or (not whitelist?)
|
||||||
|
(contains? svg-attr-list k)
|
||||||
|
(contains? svg-present-list k))
|
||||||
|
(cond
|
||||||
|
(= k :class)
|
||||||
|
(assoc res :className val)
|
||||||
|
|
||||||
|
(= k :style)
|
||||||
|
(let [v (if (string? v) (parse-style v) v)]
|
||||||
|
(assoc res k (attrs->props v false)))
|
||||||
|
|
||||||
|
:else
|
||||||
|
(let [k (if (contains? non-react-props k)
|
||||||
|
k
|
||||||
|
(-> k d/name camelize keyword))]
|
||||||
|
(assoc res k v)))
|
||||||
|
res))
|
||||||
|
{}
|
||||||
|
attrs)))
|
||||||
|
|
||||||
(defn clean-attrs
|
(defn clean-attrs
|
||||||
"Transforms attributes to their react equivalent"
|
"Transforms attributes to their react equivalent
|
||||||
|
|
||||||
|
DEPRECATED: replaced by attrs->props"
|
||||||
([attrs]
|
([attrs]
|
||||||
(clean-attrs attrs true))
|
(clean-attrs attrs true))
|
||||||
|
|
||||||
|
@ -590,8 +629,7 @@
|
||||||
#?(:cljs (js* "~{}.replace(\":\", \"-\").replace(/-./g, x=>x[1].toUpperCase())", s)
|
#?(:cljs (js* "~{}.replace(\":\", \"-\").replace(/-./g, x=>x[1].toUpperCase())", s)
|
||||||
:clj (str/camel s))))
|
:clj (str/camel s))))
|
||||||
|
|
||||||
|
(transform-key [key]
|
||||||
(transform-att [key]
|
|
||||||
(if (contains? non-react-props key)
|
(if (contains? non-react-props key)
|
||||||
key
|
key
|
||||||
(-> (d/name key)
|
(-> (d/name key)
|
||||||
|
@ -604,17 +642,26 @@
|
||||||
(map #(str/split % ":"))
|
(map #(str/split % ":"))
|
||||||
(group-by first)
|
(group-by first)
|
||||||
(map (fn [[key val]]
|
(map (fn [[key val]]
|
||||||
[(transform-att key)
|
[(transform-key key)
|
||||||
(second (first val))]))
|
(second (first val))]))
|
||||||
(into {})))
|
(into {})))
|
||||||
|
|
||||||
(clean-att [[att val]]
|
(clean-key [[key val]]
|
||||||
(let [att (keyword att)]
|
(let [key (keyword key)]
|
||||||
(cond
|
(cond
|
||||||
(= att :class) [:className val]
|
(= key :class)
|
||||||
(and (= att :style) (string? val)) [att (format-styles val)]
|
[:className val]
|
||||||
(and (= att :style) (map? val)) [att (clean-attrs val false)]
|
|
||||||
:else [(transform-att att) val])))]
|
(and (= key :style)
|
||||||
|
(string? val))
|
||||||
|
[key (format-styles val)]
|
||||||
|
|
||||||
|
(and (= key :style)
|
||||||
|
(map? val))
|
||||||
|
[key (clean-attrs val false)]
|
||||||
|
|
||||||
|
:else
|
||||||
|
[(transform-key key) val])))]
|
||||||
|
|
||||||
;; Removed this warning because slows a lot rendering with big svgs
|
;; Removed this warning because slows a lot rendering with big svgs
|
||||||
#_(let [filtered-props (->> attrs (remove known-property?) (map first))]
|
#_(let [filtered-props (->> attrs (remove known-property?) (map first))]
|
||||||
|
@ -623,7 +670,7 @@
|
||||||
|
|
||||||
(into {}
|
(into {}
|
||||||
(comp (filter known-property?)
|
(comp (filter known-property?)
|
||||||
(map clean-att))
|
(map clean-key))
|
||||||
attrs))))
|
attrs))))
|
||||||
|
|
||||||
(defn update-attr-ids
|
(defn update-attr-ids
|
||||||
|
@ -649,16 +696,17 @@
|
||||||
(defn replace-attrs-ids
|
(defn replace-attrs-ids
|
||||||
"Replaces the ids inside a property"
|
"Replaces the ids inside a property"
|
||||||
[attrs ids-mapping]
|
[attrs ids-mapping]
|
||||||
(if (and ids-mapping (seq ids-mapping))
|
(if (empty? ids-mapping)
|
||||||
(update-attr-ids attrs (fn [id] (get ids-mapping id id)))
|
attrs
|
||||||
;; Ids-mapping is null
|
(update-attr-ids attrs (fn [id] (get ids-mapping id id)))))
|
||||||
attrs))
|
|
||||||
|
|
||||||
(defn generate-id-mapping [content]
|
(defn generate-id-mapping
|
||||||
|
[content]
|
||||||
(letfn [(visit-node [result node]
|
(letfn [(visit-node [result node]
|
||||||
(let [element-id (get-in node [:attrs :id])
|
(let [element-id (dm/get-in node [:attrs :id])
|
||||||
result (cond-> result
|
result (if (some? element-id)
|
||||||
element-id (assoc element-id (str (uuid/next))))]
|
(assoc result element-id (dm/str (uuid/next)))
|
||||||
|
result)]
|
||||||
(reduce visit-node result (:content node))))]
|
(reduce visit-node result (:content node))))]
|
||||||
(visit-node {} content)))
|
(visit-node {} content)))
|
||||||
|
|
||||||
|
|
|
@ -14,6 +14,8 @@
|
||||||
[app.common.geom.point :as gpt]
|
[app.common.geom.point :as gpt]
|
||||||
[app.common.geom.rect :as grc]
|
[app.common.geom.rect :as grc]
|
||||||
[app.common.geom.shapes :as gsh]
|
[app.common.geom.shapes :as gsh]
|
||||||
|
[app.common.geom.shapes.common :as gsc]
|
||||||
|
[app.common.geom.shapes.transforms :as gst]
|
||||||
[app.common.math :as mth]
|
[app.common.math :as mth]
|
||||||
[app.common.pages.changes-builder :as pcb]
|
[app.common.pages.changes-builder :as pcb]
|
||||||
[app.common.pages.helpers :as cph]
|
[app.common.pages.helpers :as cph]
|
||||||
|
@ -65,7 +67,8 @@
|
||||||
(contains? cts/blend-modes clean-value))
|
(contains? cts/blend-modes clean-value))
|
||||||
clean-value))
|
clean-value))
|
||||||
|
|
||||||
(defn- svg-dimensions [data]
|
(defn- svg-dimensions
|
||||||
|
[data]
|
||||||
(let [width (dm/get-in data [:attrs :width] 100)
|
(let [width (dm/get-in data [:attrs :width] 100)
|
||||||
height (dm/get-in data [:attrs :height] 100)
|
height (dm/get-in data [:attrs :height] 100)
|
||||||
viewbox (dm/get-in data [:attrs :viewBox] (str "0 0 " width " " height))
|
viewbox (dm/get-in data [:attrs :viewBox] (str "0 0 " width " " height))
|
||||||
|
@ -81,12 +84,15 @@
|
||||||
(defn tag->name
|
(defn tag->name
|
||||||
"Given a tag returns its layer name"
|
"Given a tag returns its layer name"
|
||||||
[tag]
|
[tag]
|
||||||
(str "svg-" (cond (string? tag) tag
|
(let [suffix (cond
|
||||||
(keyword? tag) (d/name tag)
|
(string? tag) tag
|
||||||
(nil? tag) "node"
|
(keyword? tag) (d/name tag)
|
||||||
:else (str tag))))
|
(nil? tag) "node"
|
||||||
|
:else (dm/str tag))]
|
||||||
|
(dm/str "svg-" suffix)))
|
||||||
|
|
||||||
(defn setup-fill [shape]
|
(defn setup-fill
|
||||||
|
[shape]
|
||||||
(let [color-attr (str/trim (dm/get-in shape [:svg-attrs :fill]))
|
(let [color-attr (str/trim (dm/get-in shape [:svg-attrs :fill]))
|
||||||
color-attr (if (= color-attr "currentColor") clr/black color-attr)
|
color-attr (if (= color-attr "currentColor") clr/black color-attr)
|
||||||
color-style (str/trim (dm/get-in shape [:svg-attrs :style :fill]))
|
color-style (str/trim (dm/get-in shape [:svg-attrs :style :fill]))
|
||||||
|
@ -104,16 +110,16 @@
|
||||||
(update :svg-attrs dissoc :fill)
|
(update :svg-attrs dissoc :fill)
|
||||||
(assoc-in [:fills 0 :fill-color] (uc/parse-color color-style)))
|
(assoc-in [:fills 0 :fill-color] (uc/parse-color color-style)))
|
||||||
|
|
||||||
(dm/get-in shape [:svg-attrs :fill-opacity])
|
(dm/get-in shape [:svg-attrs :fillOpacity])
|
||||||
(-> (update :svg-attrs dissoc :fill-opacity)
|
(-> (update :svg-attrs dissoc :fillOpacity)
|
||||||
(update-in [:svg-attrs :style] dissoc :fill-opacity)
|
(update-in [:svg-attrs :style] dissoc :fillOpacity)
|
||||||
(assoc-in [:fills 0 :fill-opacity] (-> (dm/get-in shape [:svg-attrs :fill-opacity])
|
(assoc-in [:fills 0 :fill-opacity] (-> (dm/get-in shape [:svg-attrs :fillOpacity])
|
||||||
(d/parse-double 1))))
|
(d/parse-double 1))))
|
||||||
|
|
||||||
(dm/get-in shape [:svg-attrs :style :fill-opacity])
|
(dm/get-in shape [:svg-attrs :style :fillOpacity])
|
||||||
(-> (update-in [:svg-attrs :style] dissoc :fill-opacity)
|
(-> (update-in [:svg-attrs :style] dissoc :fillOpacity)
|
||||||
(update :svg-attrs dissoc :fill-opacity)
|
(update :svg-attrs dissoc :fillOpacity)
|
||||||
(assoc-in [:fills 0 :fill-opacity] (-> (dm/get-in shape [:svg-attrs :style :fill-opacity])
|
(assoc-in [:fills 0 :fill-opacity] (-> (dm/get-in shape [:svg-attrs :style :fillOpacity])
|
||||||
(d/parse-double 1)))))))
|
(d/parse-double 1)))))))
|
||||||
|
|
||||||
(defn- setup-stroke
|
(defn- setup-stroke
|
||||||
|
@ -131,30 +137,30 @@
|
||||||
|
|
||||||
opacity (when (some? color)
|
opacity (when (some? color)
|
||||||
(d/parse-double
|
(d/parse-double
|
||||||
(or (:stroke-opacity attrs)
|
(or (:strokeOpacity attrs)
|
||||||
(:stroke-opacity style))
|
(:strokeOpacity style))
|
||||||
1))
|
1))
|
||||||
|
|
||||||
width (when (some? color)
|
width (when (some? color)
|
||||||
(d/parse-double
|
(d/parse-double
|
||||||
(or (:stroke-width attrs)
|
(or (:strokeWidth attrs)
|
||||||
(:stroke-width style))
|
(:strokeWidth style))
|
||||||
1))
|
1))
|
||||||
|
|
||||||
linecap (or (get attrs :stroke-linecap)
|
linecap (or (get attrs :strokeLinecap)
|
||||||
(get style :stroke-linecap))
|
(get style :strokeLinecap))
|
||||||
linecap (some-> linecap str/trim keyword)
|
linecap (some-> linecap str/trim keyword)
|
||||||
|
|
||||||
attrs (-> attrs
|
attrs (-> attrs
|
||||||
(dissoc :stroke)
|
(dissoc :stroke)
|
||||||
(dissoc :stroke-width)
|
(dissoc :strokeWidth)
|
||||||
(dissoc :stroke-opacity)
|
(dissoc :strokeOpacity)
|
||||||
(update :style (fn [style]
|
(update :style (fn [style]
|
||||||
(-> style
|
(-> style
|
||||||
(dissoc :stroke)
|
(dissoc :stroke)
|
||||||
(dissoc :stroke-linecap)
|
(dissoc :strokeLinecap)
|
||||||
(dissoc :stroke-width)
|
(dissoc :strokeWidth)
|
||||||
(dissoc :stroke-opacity)))))]
|
(dissoc :strokeOpacity)))))]
|
||||||
|
|
||||||
(cond-> (assoc shape :svg-attrs attrs)
|
(cond-> (assoc shape :svg-attrs attrs)
|
||||||
(some? color)
|
(some? color)
|
||||||
|
@ -172,8 +178,8 @@
|
||||||
:stroke-cap-end linecap)
|
:stroke-cap-end linecap)
|
||||||
|
|
||||||
(d/any-key? (dm/get-in shape [:strokes 0])
|
(d/any-key? (dm/get-in shape [:strokes 0])
|
||||||
:stroke-color :stroke-opacity :stroke-width
|
:strokeColor :strokeOpacity :strokeWidth
|
||||||
:stroke-cap-start :stroke-cap-end)
|
:strokeCapStart :strokeCapEnd)
|
||||||
(assoc-in [:strokes 0 :stroke-style] :svg))))
|
(assoc-in [:strokes 0 :stroke-style] :svg))))
|
||||||
|
|
||||||
(defn setup-opacity [shape]
|
(defn setup-opacity [shape]
|
||||||
|
@ -188,51 +194,52 @@
|
||||||
(assoc :opacity (-> (dm/get-in shape [:svg-attrs :style :opacity])
|
(assoc :opacity (-> (dm/get-in shape [:svg-attrs :style :opacity])
|
||||||
(d/parse-double 1))))
|
(d/parse-double 1))))
|
||||||
|
|
||||||
(dm/get-in shape [:svg-attrs :mix-blend-mode])
|
(dm/get-in shape [:svg-attrs :mixBlendMode])
|
||||||
(-> (update :svg-attrs dissoc :mix-blend-mode)
|
(-> (update :svg-attrs dissoc :mixBlendMode)
|
||||||
(assoc :blend-mode (-> (dm/get-in shape [:svg-attrs :mix-blend-mode]) assert-valid-blend-mode)))
|
(assoc :blend-mode (-> (dm/get-in shape [:svg-attrs :mixBlendMode]) assert-valid-blend-mode)))
|
||||||
|
|
||||||
(dm/get-in shape [:svg-attrs :style :mix-blend-mode])
|
(dm/get-in shape [:svg-attrs :style :mixBlendMode])
|
||||||
(-> (update-in [:svg-attrs :style] dissoc :mix-blend-mode)
|
(-> (update-in [:svg-attrs :style] dissoc :mixBlendMode)
|
||||||
(assoc :blend-mode (-> (dm/get-in shape [:svg-attrs :style :mix-blend-mode]) assert-valid-blend-mode)))))
|
(assoc :blend-mode (-> (dm/get-in shape [:svg-attrs :style :mixBlendMode]) assert-valid-blend-mode)))))
|
||||||
|
|
||||||
(defn create-raw-svg
|
(defn create-raw-svg
|
||||||
[name frame-id {:keys [x y width height offset-x offset-y]} {:keys [attrs] :as data}]
|
[name frame-id {:keys [x y width height offset-x offset-y]} {:keys [attrs] :as data}]
|
||||||
(cts/setup-shape
|
(let [props (csvg/attrs->props attrs)
|
||||||
{:type :svg-raw
|
vbox (grc/make-rect offset-x offset-y width height)]
|
||||||
:name name
|
(cts/setup-shape
|
||||||
:frame-id frame-id
|
{:type :svg-raw
|
||||||
:width width
|
:name name
|
||||||
:height height
|
:frame-id frame-id
|
||||||
:x x
|
:width width
|
||||||
:y y
|
:height height
|
||||||
:content (cond-> data
|
:x x
|
||||||
(map? data) (update :attrs csvg/clean-attrs))
|
:y y
|
||||||
:svg-attrs attrs
|
:content data
|
||||||
:svg-viewbox {:width width
|
:svg-attrs props
|
||||||
:height height
|
:svg-viewbox vbox})))
|
||||||
:x offset-x
|
|
||||||
:y offset-y}}))
|
|
||||||
|
|
||||||
(defn create-svg-root
|
(defn create-svg-root
|
||||||
[frame-id parent-id {:keys [name x y width height offset-x offset-y attrs]}]
|
[frame-id parent-id {:keys [name x y width height offset-x offset-y attrs]}]
|
||||||
(cts/setup-shape
|
(let [props (-> (dissoc attrs :viewBox :view-box :xmlns)
|
||||||
{:type :group
|
(d/without-keys csvg/inheritable-props)
|
||||||
:name name
|
(csvg/attrs->props))]
|
||||||
:frame-id frame-id
|
(cts/setup-shape
|
||||||
:parent-id parent-id
|
{:type :group
|
||||||
:width width
|
:name name
|
||||||
:height height
|
:frame-id frame-id
|
||||||
:x (+ x offset-x)
|
:parent-id parent-id
|
||||||
:y (+ y offset-y)
|
:width width
|
||||||
:svg-attrs (-> attrs
|
:height height
|
||||||
(dissoc :viewBox)
|
:x (+ x offset-x)
|
||||||
(dissoc :xmlns)
|
:y (+ y offset-y)
|
||||||
(d/without-keys csvg/inheritable-props))}))
|
:svg-attrs props})))
|
||||||
|
|
||||||
(defn create-group
|
(defn create-group
|
||||||
[name frame-id {:keys [x y width height offset-x offset-y] :as svg-data} {:keys [attrs]}]
|
[name frame-id {:keys [x y width height offset-x offset-y] :as svg-data} {:keys [attrs]}]
|
||||||
(let [svg-transform (csvg/parse-transform (:transform attrs))]
|
(let [transform (csvg/parse-transform (:transform attrs))
|
||||||
|
attrs (-> (d/without-keys attrs csvg/inheritable-props)
|
||||||
|
(csvg/attrs->props))
|
||||||
|
vbox (grc/make-rect offset-x offset-y width height)]
|
||||||
(cts/setup-shape
|
(cts/setup-shape
|
||||||
{:type :group
|
{:type :group
|
||||||
:name name
|
:name name
|
||||||
|
@ -241,28 +248,22 @@
|
||||||
:y (+ y offset-y)
|
:y (+ y offset-y)
|
||||||
:width width
|
:width width
|
||||||
:height height
|
:height height
|
||||||
:svg-transform svg-transform
|
:svg-transform transform
|
||||||
:svg-attrs (d/without-keys attrs csvg/inheritable-props)
|
:svg-attrs attrs
|
||||||
|
:svg-viewbox vbox})))
|
||||||
:svg-viewbox {:width width
|
|
||||||
:height height
|
|
||||||
:x offset-x
|
|
||||||
:y offset-y}})))
|
|
||||||
|
|
||||||
(defn create-path-shape [name frame-id svg-data {:keys [attrs] :as data}]
|
(defn create-path-shape [name frame-id svg-data {:keys [attrs] :as data}]
|
||||||
(when (and (contains? attrs :d) (seq (:d attrs)))
|
(when (and (contains? attrs :d) (seq (:d attrs)))
|
||||||
|
(let [transform (csvg/parse-transform (:transform attrs))
|
||||||
|
content (cond-> (upp/parse-path (:d attrs))
|
||||||
|
(some? transform)
|
||||||
|
(gsh/transform-content transform))
|
||||||
|
|
||||||
(let [svg-transform (csvg/parse-transform (:transform attrs))
|
selrect (gsh/content->selrect content)
|
||||||
path-content (upp/parse-path (:d attrs))
|
points (grc/rect->points selrect)
|
||||||
content (cond-> path-content
|
origin (gpt/negate (gpt/point svg-data))
|
||||||
svg-transform
|
attrs (-> (dissoc attrs :d :transform)
|
||||||
(gsh/transform-content svg-transform))
|
(csvg/attrs->props))]
|
||||||
|
|
||||||
selrect (gsh/content->selrect content)
|
|
||||||
points (grc/rect->points selrect)
|
|
||||||
|
|
||||||
origin (gpt/negate (gpt/point svg-data))]
|
|
||||||
|
|
||||||
(-> (cts/setup-shape
|
(-> (cts/setup-shape
|
||||||
{:type :path
|
{:type :path
|
||||||
:name name
|
:name name
|
||||||
|
@ -270,17 +271,20 @@
|
||||||
:content content
|
:content content
|
||||||
:selrect selrect
|
:selrect selrect
|
||||||
:points points
|
:points points
|
||||||
:svg-viewbox (select-keys selrect [:x :y :width :height])
|
:svg-viewbox selrect
|
||||||
:svg-attrs (dissoc attrs :d :transform)
|
:svg-attrs attrs
|
||||||
:svg-transform svg-transform})
|
:svg-transform transform
|
||||||
|
:fills []})
|
||||||
(gsh/translate-to-frame origin)))))
|
(gsh/translate-to-frame origin)))))
|
||||||
|
|
||||||
(defn calculate-rect-metadata [rect-data transform]
|
(defn calculate-rect-metadata
|
||||||
(let [points (-> (grc/make-rect rect-data)
|
[rect transform]
|
||||||
(grc/rect->points)
|
(let [points (-> rect
|
||||||
(gsh/transform-points transform))
|
(grc/rect->points)
|
||||||
|
(gsh/transform-points transform))
|
||||||
[selrect transform transform-inverse] (gsh/calculate-geometry points)]
|
center (gsc/points->center points)
|
||||||
|
selrect (gst/calculate-selrect points center)
|
||||||
|
transform (gst/calculate-transform points center selrect)]
|
||||||
|
|
||||||
{:x (:x selrect)
|
{:x (:x selrect)
|
||||||
:y (:y selrect)
|
:y (:y selrect)
|
||||||
|
@ -289,107 +293,116 @@
|
||||||
:selrect selrect
|
:selrect selrect
|
||||||
:points points
|
:points points
|
||||||
:transform transform
|
:transform transform
|
||||||
:transform-inverse transform-inverse}))
|
:transform-inverse (when (some? transform)
|
||||||
|
(gmt/inverse transform))}))
|
||||||
|
|
||||||
(defn- parse-rect-attrs
|
(defn- parse-rect-attrs
|
||||||
[{:keys [x y width height]}]
|
[{:keys [x y width height]}]
|
||||||
{:x (d/parse-double x 0)
|
(grc/make-rect
|
||||||
:y (d/parse-double y 0)
|
(d/parse-double x 0)
|
||||||
:width (d/parse-double width 1)
|
(d/parse-double y 0)
|
||||||
:height (d/parse-double height 1)})
|
(d/parse-double width 1)
|
||||||
|
(d/parse-double height 1)))
|
||||||
|
|
||||||
(defn create-rect-shape [name frame-id svg-data {:keys [attrs] :as data}]
|
(defn create-rect-shape [name frame-id svg-data {:keys [attrs] :as data}]
|
||||||
(let [transform (->> (csvg/parse-transform (:transform attrs))
|
(let [transform (->> (csvg/parse-transform (:transform attrs))
|
||||||
(gmt/transform-in (gpt/point svg-data)))
|
(gmt/transform-in (gpt/point svg-data)))
|
||||||
|
|
||||||
origin (gpt/negate (gpt/point svg-data))
|
origin (gpt/negate (gpt/point svg-data))
|
||||||
|
rect (-> (parse-rect-attrs attrs)
|
||||||
rect-data (-> (parse-rect-attrs attrs)
|
|
||||||
(update :x - (:x origin))
|
(update :x - (:x origin))
|
||||||
(update :y - (:y origin)))]
|
(update :y - (:y origin)))
|
||||||
|
|
||||||
|
props (-> (dissoc attrs :x :y :width :height :rx :ry :transform)
|
||||||
|
(csvg/attrs->props))]
|
||||||
|
|
||||||
(cts/setup-shape
|
(cts/setup-shape
|
||||||
(-> (calculate-rect-metadata rect-data transform)
|
(-> (calculate-rect-metadata rect transform)
|
||||||
(assoc :type :rect)
|
(assoc :type :rect)
|
||||||
(assoc :name name)
|
(assoc :name name)
|
||||||
(assoc :frame-id frame-id)
|
(assoc :frame-id frame-id)
|
||||||
(assoc :svg-viewbox (select-keys rect-data [:x :y :width :height]))
|
(assoc :svg-viewbox rect)
|
||||||
(assoc :svg-attrs (dissoc attrs :x :y :width :height :rx :ry :transform))
|
(assoc :svg-attrs props)
|
||||||
|
;; We need to ensure fills are empty on import process
|
||||||
|
;; because setup-shape assings one by default.
|
||||||
|
(assoc :fills [])
|
||||||
(cond-> (contains? attrs :rx)
|
(cond-> (contains? attrs :rx)
|
||||||
(assoc :rx (d/parse-double (:rx attrs) 0)))
|
(assoc :rx (d/parse-double (:rx attrs) 0)))
|
||||||
(cond-> (contains? attrs :ry)
|
(cond-> (contains? attrs :ry)
|
||||||
(assoc :ry (d/parse-double (:ry attrs) 0)))))))
|
(assoc :ry (d/parse-double (:ry attrs) 0)))))))
|
||||||
|
|
||||||
|
|
||||||
(defn- parse-circle-attrs
|
(defn- parse-circle-attrs
|
||||||
[attrs]
|
[attrs]
|
||||||
(into [] (comp (map (d/getf attrs))
|
(into [] (comp (map (d/getf attrs))
|
||||||
(map d/parse-double))
|
(map d/parse-double))
|
||||||
[:cx :cy :r :rx :ry]))
|
[:cx :cy :r :rx :ry]))
|
||||||
|
|
||||||
(defn create-circle-shape [name frame-id svg-data {:keys [attrs] :as data}]
|
(defn create-circle-shape
|
||||||
|
[name frame-id svg-data {:keys [attrs] :as data}]
|
||||||
(let [[cx cy r rx ry]
|
(let [[cx cy r rx ry]
|
||||||
(parse-circle-attrs attrs)
|
(parse-circle-attrs attrs)
|
||||||
|
|
||||||
transform (->> (csvg/parse-transform (:transform attrs))
|
transform (->> (csvg/parse-transform (:transform attrs))
|
||||||
(gmt/transform-in (gpt/point svg-data)))
|
(gmt/transform-in (gpt/point svg-data)))
|
||||||
|
|
||||||
rx (or r rx)
|
rx (d/nilv r rx)
|
||||||
ry (or r ry)
|
ry (d/nilv r ry)
|
||||||
origin (gpt/negate (gpt/point svg-data))
|
origin (gpt/negate (gpt/point svg-data))
|
||||||
|
|
||||||
rect-data {:x (- cx rx (:x origin))
|
rect (grc/make-rect
|
||||||
:y (- cy ry (:y origin))
|
(- cx rx (:x origin))
|
||||||
:width (* 2 rx)
|
(- cy ry (:y origin))
|
||||||
:height (* 2 ry)}]
|
(* 2 rx)
|
||||||
|
(* 2 ry))
|
||||||
|
props (-> (dissoc attrs :cx :cy :r :rx :ry :transform)
|
||||||
|
(csvg/attrs->props))]
|
||||||
|
|
||||||
(cts/setup-shape
|
(cts/setup-shape
|
||||||
(-> (calculate-rect-metadata rect-data transform)
|
(-> (calculate-rect-metadata rect transform)
|
||||||
(assoc :type :circle)
|
(assoc :type :circle)
|
||||||
(assoc :name name)
|
(assoc :name name)
|
||||||
(assoc :frame-id frame-id)
|
(assoc :frame-id frame-id)
|
||||||
(assoc :svg-viewbox rect-data)
|
(assoc :svg-viewbox rect)
|
||||||
(assoc :svg-attrs (dissoc attrs :cx :cy :r :rx :ry :transform))))))
|
(assoc :svg-attrs props)
|
||||||
|
(assoc :fills [])))))
|
||||||
|
|
||||||
(defn create-image-shape [name frame-id svg-data {:keys [attrs] :as data}]
|
(defn create-image-shape
|
||||||
|
[name frame-id svg-data {:keys [attrs] :as data}]
|
||||||
(let [transform (->> (csvg/parse-transform (:transform attrs))
|
(let [transform (->> (csvg/parse-transform (:transform attrs))
|
||||||
(gmt/transform-in (gpt/point svg-data)))
|
(gmt/transform-in (gpt/point svg-data)))
|
||||||
|
|
||||||
image-url (or (:href attrs) (:xlink:href attrs))
|
image-url (or (:href attrs) (:xlink:href attrs))
|
||||||
image-data (dm/get-in svg-data [:image-data image-url])
|
image-data (dm/get-in svg-data [:image-data image-url])
|
||||||
|
|
||||||
|
|
||||||
metadata {:width (:width image-data)
|
metadata {:width (:width image-data)
|
||||||
:height (:height image-data)
|
:height (:height image-data)
|
||||||
:mtype (:mtype image-data)
|
:mtype (:mtype image-data)
|
||||||
:id (:id image-data)}
|
:id (:id image-data)}
|
||||||
|
|
||||||
origin (gpt/negate (gpt/point svg-data))
|
origin (gpt/negate (gpt/point svg-data))
|
||||||
rect-data (-> (parse-rect-attrs attrs)
|
rect (-> (parse-rect-attrs attrs)
|
||||||
(update :x - (:x origin))
|
(update :x - (:x origin))
|
||||||
(update :y - (:y origin)))]
|
(update :y - (:y origin)))
|
||||||
|
props (-> (dissoc attrs :x :y :width :height :href :xlink:href)
|
||||||
|
(csvg/attrs->props))]
|
||||||
|
|
||||||
(when (some? image-data)
|
(when (some? image-data)
|
||||||
(cts/setup-shape
|
(cts/setup-shape
|
||||||
(-> (calculate-rect-metadata rect-data transform)
|
(-> (calculate-rect-metadata rect transform)
|
||||||
(assoc :type :image)
|
(assoc :type :image)
|
||||||
(assoc :name name)
|
(assoc :name name)
|
||||||
(assoc :frame-id frame-id)
|
(assoc :frame-id frame-id)
|
||||||
(assoc :metadata metadata)
|
(assoc :metadata metadata)
|
||||||
(assoc :svg-viewbox (select-keys rect-data [:x :y :width :height]))
|
(assoc :svg-viewbox rect)
|
||||||
(assoc :svg-attrs (dissoc attrs :x :y :width :height :href :xlink:href)))))))
|
(assoc :svg-attrs props))))))
|
||||||
|
|
||||||
|
(defn parse-svg-element
|
||||||
(defn parse-svg-element [frame-id svg-data {:keys [tag attrs hidden] :as element-data} unames]
|
[frame-id svg-data {:keys [tag attrs hidden] :as element} unames]
|
||||||
(let [attrs (csvg/format-styles attrs)
|
(let [name (or (:id attrs) (tag->name tag))
|
||||||
element-data (cond-> element-data (map? element-data) (assoc :attrs attrs))
|
|
||||||
name (or (:id attrs) (tag->name tag))
|
|
||||||
att-refs (csvg/find-attr-references attrs)
|
att-refs (csvg/find-attr-references attrs)
|
||||||
references (csvg/find-def-references (:defs svg-data) att-refs)
|
defs (get svg-data :defs)
|
||||||
|
references (csvg/find-def-references defs att-refs)
|
||||||
href-id (-> (or (:href attrs) (:xlink:href attrs) "") (subs 1))
|
href-id (-> (or (:href attrs) (:xlink:href attrs) "") (subs 1))
|
||||||
defs (:defs svg-data)
|
|
||||||
|
|
||||||
use-tag? (and (= :use tag) (contains? defs href-id))]
|
use-tag? (and (= :use tag) (contains? defs href-id))]
|
||||||
|
|
||||||
(if use-tag?
|
(if use-tag?
|
||||||
|
@ -397,38 +410,43 @@
|
||||||
use-data (-> (get defs href-id)
|
use-data (-> (get defs href-id)
|
||||||
(update :attrs #(d/deep-merge % (dissoc attrs :xlink:href :href))))
|
(update :attrs #(d/deep-merge % (dissoc attrs :xlink:href :href))))
|
||||||
displacement (gpt/point (d/parse-double (:x attrs "0")) (d/parse-double (:y attrs "0")))
|
displacement (gpt/point (d/parse-double (:x attrs "0")) (d/parse-double (:y attrs "0")))
|
||||||
disp-matrix (str (gmt/translate-matrix displacement))
|
disp-matrix (dm/str (gmt/translate-matrix displacement))
|
||||||
element-data (-> element-data
|
element (-> element
|
||||||
(assoc :tag :g)
|
(assoc :tag :g)
|
||||||
(update :attrs dissoc :x :y :width :height :href :xlink:href :transform)
|
(update :attrs dissoc :x :y :width :height :href :xlink:href :transform)
|
||||||
(update :attrs csvg/add-transform disp-matrix)
|
(update :attrs csvg/add-transform disp-matrix)
|
||||||
(assoc :content [use-data]))]
|
(assoc :content [use-data]))]
|
||||||
(parse-svg-element frame-id svg-data element-data unames))
|
(parse-svg-element frame-id svg-data element unames))
|
||||||
|
|
||||||
|
(let [;; SVG graphic elements
|
||||||
|
;; :circle :ellipse :image :line :path :polygon :polyline :rect :text :use
|
||||||
|
shape (case tag
|
||||||
|
(:g :a :svg) (create-group name frame-id svg-data element)
|
||||||
|
:rect (create-rect-shape name frame-id svg-data element)
|
||||||
|
(:circle
|
||||||
|
:ellipse) (create-circle-shape name frame-id svg-data element)
|
||||||
|
:path (create-path-shape name frame-id svg-data element)
|
||||||
|
:polyline (create-path-shape name frame-id svg-data (-> element csvg/polyline->path))
|
||||||
|
:polygon (create-path-shape name frame-id svg-data (-> element csvg/polygon->path))
|
||||||
|
:line (create-path-shape name frame-id svg-data (-> element csvg/line->path))
|
||||||
|
:image (create-image-shape name frame-id svg-data element)
|
||||||
|
#_other (create-raw-svg name frame-id svg-data element))]
|
||||||
|
|
||||||
|
|
||||||
;; SVG graphic elements
|
|
||||||
;; :circle :ellipse :image :line :path :polygon :polyline :rect :text :use
|
|
||||||
(let [shape (-> (case tag
|
|
||||||
(:g :a :svg) (create-group name frame-id svg-data element-data)
|
|
||||||
:rect (create-rect-shape name frame-id svg-data element-data)
|
|
||||||
(: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 csvg/polyline->path))
|
|
||||||
:polygon (create-path-shape name frame-id svg-data (-> element-data csvg/polygon->path))
|
|
||||||
:line (create-path-shape name frame-id svg-data (-> element-data csvg/line->path))
|
|
||||||
:image (create-image-shape name frame-id svg-data element-data)
|
|
||||||
#_other (create-raw-svg name frame-id svg-data element-data)))]
|
|
||||||
(when (some? shape)
|
(when (some? shape)
|
||||||
(let [shape (-> shape
|
(let [shape (-> shape
|
||||||
(assoc :svg-defs (select-keys (:defs svg-data) references))
|
(assoc :svg-defs (select-keys defs references))
|
||||||
(setup-fill)
|
(setup-fill)
|
||||||
(setup-stroke)
|
(setup-stroke)
|
||||||
(setup-opacity))]
|
(setup-opacity)
|
||||||
|
(update :svg-attrs (fn [attrs]
|
||||||
|
(if (empty? (:style attrs))
|
||||||
|
(dissoc attrs :style)
|
||||||
|
attrs))))]
|
||||||
[(cond-> shape
|
[(cond-> shape
|
||||||
hidden (assoc :hidden true))
|
hidden (assoc :hidden true))
|
||||||
|
|
||||||
(cond->> (:content element-data)
|
(cond->> (:content element)
|
||||||
(contains? csvg/parent-tags tag)
|
(contains? csvg/parent-tags tag)
|
||||||
(mapv #(csvg/inherit-attributes attrs %)))]))))))
|
(mapv #(csvg/inherit-attributes attrs %)))]))))))
|
||||||
|
|
||||||
|
@ -449,19 +467,6 @@
|
||||||
|
|
||||||
[unames children])))
|
[unames children])))
|
||||||
|
|
||||||
(defn data-uri->blob
|
|
||||||
[data-uri]
|
|
||||||
(let [[mtype b64-data] (str/split data-uri ";base64,")
|
|
||||||
mtype (subs mtype (inc (str/index-of mtype ":")))
|
|
||||||
decoded (.atob js/window b64-data)
|
|
||||||
size (.-length ^js decoded)
|
|
||||||
content (js/Uint8Array. size)]
|
|
||||||
|
|
||||||
(doseq [i (range 0 size)]
|
|
||||||
(aset content i (.charCodeAt decoded i)))
|
|
||||||
|
|
||||||
(wapi/create-blob content mtype)))
|
|
||||||
|
|
||||||
(defn extract-name [url]
|
(defn extract-name [url]
|
||||||
(let [query-idx (str/last-index-of url "?")
|
(let [query-idx (str/last-index-of url "?")
|
||||||
url (if (> query-idx 0) (subs url 0 query-idx) url)
|
url (if (> query-idx 0) (subs url 0 query-idx) url)
|
||||||
|
@ -481,7 +486,7 @@
|
||||||
:url uri}
|
:url uri}
|
||||||
(if (str/starts-with? uri "data:")
|
(if (str/starts-with? uri "data:")
|
||||||
{:name "image"
|
{:name "image"
|
||||||
:content (data-uri->blob uri)}
|
:content (wapi/data-uri->blob uri)}
|
||||||
{:name (extract-name uri)}))))
|
{:name (extract-name uri)}))))
|
||||||
(rx/mapcat (fn [uri-data]
|
(rx/mapcat (fn [uri-data]
|
||||||
(->> (rp/cmd! (if (contains? uri-data :content)
|
(->> (rp/cmd! (if (contains? uri-data :content)
|
||||||
|
@ -524,10 +529,6 @@
|
||||||
(csvg/fix-percents)
|
(csvg/fix-percents)
|
||||||
(csvg/extract-defs))
|
(csvg/extract-defs))
|
||||||
|
|
||||||
svg-data (assoc svg-data :defs def-nodes)
|
|
||||||
root-shape (create-svg-root frame-id parent-id svg-data)
|
|
||||||
root-id (:id root-shape)
|
|
||||||
|
|
||||||
;; In penpot groups have the size of their children. To
|
;; In penpot groups have the size of their children. To
|
||||||
;; respect the imported svg size and empty space let's create
|
;; respect the imported svg size and empty space let's create
|
||||||
;; a transparent shape as background to respect the imported
|
;; a transparent shape as background to respect the imported
|
||||||
|
@ -547,6 +548,9 @@
|
||||||
(assoc :defs def-nodes)
|
(assoc :defs def-nodes)
|
||||||
(assoc :content (into [background] (:content svg-data))))
|
(assoc :content (into [background] (:content svg-data))))
|
||||||
|
|
||||||
|
root-shape (create-svg-root frame-id parent-id svg-data)
|
||||||
|
root-id (:id root-shape)
|
||||||
|
|
||||||
;; Create the root shape
|
;; Create the root shape
|
||||||
root-attrs (-> (:attrs svg-data)
|
root-attrs (-> (:attrs svg-data)
|
||||||
(csvg/format-styles))
|
(csvg/format-styles))
|
||||||
|
@ -561,7 +565,6 @@
|
||||||
|
|
||||||
(defn add-svg-shapes
|
(defn add-svg-shapes
|
||||||
[svg-data position]
|
[svg-data position]
|
||||||
;; (app.common.pprint/pprint svg-data {:length 100 :level 100})
|
|
||||||
(ptk/reify ::add-svg-shapes
|
(ptk/reify ::add-svg-shapes
|
||||||
ptk/WatchEvent
|
ptk/WatchEvent
|
||||||
(watch [it state _]
|
(watch [it state _]
|
||||||
|
|
|
@ -160,14 +160,10 @@
|
||||||
(empty? attrs))
|
(empty? attrs))
|
||||||
#js {}
|
#js {}
|
||||||
(-> attrs
|
(-> attrs
|
||||||
;; TODO: revisit, why we need to execute it each render? Can
|
|
||||||
;; we do this operation on importation and avoid unnecesary
|
|
||||||
;; work on render?
|
|
||||||
(csvg/clean-attrs)
|
|
||||||
(csvg/update-attr-ids
|
(csvg/update-attr-ids
|
||||||
(fn [id]
|
(fn [id]
|
||||||
(if (contains? defs id)
|
(if (contains? defs id)
|
||||||
(str render-id "-" id)
|
(dm/str render-id "-" id)
|
||||||
id)))
|
id)))
|
||||||
(dissoc :id)
|
(dissoc :id)
|
||||||
(obj/map->obj)))))
|
(obj/map->obj)))))
|
||||||
|
|
|
@ -15,23 +15,25 @@
|
||||||
[rumext.v2 :as mf]))
|
[rumext.v2 :as mf]))
|
||||||
|
|
||||||
;; Graphic tags
|
;; Graphic tags
|
||||||
(defonce graphic-element?
|
(def graphic-element
|
||||||
#{:svg :circle :ellipse :image :line :path :polygon :polyline :rect :symbol :text :textPath :use})
|
#{:svg :circle :ellipse :image :line :path :polygon :polyline :rect :symbol :text :textPath :use})
|
||||||
|
|
||||||
;; Context to store a re-mapping of the ids
|
;; Context to store a re-mapping of the ids
|
||||||
(def svg-ids-ctx (mf/create-context nil))
|
(def svg-ids-ctx (mf/create-context nil))
|
||||||
|
|
||||||
(defn set-styles [attrs shape render-id]
|
(defn set-styles [attrs shape render-id]
|
||||||
(let [custom-attrs (-> (usa/get-style-props shape render-id)
|
(let [props (-> (usa/get-style-props shape render-id)
|
||||||
(obj/unset! "transform"))
|
(obj/unset! "transform"))
|
||||||
|
|
||||||
attrs (or attrs {})
|
attrs (if (map? attrs)
|
||||||
attrs (cond-> attrs
|
(-> attrs csvg/attrs->props obj/map->obj)
|
||||||
(string? (:style attrs)) csvg/clean-attrs)
|
#js {})
|
||||||
style (obj/merge! (clj->js (:style attrs {}))
|
|
||||||
(obj/get custom-attrs "style"))]
|
style (obj/merge (obj/get attrs "style")
|
||||||
(-> (clj->js attrs)
|
(obj/get props "style"))]
|
||||||
(obj/merge! custom-attrs)
|
|
||||||
|
(-> attrs
|
||||||
|
(obj/merge! props)
|
||||||
(obj/set! "style" style))))
|
(obj/set! "style" style))))
|
||||||
|
|
||||||
(defn translate-shape [attrs shape]
|
(defn translate-shape [attrs shape]
|
||||||
|
@ -39,7 +41,7 @@
|
||||||
" "
|
" "
|
||||||
(:transform attrs ""))]
|
(:transform attrs ""))]
|
||||||
(cond-> attrs
|
(cond-> attrs
|
||||||
(and (:svg-viewbox shape) (graphic-element? (-> shape :content :tag)))
|
(and (:svg-viewbox shape) (contains? graphic-element (-> shape :content :tag)))
|
||||||
(assoc :transform transform))))
|
(assoc :transform transform))))
|
||||||
|
|
||||||
(mf/defc svg-root
|
(mf/defc svg-root
|
||||||
|
|
|
@ -61,7 +61,7 @@
|
||||||
childs (unchecked-get props "childs")
|
childs (unchecked-get props "childs")
|
||||||
frame (unchecked-get props "frame")
|
frame (unchecked-get props "frame")
|
||||||
render-wrapper? (or (not= :svg-raw (:type shape))
|
render-wrapper? (or (not= :svg-raw (:type shape))
|
||||||
(svg-raw/graphic-element? (get-in shape [:content :tag])))]
|
(contains? svg-raw/graphic-element (get-in shape [:content :tag])))]
|
||||||
|
|
||||||
(if render-wrapper?
|
(if render-wrapper?
|
||||||
[:> shape-container {:shape shape
|
[:> shape-container {:shape shape
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue