mirror of
https://github.com/penpot/penpot.git
synced 2025-05-25 15:36:11 +02:00
commit
925058467f
15 changed files with 217 additions and 151 deletions
16
CHANGES.md
16
CHANGES.md
|
@ -3,10 +3,15 @@
|
||||||
## :rocket: Next
|
## :rocket: Next
|
||||||
|
|
||||||
### :boom: Breaking changes
|
### :boom: Breaking changes
|
||||||
|
|
||||||
|
- Some stroke-caps can change behaviour
|
||||||
|
- Text display bug fix could potentialy make some texts jump a line
|
||||||
|
|
||||||
### :sparkles: New features
|
### :sparkles: New features
|
||||||
|
|
||||||
- Add boolean shapes: intersections, unions, difference and exclusions.
|
- Add boolean shapes: intersections, unions, difference and exclusions.
|
||||||
- Add advanced prototyping [#244](https://tree.taiga.io/project/penpot/us/244).
|
- Add advanced prototyping [#244](https://tree.taiga.io/project/penpot/us/244).
|
||||||
|
- Change order of the teams menu so it's in the joined time order
|
||||||
|
|
||||||
### :bug: Bugs fixed
|
### :bug: Bugs fixed
|
||||||
|
|
||||||
|
@ -26,12 +31,15 @@
|
||||||
- Fix zoom context menu in viewer [Taiga #2041](https://tree.taiga.io/project/penpot/issue/2041)
|
- Fix zoom context menu in viewer [Taiga #2041](https://tree.taiga.io/project/penpot/issue/2041)
|
||||||
- Fix stroke caps adjustments in relation with stroke size [Taiga #2123](https://tree.taiga.io/project/penpot/issue/2123)
|
- Fix stroke caps adjustments in relation with stroke size [Taiga #2123](https://tree.taiga.io/project/penpot/issue/2123)
|
||||||
- Fix problem duplicating paths [Taiga #2147](https://tree.taiga.io/project/penpot/issue/2147)
|
- Fix problem duplicating paths [Taiga #2147](https://tree.taiga.io/project/penpot/issue/2147)
|
||||||
|
- Fix problem inheriting attributes from SVG root when importing [Taiga #2124](https://tree.taiga.io/project/penpot/issue/2124)
|
||||||
|
- Fix problem with lines and inside/outside stroke [Taiga #2146](https://tree.taiga.io/project/penpot/issue/2146)
|
||||||
|
- Add stroke width in selection calculation [Taiga #2146](https://tree.taiga.io/project/penpot/issue/2146)
|
||||||
|
- Fix shift+wheel to horizontal scrolling in MacOS [#1217](https://github.com/penpot/penpot/issues/1217)
|
||||||
|
- Fix path stroke is not working properly with high thickness [Taiga #2154](https://tree.taiga.io/project/penpot/issue/2154)
|
||||||
|
- Fix bug with transformation operations [Taiga #2155](https://tree.taiga.io/project/penpot/issue/2155)
|
||||||
|
- Fix bug in firefox when a text box is inside a mask [Taiga #2152](https://tree.taiga.io/project/penpot/issue/2152)
|
||||||
|
|
||||||
### :arrow_up: Deps updates
|
### :arrow_up: Deps updates
|
||||||
### :boom: Breaking changes
|
|
||||||
|
|
||||||
- Some stroke-caps can change behaviour
|
|
||||||
- Text display bug fix could potentialy make some texts jump a line
|
|
||||||
|
|
||||||
### :heart: Community contributions by (Thank you!)
|
### :heart: Community contributions by (Thank you!)
|
||||||
|
|
||||||
|
|
|
@ -58,7 +58,7 @@
|
||||||
join team as t on (t.id = tp.team_id)
|
join team as t on (t.id = tp.team_id)
|
||||||
where t.deleted_at is null
|
where t.deleted_at is null
|
||||||
and tp.profile_id = ?
|
and tp.profile_id = ?
|
||||||
order by t.created_at asc")
|
order by tp.created_at asc")
|
||||||
|
|
||||||
(defn retrieve-teams
|
(defn retrieve-teams
|
||||||
[conn profile-id]
|
[conn profile-id]
|
||||||
|
|
|
@ -160,6 +160,7 @@
|
||||||
;; PATHS
|
;; PATHS
|
||||||
(d/export gsp/content->selrect)
|
(d/export gsp/content->selrect)
|
||||||
(d/export gsp/transform-content)
|
(d/export gsp/transform-content)
|
||||||
|
(d/export gsp/open-path?)
|
||||||
|
|
||||||
;; Intersection
|
;; Intersection
|
||||||
(d/export gin/overlaps?)
|
(d/export gin/overlaps?)
|
||||||
|
|
|
@ -284,12 +284,19 @@
|
||||||
(defn overlaps?
|
(defn overlaps?
|
||||||
"General case to check for overlaping between shapes and a rectangle"
|
"General case to check for overlaping between shapes and a rectangle"
|
||||||
[shape rect]
|
[shape rect]
|
||||||
|
(let [stroke-width (/ (or (:stroke-width shape) 0) 2)
|
||||||
|
rect (-> rect
|
||||||
|
(update :x - stroke-width)
|
||||||
|
(update :y - stroke-width)
|
||||||
|
(update :width + (* 2 stroke-width))
|
||||||
|
(update :height + (* 2 stroke-width))
|
||||||
|
)]
|
||||||
(or (not shape)
|
(or (not shape)
|
||||||
(let [path? (= :path (:type shape))
|
(let [path? (= :path (:type shape))
|
||||||
circle? (= :circle (:type shape))]
|
circle? (= :circle (:type shape))]
|
||||||
(and (overlaps-rect-points? rect (:points shape))
|
(and (overlaps-rect-points? rect (:points shape))
|
||||||
(or (not path?) (overlaps-path? shape rect))
|
(or (not path?) (overlaps-path? shape rect))
|
||||||
(or (not circle?) (overlaps-ellipse? shape rect))))))
|
(or (not circle?) (overlaps-ellipse? shape rect)))))))
|
||||||
|
|
||||||
(defn has-point-rect?
|
(defn has-point-rect?
|
||||||
[rect point]
|
[rect point]
|
||||||
|
|
|
@ -126,8 +126,8 @@
|
||||||
|
|
||||||
(let [tangent (curve-tangent curve t)]
|
(let [tangent (curve-tangent curve t)]
|
||||||
(cond
|
(cond
|
||||||
(> (:y tangent) 0) 1
|
(> (:y tangent) 0) -1
|
||||||
(< (:y tangent) 0) -1
|
(< (:y tangent) 0) 1
|
||||||
:else 0)))
|
:else 0)))
|
||||||
|
|
||||||
(defn curve-split
|
(defn curve-split
|
||||||
|
@ -822,30 +822,27 @@
|
||||||
(let [selrect (content->selrect content)
|
(let [selrect (content->selrect content)
|
||||||
ray-line [point (gpt/point (inc (:x point)) (:y point))]
|
ray-line [point (gpt/point (inc (:x point)) (:y point))]
|
||||||
|
|
||||||
closed-subpaths
|
closed-content
|
||||||
|
(into []
|
||||||
|
(comp (filter sp/is-closed?)
|
||||||
|
(mapcat :data))
|
||||||
(->> content
|
(->> content
|
||||||
(sp/close-subpaths)
|
(sp/close-subpaths)
|
||||||
(sp/get-subpaths)
|
(sp/get-subpaths)))
|
||||||
(filterv sp/is-closed?))
|
|
||||||
|
|
||||||
cast-ray
|
cast-ray
|
||||||
(fn [cmd]
|
(fn [cmd]
|
||||||
(case (:command cmd)
|
(case (:command cmd)
|
||||||
:line-to (ray-line-intersect point (command->line cmd))
|
:line-to (ray-line-intersect point (command->line cmd))
|
||||||
:curve-to (ray-curve-intersect ray-line (command->bezier cmd))
|
:curve-to (ray-curve-intersect ray-line (command->bezier cmd))
|
||||||
#_:else []))
|
#_:else []))]
|
||||||
|
|
||||||
is-point-in-subpath?
|
(and (gpr/contains-point? selrect point)
|
||||||
(fn [subpath]
|
(->> closed-content
|
||||||
(and (gpr/contains-point? (content->selrect (:data subpath)) point)
|
|
||||||
(->> (:data subpath)
|
|
||||||
(mapcat cast-ray)
|
(mapcat cast-ray)
|
||||||
(map second)
|
(map second)
|
||||||
(reduce +)
|
(reduce +)
|
||||||
(not= 0))))]
|
(not= 0)))))
|
||||||
|
|
||||||
(and (gpr/contains-point? selrect point)
|
|
||||||
(some is-point-in-subpath? closed-subpaths))))
|
|
||||||
|
|
||||||
(defn split-line-to
|
(defn split-line-to
|
||||||
"Given a point and a line-to command will create a two new line-to commands
|
"Given a point and a line-to command will create a two new line-to commands
|
||||||
|
@ -948,3 +945,14 @@
|
||||||
(gsc/transform-points points-center transform-inverse)
|
(gsc/transform-points points-center transform-inverse)
|
||||||
(gpr/points->selrect))]
|
(gpr/points->selrect))]
|
||||||
[points selrect]))
|
[points selrect]))
|
||||||
|
|
||||||
|
|
||||||
|
(defn open-path?
|
||||||
|
[shape]
|
||||||
|
|
||||||
|
(and (= :path (:type shape))
|
||||||
|
(not (->> shape
|
||||||
|
:content
|
||||||
|
(sp/close-subpaths)
|
||||||
|
(sp/get-subpaths)
|
||||||
|
(every? sp/is-closed?)))))
|
||||||
|
|
|
@ -73,9 +73,15 @@
|
||||||
(fn [subpaths current]
|
(fn [subpaths current]
|
||||||
(let [is-move? (= :move-to (:command current))
|
(let [is-move? (= :move-to (:command current))
|
||||||
last-idx (dec (count subpaths))]
|
last-idx (dec (count subpaths))]
|
||||||
(if is-move?
|
(cond
|
||||||
|
is-move?
|
||||||
(conj subpaths (make-subpath current))
|
(conj subpaths (make-subpath current))
|
||||||
(update subpaths last-idx add-subpath-command current))))]
|
|
||||||
|
(>= last-idx 0)
|
||||||
|
(update subpaths last-idx add-subpath-command current)
|
||||||
|
|
||||||
|
:else
|
||||||
|
subpaths)))]
|
||||||
(->> content
|
(->> content
|
||||||
(reduce reduce-subpath []))))
|
(reduce reduce-subpath []))))
|
||||||
|
|
||||||
|
|
|
@ -432,6 +432,7 @@
|
||||||
(ptk/reify ::duplicate-selected
|
(ptk/reify ::duplicate-selected
|
||||||
ptk/WatchEvent
|
ptk/WatchEvent
|
||||||
(watch [it state _]
|
(watch [it state _]
|
||||||
|
(when (nil? (get-in state [:workspace-local :transform]))
|
||||||
(let [page-id (:current-page-id state)
|
(let [page-id (:current-page-id state)
|
||||||
objects (wsh/lookup-page-objects state page-id)
|
objects (wsh/lookup-page-objects state page-id)
|
||||||
selected (wsh/lookup-selected state)
|
selected (wsh/lookup-selected state)
|
||||||
|
@ -461,7 +462,7 @@
|
||||||
:undo-changes uchanges
|
:undo-changes uchanges
|
||||||
:origin it})
|
:origin it})
|
||||||
(select-shapes selected)
|
(select-shapes selected)
|
||||||
(memorize-duplicated id-original id-duplicated))))))
|
(memorize-duplicated id-original id-duplicated)))))))
|
||||||
|
|
||||||
(defn change-hover-state
|
(defn change-hover-state
|
||||||
[id value]
|
[id value]
|
||||||
|
|
|
@ -178,7 +178,8 @@
|
||||||
:y (+ y offset-y)}
|
:y (+ y offset-y)}
|
||||||
(gsh/setup-selrect)
|
(gsh/setup-selrect)
|
||||||
(assoc :svg-attrs (-> (:attrs svg-data)
|
(assoc :svg-attrs (-> (:attrs svg-data)
|
||||||
(dissoc :viewBox :xmlns))))))
|
(dissoc :viewBox :xmlns)
|
||||||
|
(d/without-keys usvg/inheritable-props))))))
|
||||||
|
|
||||||
(defn create-group [name frame-id svg-data {:keys [attrs]}]
|
(defn create-group [name frame-id svg-data {:keys [attrs]}]
|
||||||
(let [svg-transform (usvg/parse-transform (:transform attrs))
|
(let [svg-transform (usvg/parse-transform (:transform attrs))
|
||||||
|
@ -387,7 +388,7 @@
|
||||||
(setup-stroke)))
|
(setup-stroke)))
|
||||||
|
|
||||||
children (cond->> (:content element-data)
|
children (cond->> (:content element-data)
|
||||||
(= tag :g)
|
(or (= tag :g) (= tag :svg))
|
||||||
(mapv #(usvg/inherit-attributes attrs %)))]
|
(mapv #(usvg/inherit-attributes attrs %)))]
|
||||||
[shape children]))))
|
[shape children]))))
|
||||||
|
|
||||||
|
@ -487,11 +488,15 @@
|
||||||
;; Creates the root shape
|
;; Creates the root shape
|
||||||
changes (dwc/add-shape-changes page-id objects selected root-shape false)
|
changes (dwc/add-shape-changes page-id objects selected root-shape false)
|
||||||
|
|
||||||
|
root-attrs (-> (:attrs svg-data)
|
||||||
|
(usvg/format-styles))
|
||||||
|
|
||||||
;; Reduces the children to create the changes to add the children shapes
|
;; Reduces the children to create the changes to add the children shapes
|
||||||
[_ [rchanges uchanges]]
|
[_ [rchanges uchanges]]
|
||||||
(reduce (partial add-svg-child-changes page-id objects selected frame-id root-id svg-data)
|
(reduce (partial add-svg-child-changes page-id objects selected frame-id root-id svg-data)
|
||||||
[unames changes]
|
[unames changes]
|
||||||
(d/enumerate (:content svg-data)))
|
(d/enumerate (->> (:content svg-data)
|
||||||
|
(mapv #(usvg/inherit-attributes root-attrs %)))))
|
||||||
|
|
||||||
reg-objects-action {:type :reg-objects
|
reg-objects-action {:type :reg-objects
|
||||||
:page-id page-id
|
:page-id page-id
|
||||||
|
|
|
@ -70,10 +70,7 @@
|
||||||
(defn- fix-init-point
|
(defn- fix-init-point
|
||||||
"Fix the initial point so the resizes are accurate"
|
"Fix the initial point so the resizes are accurate"
|
||||||
[initial handler shape]
|
[initial handler shape]
|
||||||
(let [{:keys [x y width height]} (:selrect shape)
|
(let [{:keys [x y width height]} (:selrect shape)]
|
||||||
{:keys [rotation]} shape
|
|
||||||
rotation (or rotation 0)]
|
|
||||||
(if (= rotation 0)
|
|
||||||
(cond-> initial
|
(cond-> initial
|
||||||
(contains? #{:left :top-left :bottom-left} handler)
|
(contains? #{:left :top-left :bottom-left} handler)
|
||||||
(assoc :x x)
|
(assoc :x x)
|
||||||
|
@ -85,8 +82,7 @@
|
||||||
(assoc :y y)
|
(assoc :y y)
|
||||||
|
|
||||||
(contains? #{:bottom :bottom-right :bottom-left} handler)
|
(contains? #{:bottom :bottom-right :bottom-left} handler)
|
||||||
(assoc :y (+ y height)))
|
(assoc :y (+ y height)))))
|
||||||
initial)))
|
|
||||||
|
|
||||||
(defn finish-transform []
|
(defn finish-transform []
|
||||||
(ptk/reify ::finish-transform
|
(ptk/reify ::finish-transform
|
||||||
|
@ -285,10 +281,19 @@
|
||||||
(letfn [(resize [shape initial layout [point lock? center? point-snap]]
|
(letfn [(resize [shape initial layout [point lock? center? point-snap]]
|
||||||
(let [{:keys [width height]} (:selrect shape)
|
(let [{:keys [width height]} (:selrect shape)
|
||||||
{:keys [rotation]} shape
|
{:keys [rotation]} shape
|
||||||
|
|
||||||
|
shape-center (gsh/center-shape shape)
|
||||||
|
shape-transform (:transform shape (gmt/matrix))
|
||||||
|
shape-transform-inverse (:transform-inverse shape (gmt/matrix))
|
||||||
|
|
||||||
rotation (or rotation 0)
|
rotation (or rotation 0)
|
||||||
|
|
||||||
|
initial (gsh/transform-point-center initial shape-center shape-transform-inverse)
|
||||||
initial (fix-init-point initial handler shape)
|
initial (fix-init-point initial handler shape)
|
||||||
|
|
||||||
|
point (gsh/transform-point-center (if (= rotation 0) point-snap point)
|
||||||
|
shape-center shape-transform-inverse)
|
||||||
|
|
||||||
shapev (-> (gpt/point width height))
|
shapev (-> (gpt/point width height))
|
||||||
|
|
||||||
scale-text (:scale-text layout)
|
scale-text (:scale-text layout)
|
||||||
|
@ -300,8 +305,7 @@
|
||||||
handler-mult (let [[x y] (handler-multipliers handler)] (gpt/point x y))
|
handler-mult (let [[x y] (handler-multipliers handler)] (gpt/point x y))
|
||||||
|
|
||||||
;; Difference between the origin point in the coordinate system of the rotation
|
;; Difference between the origin point in the coordinate system of the rotation
|
||||||
deltav (-> (gpt/to-vec initial (if (= rotation 0) point-snap point))
|
deltav (-> (gpt/to-vec initial point)
|
||||||
(gpt/transform (gmt/rotate-matrix (- rotation)))
|
|
||||||
(gpt/multiply handler-mult))
|
(gpt/multiply handler-mult))
|
||||||
|
|
||||||
;; Resize vector
|
;; Resize vector
|
||||||
|
@ -317,24 +321,23 @@
|
||||||
scalev)
|
scalev)
|
||||||
|
|
||||||
;; Resize origin point given the selected handler
|
;; Resize origin point given the selected handler
|
||||||
origin (handler-resize-origin (:selrect shape) handler)
|
handler-origin (handler-resize-origin (:selrect shape) handler)
|
||||||
|
|
||||||
shape-center (gsh/center-shape shape)
|
|
||||||
shape-transform (:transform shape (gmt/matrix))
|
|
||||||
shape-transform-inverse (:transform-inverse shape (gmt/matrix))
|
|
||||||
|
|
||||||
;; If we want resize from center, displace the shape
|
;; If we want resize from center, displace the shape
|
||||||
;; so it is still centered after resize.
|
;; so it is still centered after resize.
|
||||||
displacement (when center?
|
displacement
|
||||||
|
(when center?
|
||||||
(-> shape-center
|
(-> shape-center
|
||||||
(gpt/subtract origin)
|
(gpt/subtract handler-origin)
|
||||||
(gpt/multiply scalev)
|
(gpt/multiply scalev)
|
||||||
(gpt/add origin)
|
(gpt/add handler-origin)
|
||||||
(gpt/subtract shape-center)
|
(gpt/subtract shape-center)
|
||||||
(gpt/multiply (gpt/point -1 -1))
|
(gpt/multiply (gpt/point -1 -1))
|
||||||
(gpt/transform shape-transform)))
|
(gpt/transform shape-transform)))
|
||||||
|
|
||||||
origin (cond-> (gsh/transform-point-center origin shape-center shape-transform)
|
resize-origin
|
||||||
|
(cond-> (gsh/transform-point-center handler-origin shape-center shape-transform)
|
||||||
(some? displacement)
|
(some? displacement)
|
||||||
(gpt/add displacement))
|
(gpt/add displacement))
|
||||||
|
|
||||||
|
@ -344,7 +347,7 @@
|
||||||
(rx/of (set-modifiers ids
|
(rx/of (set-modifiers ids
|
||||||
{:displacement displacement
|
{:displacement displacement
|
||||||
:resize-vector scalev
|
:resize-vector scalev
|
||||||
:resize-origin origin
|
:resize-origin resize-origin
|
||||||
:resize-transform shape-transform
|
:resize-transform shape-transform
|
||||||
:resize-scale-text scale-text
|
:resize-scale-text scale-text
|
||||||
:resize-transform-inverse shape-transform-inverse}))))
|
:resize-transform-inverse shape-transform-inverse}))))
|
||||||
|
|
|
@ -25,22 +25,24 @@
|
||||||
[cuerdas.core :as str]
|
[cuerdas.core :as str]
|
||||||
[rumext.alpha :as mf]))
|
[rumext.alpha :as mf]))
|
||||||
|
|
||||||
(defn bounds
|
(defn calc-bounds
|
||||||
[object objects]
|
[object objects]
|
||||||
(if (= :group (:type object))
|
|
||||||
(let [children-bounds
|
|
||||||
(into []
|
|
||||||
(comp (map #(get objects %))
|
|
||||||
(map #(bounds % objects)))
|
|
||||||
(:shapes object))]
|
|
||||||
(gsh/join-rects children-bounds))
|
|
||||||
|
|
||||||
(let [padding (filters/calculate-padding object)]
|
(let [xf-get-bounds (comp (map #(get objects %)) (map #(calc-bounds % objects)))
|
||||||
|
padding (filters/calculate-padding object)
|
||||||
|
obj-bounds
|
||||||
(-> (filters/get-filters-bounds object)
|
(-> (filters/get-filters-bounds object)
|
||||||
(update :x - padding)
|
(update :x - padding)
|
||||||
(update :y - padding)
|
(update :y - padding)
|
||||||
(update :width + (* 2 padding))
|
(update :width + (* 2 padding))
|
||||||
(update :height + (* 2 padding))))))
|
(update :height + (* 2 padding)))]
|
||||||
|
|
||||||
|
(if (= :group (:type object))
|
||||||
|
(->> (:shapes object)
|
||||||
|
(into [obj-bounds] xf-get-bounds)
|
||||||
|
(gsh/join-rects))
|
||||||
|
|
||||||
|
obj-bounds)))
|
||||||
|
|
||||||
(mf/defc object-svg
|
(mf/defc object-svg
|
||||||
{::mf/wrap [mf/memo]}
|
{::mf/wrap [mf/memo]}
|
||||||
|
@ -64,7 +66,7 @@
|
||||||
objects (reduce updt-fn objects mod-ids)
|
objects (reduce updt-fn objects mod-ids)
|
||||||
object (get objects object-id)
|
object (get objects object-id)
|
||||||
|
|
||||||
{:keys [x y width height] :as bs} (bounds object objects)
|
{:keys [x y width height] :as bs} (calc-bounds object objects)
|
||||||
[_ _ width height :as coords] (->> [x y width height] (map #(* % zoom)))
|
[_ _ width height :as coords] (->> [x y width height] (map #(* % zoom)))
|
||||||
|
|
||||||
vbox (str/join " " coords)
|
vbox (str/join " " coords)
|
||||||
|
|
|
@ -14,12 +14,14 @@
|
||||||
[rumext.alpha :as mf]))
|
[rumext.alpha :as mf]))
|
||||||
|
|
||||||
(defn- stroke-type->dasharray
|
(defn- stroke-type->dasharray
|
||||||
[style]
|
[width style]
|
||||||
(case style
|
(let [values (case style
|
||||||
:mixed "5,5,1,5"
|
:mixed [5 5 1 5]
|
||||||
:dotted "5,5"
|
:dotted [5 5]
|
||||||
:dashed "10,10"
|
:dashed [10 10]
|
||||||
nil))
|
nil)]
|
||||||
|
|
||||||
|
(->> values (map #(+ % width)) (str/join ","))))
|
||||||
|
|
||||||
(defn- truncate-side
|
(defn- truncate-side
|
||||||
[shape ra-attr rb-attr dimension-attr]
|
[shape ra-attr rb-attr dimension-attr]
|
||||||
|
@ -102,10 +104,11 @@
|
||||||
|
|
||||||
(defn add-stroke [attrs shape render-id]
|
(defn add-stroke [attrs shape render-id]
|
||||||
(let [stroke-style (:stroke-style shape :none)
|
(let [stroke-style (:stroke-style shape :none)
|
||||||
stroke-color-gradient-id (str "stroke-color-gradient_" render-id)]
|
stroke-color-gradient-id (str "stroke-color-gradient_" render-id)
|
||||||
|
stroke-width (:stroke-width shape 1)]
|
||||||
(if (not= stroke-style :none)
|
(if (not= stroke-style :none)
|
||||||
(let [stroke-attrs
|
(let [stroke-attrs
|
||||||
(cond-> {:strokeWidth (:stroke-width shape 1)}
|
(cond-> {:strokeWidth stroke-width}
|
||||||
(:stroke-color-gradient shape)
|
(:stroke-color-gradient shape)
|
||||||
(assoc :stroke (str/format "url(#%s)" stroke-color-gradient-id))
|
(assoc :stroke (str/format "url(#%s)" stroke-color-gradient-id))
|
||||||
|
|
||||||
|
@ -118,7 +121,7 @@
|
||||||
(assoc :strokeOpacity (:stroke-opacity shape nil))
|
(assoc :strokeOpacity (:stroke-opacity shape nil))
|
||||||
|
|
||||||
(not= stroke-style :svg)
|
(not= stroke-style :svg)
|
||||||
(assoc :strokeDasharray (stroke-type->dasharray stroke-style))
|
(assoc :strokeDasharray (stroke-type->dasharray stroke-width stroke-style))
|
||||||
|
|
||||||
;; For simple line caps we use svg stroke-line-cap attribute. This
|
;; For simple line caps we use svg stroke-line-cap attribute. This
|
||||||
;; only works if all caps are the same and we are not using the tricks
|
;; only works if all caps are the same and we are not using the tricks
|
||||||
|
|
|
@ -7,6 +7,7 @@
|
||||||
(ns app.main.ui.shapes.custom-stroke
|
(ns app.main.ui.shapes.custom-stroke
|
||||||
(:require
|
(:require
|
||||||
[app.common.data :as d]
|
[app.common.data :as d]
|
||||||
|
[app.common.geom.shapes :as gsh]
|
||||||
[app.main.ui.context :as muc]
|
[app.main.ui.context :as muc]
|
||||||
[app.util.object :as obj]
|
[app.util.object :as obj]
|
||||||
[cuerdas.core :as str]
|
[cuerdas.core :as str]
|
||||||
|
@ -145,6 +146,8 @@
|
||||||
|
|
||||||
(mf/defc stroke-defs
|
(mf/defc stroke-defs
|
||||||
[{:keys [shape render-id]}]
|
[{:keys [shape render-id]}]
|
||||||
|
(when (and (= (:type shape) :path)
|
||||||
|
(gsh/open-path? shape))
|
||||||
(cond
|
(cond
|
||||||
(and (= :inner (:stroke-alignment shape :center))
|
(and (= :inner (:stroke-alignment shape :center))
|
||||||
(> (:stroke-width shape 0) 0))
|
(> (:stroke-width shape 0) 0))
|
||||||
|
@ -160,7 +163,7 @@
|
||||||
(some? (:stroke-cap-end shape)))
|
(some? (:stroke-cap-end shape)))
|
||||||
(= (:stroke-alignment shape) :center))
|
(= (:stroke-alignment shape) :center))
|
||||||
[:& cap-markers {:shape shape
|
[:& cap-markers {:shape shape
|
||||||
:render-id render-id}]))
|
:render-id render-id}])))
|
||||||
|
|
||||||
;; Outer alingmnent: display the shape in two layers. One
|
;; Outer alingmnent: display the shape in two layers. One
|
||||||
;; without stroke (only fill), and another one only with stroke
|
;; without stroke (only fill), and another one only with stroke
|
||||||
|
@ -253,15 +256,17 @@
|
||||||
stroke-position (:stroke-alignment shape :center)
|
stroke-position (:stroke-alignment shape :center)
|
||||||
has-stroke? (and (> stroke-width 0)
|
has-stroke? (and (> stroke-width 0)
|
||||||
(not= stroke-style :none))
|
(not= stroke-style :none))
|
||||||
|
closed? (or (not= :path (:type shape))
|
||||||
|
(not (gsh/open-path? shape)))
|
||||||
inner? (= :inner stroke-position)
|
inner? (= :inner stroke-position)
|
||||||
outer? (= :outer stroke-position)]
|
outer? (= :outer stroke-position)]
|
||||||
|
|
||||||
(cond
|
(cond
|
||||||
(and has-stroke? inner?)
|
(and has-stroke? inner? closed?)
|
||||||
[:& inner-stroke {:shape shape}
|
[:& inner-stroke {:shape shape}
|
||||||
child]
|
child]
|
||||||
|
|
||||||
(and has-stroke? outer?)
|
(and has-stroke? outer? closed?)
|
||||||
[:& outer-stroke {:shape shape}
|
[:& outer-stroke {:shape shape}
|
||||||
child]
|
child]
|
||||||
|
|
||||||
|
|
|
@ -27,13 +27,23 @@
|
||||||
[(first childs) (rest childs)]
|
[(first childs) (rest childs)]
|
||||||
[nil childs])
|
[nil childs])
|
||||||
|
|
||||||
|
;; We need to separate mask and clip into two because a bug in Firefox
|
||||||
|
;; breaks when the group has clip+mask+foreignObject
|
||||||
|
;; Clip and mask separated will work in every platform
|
||||||
|
; Firefox bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1734805
|
||||||
|
[clip-wrapper clip-props]
|
||||||
|
(if masked-group?
|
||||||
|
["g" (-> (obj/new)
|
||||||
|
(obj/set! "clipPath" (clip-url render-id mask)))]
|
||||||
|
[mf/Fragment nil])
|
||||||
|
|
||||||
[mask-wrapper mask-props]
|
[mask-wrapper mask-props]
|
||||||
(if masked-group?
|
(if masked-group?
|
||||||
["g" (-> (obj/new)
|
["g" (-> (obj/new)
|
||||||
(obj/set! "clipPath" (clip-url render-id mask))
|
|
||||||
(obj/set! "mask" (mask-url render-id mask)))]
|
(obj/set! "mask" (mask-url render-id mask)))]
|
||||||
[mf/Fragment nil])]
|
[mf/Fragment nil])]
|
||||||
|
|
||||||
|
[:> clip-wrapper clip-props
|
||||||
[:> mask-wrapper mask-props
|
[:> mask-wrapper mask-props
|
||||||
(when masked-group?
|
(when masked-group?
|
||||||
[:> render-mask #js {:frame frame :mask mask}])
|
[:> render-mask #js {:frame frame :mask mask}])
|
||||||
|
@ -41,7 +51,7 @@
|
||||||
(for [item childs]
|
(for [item childs]
|
||||||
[:& shape-wrapper {:frame frame
|
[:& shape-wrapper {:frame frame
|
||||||
:shape item
|
:shape item
|
||||||
:key (:id item)}])]))))
|
:key (:id item)}])]]))))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -363,12 +363,14 @@
|
||||||
delta-y (-> (.-deltaY ^js event)
|
delta-y (-> (.-deltaY ^js event)
|
||||||
(* unit)
|
(* unit)
|
||||||
(/ zoom))
|
(/ zoom))
|
||||||
|
|
||||||
delta-x (-> (.-deltaX ^js event)
|
delta-x (-> (.-deltaX ^js event)
|
||||||
(* unit)
|
(* unit)
|
||||||
(/ zoom))]
|
(/ zoom))]
|
||||||
(dom/prevent-default event)
|
(dom/prevent-default event)
|
||||||
(dom/stop-propagation event)
|
(dom/stop-propagation event)
|
||||||
(if (kbd/shift? event)
|
(if (and (not (cfg/check-platform? :macos)) ;; macos sends delta-x automaticaly, don't need to do it
|
||||||
|
(kbd/shift? event))
|
||||||
(st/emit! (dw/update-viewport-position {:x #(+ % delta-y)}))
|
(st/emit! (dw/update-viewport-position {:x #(+ % delta-y)}))
|
||||||
(st/emit! (dw/update-viewport-position {:x #(+ % delta-x)
|
(st/emit! (dw/update-viewport-position {:x #(+ % delta-x)
|
||||||
:y #(+ % delta-y)})))))))))
|
:y #(+ % delta-y)})))))))))
|
||||||
|
|
|
@ -229,7 +229,12 @@
|
||||||
current-transform (mf/deref refs/current-transform)
|
current-transform (mf/deref refs/current-transform)
|
||||||
|
|
||||||
selrect (:selrect shape)
|
selrect (:selrect shape)
|
||||||
transform (geom/transform-matrix shape {:no-flip true})]
|
transform (geom/transform-matrix shape {:no-flip true})
|
||||||
|
|
||||||
|
rotation (-> (gpt/point 1 0)
|
||||||
|
(gpt/transform (:transform shape))
|
||||||
|
(gpt/angle)
|
||||||
|
(mod 360))]
|
||||||
|
|
||||||
(when (not (#{:move :rotate} current-transform))
|
(when (not (#{:move :rotate} current-transform))
|
||||||
[:g.controls {:pointer-events (if disable-handlers "none" "visible")}
|
[:g.controls {:pointer-events (if disable-handlers "none" "visible")}
|
||||||
|
@ -249,7 +254,7 @@
|
||||||
:on-rotate on-rotate
|
:on-rotate on-rotate
|
||||||
:on-resize (partial on-resize position)
|
:on-resize (partial on-resize position)
|
||||||
:transform transform
|
:transform transform
|
||||||
:rotation (:rotation shape)
|
:rotation rotation
|
||||||
:color color
|
:color color
|
||||||
:overflow-text overflow-text}
|
:overflow-text overflow-text}
|
||||||
props (map->obj (merge common-props props))]
|
props (map->obj (merge common-props props))]
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue