mirror of
https://github.com/penpot/penpot.git
synced 2025-05-18 18:36:12 +02:00
♻️ Refactor SVG raw shape
This commit is contained in:
parent
815d1a906f
commit
60eae40006
1 changed files with 88 additions and 92 deletions
|
@ -23,33 +23,6 @@
|
||||||
;; 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 vbox->rect
|
|
||||||
"Converts the viewBox into a rectangle"
|
|
||||||
[vbox]
|
|
||||||
(when vbox
|
|
||||||
(let [[x y width height] (map ud/parse-float (str/split vbox " "))]
|
|
||||||
{:x x :y y :width width :height height})))
|
|
||||||
|
|
||||||
(defn vbox-center [shape]
|
|
||||||
(let [vbox-rect (-> (get-in shape [:content :attrs :viewBox] "0 0 100 100")
|
|
||||||
(vbox->rect))]
|
|
||||||
(gsh/center-rect vbox-rect)))
|
|
||||||
|
|
||||||
(defn vbox-bounds [shape]
|
|
||||||
(let [vbox-rect (-> (get-in shape [:content :attrs :viewBox] "0 0 100 100")
|
|
||||||
(vbox->rect))
|
|
||||||
vbox-center (gsh/center-rect vbox-rect)
|
|
||||||
transform (gsh/transform-matrix shape nil vbox-center)]
|
|
||||||
(-> (gsh/rect->points vbox-rect)
|
|
||||||
(gsh/transform-points vbox-center transform)
|
|
||||||
(gsh/points->rect))) )
|
|
||||||
|
|
||||||
(defn transform-viewbox [shape]
|
|
||||||
(let [center (vbox-center shape)
|
|
||||||
bounds (vbox-bounds shape)
|
|
||||||
{:keys [x y width height]} (gsh/center->rect center (:width bounds) (:height bounds))]
|
|
||||||
(str x " " y " " width " " height)))
|
|
||||||
|
|
||||||
(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 (get-in node [:attrs :id])
|
||||||
|
@ -58,79 +31,102 @@
|
||||||
(reduce visit-node result (:content node))))]
|
(reduce visit-node result (:content node))))]
|
||||||
(visit-node {} content)))
|
(visit-node {} content)))
|
||||||
|
|
||||||
|
|
||||||
|
(defonce replace-regex #"[^#]*#([^)\s]+).*")
|
||||||
|
|
||||||
|
(defn replace-attrs-ids
|
||||||
|
"Replaces the ids inside a property"
|
||||||
|
[ids-mapping attrs]
|
||||||
|
|
||||||
|
(letfn [(replace-ids [key val]
|
||||||
|
(if (map? val)
|
||||||
|
(cd/mapm replace-ids val)
|
||||||
|
(let [[_ from-id] (re-matches replace-regex val)]
|
||||||
|
(if (and from-id (contains? ids-mapping from-id))
|
||||||
|
(str/replace val from-id (get ids-mapping from-id))
|
||||||
|
val))))]
|
||||||
|
(cd/mapm replace-ids attrs)))
|
||||||
|
|
||||||
|
(mf/defc svg-root
|
||||||
|
{::mf/wrap-props false}
|
||||||
|
[props]
|
||||||
|
|
||||||
|
(let [shape (unchecked-get props "shape")
|
||||||
|
children (unchecked-get props "children")
|
||||||
|
|
||||||
|
{:keys [x y width height]} shape
|
||||||
|
{:keys [tag attrs] :as content} (:content shape)
|
||||||
|
|
||||||
|
ids-mapping (mf/use-memo #(generate-id-mapping content))
|
||||||
|
|
||||||
|
attrs (-> (clj->js attrs)
|
||||||
|
(obj/set! "x" x)
|
||||||
|
(obj/set! "y" y)
|
||||||
|
(obj/set! "width" width)
|
||||||
|
(obj/set! "height" height)
|
||||||
|
(obj/set! "preserveAspectRatio" "none"))]
|
||||||
|
|
||||||
|
[:& (mf/provider svg-ids-ctx) {:value ids-mapping}
|
||||||
|
[:g.svg-raw {:transform (gsh/transform-matrix shape)}
|
||||||
|
[:> "svg" attrs children]]]))
|
||||||
|
|
||||||
|
(mf/defc svg-element
|
||||||
|
{::mf/wrap-props false}
|
||||||
|
[props]
|
||||||
|
(let [shape (unchecked-get props "shape")
|
||||||
|
children (unchecked-get props "children")
|
||||||
|
|
||||||
|
{:keys [content]} shape
|
||||||
|
{:keys [attrs tag]} content
|
||||||
|
|
||||||
|
ids-mapping (mf/use-ctx svg-ids-ctx)
|
||||||
|
attrs (mf/use-memo #(replace-attrs-ids ids-mapping attrs))
|
||||||
|
custom-attrs (usa/extract-style-attrs shape)
|
||||||
|
|
||||||
|
element-id (get-in content [:attrs :id])
|
||||||
|
|
||||||
|
style (obj/merge! (clj->js (:style attrs {}))
|
||||||
|
(obj/get custom-attrs "style"))
|
||||||
|
|
||||||
|
attrs (-> (clj->js attrs)
|
||||||
|
(obj/merge! custom-attrs)
|
||||||
|
(obj/set! "style" style))
|
||||||
|
|
||||||
|
attrs (cond-> attrs
|
||||||
|
element-id (obj/set! "id" (get ids-mapping element-id)))
|
||||||
|
]
|
||||||
|
[:> (name tag) attrs children]))
|
||||||
|
|
||||||
(defn svg-raw-shape [shape-wrapper]
|
(defn svg-raw-shape [shape-wrapper]
|
||||||
(mf/fnc svg-raw-shape
|
(mf/fnc svg-raw-shape
|
||||||
{::mf/wrap-props false}
|
{::mf/wrap-props false}
|
||||||
[props]
|
[props]
|
||||||
(let [frame (unchecked-get props "frame")
|
|
||||||
shape (unchecked-get props "shape")
|
|
||||||
childs (unchecked-get props "childs")
|
|
||||||
|
|
||||||
{:keys [tag attrs] :as content} (:content shape)
|
(let [frame (unchecked-get props "frame")
|
||||||
|
shape (unchecked-get props "shape")
|
||||||
|
childs (unchecked-get props "childs")
|
||||||
|
|
||||||
new-mapping (mf/use-memo #(when (= tag :svg) (generate-id-mapping content)))
|
{:keys [content]} shape
|
||||||
ids-mapping (if (= tag :svg)
|
{:keys [tag]} content
|
||||||
new-mapping
|
|
||||||
(mf/use-ctx svg-ids-ctx))
|
|
||||||
|
|
||||||
rex #"[^#]*#([^)\s]+).*"
|
svg-root? (and (map? content) (= tag :svg))
|
||||||
|
svg-tag? (map? content)
|
||||||
|
svg-leaf? (string? content)]
|
||||||
|
|
||||||
;; Replaces the attributes ID's so there are no collisions between shapes
|
(cond
|
||||||
replace-ids
|
svg-root?
|
||||||
(fn replace-ids [key val]
|
[:& svg-root {:shape shape}
|
||||||
(if (map? val)
|
(for [item childs]
|
||||||
(cd/mapm replace-ids val)
|
[:& shape-wrapper {:frame frame :shape item :key (:id item)}])]
|
||||||
(let [[_ from-id] (re-matches rex val)]
|
|
||||||
(if (and from-id (contains? ids-mapping from-id))
|
|
||||||
(str/replace val from-id (get ids-mapping from-id))
|
|
||||||
val))))
|
|
||||||
|
|
||||||
attrs (cd/mapm replace-ids attrs)
|
svg-tag?
|
||||||
|
[:& svg-element {:shape shape}
|
||||||
|
(for [item childs]
|
||||||
|
[:& shape-wrapper {:frame frame :shape item :key (:id item)}])]
|
||||||
|
|
||||||
custom-attrs (usa/extract-style-attrs shape)
|
svg-leaf?
|
||||||
|
content
|
||||||
|
|
||||||
style (obj/merge! (clj->js (:style attrs {}))
|
:else nil))))
|
||||||
(obj/get custom-attrs "style"))
|
|
||||||
|
|
||||||
attrs (-> (clj->js attrs)
|
|
||||||
(obj/merge! custom-attrs)
|
|
||||||
(obj/set! "style" style))
|
|
||||||
|
|
||||||
element-id (get-in content [:attrs :id])]
|
|
||||||
|
|
||||||
(cond
|
|
||||||
;; Root SVG TAG
|
|
||||||
(and (map? content) (= tag :svg))
|
|
||||||
(let [{:keys [x y width height]} shape
|
|
||||||
attrs (-> attrs
|
|
||||||
(obj/set! "x" x)
|
|
||||||
(obj/set! "y" y)
|
|
||||||
(obj/set! "width" width)
|
|
||||||
(obj/set! "height" height)
|
|
||||||
(obj/set! "preserveAspectRatio" "none")
|
|
||||||
#_(obj/set! "viewBox" (transform-viewbox shape)))]
|
|
||||||
|
|
||||||
[:& (mf/provider svg-ids-ctx) {:value ids-mapping}
|
|
||||||
[:g.svg-raw {:transform (gsh/transform-matrix shape)}
|
|
||||||
[:> "svg" attrs
|
|
||||||
(for [item childs]
|
|
||||||
[:& shape-wrapper {:frame frame
|
|
||||||
:shape item
|
|
||||||
:key (:id item)}])]]])
|
|
||||||
|
|
||||||
;; Other tags different than root
|
|
||||||
(map? content)
|
|
||||||
(let [attrs (cond-> attrs
|
|
||||||
element-id (obj/set! "id" (get ids-mapping element-id)))]
|
|
||||||
[:> (name tag) attrs
|
|
||||||
(for [item childs]
|
|
||||||
[:& shape-wrapper {:frame frame
|
|
||||||
:shape item
|
|
||||||
:key (:id item)}])])
|
|
||||||
|
|
||||||
;; String content
|
|
||||||
(string? content) content
|
|
||||||
|
|
||||||
:else nil))))
|
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue