mirror of
https://github.com/penpot/penpot.git
synced 2025-05-24 21:46:12 +02:00
🚧 Start working on shape rotation (with mouse handlers).
This commit is contained in:
parent
747213dea3
commit
338a0b97ac
4 changed files with 89 additions and 36 deletions
|
@ -89,6 +89,7 @@
|
||||||
|
|
||||||
g.controls {
|
g.controls {
|
||||||
rect.main { pointer-events: none; }
|
rect.main { pointer-events: none; }
|
||||||
|
circle.rotate { cursor: ns-resize; } // TODO
|
||||||
circle.top-left { cursor: nwse-resize; }
|
circle.top-left { cursor: nwse-resize; }
|
||||||
circle.bottom-right { cursor: nwse-resize; }
|
circle.bottom-right { cursor: nwse-resize; }
|
||||||
circle.top-right { cursor: nesw-resize; }
|
circle.top-right { cursor: nesw-resize; }
|
||||||
|
|
|
@ -49,17 +49,21 @@
|
||||||
|
|
||||||
{:keys [x y width height]} shape
|
{:keys [x y width height]} shape
|
||||||
|
|
||||||
transform (when (pos? rotation)
|
;; transform (when (pos? rotation)
|
||||||
(str (rotate (gmt/matrix) shape)))
|
;; (str (rotate (gmt/matrix) shape)))
|
||||||
|
|
||||||
moving? (boolean modifier-mtx)
|
transform (str/format "rotate(%s %s %s)"
|
||||||
|
rotation
|
||||||
|
(+ x (/ width 2))
|
||||||
|
(+ y (/ height 2)))
|
||||||
|
|
||||||
props (-> (attrs/extract-style-attrs shape)
|
props (-> (attrs/extract-style-attrs shape)
|
||||||
(assoc :x x
|
(assoc :x x
|
||||||
:y y
|
:y y
|
||||||
|
;; :transform transform
|
||||||
:id (str "shape-" id)
|
:id (str "shape-" id)
|
||||||
:className (classnames :move-cursor moving?)
|
|
||||||
:width width
|
:width width
|
||||||
:height height
|
:height height
|
||||||
:transform transform))]
|
;; :transform transform
|
||||||
|
))]
|
||||||
[:& "rect" props]))
|
[:& "rect" props]))
|
||||||
|
|
|
@ -10,6 +10,7 @@
|
||||||
(:require
|
(:require
|
||||||
[beicon.core :as rx]
|
[beicon.core :as rx]
|
||||||
[lentes.core :as l]
|
[lentes.core :as l]
|
||||||
|
[cuerdas.core :as str]
|
||||||
[potok.core :as ptk]
|
[potok.core :as ptk]
|
||||||
[rumext.alpha :as mf]
|
[rumext.alpha :as mf]
|
||||||
[uxbox.main.data.workspace :as dw]
|
[uxbox.main.data.workspace :as dw]
|
||||||
|
@ -21,16 +22,6 @@
|
||||||
[uxbox.util.dom :as dom]
|
[uxbox.util.dom :as dom]
|
||||||
[uxbox.util.geom.point :as gpt]))
|
[uxbox.util.geom.point :as gpt]))
|
||||||
|
|
||||||
;; --- Refs & Constants
|
|
||||||
|
|
||||||
(def ^:private +circle-props+
|
|
||||||
{:r 6
|
|
||||||
:style {:fillOpacity "1"
|
|
||||||
:strokeWidth "2px"
|
|
||||||
:vectorEffect "non-scaling-stroke"}
|
|
||||||
:fill "rgba(49,239,184,.7)"
|
|
||||||
:stroke "#31EFB8"})
|
|
||||||
|
|
||||||
;; --- Resize Implementation
|
;; --- Resize Implementation
|
||||||
|
|
||||||
(defn- start-resize
|
(defn- start-resize
|
||||||
|
@ -75,6 +66,37 @@
|
||||||
(rx/of (dw/materialize-temporal-modifier-in-bulk ids)
|
(rx/of (dw/materialize-temporal-modifier-in-bulk ids)
|
||||||
::dw/page-data-update)))))))
|
::dw/page-data-update)))))))
|
||||||
|
|
||||||
|
(defn start-rotate
|
||||||
|
[shape]
|
||||||
|
(ptk/reify ::start-rotate
|
||||||
|
ptk/WatchEvent
|
||||||
|
(watch [_ state stream]
|
||||||
|
(let [shape (geom/shape->rect-shape shape)
|
||||||
|
stoper (rx/filter ms/mouse-up? stream)
|
||||||
|
center (gpt/point (+ (:x shape) (/ (:width shape) 2))
|
||||||
|
(+ (:y shape) (/ (:height shape) 2)))]
|
||||||
|
|
||||||
|
(rx/concat
|
||||||
|
(->> ms/mouse-position
|
||||||
|
;; (rx/map apply-zoom)
|
||||||
|
;; (rx/mapcat apply-grid-alignment)
|
||||||
|
(rx/with-latest vector ms/mouse-position-ctrl)
|
||||||
|
;; (rx/map normalize-proportion-lock)
|
||||||
|
;; (rx/mapcat (partial resize shape))
|
||||||
|
(rx/map (fn [[pos ctrl?]]
|
||||||
|
(let [angle (+ (gpt/angle pos center) 90)
|
||||||
|
angle (if (neg? angle)
|
||||||
|
(+ 360 angle)
|
||||||
|
angle)
|
||||||
|
modval (mod angle 90)
|
||||||
|
angle (if ctrl?
|
||||||
|
(if (< 50 modval)
|
||||||
|
(+ angle (- 90 modval))
|
||||||
|
(- angle modval))
|
||||||
|
angle)]
|
||||||
|
(dw/update-shape (:id shape) {:rotation angle}))))
|
||||||
|
(rx/take-until stoper)))))))
|
||||||
|
|
||||||
;; --- Controls (Component)
|
;; --- Controls (Component)
|
||||||
|
|
||||||
(def ^:private handler-size-threshold
|
(def ^:private handler-size-threshold
|
||||||
|
@ -98,52 +120,73 @@
|
||||||
:cy cy}])
|
:cy cy}])
|
||||||
|
|
||||||
(mf/defc controls
|
(mf/defc controls
|
||||||
[{:keys [shape zoom on-click] :as props}]
|
[{:keys [shape zoom on-resize on-rotate] :as props}]
|
||||||
(let [{:keys [x y width height]} shape
|
(let [{:keys [x y width height]} shape
|
||||||
radius (if (> (max width height) handler-size-threshold) 6.0 4.0)]
|
radius (if (> (max width height) handler-size-threshold) 6.0 4.0)
|
||||||
[:g.controls
|
|
||||||
|
transform (str/format "rotate(%s %s %s)"
|
||||||
|
(:rotation shape 0)
|
||||||
|
(+ (:x shape) (/ (:width shape) 2))
|
||||||
|
(+ (:y shape) (/ (:height shape) 2)))]
|
||||||
|
|
||||||
|
[:g.controls #_{:transform transform}
|
||||||
[:rect.main {:x x :y y
|
[:rect.main {:x x :y y
|
||||||
:width width
|
:width width
|
||||||
:height height
|
:height height
|
||||||
:stroke-dasharray (str (/ 8.0 zoom) "," (/ 5 zoom))
|
:stroke-dasharray (str (/ 8.0 zoom) "," (/ 5 zoom))
|
||||||
:style {:stroke "#31EFB8" :fill "transparent"
|
:style {:stroke "#31EFB8" :fill "transparent"
|
||||||
:stroke-opacity "1"}}]
|
:stroke-opacity "1"}}]
|
||||||
|
[:path {:stroke "#31EFB8"
|
||||||
|
:stroke-opacity "1"
|
||||||
|
:stroke-dasharray (str (/ 8.0 zoom) "," (/ 5 zoom))
|
||||||
|
:fill "transparent"
|
||||||
|
:d (str/format "M %s %s L %s %s"
|
||||||
|
(+ x (/ width 2))
|
||||||
|
y
|
||||||
|
(+ x (/ width 2))
|
||||||
|
(- y 30))}]
|
||||||
|
|
||||||
|
[:& control-item {:class "rotate"
|
||||||
|
:r (/ radius zoom)
|
||||||
|
:cx (+ x (/ width 2))
|
||||||
|
:on-click on-rotate
|
||||||
|
:cy (- y 30)}]
|
||||||
[:& control-item {:class "top"
|
[:& control-item {:class "top"
|
||||||
:on-click #(on-click :top %)
|
:on-click #(on-resize :top %)
|
||||||
:r (/ radius zoom)
|
:r (/ radius zoom)
|
||||||
:cx (+ x (/ width 2))
|
:cx (+ x (/ width 2))
|
||||||
:cy (- y 2)}]
|
:cy (- y 2)}]
|
||||||
[:& control-item {:on-click #(on-click :right %)
|
[:& control-item {:on-click #(on-resize :right %)
|
||||||
:r (/ radius zoom)
|
:r (/ radius zoom)
|
||||||
:cy (+ y (/ height 2))
|
:cy (+ y (/ height 2))
|
||||||
:cx (+ x width 1)
|
:cx (+ x width 1)
|
||||||
:class "right"}]
|
:class "right"}]
|
||||||
[:& control-item {:on-click #(on-click :bottom %)
|
[:& control-item {:on-click #(on-resize :bottom %)
|
||||||
:r (/ radius zoom)
|
:r (/ radius zoom)
|
||||||
:cx (+ x (/ width 2))
|
:cx (+ x (/ width 2))
|
||||||
:cy (+ y height 2)
|
:cy (+ y height 2)
|
||||||
:class "bottom"}]
|
:class "bottom"}]
|
||||||
[:& control-item {:on-click #(on-click :left %)
|
[:& control-item {:on-click #(on-resize :left %)
|
||||||
:r (/ radius zoom)
|
:r (/ radius zoom)
|
||||||
:cy (+ y (/ height 2))
|
:cy (+ y (/ height 2))
|
||||||
:cx (- x 3)
|
:cx (- x 3)
|
||||||
:class "left"}]
|
:class "left"}]
|
||||||
[:& control-item {:on-click #(on-click :top-left %)
|
[:& control-item {:on-click #(on-resize :top-left %)
|
||||||
:r (/ radius zoom)
|
:r (/ radius zoom)
|
||||||
:cx x
|
:cx x
|
||||||
:cy y
|
:cy y
|
||||||
:class "top-left"}]
|
:class "top-left"}]
|
||||||
[:& control-item {:on-click #(on-click :top-right %)
|
[:& control-item {:on-click #(on-resize :top-right %)
|
||||||
:r (/ radius zoom)
|
:r (/ radius zoom)
|
||||||
:cx (+ x width)
|
:cx (+ x width)
|
||||||
:cy y
|
:cy y
|
||||||
:class "top-right"}]
|
:class "top-right"}]
|
||||||
[:& control-item {:on-click #(on-click :bottom-left %)
|
[:& control-item {:on-click #(on-resize :bottom-left %)
|
||||||
:r (/ radius zoom)
|
:r (/ radius zoom)
|
||||||
:cx x
|
:cx x
|
||||||
:cy (+ y height)
|
:cy (+ y height)
|
||||||
:class "bottom-left"}]
|
:class "bottom-left"}]
|
||||||
[:& control-item {:on-click #(on-click :bottom-right %)
|
[:& control-item {:on-click #(on-resize :bottom-right %)
|
||||||
:r (/ radius zoom)
|
:r (/ radius zoom)
|
||||||
:cx (+ x width)
|
:cx (+ x width)
|
||||||
:cy (+ y height)
|
:cy (+ y height)
|
||||||
|
@ -195,11 +238,11 @@
|
||||||
(map #(geom/selection-rect %))
|
(map #(geom/selection-rect %))
|
||||||
(geom/shapes->rect-shape)
|
(geom/shapes->rect-shape)
|
||||||
(geom/selection-rect))
|
(geom/selection-rect))
|
||||||
on-click #(do (dom/stop-propagation %2)
|
on-resize #(do (dom/stop-propagation %2)
|
||||||
(st/emit! (start-resize %1 selected shape)))]
|
(st/emit! (start-resize %1 selected shape)))]
|
||||||
[:& controls {:shape shape
|
[:& controls {:shape shape
|
||||||
:zoom zoom
|
:zoom zoom
|
||||||
:on-click on-click}]))
|
:on-resize on-resize}]))
|
||||||
|
|
||||||
(mf/defc text-edition-selection-handlers
|
(mf/defc text-edition-selection-handlers
|
||||||
[{:keys [shape zoom] :as props}]
|
[{:keys [shape zoom] :as props}]
|
||||||
|
@ -216,10 +259,15 @@
|
||||||
|
|
||||||
(mf/defc single-selection-handlers
|
(mf/defc single-selection-handlers
|
||||||
[{:keys [shape zoom] :as props}]
|
[{:keys [shape zoom] :as props}]
|
||||||
(let [on-click #(do (dom/stop-propagation %2)
|
(let [on-resize #(do (dom/stop-propagation %2)
|
||||||
(st/emit! (start-resize %1 #{(:id shape)} shape)))
|
(st/emit! (start-resize %1 #{(:id shape)} shape)))
|
||||||
|
on-rotate #(do (dom/stop-propagation %)
|
||||||
|
#_(st/emit! (start-rotate shape)))
|
||||||
shape (geom/selection-rect shape)]
|
shape (geom/selection-rect shape)]
|
||||||
[:& controls {:shape shape :zoom zoom :on-click on-click}]))
|
[:& controls {:shape shape
|
||||||
|
:zoom zoom
|
||||||
|
:on-rotate on-rotate
|
||||||
|
:on-resize on-resize}]))
|
||||||
|
|
||||||
(mf/defc selection-handlers
|
(mf/defc selection-handlers
|
||||||
[{:keys [selected edition zoom] :as props}]
|
[{:keys [selected edition zoom] :as props}]
|
||||||
|
|
|
@ -116,7 +116,7 @@
|
||||||
If the second vector is not provided, the angle
|
If the second vector is not provided, the angle
|
||||||
will be measured from x-axis."
|
will be measured from x-axis."
|
||||||
([p]
|
([p]
|
||||||
{:pre [(point? p)]}
|
|
||||||
(-> (mth/atan2 (:y p) (:x p))
|
(-> (mth/atan2 (:y p) (:x p))
|
||||||
(mth/degrees)))
|
(mth/degrees)))
|
||||||
([p center]
|
([p center]
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue