mirror of
https://github.com/penpot/penpot.git
synced 2025-02-12 18:18:24 -05:00
✨ Plugins create svg shapes
This commit is contained in:
parent
21d38a058b
commit
67d48435e7
6 changed files with 128 additions and 103 deletions
|
@ -22,6 +22,7 @@
|
|||
[app.common.svg :as csvg]
|
||||
[app.common.svg.path :as path]
|
||||
[app.common.types.shape :as cts]
|
||||
[app.common.uuid :as uuid]
|
||||
[cuerdas.core :as str]))
|
||||
|
||||
(def default-rect
|
||||
|
@ -78,67 +79,68 @@
|
|||
(declare parse-svg-element)
|
||||
|
||||
(defn create-svg-shapes
|
||||
[svg-data {:keys [x y]} objects frame-id parent-id selected center?]
|
||||
(let [[vb-x vb-y vb-width vb-height] (svg-dimensions svg-data)
|
||||
([svg-data pos objects frame-id parent-id selected center?]
|
||||
(create-svg-shapes (uuid/next) svg-data pos objects frame-id parent-id selected center?))
|
||||
([id svg-data {:keys [x y]} objects frame-id parent-id selected center?]
|
||||
(let [[vb-x vb-y vb-width vb-height] (svg-dimensions svg-data)
|
||||
|
||||
unames (cfh/get-used-names objects)
|
||||
svg-name (str/replace (:name svg-data) ".svg" "")
|
||||
|
||||
unames (cfh/get-used-names objects)
|
||||
svg-name (str/replace (:name svg-data) ".svg" "")
|
||||
svg-data (-> svg-data
|
||||
(assoc :x (mth/round
|
||||
(if center?
|
||||
(- x vb-x (/ vb-width 2))
|
||||
x)))
|
||||
(assoc :y (mth/round
|
||||
(if center?
|
||||
(- y vb-y (/ vb-height 2))
|
||||
y)))
|
||||
(assoc :offset-x vb-x)
|
||||
(assoc :offset-y vb-y)
|
||||
(assoc :width vb-width)
|
||||
(assoc :height vb-height)
|
||||
(assoc :name svg-name))
|
||||
|
||||
svg-data (-> svg-data
|
||||
(assoc :x (mth/round
|
||||
(if center?
|
||||
(- x vb-x (/ vb-width 2))
|
||||
x)))
|
||||
(assoc :y (mth/round
|
||||
(if center?
|
||||
(- y vb-y (/ vb-height 2))
|
||||
y)))
|
||||
(assoc :offset-x vb-x)
|
||||
(assoc :offset-y vb-y)
|
||||
(assoc :width vb-width)
|
||||
(assoc :height vb-height)
|
||||
(assoc :name svg-name))
|
||||
[def-nodes svg-data]
|
||||
(-> svg-data
|
||||
(csvg/fix-default-values)
|
||||
(csvg/fix-percents)
|
||||
(csvg/extract-defs))
|
||||
|
||||
[def-nodes svg-data]
|
||||
(-> svg-data
|
||||
(csvg/fix-default-values)
|
||||
(csvg/fix-percents)
|
||||
(csvg/extract-defs))
|
||||
;; In penpot groups have the size of their children. To
|
||||
;; respect the imported svg size and empty space let's create
|
||||
;; a transparent shape as background to respect the imported
|
||||
;; size
|
||||
background
|
||||
{:tag :rect
|
||||
:attrs {:x (dm/str vb-x)
|
||||
:y (dm/str vb-y)
|
||||
:width (dm/str vb-width)
|
||||
:height (dm/str vb-height)
|
||||
:fill "none"
|
||||
:id "base-background"}
|
||||
:hidden true
|
||||
:content []}
|
||||
|
||||
;; In penpot groups have the size of their children. To
|
||||
;; respect the imported svg size and empty space let's create
|
||||
;; a transparent shape as background to respect the imported
|
||||
;; size
|
||||
background
|
||||
{:tag :rect
|
||||
:attrs {:x (dm/str vb-x)
|
||||
:y (dm/str vb-y)
|
||||
:width (dm/str vb-width)
|
||||
:height (dm/str vb-height)
|
||||
:fill "none"
|
||||
:id "base-background"}
|
||||
:hidden true
|
||||
:content []}
|
||||
svg-data (-> svg-data
|
||||
(assoc :defs def-nodes)
|
||||
(assoc :content (into [background] (:content svg-data))))
|
||||
|
||||
svg-data (-> svg-data
|
||||
(assoc :defs def-nodes)
|
||||
(assoc :content (into [background] (:content svg-data))))
|
||||
root-shape (create-svg-root id frame-id parent-id svg-data)
|
||||
root-id (:id root-shape)
|
||||
|
||||
root-shape (create-svg-root frame-id parent-id svg-data)
|
||||
root-id (:id root-shape)
|
||||
;; Create the root shape
|
||||
root-attrs (-> (:attrs svg-data)
|
||||
(csvg/format-styles))
|
||||
|
||||
;; Create the root shape
|
||||
root-attrs (-> (:attrs svg-data)
|
||||
(csvg/format-styles))
|
||||
[_ children]
|
||||
(reduce (partial create-svg-children objects selected frame-id root-id svg-data)
|
||||
[unames []]
|
||||
(d/enumerate (->> (:content svg-data)
|
||||
(mapv #(csvg/inherit-attributes root-attrs %)))))]
|
||||
|
||||
[_ children]
|
||||
(reduce (partial create-svg-children objects selected frame-id root-id svg-data)
|
||||
[unames []]
|
||||
(d/enumerate (->> (:content svg-data)
|
||||
(mapv #(csvg/inherit-attributes root-attrs %)))))]
|
||||
|
||||
[root-shape children]))
|
||||
[root-shape children])))
|
||||
|
||||
(defn create-raw-svg
|
||||
[name frame-id {:keys [x y width height offset-x offset-y]} {:keys [attrs] :as data}]
|
||||
|
@ -157,12 +159,13 @@
|
|||
:svg-viewbox vbox})))
|
||||
|
||||
(defn create-svg-root
|
||||
[frame-id parent-id {:keys [name x y width height offset-x offset-y attrs]}]
|
||||
[id frame-id parent-id {:keys [name x y width height offset-x offset-y attrs]}]
|
||||
(let [props (-> (dissoc attrs :viewBox :view-box :xmlns)
|
||||
(d/without-keys csvg/inheritable-props)
|
||||
(csvg/attrs->props))]
|
||||
(cts/setup-shape
|
||||
{:type :group
|
||||
{:id id
|
||||
:type :group
|
||||
:name name
|
||||
:frame-id frame-id
|
||||
:parent-id parent-id
|
||||
|
|
|
@ -203,7 +203,7 @@
|
|||
ptk/WatchEvent
|
||||
(watch [_ state _]
|
||||
(let [selected (wsh/lookup-selected state)]
|
||||
(rx/of group-shapes nil selected)))))
|
||||
(rx/of (group-shapes nil selected))))))
|
||||
|
||||
(defn ungroup-shapes
|
||||
[ids & {:keys [change-selection?] :or {change-selection? false}}]
|
||||
|
|
|
@ -459,3 +459,12 @@
|
|||
(rx/tap on-success)
|
||||
(rx/catch on-error)
|
||||
(rx/finalize #(st/emit! (msg/hide-tag :media-loading)))))))))
|
||||
|
||||
(defn create-svg-shape
|
||||
[id name svg-string position]
|
||||
(ptk/reify ::create-svg-shape
|
||||
ptk/WatchEvent
|
||||
(watch [_ _ _]
|
||||
(->> (svg->clj [name svg-string])
|
||||
(rx/take 1)
|
||||
(rx/map #(svg/add-svg-shapes id % position {:change-selection? false}))))))
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
[app.common.svg :as csvg]
|
||||
[app.common.svg.shapes-builder :as csvg.shapes-builder]
|
||||
[app.common.types.shape-tree :as ctst]
|
||||
[app.common.uuid :as uuid]
|
||||
[app.main.data.workspace.changes :as dch]
|
||||
[app.main.data.workspace.selection :as dws]
|
||||
[app.main.data.workspace.state-helpers :as wsh]
|
||||
|
@ -60,52 +61,58 @@
|
|||
(rx/reduce conj {})))
|
||||
|
||||
(defn add-svg-shapes
|
||||
[svg-data position]
|
||||
(ptk/reify ::add-svg-shapes
|
||||
ptk/WatchEvent
|
||||
(watch [it state _]
|
||||
(try
|
||||
(let [page-id (:current-page-id state)
|
||||
objects (wsh/lookup-page-objects state page-id)
|
||||
frame-id (ctst/top-nested-frame objects position)
|
||||
selected (wsh/lookup-selected state)
|
||||
base (cfh/get-base-shape objects selected)
|
||||
([svg-data position]
|
||||
(add-svg-shapes nil svg-data position nil))
|
||||
|
||||
selected-id (first selected)
|
||||
selected-frame? (and (= 1 (count selected))
|
||||
(= :frame (dm/get-in objects [selected-id :type])))
|
||||
([id svg-data position {:keys [change-selection?] :or {change-selection? false}}]
|
||||
(ptk/reify ::add-svg-shapes
|
||||
ptk/WatchEvent
|
||||
(watch [it state _]
|
||||
(try
|
||||
(let [id (d/nilv id (uuid/next))
|
||||
page-id (:current-page-id state)
|
||||
objects (wsh/lookup-page-objects state page-id)
|
||||
frame-id (ctst/top-nested-frame objects position)
|
||||
selected (wsh/lookup-selected state)
|
||||
base (cfh/get-base-shape objects selected)
|
||||
|
||||
parent-id (if (or selected-frame? (empty? selected))
|
||||
frame-id
|
||||
(:parent-id base))
|
||||
selected-id (first selected)
|
||||
selected-frame? (and (= 1 (count selected))
|
||||
(= :frame (dm/get-in objects [selected-id :type])))
|
||||
|
||||
[new-shape new-children]
|
||||
(csvg.shapes-builder/create-svg-shapes svg-data position objects frame-id parent-id selected true)
|
||||
parent-id (if (or selected-frame? (empty? selected))
|
||||
frame-id
|
||||
(:parent-id base))
|
||||
|
||||
changes (-> (pcb/empty-changes it page-id)
|
||||
(pcb/with-objects objects)
|
||||
(pcb/add-object new-shape))
|
||||
[new-shape new-children]
|
||||
(csvg.shapes-builder/create-svg-shapes id svg-data position objects frame-id parent-id selected true)
|
||||
|
||||
changes (reduce (fn [changes new-child]
|
||||
(pcb/add-object changes new-child))
|
||||
changes
|
||||
new-children)
|
||||
changes (-> (pcb/empty-changes it page-id)
|
||||
(pcb/with-objects objects)
|
||||
(pcb/add-object new-shape))
|
||||
|
||||
changes (pcb/resize-parents changes
|
||||
(->> (:redo-changes changes)
|
||||
(filter #(= :add-obj (:type %)))
|
||||
(map :id)
|
||||
(reverse)
|
||||
(vec)))
|
||||
undo-id (js/Symbol)]
|
||||
changes (reduce (fn [changes new-child]
|
||||
(pcb/add-object changes new-child))
|
||||
changes
|
||||
new-children)
|
||||
|
||||
(rx/of (dwu/start-undo-transaction undo-id)
|
||||
(dch/commit-changes changes)
|
||||
(dws/select-shapes (d/ordered-set (:id new-shape)))
|
||||
(ptk/data-event :layout/update {:ids [(:id new-shape)]})
|
||||
(dwu/commit-undo-transaction undo-id)))
|
||||
changes (pcb/resize-parents changes
|
||||
(->> (:redo-changes changes)
|
||||
(filter #(= :add-obj (:type %)))
|
||||
(map :id)
|
||||
(reverse)
|
||||
(vec)))
|
||||
undo-id (js/Symbol)]
|
||||
|
||||
(rx/of (dwu/start-undo-transaction undo-id)
|
||||
(dch/commit-changes changes)
|
||||
(when change-selection?
|
||||
(dws/select-shapes (d/ordered-set (:id new-shape))))
|
||||
(ptk/data-event :layout/update {:ids [(:id new-shape)]})
|
||||
(dwu/commit-undo-transaction undo-id)))
|
||||
|
||||
(catch :default cause
|
||||
(js/console.log (.-stack cause))
|
||||
(rx/throw {:type :svg-parser
|
||||
:data cause})))))))
|
||||
|
||||
(catch :default cause
|
||||
(js/console.log (.-stack cause))
|
||||
(rx/throw {:type :svg-parser
|
||||
:data cause}))))))
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
(:require
|
||||
[app.common.data.macros :as dm]
|
||||
[app.common.files.changes-builder :as cb]
|
||||
[app.common.geom.point :as gpt]
|
||||
[app.common.record :as cr]
|
||||
[app.common.types.shape :as cts]
|
||||
[app.common.uuid :as uuid]
|
||||
|
@ -127,7 +128,14 @@
|
|||
(createRectangle
|
||||
[_]
|
||||
(create-shape :rect))
|
||||
)
|
||||
|
||||
(createShapeFromSvg
|
||||
[_ svg-string]
|
||||
(let [id (uuid/next)
|
||||
page-id (:current-page-id @st/state)]
|
||||
(st/emit! (dwm/create-svg-shape id "svg" svg-string (gpt/point 0 0)))
|
||||
(shape/data->shape-proxy
|
||||
(dm/get-in @st/state [:workspace-data :pages-index page-id :objects id])))))
|
||||
|
||||
(defn create-context
|
||||
[]
|
||||
|
|
|
@ -67,12 +67,12 @@
|
|||
(appendChild [self child]
|
||||
(let [parent-id (get-data self :id)
|
||||
child-id (uuid/uuid (obj/get child "id"))]
|
||||
(st/emit! (udw/relocate-shapes #{ child-id } parent-id 0))))
|
||||
(st/emit! (udw/relocate-shapes #{child-id} parent-id 0))))
|
||||
|
||||
(insertChild [self index child]
|
||||
(let [parent-id (get-data self :id)
|
||||
child-id (uuid/uuid (obj/get child "id"))]
|
||||
(st/emit! (udw/relocate-shapes #{ child-id } parent-id index)))))
|
||||
(st/emit! (udw/relocate-shapes #{child-id} parent-id index)))))
|
||||
|
||||
(crc/define-properties!
|
||||
ShapeProxy
|
||||
|
@ -124,16 +124,14 @@
|
|||
:set (fn [self value]
|
||||
(let [id (get-data self :id)
|
||||
value (mapv #(utils/from-js %) value)]
|
||||
(st/emit! (dwc/update-shapes [id] #(assoc % :fills value)))))
|
||||
}
|
||||
(st/emit! (dwc/update-shapes [id] #(assoc % :fills value)))))}
|
||||
|
||||
{:name "strokes"
|
||||
:get #(get-state % :strokes make-strokes)
|
||||
:set (fn [self value]
|
||||
(let [id (get-data self :id)
|
||||
value (mapv #(utils/from-js %) value)]
|
||||
(st/emit! (dwc/update-shapes [id] #(assoc % :strokes value)))))
|
||||
})
|
||||
(st/emit! (dwc/update-shapes [id] #(assoc % :strokes value)))))})
|
||||
|
||||
(cond-> (or (cfh/frame-shape? data) (cfh/group-shape? data) (cfh/svg-raw-shape? data) (cfh/bool-shape? data))
|
||||
(crc/add-properties!
|
||||
|
|
Loading…
Add table
Reference in a new issue