mirror of
https://github.com/penpot/penpot.git
synced 2025-06-06 15:21:38 +02:00
✨ Improved geometry for rects
This commit is contained in:
parent
23d531a664
commit
94c5004c33
7 changed files with 228 additions and 88 deletions
|
@ -23,8 +23,6 @@
|
||||||
(toString [_]
|
(toString [_]
|
||||||
(str "matrix(" a "," b "," c "," d "," e "," f ")")))
|
(str "matrix(" a "," b "," c "," d "," e "," f ")")))
|
||||||
|
|
||||||
(defonce matrix-regex #"matrix\((.*),(.*),(.*),(.*),(.*),(.*)\)")
|
|
||||||
|
|
||||||
(defn matrix
|
(defn matrix
|
||||||
"Create a new matrix instance."
|
"Create a new matrix instance."
|
||||||
([]
|
([]
|
||||||
|
@ -32,13 +30,6 @@
|
||||||
([a b c d e f]
|
([a b c d e f]
|
||||||
(Matrix. a b c d e f)))
|
(Matrix. a b c d e f)))
|
||||||
|
|
||||||
(defn parse-matrix [mtx]
|
|
||||||
(let [[_ a b c d e f] (re-matches matrix-regex mtx)]
|
|
||||||
(->> [a b c d e f]
|
|
||||||
(map str/trim)
|
|
||||||
(map d/parse-double)
|
|
||||||
(apply matrix))))
|
|
||||||
|
|
||||||
(defn multiply
|
(defn multiply
|
||||||
([{m1a :a m1b :b m1c :c m1d :d m1e :e m1f :f}
|
([{m1a :a m1b :b m1c :c m1d :d m1e :e m1f :f}
|
||||||
{m2a :a m2b :b m2c :c m2d :d m2e :e m2f :f}]
|
{m2a :a m2b :b m2c :c m2d :d m2e :e m2f :f}]
|
||||||
|
@ -64,8 +55,6 @@
|
||||||
[v]
|
[v]
|
||||||
(instance? Matrix v))
|
(instance? Matrix v))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
(def base (matrix))
|
(def base (matrix))
|
||||||
|
|
||||||
(defn base?
|
(defn base?
|
||||||
|
|
|
@ -204,6 +204,11 @@
|
||||||
(defn to-vec [p1 p2]
|
(defn to-vec [p1 p2]
|
||||||
(subtract p2 p1))
|
(subtract p2 p1))
|
||||||
|
|
||||||
|
(defn scale [v scalar]
|
||||||
|
(-> v
|
||||||
|
(update :x * scalar)
|
||||||
|
(update :y * scalar)))
|
||||||
|
|
||||||
(defn dot [{x1 :x y1 :y} {x2 :x y2 :y}]
|
(defn dot [{x1 :x y1 :y} {x2 :x y2 :y}]
|
||||||
(+ (* x1 x2) (* y1 y2)))
|
(+ (* x1 x2) (* y1 y2)))
|
||||||
|
|
||||||
|
|
|
@ -41,13 +41,6 @@
|
||||||
(nil? tag) "node"
|
(nil? tag) "node"
|
||||||
:else (str tag))))
|
:else (str tag))))
|
||||||
|
|
||||||
(defn fix-dot-number
|
|
||||||
"Fixes decimal numbers starting in dot but without leading 0"
|
|
||||||
[num-str]
|
|
||||||
(if (str/starts-with? num-str ".")
|
|
||||||
(str "0" num-str)
|
|
||||||
num-str))
|
|
||||||
|
|
||||||
(defn setup-fill [shape]
|
(defn setup-fill [shape]
|
||||||
(cond-> shape
|
(cond-> shape
|
||||||
;; Color present as attribute
|
;; Color present as attribute
|
||||||
|
@ -97,7 +90,8 @@
|
||||||
(-> (update-in [:svg-attrs :style] dissoc :stroke-width)
|
(-> (update-in [:svg-attrs :style] dissoc :stroke-width)
|
||||||
(assoc :stroke-width (-> (get-in shape [:svg-attrs :style :stroke-width])
|
(assoc :stroke-width (-> (get-in shape [:svg-attrs :style :stroke-width])
|
||||||
(ud/parse-float)))))]
|
(ud/parse-float)))))]
|
||||||
(if (d/any-key? shape :stroke-color :stroke-opacity :stroke-width)
|
shape
|
||||||
|
#_(if (d/any-key? shape :stroke-color :stroke-opacity :stroke-width)
|
||||||
(merge default-stroke shape)
|
(merge default-stroke shape)
|
||||||
shape)))
|
shape)))
|
||||||
|
|
||||||
|
@ -131,14 +125,13 @@
|
||||||
(assoc :svg-attrs (-> (:attrs svg-data)
|
(assoc :svg-attrs (-> (:attrs svg-data)
|
||||||
(dissoc :viewBox :xmlns))))))
|
(dissoc :viewBox :xmlns))))))
|
||||||
|
|
||||||
(defn apply-svg-transform [content transform-str]
|
|
||||||
(let [transform (gmt/parse-matrix transform-str)]
|
|
||||||
(gsh/transform-content content transform)))
|
|
||||||
|
|
||||||
(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}]
|
||||||
(let [content (cond-> (ugp/path->content (:d attrs))
|
(let [svg-transform (usvg/parse-transform (:transform attrs))
|
||||||
(contains? attrs :transform)
|
content (cond-> (ugp/path->content (:d attrs))
|
||||||
(apply-svg-transform (:transform attrs)))
|
svg-transform
|
||||||
|
(gsh/transform-content svg-transform))
|
||||||
|
|
||||||
|
attrs (d/update-when attrs :transform #(-> (usvg/parse-transform %) str))
|
||||||
|
|
||||||
selrect (gsh/content->selrect content)
|
selrect (gsh/content->selrect content)
|
||||||
points (gsh/rect->points selrect)]
|
points (gsh/rect->points selrect)]
|
||||||
|
@ -151,7 +144,8 @@
|
||||||
:points points}
|
:points points}
|
||||||
(assoc :svg-viewbox (select-keys selrect [:x :y :width :height]))
|
(assoc :svg-viewbox (select-keys selrect [:x :y :width :height]))
|
||||||
(assoc :svg-attrs (dissoc attrs :d :transform))
|
(assoc :svg-attrs (dissoc attrs :d :transform))
|
||||||
#_(gsh/translate-to-frame svg-data))))
|
(assoc :svg-transform svg-transform)
|
||||||
|
(gsh/translate-to-frame svg-data))))
|
||||||
|
|
||||||
(defn create-group [name frame-id svg-data {:keys [attrs]}]
|
(defn create-group [name frame-id svg-data {:keys [attrs]}]
|
||||||
(let [{:keys [x y width height]} svg-data]
|
(let [{:keys [x y width height]} svg-data]
|
||||||
|
@ -208,6 +202,7 @@
|
||||||
(ptk/reify ::svg-uploaded
|
(ptk/reify ::svg-uploaded
|
||||||
ptk/WatchEvent
|
ptk/WatchEvent
|
||||||
(watch [_ state stream]
|
(watch [_ state stream]
|
||||||
|
(try
|
||||||
(let [page-id (:current-page-id state)
|
(let [page-id (:current-page-id state)
|
||||||
objects (dwc/lookup-page-objects state page-id)
|
objects (dwc/lookup-page-objects state page-id)
|
||||||
frame-id (cp/frame-id-by-position objects {:x x :y y})
|
frame-id (cp/frame-id-by-position objects {:x x :y y})
|
||||||
|
@ -241,4 +236,8 @@
|
||||||
reducer-fn (partial add-svg-child-changes page-id objects selected frame-id root-id svg-data ids-mappings)
|
reducer-fn (partial add-svg-child-changes page-id objects selected frame-id root-id svg-data ids-mappings)
|
||||||
[_ [rchanges uchanges]] (reduce reducer-fn [unames changes] (d/enumerate (:content svg-data)))]
|
[_ [rchanges uchanges]] (reduce reducer-fn [unames changes] (d/enumerate (:content svg-data)))]
|
||||||
(rx/of (dwc/commit-changes rchanges uchanges {:commit-local? true})
|
(rx/of (dwc/commit-changes rchanges uchanges {:commit-local? true})
|
||||||
(dwc/select-shapes (d/ordered-set root-id)))))))
|
(dwc/select-shapes (d/ordered-set root-id))))
|
||||||
|
|
||||||
|
(catch :default e
|
||||||
|
(.error js/console e))
|
||||||
|
))))
|
||||||
|
|
|
@ -85,7 +85,8 @@
|
||||||
|
|
||||||
;; If contains svg-attrs the origin is svg. If it's not svg origin
|
;; If contains svg-attrs the origin is svg. If it's not svg origin
|
||||||
;; we setup the default fill as transparent (instead of black)
|
;; we setup the default fill as transparent (instead of black)
|
||||||
(not (contains? shape :svg-attrs))
|
(and (not (contains? shape :svg-attrs))
|
||||||
|
(not (= :svg-raw (:type shape))))
|
||||||
{:fill "transparent"}
|
{:fill "transparent"}
|
||||||
|
|
||||||
:else
|
:else
|
||||||
|
|
|
@ -84,12 +84,17 @@
|
||||||
|
|
||||||
(mf/defc svg-defs [{:keys [shape render-id]}]
|
(mf/defc svg-defs [{:keys [shape render-id]}]
|
||||||
(let [svg-defs (:svg-defs shape)
|
(let [svg-defs (:svg-defs shape)
|
||||||
|
_ (when (:svg-transform shape) (.log js/console (str (:svg-transform shape))))
|
||||||
transform (mf/use-memo
|
transform (mf/use-memo
|
||||||
(mf/deps shape)
|
(mf/deps shape)
|
||||||
#(if (= :svg-raw (:type shape))
|
#(if (= :svg-raw (:type shape))
|
||||||
(gmt/matrix)
|
(gmt/matrix)
|
||||||
(usvg/svg-transform-matrix shape)))
|
(usvg/svg-transform-matrix shape)))
|
||||||
|
|
||||||
|
;;transform (gmt/multiply
|
||||||
|
;; transform
|
||||||
|
;; (:svg-transform shape (gmt/matrix)))
|
||||||
|
|
||||||
prefix-id
|
prefix-id
|
||||||
(fn [id]
|
(fn [id]
|
||||||
(cond->> id
|
(cond->> id
|
||||||
|
|
|
@ -15,8 +15,17 @@
|
||||||
[app.util.a2c :refer [a2c]]
|
[app.util.a2c :refer [a2c]]
|
||||||
[app.util.data :as d]
|
[app.util.data :as d]
|
||||||
[app.util.geom.path-impl-simplify :as impl-simplify]
|
[app.util.geom.path-impl-simplify :as impl-simplify]
|
||||||
|
[app.util.svg :as usvg]
|
||||||
[cuerdas.core :as str]))
|
[cuerdas.core :as str]))
|
||||||
|
|
||||||
|
(defn calculate-opposite-handler
|
||||||
|
"Given a point and its handler, gives the symetric handler"
|
||||||
|
[point handler]
|
||||||
|
(let [handler-vector (gpt/to-vec point handler)]
|
||||||
|
(gpt/add point (gpt/negate handler-vector))))
|
||||||
|
|
||||||
|
;;;
|
||||||
|
|
||||||
(defn simplify
|
(defn simplify
|
||||||
([points]
|
([points]
|
||||||
(simplify points 0.1))
|
(simplify points 0.1))
|
||||||
|
@ -33,11 +42,6 @@
|
||||||
|
|
||||||
(def flag-regex #"[01]")
|
(def flag-regex #"[01]")
|
||||||
|
|
||||||
(defn fix-dot-number [val]
|
|
||||||
(if (str/starts-with? val ".")
|
|
||||||
(str "0" val)
|
|
||||||
val))
|
|
||||||
|
|
||||||
(defn extract-params [cmd-str extract-commands]
|
(defn extract-params [cmd-str extract-commands]
|
||||||
(loop [result []
|
(loop [result []
|
||||||
extract-idx 0
|
extract-idx 0
|
||||||
|
@ -51,7 +55,7 @@
|
||||||
match (re-find regex remain)]
|
match (re-find regex remain)]
|
||||||
|
|
||||||
(if match
|
(if match
|
||||||
(let [value (-> match first fix-dot-number d/read-string)
|
(let [value (-> match first usvg/fix-dot-number d/read-string)
|
||||||
remain (str/replace-first remain regex "")
|
remain (str/replace-first remain regex "")
|
||||||
current (assoc current param value)
|
current (assoc current param value)
|
||||||
extract-idx (inc extract-idx)
|
extract-idx (inc extract-idx)
|
||||||
|
@ -144,8 +148,8 @@
|
||||||
|
|
||||||
(defmethod parse-command "S" [cmd]
|
(defmethod parse-command "S" [cmd]
|
||||||
(let [relative (str/starts-with? cmd "s")
|
(let [relative (str/starts-with? cmd "s")
|
||||||
param-list (extract-params cmd [[:c1x :number]
|
param-list (extract-params cmd [[:cx :number]
|
||||||
[:c2y :number]
|
[:cy :number]
|
||||||
[:x :number]
|
[:x :number]
|
||||||
[:y :number]])]
|
[:y :number]])]
|
||||||
(for [params param-list]
|
(for [params param-list]
|
||||||
|
@ -155,8 +159,8 @@
|
||||||
|
|
||||||
(defmethod parse-command "Q" [cmd]
|
(defmethod parse-command "Q" [cmd]
|
||||||
(let [relative (str/starts-with? cmd "s")
|
(let [relative (str/starts-with? cmd "s")
|
||||||
param-list (extract-params cmd [[:c1x :number]
|
param-list (extract-params cmd [[:cx :number]
|
||||||
[:c1y :number]
|
[:cy :number]
|
||||||
[:x :number]
|
[:x :number]
|
||||||
[:y :number]])]
|
[:y :number]])]
|
||||||
(for [params param-list]
|
(for [params param-list]
|
||||||
|
@ -203,12 +207,13 @@
|
||||||
param-list (command->param-list entry)]
|
param-list (command->param-list entry)]
|
||||||
(str/fmt "%s%s" command-str (str/join " " param-list))))
|
(str/fmt "%s%s" command-str (str/join " " param-list))))
|
||||||
|
|
||||||
(defn cmd-pos [{:keys [params]}]
|
(defn cmd-pos [prev-pos {:keys [relative params]}]
|
||||||
(when (and (contains? params :x)
|
(let [{:keys [x y] :or {x (:x prev-pos) y (:y prev-pos)}} params]
|
||||||
(contains? params :y))
|
(if relative
|
||||||
(gpt/point params)))
|
(-> prev-pos (update :x + x) (update :y + y))
|
||||||
|
(gpt/point x y))))
|
||||||
|
|
||||||
(defn arc->beziers [prev command]
|
(defn arc->beziers [from-p command]
|
||||||
(let [to-command
|
(let [to-command
|
||||||
(fn [[_ _ c1x c1y c2x c2y x y]]
|
(fn [[_ _ c1x c1y c2x c2y x y]]
|
||||||
{:command :curve-to
|
{:command :curve-to
|
||||||
|
@ -217,7 +222,7 @@
|
||||||
:c2x c2x :c2y c2y
|
:c2x c2x :c2y c2y
|
||||||
:x x :y y}})
|
:x x :y y}})
|
||||||
|
|
||||||
{from-x :x from-y :y} (:params prev)
|
{from-x :x from-y :y} from-p
|
||||||
{:keys [rx ry x-axis-rotation large-arc-flag sweep-flag x y]} (:params command)
|
{:keys [rx ry x-axis-rotation large-arc-flag sweep-flag x y]} (:params command)
|
||||||
result (a2c from-x from-y x y large-arc-flag sweep-flag rx ry x-axis-rotation)]
|
result (a2c from-x from-y x y large-arc-flag sweep-flag rx ry x-axis-rotation)]
|
||||||
|
|
||||||
|
@ -227,35 +232,99 @@
|
||||||
"Removes some commands and convert relative to absolute coordinates"
|
"Removes some commands and convert relative to absolute coordinates"
|
||||||
[commands]
|
[commands]
|
||||||
|
|
||||||
(let [simplify-command
|
(let [smooth->curve (fn [{:keys [params]} pos]
|
||||||
|
{:c1x (:x pos)
|
||||||
|
:c1y (:y pos)
|
||||||
|
:c2x (:cx params)
|
||||||
|
:c2y (:cy params)})
|
||||||
|
|
||||||
|
quadratic->curve (fn [{:keys [params]} pos]
|
||||||
|
(let [sp (gpt/point (:x pos) (:y pos)) ;; start point
|
||||||
|
ep (gpt/point (:x params) (:y params)) ;; end-point
|
||||||
|
cp (gpt/point (:cx params) (:cy params)) ;; control-point
|
||||||
|
|
||||||
|
cp1 (-> (gpt/to-vec sp cp)
|
||||||
|
(gpt/scale (/ 2 3))
|
||||||
|
(gpt/add sp))
|
||||||
|
|
||||||
|
cp2 (-> (gpt/to-vec ep cp)
|
||||||
|
(gpt/scale (/ 2 3))
|
||||||
|
(gpt/add ep))]
|
||||||
|
|
||||||
|
{:c1x (:x cp1)
|
||||||
|
:c1y (:y cp1)
|
||||||
|
:c2x (:x cp2)
|
||||||
|
:c2y (:y cp2)}))
|
||||||
|
|
||||||
|
|
||||||
|
smooth-quadratic->curve (fn [cmd {:keys [params]} pos]
|
||||||
|
(let [point (gpt/point (:x params) (:y params))
|
||||||
|
handler (gpt/point (:cx params) (:cy params))
|
||||||
|
oh (calculate-opposite-handler point handler)]
|
||||||
|
(quadratic->curve (update cmd :params assoc :cx (:x oh) :cy (:y oh)) pos)))
|
||||||
|
|
||||||
|
simplify-command
|
||||||
(fn [[pos result] [command prev]]
|
(fn [[pos result] [command prev]]
|
||||||
(let [command
|
(let [command
|
||||||
|
(cond-> command
|
||||||
|
(:relative command)
|
||||||
|
(-> (assoc :relative false)
|
||||||
|
(cd/update-in-when [:params :c1x] + (:x pos))
|
||||||
|
(cd/update-in-when [:params :c1y] + (:y pos))
|
||||||
|
|
||||||
|
(cd/update-in-when [:params :c2x] + (:x pos))
|
||||||
|
(cd/update-in-when [:params :c2y] + (:y pos))
|
||||||
|
|
||||||
|
(cd/update-in-when [:params :cx] + (:x pos))
|
||||||
|
(cd/update-in-when [:params :cy] + (:y pos))
|
||||||
|
|
||||||
|
(cd/update-in-when [:params :x] + (:x pos))
|
||||||
|
(cd/update-in-when [:params :y] + (:y pos))
|
||||||
|
|
||||||
|
(cond->
|
||||||
|
(= :line-to-horizontal (:command command))
|
||||||
|
(cd/update-in-when [:params :value] + (:x pos))
|
||||||
|
|
||||||
|
(= :line-to-vertical (:command command))
|
||||||
|
(cd/update-in-when [:params :value] + (:y pos)))))
|
||||||
|
|
||||||
|
params (:params command)
|
||||||
|
command
|
||||||
(cond-> command
|
(cond-> command
|
||||||
(= :line-to-horizontal (:command command))
|
(= :line-to-horizontal (:command command))
|
||||||
(-> (assoc :command :line-to)
|
(-> (assoc :command :line-to)
|
||||||
(update :params dissoc :value)
|
(update :params dissoc :value)
|
||||||
(assoc-in [:params :x] (get-in command [:params :value]))
|
(assoc-in [:params :x] (:value params))
|
||||||
(assoc-in [:params :y] (if (:relative command) 0 (:y pos))))
|
(assoc-in [:params :y] (:y pos)))
|
||||||
|
|
||||||
(= :line-to-vertical (:command command))
|
(= :line-to-vertical (:command command))
|
||||||
(-> (assoc :command :line-to)
|
(-> (assoc :command :line-to)
|
||||||
(update :params dissoc :value)
|
(update :params dissoc :value)
|
||||||
(assoc-in [:params :y] (get-in command [:params :value]))
|
(assoc-in [:params :y] (:value params))
|
||||||
(assoc-in [:params :x] (if (:relative command) 0 (:x pos))))
|
(assoc-in [:params :x] (:x pos)))
|
||||||
|
|
||||||
(:relative command)
|
(= :smooth-curve-to (:command command))
|
||||||
(-> (assoc :relative false)
|
(-> (assoc :command :curve-to)
|
||||||
(cd/update-in-when [:params :x] + (:x pos))
|
(update :params dissoc :cx :cy)
|
||||||
(cd/update-in-when [:params :y] + (:y pos))))
|
(update :params merge (smooth->curve command pos)))
|
||||||
|
|
||||||
|
(= :quadratic-bezier-curve-to (:command command))
|
||||||
|
(-> (assoc :command :curve-to)
|
||||||
|
(update :params dissoc :cx :cy)
|
||||||
|
(update :params merge (quadratic->curve command pos)))
|
||||||
|
|
||||||
|
(= :smooth-quadratic-bezier-curve-to (:command command))
|
||||||
|
(-> (assoc :command :curve-to)
|
||||||
|
(update :params merge (smooth-quadratic->curve command prev pos))))
|
||||||
|
|
||||||
result #_(conj result command)
|
result #_(conj result command)
|
||||||
(if (= :elliptical-arc (:command command))
|
(if (= :elliptical-arc (:command command))
|
||||||
(cd/concat result (arc->beziers prev command))
|
(cd/concat result (arc->beziers pos command))
|
||||||
(conj result command))]
|
(conj result command))]
|
||||||
[(cmd-pos command) result]))
|
[(cmd-pos pos command) result]))
|
||||||
|
|
||||||
start (first commands)
|
start (first commands)
|
||||||
start-pos (cmd-pos start)]
|
start-pos (gpt/point (:params start))]
|
||||||
|
|
||||||
|
|
||||||
(->> (map vector (rest commands) commands)
|
(->> (map vector (rest commands) commands)
|
||||||
|
|
|
@ -10,7 +10,7 @@
|
||||||
(ns app.util.svg
|
(ns app.util.svg
|
||||||
(:require
|
(:require
|
||||||
[app.common.uuid :as uuid]
|
[app.common.uuid :as uuid]
|
||||||
[app.common.data :as cd]
|
[app.common.data :as d]
|
||||||
[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]
|
||||||
|
@ -22,6 +22,19 @@
|
||||||
(->> (re-seq replace-regex val)
|
(->> (re-seq replace-regex val)
|
||||||
(mapv second)))
|
(mapv second)))
|
||||||
|
|
||||||
|
(defn fix-dot-number
|
||||||
|
"Fixes decimal numbers starting in dot but without leading 0"
|
||||||
|
[num-str]
|
||||||
|
(cond
|
||||||
|
(str/starts-with? num-str ".")
|
||||||
|
(str "0" num-str)
|
||||||
|
|
||||||
|
(str/starts-with? num-str "-.")
|
||||||
|
(str "-0" (subs num-str 1))
|
||||||
|
|
||||||
|
:else
|
||||||
|
num-str))
|
||||||
|
|
||||||
(defn clean-attrs
|
(defn clean-attrs
|
||||||
"Transforms attributes to their react equivalent"
|
"Transforms attributes to their react equivalent"
|
||||||
[attrs]
|
[attrs]
|
||||||
|
@ -59,7 +72,7 @@
|
||||||
(letfn [(update-ids [key val]
|
(letfn [(update-ids [key val]
|
||||||
(cond
|
(cond
|
||||||
(map? val)
|
(map? val)
|
||||||
(cd/mapm update-ids val)
|
(d/mapm update-ids val)
|
||||||
|
|
||||||
(= key :id)
|
(= key :id)
|
||||||
(replace-fn val)
|
(replace-fn val)
|
||||||
|
@ -69,7 +82,7 @@
|
||||||
(fn [result it]
|
(fn [result it]
|
||||||
(str/replace result it (replace-fn it)))]
|
(str/replace result it (replace-fn it)))]
|
||||||
(reduce replace-id val (extract-ids val)))))]
|
(reduce replace-id val (extract-ids val)))))]
|
||||||
(cd/mapm update-ids attrs)))
|
(d/mapm update-ids attrs)))
|
||||||
|
|
||||||
(defn replace-attrs-ids
|
(defn replace-attrs-ids
|
||||||
"Replaces the ids inside a property"
|
"Replaces the ids inside a property"
|
||||||
|
@ -119,7 +132,7 @@
|
||||||
(defn find-node-references [node]
|
(defn find-node-references [node]
|
||||||
(let [current (->> (find-attr-references (:attrs node)) (into #{}))
|
(let [current (->> (find-attr-references (:attrs node)) (into #{}))
|
||||||
children (->> (:content node) (map find-node-references) (flatten) (into #{}))]
|
children (->> (:content node) (map find-node-references) (flatten) (into #{}))]
|
||||||
(-> (cd/concat current children)
|
(-> (d/concat current children)
|
||||||
(vec))))
|
(vec))))
|
||||||
|
|
||||||
(defn find-def-references [defs references]
|
(defn find-def-references [defs references]
|
||||||
|
@ -141,7 +154,7 @@
|
||||||
:else
|
:else
|
||||||
(let [node (get defs to-check)
|
(let [node (get defs to-check)
|
||||||
new-refs (find-node-references node)]
|
new-refs (find-node-references node)]
|
||||||
(recur (cd/concat result new-refs)
|
(recur (d/concat result new-refs)
|
||||||
(conj checked? to-check)
|
(conj checked? to-check)
|
||||||
(first pending)
|
(first pending)
|
||||||
(rest pending))))))
|
(rest pending))))))
|
||||||
|
@ -166,3 +179,62 @@
|
||||||
;; :else
|
;; :else
|
||||||
(gmt/matrix)))
|
(gmt/matrix)))
|
||||||
|
|
||||||
|
;; Parse transform attributes to native matrix format so we can transform paths instead of
|
||||||
|
;; relying in SVG transformation. This is necessary to import SVG's and not to break path tooling
|
||||||
|
;;
|
||||||
|
;; Transforms spec:
|
||||||
|
;; https://www.w3.org/TR/SVG11/single-page.html#coords-TransformAttribute
|
||||||
|
|
||||||
|
(def matrices-regex #"(matrix|translate|scale|rotate|skewX|skewY)\(([^\)]*)\)")
|
||||||
|
(def params-regex #"[+-]?\d*(\.\d+)?(e[+-]?\d+)?")
|
||||||
|
|
||||||
|
(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) (nth params 1))]))
|
||||||
|
|
||||||
|
(defn format-scale-params [params]
|
||||||
|
(assert (or (= (count params) 1) (= (count params) 2)))
|
||||||
|
(if (= (count params) 1)
|
||||||
|
[(gpt/point (nth params 0))]
|
||||||
|
[(gpt/point (nth params 0) (nth params 1))]))
|
||||||
|
|
||||||
|
(defn format-rotate-params [params]
|
||||||
|
(assert (or (= (count params) 1) (= (count params) 3)) (str "??" (count params)))
|
||||||
|
(if (= (count params) 1)
|
||||||
|
[(nth params 0)]
|
||||||
|
[(nth params 0) (gpt/point (nth params 1) (nth params 2))]))
|
||||||
|
|
||||||
|
(defn format-skew-x-params [params]
|
||||||
|
(assert (= (count params) 1))
|
||||||
|
[(nth params 0) 0])
|
||||||
|
|
||||||
|
(defn format-skew-y-params [params]
|
||||||
|
(assert (= (count params) 1))
|
||||||
|
[0 (nth params 0)])
|
||||||
|
|
||||||
|
(defn to-matrix [{:keys [type params]}]
|
||||||
|
(assert (#{"matrix" "translate" "scale" "rotate" "skewX" "skewY"} type))
|
||||||
|
(case type
|
||||||
|
"matrix" (apply gmt/matrix params)
|
||||||
|
"translate" (apply gmt/translate-matrix (format-translate-params params))
|
||||||
|
"scale" (apply gmt/scale-matrix (format-scale-params params))
|
||||||
|
"rotate" (apply gmt/rotate-matrix (format-rotate-params params))
|
||||||
|
"skewX" (apply gmt/skew-matrix (format-skew-x-params params))
|
||||||
|
"skewY" (apply gmt/skew-matrix (format-skew-y-params params))))
|
||||||
|
|
||||||
|
(defn parse-transform [transform-attr]
|
||||||
|
(when transform-attr
|
||||||
|
(let [process-matrix
|
||||||
|
(fn [[_ type params]]
|
||||||
|
(let [params (->> (re-seq params-regex params)
|
||||||
|
(filter #(-> % first empty? not))
|
||||||
|
(map (comp d/parse-double first)))]
|
||||||
|
{:type type :params params}))
|
||||||
|
|
||||||
|
matrices (->> (re-seq matrices-regex transform-attr)
|
||||||
|
(map process-matrix)
|
||||||
|
(map to-matrix))]
|
||||||
|
(reduce gmt/multiply (gmt/matrix) matrices))))
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue