mirror of
https://github.com/penpot/penpot.git
synced 2025-03-13 16:21:57 -05:00
🐛 Some fixes to SVG imports
This commit is contained in:
parent
3301148da6
commit
61c111d5ae
9 changed files with 162 additions and 74 deletions
|
@ -65,6 +65,7 @@
|
|||
- Fix paste ordering for frames not being respected [Taiga #3097](https://tree.taiga.io/project/penpot/issue/3097)
|
||||
- Improved command support for MacOS [Taiga #2789](https://tree.taiga.io/project/penpot/issue/2789)
|
||||
- Fix shift+2 shortcut in MacOS with non-english keyboards [Taiga #3038](https://tree.taiga.io/project/penpot/issue/3038)
|
||||
- Some fixes to SVG imports [Taiga #3122](https://tree.taiga.io/project/penpot/issue/3122) [#1720](https://github.com/penpot/penpot/issues/1720) [Taiga #2884](https://tree.taiga.io/project/penpot/issue/2884)
|
||||
|
||||
### :arrow_up: Deps updates
|
||||
### :heart: Community contributions by (Thank you!)
|
||||
|
|
|
@ -105,6 +105,7 @@
|
|||
(dm/export gco/transform-points)
|
||||
|
||||
(dm/export gpr/make-rect)
|
||||
(dm/export gpr/make-selrect)
|
||||
(dm/export gpr/rect->selrect)
|
||||
(dm/export gpr/rect->points)
|
||||
(dm/export gpr/points->selrect)
|
||||
|
|
|
@ -70,32 +70,30 @@
|
|||
:else (str tag))))
|
||||
|
||||
(defn setup-fill [shape]
|
||||
(if (some? (:fills shape))
|
||||
shape
|
||||
(cond-> shape
|
||||
;; Color present as attribute
|
||||
(uc/color? (str/trim (get-in shape [:svg-attrs :fill])))
|
||||
(-> (update :svg-attrs dissoc :fill)
|
||||
(assoc-in [:fills 0 :fill-color] (-> (get-in shape [:svg-attrs :fill])
|
||||
(str/trim)
|
||||
(uc/parse-color))))
|
||||
(cond-> shape
|
||||
;; Color present as attribute
|
||||
(uc/color? (str/trim (get-in shape [:svg-attrs :fill])))
|
||||
(-> (update :svg-attrs dissoc :fill)
|
||||
(assoc-in [:fills 0 :fill-color] (-> (get-in shape [:svg-attrs :fill])
|
||||
(str/trim)
|
||||
(uc/parse-color))))
|
||||
|
||||
;; Color present as style
|
||||
(uc/color? (str/trim (get-in shape [:svg-attrs :style :fill])))
|
||||
(-> (update-in [:svg-attrs :style] dissoc :fill)
|
||||
(assoc-in [:fills 0 :fill-color] (-> (get-in shape [:svg-attrs :style :fill])
|
||||
(str/trim)
|
||||
(uc/parse-color))))
|
||||
;; Color present as style
|
||||
(uc/color? (str/trim (get-in shape [:svg-attrs :style :fill])))
|
||||
(-> (update-in [:svg-attrs :style] dissoc :fill)
|
||||
(assoc-in [:fills 0 :fill-color] (-> (get-in shape [:svg-attrs :style :fill])
|
||||
(str/trim)
|
||||
(uc/parse-color))))
|
||||
|
||||
(get-in shape [:svg-attrs :fill-opacity])
|
||||
(-> (update :svg-attrs dissoc :fill-opacity)
|
||||
(assoc-in [:fills 0 :fill-opacity] (-> (get-in shape [:svg-attrs :fill-opacity])
|
||||
(d/parse-double))))
|
||||
(get-in shape [:svg-attrs :fill-opacity])
|
||||
(-> (update :svg-attrs dissoc :fill-opacity)
|
||||
(assoc-in [:fills 0 :fill-opacity] (-> (get-in shape [:svg-attrs :fill-opacity])
|
||||
(d/parse-double))))
|
||||
|
||||
(get-in shape [:svg-attrs :style :fill-opacity])
|
||||
(-> (update-in [:svg-attrs :style] dissoc :fill-opacity)
|
||||
(assoc-in [:fills 0 :fill-opacity] (-> (get-in shape [:svg-attrs :style :fill-opacity])
|
||||
(d/parse-double)))))))
|
||||
(get-in shape [:svg-attrs :style :fill-opacity])
|
||||
(-> (update-in [:svg-attrs :style] dissoc :fill-opacity)
|
||||
(assoc-in [:fills 0 :fill-opacity] (-> (get-in shape [:svg-attrs :style :fill-opacity])
|
||||
(d/parse-double))))))
|
||||
|
||||
(defn setup-stroke [shape]
|
||||
(let [stroke-linecap (-> (or (get-in shape [:svg-attrs :stroke-linecap])
|
||||
|
|
|
@ -6,9 +6,9 @@
|
|||
|
||||
(ns app.main.ui.shapes.svg-defs
|
||||
(:require
|
||||
[app.common.data :as d]
|
||||
[app.common.data.macros :as dm]
|
||||
[app.common.geom.matrix :as gmt]
|
||||
[app.common.geom.point :as gpt]
|
||||
[app.main.ui.shapes.filters :as f]
|
||||
[app.util.object :as obj]
|
||||
[app.util.svg :as usvg]
|
||||
[rumext.alpha :as mf]))
|
||||
|
@ -21,24 +21,7 @@
|
|||
(str transform-matrix " " val)
|
||||
(str transform-matrix)))))
|
||||
|
||||
(defn transform-region [attrs transform]
|
||||
(let [{x-str :x y-str :y width-str :width height-str :height} attrs
|
||||
data (map d/parse-double [x-str y-str width-str height-str])]
|
||||
(if (every? (comp not nil?) data)
|
||||
(let [[x y width height] data
|
||||
p1 (-> (gpt/point x y)
|
||||
(gpt/transform transform))
|
||||
p2 (-> (gpt/point (+ x width) (+ y height))
|
||||
(gpt/transform transform))]
|
||||
|
||||
(assoc attrs
|
||||
:x (:x p1)
|
||||
:y (:y p1)
|
||||
:width (- (:x p2) (:x p1))
|
||||
:height (- (:y p2) (:y p1))))
|
||||
attrs)))
|
||||
|
||||
(mf/defc svg-node [{:keys [node prefix-id transform]}]
|
||||
(mf/defc svg-node [{:keys [type node prefix-id transform bounds]}]
|
||||
(cond
|
||||
(string? node) node
|
||||
|
||||
|
@ -63,23 +46,34 @@
|
|||
attrs (-> attrs
|
||||
(usvg/update-attr-ids prefix-id)
|
||||
(usvg/clean-attrs)
|
||||
|
||||
;; This clasname will be used to change the transform on the viewport
|
||||
;; only necessary for groups because shapes have their own transform
|
||||
(cond-> (and (or transform-gradient?
|
||||
transform-pattern?
|
||||
transform-clippath?
|
||||
transform-filter?
|
||||
transform-mask?)
|
||||
(= :group type))
|
||||
(update :className #(if % (dm/str % " svg-def") "svg-def")))
|
||||
(cond->
|
||||
transform-gradient? (add-matrix :gradientTransform transform)
|
||||
transform-pattern? (add-matrix :patternTransform transform)
|
||||
transform-clippath? (add-matrix :transform transform)
|
||||
(or transform-filter?
|
||||
transform-mask?) (transform-region transform)))
|
||||
transform-mask?) (merge attrs bounds)))
|
||||
|
||||
[wrapper wrapper-props] (if (= tag :mask)
|
||||
["g" #js {:transform (str transform)}]
|
||||
["g" #js {:className "svg-mask-wrapper"
|
||||
:transform (str transform)}]
|
||||
[mf/Fragment (obj/new)])]
|
||||
|
||||
[:> (name tag) (clj->js attrs)
|
||||
[:> wrapper wrapper-props
|
||||
(for [node content] [:& svg-node {:node node
|
||||
(for [node content] [:& svg-node {:type type
|
||||
:node node
|
||||
:prefix-id prefix-id
|
||||
:transform transform}])]])))
|
||||
:transform transform
|
||||
:bounds bounds}])]])))
|
||||
|
||||
(mf/defc svg-defs [{:keys [shape render-id]}]
|
||||
(let [svg-defs (:svg-defs shape)
|
||||
|
@ -91,8 +85,8 @@
|
|||
(usvg/svg-transform-matrix shape)))
|
||||
|
||||
;; Paths doesn't have transform so we have to transform its gradients
|
||||
transform (if (contains? shape :svg-transform)
|
||||
(gmt/multiply transform (or (:svg-transform shape) (gmt/matrix)))
|
||||
transform (if (some? (:svg-transform shape))
|
||||
(gmt/multiply transform (:svg-transform shape))
|
||||
transform)
|
||||
|
||||
prefix-id
|
||||
|
@ -103,7 +97,9 @@
|
|||
;; TODO: no key?
|
||||
(when (seq svg-defs)
|
||||
(for [svg-def (vals svg-defs)]
|
||||
[:& svg-node {:node svg-def
|
||||
[:& svg-node {:type (:type shape)
|
||||
:node svg-def
|
||||
:prefix-id prefix-id
|
||||
:transform transform}]))))
|
||||
:transform transform
|
||||
:bounds (f/get-filters-bounds shape)}]))))
|
||||
|
||||
|
|
|
@ -117,8 +117,8 @@
|
|||
;; Note that the "indeterminate" attribute only may be set by code, not as a static attribute.
|
||||
;; See https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input/checkbox#attr-indeterminate
|
||||
(if (= hide-fill-on-export? :multiple)
|
||||
(dom/set-attribute checkbox "indeterminate" true)
|
||||
(dom/remove-attribute checkbox "indeterminate")))))
|
||||
(dom/set-attribute! checkbox "indeterminate" true)
|
||||
(dom/remove-attribute! checkbox "indeterminate")))))
|
||||
|
||||
[:div.element-set
|
||||
[:div.element-set-title
|
||||
|
|
|
@ -201,25 +201,43 @@
|
|||
(mf/use-memo
|
||||
(mf/deps modifiers)
|
||||
(fn []
|
||||
(d/mapm (fn [id {modifiers :modifiers}]
|
||||
(let [center (gsh/center-shape (get objects id))]
|
||||
(gsh/modifiers->transform center modifiers)))
|
||||
modifiers)))
|
||||
(when (some? modifiers)
|
||||
(d/mapm (fn [id {modifiers :modifiers}]
|
||||
(let [center (gsh/center-shape (get objects id))]
|
||||
(gsh/modifiers->transform center modifiers)))
|
||||
modifiers))))
|
||||
|
||||
shapes
|
||||
(mf/use-memo
|
||||
(mf/deps transforms)
|
||||
(fn []
|
||||
(->> (keys transforms)
|
||||
(mapv (d/getf objects)))))]
|
||||
(mapv (d/getf objects)))))
|
||||
|
||||
prev-shapes (mf/use-var nil)
|
||||
prev-modifiers (mf/use-var nil)
|
||||
prev-transforms (mf/use-var nil)]
|
||||
|
||||
;; Layout effect is important so the code is executed before the modifiers
|
||||
;; are applied to the shape
|
||||
(mf/use-layout-effect
|
||||
(mf/deps transforms)
|
||||
(fn []
|
||||
(utils/update-transform shapes transforms modifiers)
|
||||
#(utils/remove-transform shapes)))))
|
||||
(when (and (nil? @prev-transforms)
|
||||
(some? transforms))
|
||||
(utils/start-transform! shapes))
|
||||
|
||||
(when (some? modifiers)
|
||||
(utils/update-transform! shapes transforms modifiers))
|
||||
|
||||
|
||||
(when (and (some? @prev-modifiers)
|
||||
(not (some? modifiers)))
|
||||
(utils/remove-transform! @prev-shapes))
|
||||
|
||||
(reset! prev-modifiers modifiers)
|
||||
(reset! prev-transforms transforms)
|
||||
(reset! prev-shapes shapes)))))
|
||||
|
||||
(defn inside-vbox [vbox objects frame-id]
|
||||
(let [frame (get objects frame-id)]
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
[app.common.data.macros :as dm]
|
||||
[app.common.geom.matrix :as gmt]
|
||||
[app.common.geom.point :as gpt]
|
||||
[app.common.geom.shapes :as gsh]
|
||||
[app.main.ui.cursors :as cur]
|
||||
[app.util.dom :as dom]))
|
||||
|
||||
|
@ -100,7 +101,10 @@
|
|||
(dom/query shape-node ".mask-shape")]
|
||||
|
||||
group?
|
||||
[]
|
||||
(let [shape-defs (dom/query shape-node "defs")]
|
||||
(d/concat-vec
|
||||
(dom/query-all shape-defs ".svg-def")
|
||||
(dom/query-all shape-defs ".svg-mask-wrapper")))
|
||||
|
||||
text?
|
||||
[shape-node
|
||||
|
@ -112,7 +116,59 @@
|
|||
:else
|
||||
[shape-node])))
|
||||
|
||||
(defn update-transform [shapes transforms modifiers]
|
||||
(defn transform-region!
|
||||
[node modifiers]
|
||||
|
||||
(let [{:keys [x y width height]}
|
||||
(-> (gsh/make-selrect
|
||||
(-> (dom/get-attribute node "data-old-x") d/parse-double)
|
||||
(-> (dom/get-attribute node "data-old-y") d/parse-double)
|
||||
(-> (dom/get-attribute node "data-old-width") d/parse-double)
|
||||
(-> (dom/get-attribute node "data-old-height") d/parse-double))
|
||||
(gsh/transform-selrect modifiers))]
|
||||
(dom/set-attribute! node "x" x)
|
||||
(dom/set-attribute! node "y" y)
|
||||
(dom/set-attribute! node "width" width)
|
||||
(dom/set-attribute! node "height" height)))
|
||||
|
||||
(defn start-transform!
|
||||
[shapes]
|
||||
(doseq [shape shapes]
|
||||
(when-let [nodes (get-nodes shape)]
|
||||
(doseq [node nodes]
|
||||
(let [old-transform (dom/get-attribute node "transform")]
|
||||
(when (some? old-transform)
|
||||
(dom/set-attribute! node "data-old-transform" old-transform))
|
||||
|
||||
(when (or (= (dom/get-tag-name node) "linearGradient")
|
||||
(= (dom/get-tag-name node) "radialGradient"))
|
||||
(let [gradient-transform (dom/get-attribute node "gradientTransform")]
|
||||
(when (some? gradient-transform)
|
||||
(dom/set-attribute! node "data-old-gradientTransform" gradient-transform))))
|
||||
|
||||
(when (= (dom/get-tag-name node) "pattern")
|
||||
(let [pattern-transform (dom/get-attribute node "patternTransform")]
|
||||
(when (some? pattern-transform)
|
||||
(dom/set-attribute! node "data-old-patternTransform" pattern-transform))))
|
||||
|
||||
(when (or (= (dom/get-tag-name node) "mask")
|
||||
(= (dom/get-tag-name node) "filter"))
|
||||
(dom/set-attribute! node "data-old-x" (dom/get-attribute node "x"))
|
||||
(dom/set-attribute! node "data-old-y" (dom/get-attribute node "y"))
|
||||
(dom/set-attribute! node "data-old-width" (dom/get-attribute node "width"))
|
||||
(dom/set-attribute! node "data-old-height" (dom/get-attribute node "height"))))))))
|
||||
|
||||
(defn set-transform-att!
|
||||
[node att value]
|
||||
|
||||
(let [old-att (dom/get-attribute node (dm/str "data-old-" att))
|
||||
new-value (if (some? old-att)
|
||||
(dm/str value " " old-att)
|
||||
(str value))]
|
||||
(dom/set-attribute! node att (str new-value))))
|
||||
|
||||
(defn update-transform!
|
||||
[shapes transforms modifiers]
|
||||
(doseq [{:keys [id type] :as shape} shapes]
|
||||
(when-let [nodes (get-nodes shape)]
|
||||
(let [transform (get transforms id)
|
||||
|
@ -127,24 +183,38 @@
|
|||
|
||||
(doseq [node nodes]
|
||||
(cond
|
||||
(or (dom/class? node "text-shape") (dom/class? node "text-svg"))
|
||||
;; Text shapes need special treatment because their resize only change
|
||||
;; the text area, not the change size/position
|
||||
(or (dom/class? node "text-shape")
|
||||
(dom/class? node "text-svg"))
|
||||
(when (some? text-transform)
|
||||
(dom/set-attribute node "transform" (str text-transform)))
|
||||
(set-transform-att! node "transform" text-transform))
|
||||
|
||||
(or (= (dom/get-tag-name node) "foreignObject")
|
||||
(dom/class? node "text-clip"))
|
||||
(let [cur-width (dom/get-attribute node "width")
|
||||
cur-height (dom/get-attribute node "height")]
|
||||
(when (and (some? text-width) (not= cur-width text-width))
|
||||
(dom/set-attribute node "width" text-width))
|
||||
|
||||
(dom/set-attribute! node "width" text-width))
|
||||
(when (and (some? text-height) (not= cur-height text-height))
|
||||
(dom/set-attribute node "height" text-height)))
|
||||
(dom/set-attribute! node "height" text-height)))
|
||||
|
||||
(or (= (dom/get-tag-name node) "mask")
|
||||
(= (dom/get-tag-name node) "filter"))
|
||||
(transform-region! node modifiers)
|
||||
|
||||
(or (= (dom/get-tag-name node) "linearGradient")
|
||||
(= (dom/get-tag-name node) "radialGradient"))
|
||||
(set-transform-att! node "gradientTransform" transform)
|
||||
|
||||
(= (dom/get-tag-name node) "pattern")
|
||||
(set-transform-att! node "patternTransform" transform)
|
||||
|
||||
(and (some? transform) (some? node))
|
||||
(dom/set-attribute node "transform" (str transform))))))))
|
||||
(set-transform-att! node "transform" transform)))))))
|
||||
|
||||
(defn remove-transform [shapes]
|
||||
(defn remove-transform!
|
||||
[shapes]
|
||||
(doseq [shape shapes]
|
||||
(when-let [nodes (get-nodes shape)]
|
||||
(doseq [node nodes]
|
||||
|
@ -155,7 +225,10 @@
|
|||
nil
|
||||
|
||||
:else
|
||||
(dom/remove-attribute node "transform")))))))
|
||||
(let [old-transform (dom/get-attribute node "data-old-transform")]
|
||||
(when-not (some? old-transform)
|
||||
(dom/remove-attribute! node "data-old-transform")
|
||||
(dom/remove-attribute! node "transform")))))))))
|
||||
|
||||
(defn format-viewbox [vbox]
|
||||
(dm/str (:x vbox 0) " "
|
||||
|
|
|
@ -415,11 +415,11 @@
|
|||
"application/pdf" "pdf"
|
||||
nil))
|
||||
|
||||
(defn set-attribute [^js node ^string attr value]
|
||||
(defn set-attribute! [^js node ^string attr value]
|
||||
(when (some? node)
|
||||
(.setAttribute node attr value)))
|
||||
|
||||
(defn remove-attribute [^js node ^string attr]
|
||||
(defn remove-attribute! [^js node ^string attr]
|
||||
(when (some? node)
|
||||
(.removeAttribute node attr)))
|
||||
|
||||
|
|
|
@ -715,7 +715,8 @@
|
|||
(gmt/matrix)
|
||||
|
||||
;; Paths doesn't have transform so we have to transform its gradients
|
||||
(if (= :path (:type shape))
|
||||
(if (or (= :path (:type shape))
|
||||
(= :group (:type shape)))
|
||||
(gsh/transform-matrix shape)
|
||||
(gmt/matrix))
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue