mirror of
https://github.com/penpot/penpot.git
synced 2025-06-14 02:31:37 +02:00
✨ Upload SVG as shapes
This commit is contained in:
parent
5b79928590
commit
802f19453d
28 changed files with 839 additions and 244 deletions
|
@ -23,15 +23,22 @@
|
|||
nil))
|
||||
|
||||
(defn add-border-radius [attrs shape]
|
||||
(obj/merge! attrs #js {:rx (:rx shape)
|
||||
:ry (:ry shape)}))
|
||||
(if (or (:rx shape) (:ry shape))
|
||||
(obj/merge! attrs #js {:rx (:rx shape)
|
||||
:ry (:ry shape)})
|
||||
attrs))
|
||||
|
||||
(defn add-fill [attrs shape render-id]
|
||||
(let [fill-color-gradient-id (str "fill-color-gradient_" render-id)]
|
||||
(if (:fill-color-gradient shape)
|
||||
(cond
|
||||
(:fill-color-gradient shape)
|
||||
(obj/merge! attrs #js {:fill (str/format "url(#%s)" fill-color-gradient-id)})
|
||||
|
||||
(or (:fill-color shape) (:fill-opacity shape))
|
||||
(obj/merge! attrs #js {:fill (or (:fill-color shape) "transparent")
|
||||
:fillOpacity (:fill-opacity shape nil)}))))
|
||||
:fillOpacity (:fill-opacity shape nil)})
|
||||
|
||||
:else attrs)))
|
||||
|
||||
(defn add-stroke [attrs shape render-id]
|
||||
(let [stroke-style (:stroke-style shape :none)
|
||||
|
|
|
@ -9,12 +9,12 @@
|
|||
|
||||
(ns app.main.ui.shapes.filters
|
||||
(:require
|
||||
[rumext.alpha :as mf]
|
||||
[cuerdas.core :as str]
|
||||
[app.util.color :as color]
|
||||
[app.common.data :as d]
|
||||
[app.common.math :as mth]
|
||||
[app.common.uuid :as uuid]))
|
||||
[app.common.uuid :as uuid]
|
||||
[app.util.color :as color]
|
||||
[cuerdas.core :as str]
|
||||
[rumext.alpha :as mf]))
|
||||
|
||||
(defn get-filter-id []
|
||||
(str "filter_" (uuid/next)))
|
||||
|
@ -109,37 +109,6 @@
|
|||
:in2 filter-in
|
||||
:result filter-id}])
|
||||
|
||||
(defn filter-bounds [shape filter-entry]
|
||||
(let [{:keys [x y width height]} (:selrect shape)
|
||||
{:keys [offset-x offset-y blur spread] :or {offset-x 0 offset-y 0 blur 0 spread 0}} (:params filter-entry)
|
||||
filter-x (min x (+ x offset-x (- spread) (- blur) -5))
|
||||
filter-y (min y (+ y offset-y (- spread) (- blur) -5))
|
||||
filter-width (+ width (mth/abs offset-x) (* spread 2) (* blur 2) 10)
|
||||
filter-height (+ height (mth/abs offset-x) (* spread 2) (* blur 2) 10)]
|
||||
{:x1 filter-x
|
||||
:y1 filter-y
|
||||
:x2 (+ filter-x filter-width)
|
||||
:y2 (+ filter-y filter-height)}))
|
||||
|
||||
(defn get-filters-bounds
|
||||
[shape filters blur-value]
|
||||
|
||||
(let [filter-bounds (->> filters
|
||||
(filter #(= :drop-shadow (:type %)))
|
||||
(map (partial filter-bounds shape) ))
|
||||
;; We add the selrect so the minimum size will be the selrect
|
||||
filter-bounds (conj filter-bounds (:selrect shape))
|
||||
x1 (apply min (map :x1 filter-bounds))
|
||||
y1 (apply min (map :y1 filter-bounds))
|
||||
x2 (apply max (map :x2 filter-bounds))
|
||||
y2 (apply max (map :y2 filter-bounds))
|
||||
|
||||
x1 (- x1 (* blur-value 2))
|
||||
x2 (+ x2 (* blur-value 2))
|
||||
y1 (- y1 (* blur-value 2))
|
||||
y2 (+ y2 (* blur-value 2))]
|
||||
[x1 y1 (- x2 x1) (- y2 y1)]))
|
||||
|
||||
(defn blur-filters [type value]
|
||||
(->> [value]
|
||||
(remove :hidden)
|
||||
|
@ -185,18 +154,11 @@
|
|||
(->> shape :blur (blur-filters :layer-blur)))
|
||||
|
||||
;; Adds the previous filter as `filter-in` parameter
|
||||
filters (map #(assoc %1 :filter-in %2) filters (cons nil (map :id filters)))
|
||||
|
||||
[filter-x filter-y filter-width filter-height] (get-filters-bounds shape filters (or (-> shape :blur :value) 0))]
|
||||
filters (map #(assoc %1 :filter-in %2) filters (cons nil (map :id filters)))]
|
||||
|
||||
[:*
|
||||
(when (> (count filters) 2)
|
||||
[:filter {:id filter-id
|
||||
:x filter-x
|
||||
:y filter-y
|
||||
:width filter-width
|
||||
:height filter-height
|
||||
:filterUnits "userSpaceOnUse"
|
||||
:color-interpolation-filters "sRGB"}
|
||||
|
||||
(for [entry filters]
|
||||
|
|
123
frontend/src/app/main/ui/shapes/svg_raw.cljs
Normal file
123
frontend/src/app/main/ui/shapes/svg_raw.cljs
Normal file
|
@ -0,0 +1,123 @@
|
|||
;; This Source Code Form is subject to the terms of the Mozilla Public
|
||||
;; License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
;; file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
;;
|
||||
;; This Source Code Form is "Incompatible With Secondary Licenses", as
|
||||
;; defined by the Mozilla Public License, v. 2.0.
|
||||
;;
|
||||
;; Copyright (c) 2020 UXBOX Labs SL
|
||||
|
||||
(ns app.main.ui.shapes.svg-raw
|
||||
(:require
|
||||
[app.common.geom.matrix :as gmt]
|
||||
[app.common.geom.point :as gpt]
|
||||
[app.common.geom.shapes :as gsh]
|
||||
[app.main.ui.shapes.attrs :as usa]
|
||||
[app.util.data :as d]
|
||||
[app.util.object :as obj]
|
||||
[cuerdas.core :as str]
|
||||
[rumext.alpha :as mf]))
|
||||
|
||||
(defn clean-attrs
|
||||
"Transforms attributes to their react equivalent"
|
||||
[attrs]
|
||||
(letfn [(transform-key [key]
|
||||
(-> (name key)
|
||||
(str/replace ":" "-")
|
||||
(str/camel)
|
||||
(keyword)))
|
||||
|
||||
(format-styles [style-str]
|
||||
(->> (str/split style-str ";")
|
||||
(map str/trim)
|
||||
(map #(str/split % ":"))
|
||||
(group-by first)
|
||||
(map (fn [[key val]]
|
||||
(vector
|
||||
(transform-key key)
|
||||
(second (first val)))))
|
||||
(into {})))
|
||||
|
||||
(map-fn [[key val]]
|
||||
(cond
|
||||
(= key :style) [key (format-styles val)]
|
||||
:else (vector (transform-key key) val)))]
|
||||
|
||||
(->> attrs
|
||||
(map map-fn)
|
||||
(into {}))))
|
||||
|
||||
(defn vbox->rect
|
||||
"Converts the viewBox into a rectangle"
|
||||
[vbox]
|
||||
(when vbox
|
||||
(let [[x y width height] (map d/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 svg-raw-shape [shape-wrapper]
|
||||
(mf/fnc svg-raw-shape
|
||||
{::mf/wrap-props false}
|
||||
[props]
|
||||
(let [frame (unchecked-get props "frame")
|
||||
shape (unchecked-get props "shape")
|
||||
childs (unchecked-get props "childs")
|
||||
|
||||
{:keys [tag attrs] :as content} (:content shape)
|
||||
|
||||
attrs (obj/merge! (clj->js (clean-attrs attrs))
|
||||
(usa/extract-style-attrs shape))]
|
||||
|
||||
(cond
|
||||
;; Root SVG TAG
|
||||
(and (map? content) (= tag :svg))
|
||||
(let [;; {:keys [x y width height]} (-> (:points shape) gsh/points->selrect)
|
||||
{: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)))]
|
||||
|
||||
[: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)
|
||||
[:> (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