mirror of
https://github.com/penpot/penpot.git
synced 2025-03-15 17:21:17 -05:00
✨ Allows rotation for shapes
This commit is contained in:
parent
5636881463
commit
84007e6ad1
10 changed files with 105 additions and 49 deletions
|
@ -293,7 +293,9 @@
|
|||
"Function that checks if a number is nil or nan. Will return 0 when not
|
||||
valid and the number otherwise."
|
||||
[v]
|
||||
(if (or (not v) (mth/nan? v)) 0 v))
|
||||
(if (or (not v)
|
||||
(not (mth/finite? v))
|
||||
(mth/nan? v)) 0 v))
|
||||
|
||||
|
||||
(defmacro export
|
||||
|
|
|
@ -48,7 +48,7 @@
|
|||
(us/assert #{:width :height} attr)
|
||||
(us/assert number? value)
|
||||
(let [{:keys [proportion proportion-lock]} shape
|
||||
size (select-keys shape [:width :height])
|
||||
size (select-keys (:selrect shape) [:width :height])
|
||||
new-size (if-not proportion-lock
|
||||
(assoc size attr value)
|
||||
(if (= attr :width)
|
||||
|
@ -260,6 +260,7 @@
|
|||
(d/export gco/center-shape)
|
||||
(d/export gco/center-selrect)
|
||||
(d/export gco/center-rect)
|
||||
(d/export gco/center-points)
|
||||
(d/export gpr/rect->selrect)
|
||||
(d/export gpr/rect->points)
|
||||
(d/export gpr/points->selrect)
|
||||
|
@ -268,7 +269,9 @@
|
|||
(d/export gtr/transform-point-center)
|
||||
(d/export gtr/transform-rect)
|
||||
(d/export gtr/update-group-selrect)
|
||||
(d/export gtr/transform-points)
|
||||
|
||||
;; PATHS
|
||||
(d/export gsp/content->points)
|
||||
(d/export gsp/content->selrect)
|
||||
(d/export gsp/transform-content)
|
||||
|
|
|
@ -14,7 +14,13 @@
|
|||
[app.common.geom.shapes.common :as gco]
|
||||
[app.common.geom.shapes.path :as gpa]
|
||||
[app.common.geom.shapes.rect :as gpr]
|
||||
[app.common.math :as mth]))
|
||||
[app.common.math :as mth]
|
||||
[app.common.data :as d]))
|
||||
|
||||
(defn- modif-rotation [shape]
|
||||
(let [cur-rotation (d/check-num (:rotation shape))
|
||||
delta-angle (d/check-num (get-in shape [:modifiers :rotation]))]
|
||||
(mod (+ cur-rotation delta-angle) 360)))
|
||||
|
||||
(defn transform-matrix
|
||||
"Returns a transformation matrix without changing the shape properties.
|
||||
|
@ -191,18 +197,23 @@
|
|||
(defn apply-transform-path
|
||||
[shape transform]
|
||||
(let [content (gpa/transform-content (:content shape) transform)
|
||||
selrect (gpa/content->selrect content)
|
||||
points (gpr/rect->points selrect)
|
||||
;;rotation (mod (+ (:rotation shape 0)
|
||||
;; (or (get-in shape [:modifiers :rotation]) 0))
|
||||
;; 360)
|
||||
]
|
||||
|
||||
;; Calculate the new selrect by "unrotate" the shape
|
||||
rotation (modif-rotation shape)
|
||||
center (gpt/transform (gco/center-shape shape) transform)
|
||||
content-rotated (gpa/transform-content content (gmt/rotate-matrix (- rotation) center))
|
||||
selrect (gpa/content->selrect content-rotated)
|
||||
|
||||
;; Transform the points
|
||||
points (-> (:points shape)
|
||||
(transform-points transform))]
|
||||
(assoc shape
|
||||
:content content
|
||||
:points points
|
||||
:selrect selrect
|
||||
;;:rotation rotation
|
||||
)))
|
||||
:transform (gmt/rotate-matrix rotation)
|
||||
:transform-inverse (gmt/rotate-matrix (- rotation))
|
||||
:rotation rotation)))
|
||||
|
||||
(defn apply-transform-rect
|
||||
"Given a new set of points transformed, set up the rectangle so it keeps
|
||||
|
|
|
@ -1038,9 +1038,12 @@
|
|||
(let [page-id (:current-page-id state)
|
||||
objects (dwc/lookup-page-objects state page-id)
|
||||
shape (get objects id)
|
||||
cpos (gpt/point (:x shape) (:y shape))
|
||||
pos (gpt/point (or (:x position) (:x shape))
|
||||
(or (:y position) (:y shape)))
|
||||
|
||||
bbox (-> shape :points gsh/points->selrect)
|
||||
|
||||
cpos (gpt/point (:x bbox) (:y bbox))
|
||||
pos (gpt/point (or (:x position) (:x bbox))
|
||||
(or (:y position) (:y bbox)))
|
||||
displ (gmt/translate-matrix (gpt/subtract pos cpos))]
|
||||
(rx/of (dwt/set-modifiers [id] {:displacement displ})
|
||||
(dwt/apply-modifiers [id]))))))
|
||||
|
@ -1544,6 +1547,7 @@
|
|||
(d/export dwt/start-move-selected)
|
||||
(d/export dwt/move-selected)
|
||||
(d/export dwt/set-rotation)
|
||||
(d/export dwt/increase-rotation)
|
||||
(d/export dwt/set-modifiers)
|
||||
(d/export dwt/apply-modifiers)
|
||||
(d/export dwt/update-dimensions)
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
[app.common.math :as mth]
|
||||
[app.common.geom.point :as gpt]
|
||||
[app.common.geom.shapes :as gsh]
|
||||
[app.common.geom.matrix :as gmt]
|
||||
[app.util.data :as ud]
|
||||
[app.common.data :as cd]
|
||||
[app.util.geom.path :as ugp]
|
||||
|
@ -87,12 +88,37 @@
|
|||
[:workspace-drawing :object])
|
||||
path)))
|
||||
|
||||
(defn- points->components [shape content]
|
||||
(let [rotation (:rotation shape 0)
|
||||
center (gsh/center-shape shape)
|
||||
content-rotated (gsh/transform-content content (gmt/rotate-matrix (- rotation) center))
|
||||
|
||||
;; Calculates the new selrect with points given the old center
|
||||
points (-> (gsh/content->selrect content-rotated)
|
||||
(gsh/rect->points)
|
||||
(gsh/transform-points center (:transform shape (gmt/matrix))))
|
||||
|
||||
points-center (gsh/center-points points)
|
||||
|
||||
;; Points is now the selrect but the center is different so we can create the selrect
|
||||
;; through points
|
||||
selrect (-> points
|
||||
(gsh/transform-points points-center (:transform-inverse shape (gmt/matrix)))
|
||||
(gsh/points->selrect))]
|
||||
[points selrect]))
|
||||
|
||||
(defn update-selrect
|
||||
"Updates the selrect and points for a path"
|
||||
[shape]
|
||||
(let [selrect (gsh/content->selrect (:content shape))
|
||||
points (gsh/rect->points selrect)]
|
||||
(assoc shape :points points :selrect selrect)))
|
||||
(if (= (:rotation shape 0) 0)
|
||||
(let [content (:content shape)
|
||||
selrect (gsh/content->selrect content)
|
||||
points (gsh/rect->points selrect)]
|
||||
(assoc shape :points points :selrect selrect))
|
||||
|
||||
(let [content (:content shape)
|
||||
[points selrect] (points->components shape content)]
|
||||
(assoc shape :points points :selrect selrect))))
|
||||
|
||||
(defn closest-angle [angle]
|
||||
(cond
|
||||
|
@ -157,13 +183,12 @@
|
|||
;; TODO: Enter now finish path but can finish drawing/editing as well
|
||||
(= enter-keycode (:key event)))))
|
||||
|
||||
(defn generate-path-changes [page-id shape-id old-content new-content]
|
||||
(defn generate-path-changes [page-id shape old-content new-content]
|
||||
(us/verify ::content old-content)
|
||||
(us/verify ::content new-content)
|
||||
(let [old-selrect (gsh/content->selrect old-content)
|
||||
old-points (gsh/rect->points old-selrect)
|
||||
new-selrect (gsh/content->selrect new-content)
|
||||
new-points (gsh/rect->points new-selrect)
|
||||
(let [shape-id (:id shape)
|
||||
[old-points old-selrect] (points->components shape old-content)
|
||||
[new-points new-selrect] (points->components shape new-content)
|
||||
|
||||
rch [{:type :mod-obj
|
||||
:id shape-id
|
||||
|
@ -393,7 +418,7 @@
|
|||
shape (get-in state (get-path state))
|
||||
selected-points (get-in state [:workspace-local :edit-path id :selected-points] #{})
|
||||
new-content (reduce ugp/make-corner-point (:content shape) selected-points)
|
||||
[rch uch] (generate-path-changes page-id id (:content shape) new-content)]
|
||||
[rch uch] (generate-path-changes page-id shape (:content shape) new-content)]
|
||||
(rx/of (dwc/commit-changes rch uch {:commit-local? true}))))))
|
||||
|
||||
(defn make-curve []
|
||||
|
@ -405,7 +430,7 @@
|
|||
shape (get-in state (get-path state))
|
||||
selected-points (get-in state [:workspace-local :edit-path id :selected-points] #{})
|
||||
new-content (reduce ugp/make-curve-point (:content shape) selected-points)
|
||||
[rch uch] (generate-path-changes page-id id (:content shape) new-content)]
|
||||
[rch uch] (generate-path-changes page-id shape (:content shape) new-content)]
|
||||
(rx/of (dwc/commit-changes rch uch {:commit-local? true}))))))
|
||||
|
||||
(defn path-handler-enter [index prefix]
|
||||
|
@ -552,7 +577,7 @@
|
|||
shape (get-in state (get-path state))
|
||||
content-modifiers (get-in state [:workspace-local :edit-path id :content-modifiers])
|
||||
new-content (ugp/apply-content-modifiers (:content shape) content-modifiers)
|
||||
[rch uch] (generate-path-changes page-id (:id shape) (:content shape) new-content)]
|
||||
[rch uch] (generate-path-changes page-id shape (:content shape) new-content)]
|
||||
|
||||
(rx/of (dwc/commit-changes rch uch {:commit-local? true})
|
||||
(fn [state] (update-in state [:workspace-local :edit-path id] dissoc :content-modifiers)))))))
|
||||
|
@ -573,7 +598,7 @@
|
|||
shape (get-in state (get-path state))
|
||||
page-id (:current-page-id state)
|
||||
old-content (get-in state [:workspace-local :edit-path id :old-content])
|
||||
[rch uch] (generate-path-changes page-id id old-content (:content shape))]
|
||||
[rch uch] (generate-path-changes page-id shape old-content (:content shape))]
|
||||
(rx/of (dwc/commit-changes rch uch {:commit-local? true}))))))
|
||||
|
||||
(declare start-draw-mode)
|
||||
|
|
|
@ -431,6 +431,20 @@
|
|||
(let [page-id (:current-page-id state)]
|
||||
(d/update-in-when state [:workspace-data :pages-index page-id :objects] set-rotation)))))))
|
||||
|
||||
(defn increase-rotation [ids rotation]
|
||||
(ptk/reify ::increase-rotation
|
||||
ptk/WatchEvent
|
||||
(watch [_ state stream]
|
||||
|
||||
(let [page-id (:current-page-id state)
|
||||
objects (dwc/lookup-page-objects state page-id)
|
||||
rotate-shape (fn [shape]
|
||||
(let [delta (- rotation (:rotation shape))]
|
||||
(set-rotation delta [shape])))]
|
||||
(rx/concat
|
||||
(rx/from (->> ids (map #(get objects %)) (map rotate-shape)))
|
||||
(rx/of (apply-modifiers ids)))))))
|
||||
|
||||
(defn apply-modifiers
|
||||
[ids]
|
||||
(us/verify (s/coll-of uuid?) ids)
|
||||
|
|
|
@ -13,7 +13,6 @@
|
|||
[rumext.alpha :as mf]
|
||||
[app.main.ui.shapes.attrs :as attrs]
|
||||
[app.main.ui.shapes.custom-stroke :refer [shape-custom-stroke]]
|
||||
[app.common.geom.shapes :as geom]
|
||||
[app.util.object :as obj]
|
||||
[app.util.geom.path :as ugp]))
|
||||
|
||||
|
@ -24,14 +23,11 @@
|
|||
[props]
|
||||
(let [shape (unchecked-get props "shape")
|
||||
background? (unchecked-get props "background?")
|
||||
;; {:keys [id x y width height]} (geom/shape->rect-shape shape)
|
||||
{:keys [id x y width height]} (:selrect shape)
|
||||
transform (geom/transform-matrix shape)
|
||||
pdata (ugp/content->path (:content shape))
|
||||
props (-> (attrs/extract-style-attrs shape)
|
||||
(obj/merge!
|
||||
#js {:transform transform
|
||||
:d pdata}))]
|
||||
#js {:d pdata}))]
|
||||
(if background?
|
||||
[:g
|
||||
[:path {:stroke "transparent"
|
||||
|
|
|
@ -44,16 +44,17 @@
|
|||
(def selection-rect-width 1)
|
||||
|
||||
(mf/defc selection-rect [{:keys [transform rect zoom color]}]
|
||||
(let [{:keys [x y width height]} rect]
|
||||
[:rect.main
|
||||
{:x x
|
||||
:y y
|
||||
:width width
|
||||
:height height
|
||||
:transform transform
|
||||
:style {:stroke color
|
||||
:stroke-width (/ selection-rect-width zoom)
|
||||
:fill "transparent"}}]))
|
||||
(when rect
|
||||
(let [{:keys [x y width height]} rect]
|
||||
[:rect.main
|
||||
{:x x
|
||||
:y y
|
||||
:width width
|
||||
:height height
|
||||
:transform transform
|
||||
:style {:stroke color
|
||||
:stroke-width (/ selection-rect-width zoom)
|
||||
:fill "transparent"}}])))
|
||||
|
||||
(defn- handlers-for-selection [{:keys [x y width height]}]
|
||||
[;; TOP-LEFT
|
||||
|
@ -181,9 +182,7 @@
|
|||
current-transform (mf/deref refs/current-transform)
|
||||
|
||||
selrect (:selrect shape)
|
||||
transform (geom/transform-matrix shape {:no-flip true})
|
||||
|
||||
tr-shape (geom/transform-shape shape)]
|
||||
transform (geom/transform-matrix shape {:no-flip true})]
|
||||
|
||||
(when (not (#{:move :rotate} current-transform))
|
||||
[:g.controls
|
||||
|
@ -193,7 +192,7 @@
|
|||
:transform transform
|
||||
:zoom zoom
|
||||
:color color}]
|
||||
[:& outline {:shape tr-shape :color color}]
|
||||
[:& outline {:shape shape :color color}]
|
||||
|
||||
;; Handlers
|
||||
(for [{:keys [type position props]} (handlers-for-selection selrect)]
|
||||
|
|
|
@ -35,11 +35,12 @@
|
|||
:stroke-width "1px"
|
||||
:stroke-opacity 0.5}]]))
|
||||
|
||||
(mf/defc render-rect [{{:keys [x y width height]} :rect :keys [color]}]
|
||||
(mf/defc render-rect [{{:keys [x y width height]} :rect :keys [color transform]}]
|
||||
[:rect {:x x
|
||||
:y y
|
||||
:width width
|
||||
:height height
|
||||
:transform (or transform "none")
|
||||
:style {:stroke color
|
||||
:fill "transparent"
|
||||
:stroke-width "1px"
|
||||
|
@ -76,7 +77,7 @@
|
|||
:fill line-color
|
||||
:stroke "white"
|
||||
:stroke-width 0.1}
|
||||
(str/format "%s - (%s, %s)" (str/slice (str (:id shape)) 0 8) (fixed (:x shape)) (fixed (:y shape)))]
|
||||
(str/format "%s - (%s, %s)" (str/slice (str (:id shape)) 0 8) (fixed (:x selrect)) (fixed (:y selrect)))]
|
||||
|
||||
[:& cross-point {:point shape-center
|
||||
:zoom zoom
|
||||
|
@ -87,7 +88,7 @@
|
|||
:zoom zoom
|
||||
:color line-color}])
|
||||
|
||||
[:& render-rect-points {:rect selrect
|
||||
[:& render-rect-points {:points (:points shape)
|
||||
:color line-color}]
|
||||
|
||||
[:& render-rect {:rect selrect
|
||||
|
|
|
@ -45,7 +45,8 @@
|
|||
:ry (/ height 2)}
|
||||
|
||||
:path
|
||||
{:d (ugp/content->path (:content shape))}
|
||||
{:d (ugp/content->path (:content shape))
|
||||
:transform nil}
|
||||
|
||||
{:x x
|
||||
:y y
|
||||
|
|
Loading…
Add table
Reference in a new issue