mirror of
https://github.com/penpot/penpot.git
synced 2025-06-13 09:51:39 +02:00
♻️ Adds new properties to shapes
This commit is contained in:
parent
b5a6d9981d
commit
e06d8e754f
20 changed files with 288 additions and 136 deletions
|
@ -9,6 +9,7 @@
|
|||
|
||||
(ns uxbox.main.data.workspace
|
||||
(:require
|
||||
[uxbox.util.debug :refer [logjs]]
|
||||
[beicon.core :as rx]
|
||||
[cljs.spec.alpha :as s]
|
||||
[clojure.set :as set]
|
||||
|
@ -16,6 +17,7 @@
|
|||
[uxbox.common.data :as d]
|
||||
[uxbox.common.exceptions :as ex]
|
||||
[uxbox.common.pages :as cp]
|
||||
[uxbox.common.migrations :as mg]
|
||||
[uxbox.common.spec :as us]
|
||||
[uxbox.common.uuid :as uuid]
|
||||
[uxbox.config :as cfg]
|
||||
|
@ -149,6 +151,7 @@
|
|||
ptk/UpdateEvent
|
||||
(update [_ state]
|
||||
(let [page (get-in state [:workspace-pages page-id])
|
||||
page (mg/migrate-page page)
|
||||
local (get-in state [:workspace-cache page-id] workspace-default)]
|
||||
(-> state
|
||||
(assoc :current-page-id page-id ; mainly used by events
|
||||
|
|
|
@ -165,9 +165,8 @@
|
|||
|
||||
(defn- calculate-frame-overlap
|
||||
[frames shape]
|
||||
(let [shape (geom/shape->rect-shape shape)
|
||||
xf (comp
|
||||
(filter #(geom/overlaps? % shape))
|
||||
(let [xf (comp
|
||||
(filter #(geom/overlaps? % (:selrect shape)))
|
||||
(take 1))
|
||||
frame (first (into [] xf frames))]
|
||||
(or (:id frame) uuid/zero)))
|
||||
|
|
|
@ -210,7 +210,8 @@
|
|||
params {:name name
|
||||
:file-id file-id
|
||||
:ordering ordering
|
||||
:data cp/default-page-data}]
|
||||
:data cp/default-page-data
|
||||
:version cp/page-version}]
|
||||
(->> (rp/mutation :create-page params)
|
||||
(rx/map page-created))))))
|
||||
|
||||
|
|
|
@ -80,6 +80,8 @@
|
|||
(let [{:keys [width height rotation]} shape
|
||||
shapev (-> (gpt/point width height))
|
||||
|
||||
rotation (if (#{:curve :path} (:type shape)) 0 rotation)
|
||||
|
||||
;; Vector modifiers depending on the handler
|
||||
handler-modif (let [[x y] (handler-modifiers handler)] (gpt/point x y))
|
||||
|
||||
|
@ -129,7 +131,7 @@
|
|||
|
||||
ptk/WatchEvent
|
||||
(watch [_ state stream]
|
||||
(let [shape (gsh/shape->rect-shape shape)
|
||||
(let [;;shape (gsh/shape->rect-shape shape)
|
||||
initial @ms/mouse-position
|
||||
stoper (rx/filter ms/mouse-up? stream)
|
||||
page-id (get state :current-page-id)
|
||||
|
|
|
@ -44,8 +44,7 @@
|
|||
{::mf/wrap-props false}
|
||||
[props]
|
||||
(let [{:keys [x y width height]
|
||||
:as shape} (->> (unchecked-get props "shape")
|
||||
(geom/selection-rect-shape))
|
||||
:as shape} (->> (unchecked-get props "shape") :selrect)
|
||||
|
||||
childs (unchecked-get props "childs")
|
||||
frame (unchecked-get props "frame")
|
||||
|
|
|
@ -196,7 +196,8 @@
|
|||
(assoc-in [:workspace-local :drawing ::initialized?] true)))
|
||||
|
||||
(insert-point-segment [state point]
|
||||
(update-in state [:workspace-local :drawing :segments] (fnil conj []) point))
|
||||
(-> state
|
||||
(update-in [:workspace-local :drawing :segments] (fnil conj []) point)))
|
||||
|
||||
(update-point-segment [state index point]
|
||||
(let [segments (count (get-in state [:workspace-local :drawing :segments]))
|
||||
|
@ -204,8 +205,12 @@
|
|||
(cond-> state
|
||||
exists? (assoc-in [:workspace-local :drawing :segments index] point))))
|
||||
|
||||
(remove-dangling-segmnet [state]
|
||||
(update-in state [:workspace-local :drawing :segments] #(vec (butlast %))))]
|
||||
(finish-drawing-path [state]
|
||||
(update-in
|
||||
state [:workspace-local :drawing]
|
||||
(fn [shape] (-> shape
|
||||
(update :segments #(vec (butlast %)))
|
||||
(geom/update-path-selrect)))))]
|
||||
|
||||
(ptk/reify ::handle-drawing-path
|
||||
ptk/WatchEvent
|
||||
|
@ -263,9 +268,11 @@
|
|||
point)]
|
||||
#(update-point-segment % index point))))
|
||||
(rx/take-until stoper))
|
||||
(rx/of remove-dangling-segmnet
|
||||
(rx/of finish-drawing-path
|
||||
handle-finish-drawing))))))))
|
||||
|
||||
(def simplify-tolerance 0.3)
|
||||
|
||||
(def handle-drawing-curve
|
||||
(letfn [(stoper-event? [{:keys [type shift] :as event}]
|
||||
(ms/mouse-event? event) (= type :up))
|
||||
|
@ -276,8 +283,13 @@
|
|||
(insert-point-segment [state point]
|
||||
(update-in state [:workspace-local :drawing :segments] (fnil conj []) point))
|
||||
|
||||
(simplify-drawing-path [state tolerance]
|
||||
(update-in state [:workspace-local :drawing :segments] path/simplify tolerance))]
|
||||
(finish-drawing-curve [state]
|
||||
(update-in
|
||||
state [:workspace-local :drawing]
|
||||
(fn [shape]
|
||||
(-> shape
|
||||
(update :segments #(path/simplify % simplify-tolerance))
|
||||
(geom/update-path-selrect)))))]
|
||||
|
||||
(ptk/reify ::handle-drawing-curve
|
||||
ptk/WatchEvent
|
||||
|
@ -290,7 +302,7 @@
|
|||
(->> mouse
|
||||
(rx/map (fn [pt] #(insert-point-segment % pt)))
|
||||
(rx/take-until stoper))
|
||||
(rx/of #(simplify-drawing-path % 0.3)
|
||||
(rx/of finish-drawing-curve
|
||||
handle-finish-drawing)))))))
|
||||
|
||||
(def handle-finish-drawing
|
||||
|
@ -308,10 +320,8 @@
|
|||
:text 16
|
||||
5)
|
||||
shape (-> shape
|
||||
(geom/transform-shape)
|
||||
(update :width #(max shape-min-width %))
|
||||
(update :height #(max shape-min-height %))
|
||||
(dissoc shape ::initialized?))]
|
||||
geom/transform-shape
|
||||
(dissoc ::initialized?)) ]
|
||||
;; Add & select the created shape to the workspace
|
||||
(rx/of dw/deselect-all
|
||||
(dw/add-shape shape)))))))))
|
||||
|
@ -336,7 +346,7 @@
|
|||
|
||||
(mf/defc generic-draw-area
|
||||
[{:keys [shape zoom]}]
|
||||
(let [{:keys [x y width height]} (geom/selection-rect-shape shape)]
|
||||
(let [{:keys [x y width height]} (:selrect shape)]
|
||||
(when (and x y)
|
||||
[:g
|
||||
[:& shapes/shape-wrapper {:shape shape}]
|
||||
|
|
|
@ -187,7 +187,7 @@
|
|||
[:g.controls
|
||||
|
||||
;; Selection rect
|
||||
[:& selection-rect {:rect shape
|
||||
[:& selection-rect {:rect selrect
|
||||
:transform transform
|
||||
:zoom zoom}]
|
||||
|
||||
|
@ -283,7 +283,6 @@
|
|||
(let [shape-id (:id shape)
|
||||
shape (geom/transform-shape shape)
|
||||
shape' (if (debug? :simple-selection) (geom/selection-rect [shape]) shape)
|
||||
|
||||
on-resize
|
||||
#(do (dom/stop-propagation %2)
|
||||
(st/emit! (dw/start-resize %1 #{shape-id} shape')))
|
||||
|
|
|
@ -20,7 +20,7 @@
|
|||
;; namespace under uxbox.ui.workspace.shapes.* prefix, all the
|
||||
;; others are defined using a generic wrapper implemented in
|
||||
;; common.
|
||||
[uxbox.main.ui.workspace.shapes.bbox :as bbox]
|
||||
[uxbox.main.ui.workspace.shapes.bounding-box :refer [bounding-box]]
|
||||
[uxbox.main.ui.workspace.shapes.common :as common]
|
||||
[uxbox.main.ui.workspace.shapes.frame :as frame]
|
||||
[uxbox.main.ui.workspace.shapes.group :as group]
|
||||
|
@ -71,7 +71,8 @@
|
|||
;; Only used when drawing a new frame.
|
||||
:frame [:> frame-wrapper {:shape shape}]
|
||||
nil)
|
||||
[:& bbox/bounding-box {:shape shape :frame frame}]])))
|
||||
[:& bounding-box {:shape (->> shape (geom/transform-shape frame)) :frame frame}]])))
|
||||
|
||||
(def group-wrapper (group/group-wrapper-factory shape-wrapper))
|
||||
(def frame-wrapper (frame/frame-wrapper-factory shape-wrapper))
|
||||
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
;;
|
||||
;; Copyright (c) 2020 UXBOX Labs SL
|
||||
|
||||
(ns uxbox.main.ui.workspace.shapes.bbox
|
||||
(ns uxbox.main.ui.workspace.shapes.bounding-box
|
||||
(:require
|
||||
[cuerdas.core :as str]
|
||||
[rumext.alpha :as mf]
|
||||
|
@ -13,37 +13,61 @@
|
|||
[uxbox.common.geom.matrix :as gmt]
|
||||
[uxbox.common.geom.point :as gpt]
|
||||
[uxbox.util.debug :refer [debug?]]
|
||||
[uxbox.main.refs :as refs]
|
||||
["randomcolor" :as rdcolor]))
|
||||
|
||||
(defn fixed
|
||||
[num]
|
||||
(when num (.toFixed num 2)))
|
||||
|
||||
(mf/defc cross-point [{:keys [point zoom color]}]
|
||||
(let [width (/ 10 zoom)]
|
||||
[:g.point
|
||||
[:line {:x1 (- (:x point) 10) :y1 (- (:y point) 10)
|
||||
:x2 (+ (:x point) 10) :y2 (+ (:y point) 10)
|
||||
:stroke color
|
||||
:stroke-width "1px"
|
||||
:stroke-opacity 0.5}]
|
||||
|
||||
[:line {:x1 (+ (:x point) 10) :y1 (- (:y point) 10)
|
||||
:x2 (- (:x point) 10) :y2 (+ (:y point) 10)
|
||||
:stroke color
|
||||
:stroke-width "1px"
|
||||
:stroke-opacity 0.5}]]))
|
||||
|
||||
(mf/defc bounding-box
|
||||
{::mf/wrap-props false}
|
||||
[props]
|
||||
(when (debug? :bounding-boxes)
|
||||
(let [shape (unchecked-get props "shape")
|
||||
frame (unchecked-get props "frame")
|
||||
selrect (-> shape
|
||||
(geom/selection-rect-shape)
|
||||
(geom/translate-to-frame frame))
|
||||
shape-center (geom/center selrect)
|
||||
line-color (rdcolor #js {:seed (str (:id shape))})]
|
||||
[:g
|
||||
selrect (-> shape :selrect)
|
||||
shape-center (geom/center shape)
|
||||
line-color (rdcolor #js {:seed (str (:id shape))})
|
||||
zoom (mf/deref refs/selected-zoom)]
|
||||
[:g.bounding-box
|
||||
[:text {:x (:x selrect)
|
||||
:y (- (:y selrect) 5)
|
||||
:font-size 10
|
||||
:fill "red"
|
||||
: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)))]
|
||||
|
||||
[:& cross-point {:point shape-center
|
||||
:zoom zoom
|
||||
:color line-color}]
|
||||
|
||||
(for [point (:points shape)]
|
||||
[:& cross-point {:point point
|
||||
:zoom zoom
|
||||
:color line-color}])
|
||||
|
||||
[:rect {:x (:x selrect)
|
||||
:y (:y selrect)
|
||||
:width (:width selrect)
|
||||
:height (:height selrect)
|
||||
:style {:stroke "red"
|
||||
:style {:stroke line-color
|
||||
:fill "transparent"
|
||||
:stroke-width "1px"
|
||||
:stroke-opacity 0.5
|
|
@ -40,8 +40,8 @@
|
|||
"Calculate the best position to draw an interaction line
|
||||
between two shapes"
|
||||
[orig-shape dest-shape]
|
||||
(let [orig-rect (geom/selection-rect-shape orig-shape)
|
||||
dest-rect (geom/selection-rect-shape dest-shape)
|
||||
(let [orig-rect (:selrect orig-shape)
|
||||
dest-rect (:selrect dest-shape)
|
||||
|
||||
orig-x-left (:x orig-rect)
|
||||
orig-x-right (+ orig-x-left (:width orig-rect))
|
||||
|
@ -71,7 +71,7 @@
|
|||
"Calculate the best position to draw an interaction line
|
||||
between one shape and one point"
|
||||
[orig-shape dest-point]
|
||||
(let [orig-rect (geom/selection-rect-shape orig-shape)
|
||||
(let [orig-rect (:selrect orig-shape)
|
||||
|
||||
orig-x-left (:x orig-rect)
|
||||
orig-x-right (+ orig-x-left (:width orig-rect))
|
||||
|
@ -159,7 +159,7 @@
|
|||
|
||||
(mf/defc interaction-handle
|
||||
[{:keys [shape selected zoom] :as props}]
|
||||
(let [shape-rect (geom/selection-rect-shape shape)
|
||||
(let [shape-rect (:selrect shape)
|
||||
handle-x (+ (:x shape-rect) (:width shape-rect))
|
||||
handle-y (+ (:y shape-rect) (/ (:height shape-rect) 2))]
|
||||
[:g {:on-mouse-down #(on-mouse-down % shape selected)}
|
||||
|
|
|
@ -25,13 +25,9 @@
|
|||
|
||||
(defn user-coords-vector
|
||||
[shape]
|
||||
(let [{sel-x :x sel-y :y :as selrect}
|
||||
(-> shape
|
||||
gsh/shape->path
|
||||
(gsh/center-transform (:transform shape))
|
||||
gsh/shape->rect-shape)
|
||||
(let [oldselrec (-> shape gsh/shape->path (gsh/center-transform (:transform shape)) gsh/shape->rect-shape)
|
||||
{sel-x :x sel-y :y :as selrec} #_(:selrect shape) oldselrec
|
||||
{rec-x :x rec-y :y} (-> shape gsh/shape->rect-shape)
|
||||
|
||||
dx (- rec-x sel-x)
|
||||
dy (- rec-y sel-y)]
|
||||
(-> (gpt/point dx dy)
|
||||
|
@ -141,13 +137,13 @@
|
|||
:type "number"
|
||||
:no-validate true
|
||||
:on-change on-pos-x-change
|
||||
:value (:x shape)}]]
|
||||
:value (-> shape :x (math/precision 2))}]]
|
||||
[:div.input-element.Yaxis
|
||||
[:input.input-text {:placeholder "y"
|
||||
:type "number"
|
||||
:no-validate true
|
||||
:on-change on-pos-y-change
|
||||
:value (:y shape)}]]])
|
||||
:value (-> shape :y (math/precision 2))}]]])
|
||||
|
||||
(when (options :rotation)
|
||||
[:div.row-flex
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
|
||||
(def debug-options #{:bounding-boxes :group :events :rotation-handler :resize-handler :selection-center #_:simple-selection })
|
||||
|
||||
(defonce ^:dynamic *debug* (atom #{}))
|
||||
(defonce ^:dynamic *debug* (atom #{:bounding-boxes}))
|
||||
|
||||
(defn debug-all! [] (reset! *debug* debug-options))
|
||||
(defn debug-none! [] (reset! *debug* #{}))
|
||||
|
|
|
@ -26,9 +26,8 @@
|
|||
|
||||
(defn shape-snap-points
|
||||
[shape]
|
||||
(let [modified-path (gsh/transform-apply-modifiers shape)
|
||||
shape-center (gsh/center modified-path)]
|
||||
(let [shape (gsh/transform-shape shape)
|
||||
shape-center (gsh/center shape)]
|
||||
(case (:type shape)
|
||||
:frame (-> modified-path gsh/shape->rect-shape frame-snap-points)
|
||||
(:path :curve) (into #{shape-center} (-> modified-path gsh/shape->rect-shape :segments))
|
||||
(into #{shape-center} (-> modified-path :segments)))))
|
||||
:frame (-> shape gsh/shape->rect-shape frame-snap-points)
|
||||
(into #{shape-center} (-> shape :points)))))
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
[okulary.core :as l]
|
||||
[uxbox.common.uuid :as uuid]
|
||||
[uxbox.common.pages :as cp]
|
||||
[uxbox.common.data :as d]
|
||||
[uxbox.worker.impl :as impl]
|
||||
[uxbox.util.range-tree :as rt]
|
||||
[uxbox.util.geom.snap-points :as snap]
|
||||
|
@ -38,11 +39,6 @@
|
|||
(mapcat (process-shape coord))
|
||||
(reduce into-tree (rt/make-tree)))))
|
||||
|
||||
(defn- mapm
|
||||
"Map over the values of a map"
|
||||
[mfn coll]
|
||||
(into {} (map (fn [[key val]] [key (mfn key val)]) coll)))
|
||||
|
||||
(defn- initialize-snap-data
|
||||
"Initialize the snap information with the current workspace information"
|
||||
[objects]
|
||||
|
@ -51,16 +47,16 @@
|
|||
(group-by :frame-id))
|
||||
frame-shapes (->> (cp/select-frames objects)
|
||||
(reduce #(update %1 (:id %2) conj %2) frame-shapes))]
|
||||
(mapm (fn [frame-id shapes] {:x (create-coord-data frame-id shapes :x)
|
||||
(d/mapm (fn [frame-id shapes] {:x (create-coord-data frame-id shapes :x)
|
||||
:y (create-coord-data frame-id shapes :y)})
|
||||
frame-shapes)))
|
||||
|
||||
(defn- log-state
|
||||
"Helper function to print a friendly version of the snap tree. Debugging purposes"
|
||||
[]
|
||||
(let [process-frame-data #(mapm rt/as-map %)
|
||||
process-page-data #(mapm process-frame-data %)]
|
||||
(js/console.log "STATE" (clj->js (mapm process-page-data @state)))))
|
||||
(let [process-frame-data #(d/mapm rt/as-map %)
|
||||
process-page-data #(d/mapm process-frame-data %)]
|
||||
(js/console.log "STATE" (clj->js (d/mapm process-page-data @state)))))
|
||||
|
||||
(defn- index-page [state page-id objects]
|
||||
(let [snap-data (initialize-snap-data objects)]
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue