mirror of
https://github.com/penpot/penpot.git
synced 2025-03-11 23:31:21 -05:00
🎉 Reimplement canvas as svg (instead of g+rect).
This commit is contained in:
parent
63a339dd31
commit
86ba4fd083
12 changed files with 442 additions and 152 deletions
|
@ -960,28 +960,107 @@
|
|||
(let [shape (get-in state [:workspace-data :shapes-by-id id])]
|
||||
(assoc shape :id (uuid/next))))
|
||||
|
||||
;; (defn duplicate-shapes
|
||||
;; [ids]
|
||||
;; (us/verify (s/every ::us/uuid) ids)
|
||||
;; (ptk/reify ::duplicate-selected
|
||||
;; ptk/UpdateEvent
|
||||
;; (update [_ state]
|
||||
;; (let [duplicate #(-> (get-in state [:workspace-data :shapes-by-id %])
|
||||
;; (assoc :id (uuid/next)))]
|
||||
;; (reduce
|
||||
|
||||
;; shapes (map duplicate selected)
|
||||
;; sid (:session-id state)
|
||||
;; changes (mapv (fn [shape]
|
||||
;; {:type :add-shape
|
||||
;; :id (:id shape)
|
||||
;; :shape shape
|
||||
;; :session-id sid})
|
||||
;; shapes)
|
||||
;; uchanges (mapv (fn [shape]
|
||||
;; {:type :del-shape
|
||||
;; :id (:id shape)
|
||||
;; :session-id sid})
|
||||
;; shapes)]
|
||||
;; (rx/merge
|
||||
|
||||
(defn duplicate-shapes
|
||||
[shapes]
|
||||
(ptk/reify ::duplicate-shapes
|
||||
ptk/UpdateEvent
|
||||
(update [_ state]
|
||||
(reduce (fn [state {:keys [id] :as shape}]
|
||||
(-> state
|
||||
(assoc-in [:workspace-data :shapes-by-id id] shape)
|
||||
(update-in [:workspace-data :shapes] (fnil conj []) id)))
|
||||
state
|
||||
shapes))
|
||||
|
||||
ptk/WatchEvent
|
||||
(watch [_ state stream]
|
||||
(let [rchanges (mapv (fn [shape]
|
||||
{:type :add-shape
|
||||
:id (:id shape)
|
||||
:shape shape
|
||||
:session-id (:session-id state)})
|
||||
shapes)
|
||||
uchanges (mapv (fn [shape]
|
||||
{:type :del-shape
|
||||
:id (:id shape)
|
||||
:session-id (:session-id state)})
|
||||
shapes)]
|
||||
(rx/of (commit-changes rchanges uchanges))))))
|
||||
|
||||
(defn duplicate-canvas
|
||||
[{:keys [id] :as canvas} prev-id]
|
||||
(ptk/reify ::duplicate-canvas
|
||||
ptk/UpdateEvent
|
||||
(update [_ state]
|
||||
(-> state
|
||||
(assoc-in [:workspace-data :shapes-by-id id] canvas)
|
||||
(update-in [:workspace-data :canvas] (fnil conj []) id)))
|
||||
|
||||
ptk/WatchEvent
|
||||
(watch [_ state stream]
|
||||
(let [shapes (->> (vals (get-in state [:workspace-data :shapes-by-id]))
|
||||
(filter #(= (:canvas %) prev-id))
|
||||
(map #(assoc % :id (uuid/next)))
|
||||
(map #(assoc % :canvas id)))
|
||||
|
||||
rchange {:type :add-canvas
|
||||
:id id
|
||||
:shape canvas
|
||||
:session-id (:session-id state)}
|
||||
uchange {:type :del-canvas
|
||||
:id id
|
||||
:session-id (:session-id state)}]
|
||||
(rx/of (duplicate-shapes shapes)
|
||||
(commit-changes [rchange] [uchange]))))))
|
||||
|
||||
|
||||
(def duplicate-selected
|
||||
(ptk/reify ::duplicate-selected
|
||||
ptk/WatchEvent
|
||||
(watch [_ state stream]
|
||||
(let [selected (get-in state [:workspace-local :selected])
|
||||
duplicate (partial impl-duplicate-shape state)
|
||||
shapes (map duplicate selected)
|
||||
sid (:session-id state)
|
||||
changes (mapv (fn [shape]
|
||||
{:type :add-shape
|
||||
:id (:id shape)
|
||||
:shape shape
|
||||
:session-id sid})
|
||||
shapes)
|
||||
uchanges (mapv (fn [shape]
|
||||
{:type :del-shape
|
||||
:id (:id shape)
|
||||
:session-id sid})
|
||||
shapes)]
|
||||
(rx/merge
|
||||
(rx/from (map (fn [s] #(impl-assoc-shape % s)) shapes))
|
||||
(rx/of (commit-changes changes uchanges)))))))
|
||||
(let [selected (get-in state [:workspace-local :selected])
|
||||
dup #(-> (get-in state [:workspace-data :shapes-by-id %])
|
||||
(assoc :id (uuid/next)))
|
||||
shapes (map dup selected)
|
||||
shape? #(not= (:type %) :canvas)]
|
||||
(cond
|
||||
(and (= (count shapes) 1)
|
||||
(= (:type (first shapes)) :canvas))
|
||||
(rx/of (duplicate-canvas (first shapes) (first selected)))
|
||||
|
||||
(and (pos? (count shapes))
|
||||
(every? shape? shapes))
|
||||
(rx/of (duplicate-shapes shapes))
|
||||
|
||||
:else
|
||||
(rx/empty))))))
|
||||
|
||||
|
||||
|
||||
;; --- Toggle shape's selection status (selected or deselected)
|
||||
|
||||
|
@ -1080,8 +1159,6 @@
|
|||
;; --- Shape Movement (using keyboard shorcuts)
|
||||
|
||||
(declare initial-selection-align)
|
||||
(declare apply-temporal-displacement-in-bulk)
|
||||
(declare materialize-temporal-modifier-in-bulk)
|
||||
|
||||
(defn- get-displacement-with-grid
|
||||
"Retrieve the correct displacement delta point for the
|
||||
|
@ -1109,6 +1186,9 @@
|
|||
|
||||
(s/def ::direction #{:up :down :right :left})
|
||||
|
||||
(declare apply-displacement-in-bulk)
|
||||
(declare materialize-displacement-in-bulk)
|
||||
|
||||
(defn move-selected
|
||||
[direction align?]
|
||||
(us/verify ::direction direction)
|
||||
|
@ -1124,8 +1204,8 @@
|
|||
displacement (if align?
|
||||
(get-displacement-with-grid shape direction options)
|
||||
(get-displacement shape direction))]
|
||||
(rx/of (apply-temporal-displacement-in-bulk selected displacement)
|
||||
(materialize-temporal-modifier-in-bulk selected))))))
|
||||
(rx/of (apply-displacement-in-bulk selected displacement)
|
||||
(materialize-displacement-in-bulk selected))))))
|
||||
|
||||
;; --- Delete Selected
|
||||
|
||||
|
@ -1289,34 +1369,10 @@
|
|||
(:y1 sshape))]
|
||||
(->> (uwrk/align-point point)
|
||||
(rx/map (fn [{:keys [x y] :as pt}]
|
||||
(apply-temporal-displacement-in-bulk ids (gpt/subtract pt point)))))))))
|
||||
(apply-displacement-in-bulk ids (gpt/subtract pt point)))))))))
|
||||
|
||||
;; --- Temportal displacement for Shape / Selection
|
||||
|
||||
(defn assoc-temporal-modifier-in-bulk
|
||||
[ids xfmt]
|
||||
(us/verify ::set-of-uuid ids)
|
||||
(us/verify gmt/matrix? xfmt)
|
||||
(ptk/reify ::assoc-temporal-modifier-in-bulk
|
||||
ptk/UpdateEvent
|
||||
(update [_ state]
|
||||
(reduce #(assoc-in %1 [:workspace-data :shapes-by-id %2 :modifier-mtx] xfmt) state ids))))
|
||||
|
||||
(defn apply-temporal-displacement-in-bulk
|
||||
"Apply the same displacement delta to all shapes identified by the
|
||||
set if ids."
|
||||
[ids delta]
|
||||
(us/verify ::set-of-uuid ids)
|
||||
(us/verify gpt/point? delta)
|
||||
(letfn [(process-shape [state id]
|
||||
(let [prev (get-in state [:workspace-data :shapes-by-id id :modifier-mtx] (gmt/matrix))
|
||||
xfmt (gmt/translate prev delta)]
|
||||
(assoc-in state [:workspace-data :shapes-by-id id :modifier-mtx] xfmt)))]
|
||||
(ptk/reify ::apply-temporal-displacement-in-bulk
|
||||
ptk/UpdateEvent
|
||||
(update [_ state]
|
||||
(reduce process-shape state ids)))))
|
||||
|
||||
(defn- recalculate-shape-canvas-relation
|
||||
[state shape]
|
||||
(let [shape' (geom/shape->rect-shape shape)
|
||||
|
@ -1330,21 +1386,109 @@
|
|||
(first))]
|
||||
(assoc shape :canvas id)))
|
||||
|
||||
(defn materialize-temporal-modifier-in-bulk
|
||||
(defn assoc-resize-modifier-in-bulk
|
||||
[ids xfmt]
|
||||
(us/verify ::set-of-uuid ids)
|
||||
(us/verify gmt/matrix? xfmt)
|
||||
(ptk/reify ::assoc-resize-modifier-in-bulk
|
||||
ptk/UpdateEvent
|
||||
(update [_ state]
|
||||
(reduce #(assoc-in %1 [:workspace-data :shapes-by-id %2 :resize-modifier] xfmt) state ids))))
|
||||
|
||||
(defn materialize-resize-modifier-in-bulk
|
||||
[ids]
|
||||
(letfn [(process-shape [state id]
|
||||
(let [shape (get-in state [:workspace-data :shapes-by-id id])
|
||||
xfmt (or (:modifier-mtx shape) (gmt/matrix))
|
||||
shape-old (dissoc shape :modifier-mtx)
|
||||
shape-new (geom/transform shape-old xfmt)
|
||||
shape-new (recalculate-shape-canvas-relation state shape-new)]
|
||||
(assoc-in state [:workspace-data :shapes-by-id id] shape-new)))]
|
||||
(ptk/reify ::materialize-temporal-modifier-in-bulk
|
||||
modifier (:resize-modifier shape (gmt/matrix))
|
||||
|
||||
shape (-> (dissoc shape :resize-modifier)
|
||||
(geom/transform modifier))
|
||||
shape (recalculate-shape-canvas-relation state shape)]
|
||||
(assoc-in state [:workspace-data :shapes-by-id id] shape)))]
|
||||
(ptk/reify ::materialize-resize-modifier-in-bulk
|
||||
IBatchedChange
|
||||
ptk/UpdateEvent
|
||||
(update [_ state]
|
||||
(reduce process-shape state ids)))))
|
||||
|
||||
(defn apply-displacement-in-bulk
|
||||
"Apply the same displacement delta to all shapes identified by the
|
||||
set if ids."
|
||||
[ids delta]
|
||||
(us/verify ::set-of-uuid ids)
|
||||
(us/verify gpt/point? delta)
|
||||
(letfn [(process-shape [state id]
|
||||
(let [shape (get-in state [:workspace-data :shapes-by-id id])
|
||||
prev (:displacement-modifier shape (gmt/matrix))
|
||||
curr (gmt/translate prev delta)]
|
||||
(->> (assoc shape :displacement-modifier curr)
|
||||
(assoc-in state [:workspace-data :shapes-by-id id]))))]
|
||||
(ptk/reify ::apply-displacement-in-bulk
|
||||
ptk/UpdateEvent
|
||||
(update [_ state]
|
||||
(reduce process-shape state ids)))))
|
||||
|
||||
(defn materialize-displacement-in-bulk
|
||||
[ids]
|
||||
(letfn [(process-shape [state id]
|
||||
(let [shape (get-in state [:workspace-data :shapes-by-id id])
|
||||
modifier (:displacement-modifier shape (gmt/matrix))
|
||||
|
||||
shape (-> (dissoc shape :displacement-modifier)
|
||||
(geom/transform modifier))
|
||||
shape (recalculate-shape-canvas-relation state shape)]
|
||||
(assoc-in state [:workspace-data :shapes-by-id id] shape)))]
|
||||
(ptk/reify ::materialize-displacement-in-bulk
|
||||
IBatchedChange
|
||||
ptk/UpdateEvent
|
||||
(update [_ state]
|
||||
(reduce process-shape state ids)))))
|
||||
|
||||
|
||||
(defn apply-canvas-displacement
|
||||
"Apply the same displacement delta to all shapes identified by the
|
||||
set if ids."
|
||||
[id delta]
|
||||
(us/verify ::us/uuid id)
|
||||
(us/verify gpt/point? delta)
|
||||
(ptk/reify ::apply-canvas-displacement
|
||||
ptk/UpdateEvent
|
||||
(update [_ state]
|
||||
(let [shape (get-in state [:workspace-data :shapes-by-id id])
|
||||
prev-xfmt (:displacement-modifier shape (gmt/matrix))
|
||||
xfmt (gmt/translate prev-xfmt delta)]
|
||||
(->> (assoc shape :displacement-modifier xfmt)
|
||||
(assoc-in state [:workspace-data :shapes-by-id id]))))))
|
||||
|
||||
(defn materialize-canvas-displacement
|
||||
[id]
|
||||
(us/verify ::us/uuid id)
|
||||
(ptk/reify ::materialize-canvas-displacement
|
||||
IBatchedChange
|
||||
ptk/UpdateEvent
|
||||
(update [_ state]
|
||||
(let [data (:workspace-data state)
|
||||
shapes-map (:shapes-by-id data)
|
||||
|
||||
canvas (get shapes-map id)
|
||||
|
||||
xfmt (or (:displacement-modifier canvas) (gmt/matrix))
|
||||
|
||||
canvas (-> canvas
|
||||
(dissoc :displacement-modifier)
|
||||
(geom/transform xfmt))
|
||||
|
||||
shapes (->> (:shapes data [])
|
||||
(map #(get shapes-map %))
|
||||
(filter #(= (:canvas %) id))
|
||||
(map #(geom/transform % xfmt)))
|
||||
|
||||
shapes (d/index-by :id shapes)
|
||||
shapes (assoc shapes (:id canvas) canvas)]
|
||||
|
||||
(update-in state [:workspace-data :shapes-by-id] merge shapes)))))
|
||||
|
||||
|
||||
(defn commit-changes
|
||||
([changes undo-changes] (commit-changes changes undo-changes true))
|
||||
([changes undo-changes save-undo?]
|
||||
|
|
|
@ -2,7 +2,10 @@
|
|||
;; 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/.
|
||||
;;
|
||||
;; Copyright (c) 2016-2019 Andrey Antukh <niwi@niwi.nz>
|
||||
;; This Source Code Form is "Incompatible With Secondary Licenses", as
|
||||
;; defined by the Mozilla Public License, v. 2.0.
|
||||
;;
|
||||
;; Copyright (c) 2016-2020 Andrey Antukh <niwi@niwi.nz>
|
||||
|
||||
(ns uxbox.main.ui.shapes
|
||||
(:require
|
||||
|
@ -10,25 +13,7 @@
|
|||
[rumext.alpha :as mf]
|
||||
[uxbox.main.refs :as refs]
|
||||
[uxbox.main.store :as st]
|
||||
[uxbox.main.ui.shapes.circle :as circle]
|
||||
[uxbox.main.ui.shapes.icon :as icon]
|
||||
[uxbox.main.ui.shapes.image :as image]
|
||||
[uxbox.main.ui.shapes.path :as path]
|
||||
[uxbox.main.ui.shapes.rect :as rect]
|
||||
[uxbox.main.ui.shapes.canvas :as canvas]
|
||||
[uxbox.main.ui.shapes.text :as text]))
|
||||
|
||||
(mf/defc shape-wrapper
|
||||
{:wrap [mf/wrap-memo]}
|
||||
[{:keys [shape] :as props}]
|
||||
(when (and shape (not (:hidden shape)))
|
||||
(case (:type shape)
|
||||
:canvas [:& canvas/canvas-wrapper {:shape shape}]
|
||||
:curve [:& path/path-wrapper {:shape shape}]
|
||||
:text [:& text/text-wrapper {:shape shape}]
|
||||
:icon [:& icon/icon-wrapper {:shape shape}]
|
||||
:rect [:& rect/rect-wrapper {:shape shape}]
|
||||
:path [:& path/path-wrapper {:shape shape}]
|
||||
:image [:& image/image-wrapper {:shape shape}]
|
||||
:circle [:& circle/circle-wrapper {:shape shape}])))
|
||||
[uxbox.main.ui.shapes.canvas :as canvas]))
|
||||
|
||||
(def shape-wrapper canvas/shape-wrapper)
|
||||
(def canvas-wrapper canvas/canvas-wrapper)
|
||||
|
|
|
@ -2,8 +2,11 @@
|
|||
;; 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/.
|
||||
;;
|
||||
;; Copyright (c) 2015-2016 Andrey Antukh <niwi@niwi.nz>
|
||||
;; Copyright (c) 2015-2016 Juan de la Cruz <delacruzgarciajuan@gmail.com>
|
||||
;; This Source Code Form is "Incompatible With Secondary Licenses", as
|
||||
;; defined by the Mozilla Public License, v. 2.0.
|
||||
;;
|
||||
;; Copyright (c) 2015-2020 Andrey Antukh <niwi@niwi.nz>
|
||||
;; Copyright (c) 2015-2020 Juan de la Cruz <delacruzgarciajuan@gmail.com>
|
||||
|
||||
(ns uxbox.main.ui.shapes.canvas
|
||||
(:require
|
||||
|
@ -13,29 +16,97 @@
|
|||
[uxbox.main.data.workspace :as dw]
|
||||
[uxbox.main.geom :as geom]
|
||||
[uxbox.main.refs :as refs]
|
||||
[uxbox.main.ui.shapes.common :as common]
|
||||
[uxbox.main.store :as st]
|
||||
[uxbox.main.ui.shapes.rect :refer [rect-shape]]
|
||||
[uxbox.main.ui.shapes.attrs :as attrs]
|
||||
[uxbox.main.ui.shapes.circle :as circle]
|
||||
[uxbox.main.ui.shapes.common :as common]
|
||||
[uxbox.main.ui.shapes.icon :as icon]
|
||||
[uxbox.main.ui.shapes.image :as image]
|
||||
[uxbox.main.ui.shapes.path :as path]
|
||||
[uxbox.main.ui.shapes.rect :as rect]
|
||||
[uxbox.main.ui.shapes.text :as text]
|
||||
[uxbox.util.data :refer [parse-int]]
|
||||
[uxbox.util.dom :as dom]
|
||||
[uxbox.util.geom.matrix :as gmt]
|
||||
[uxbox.util.geom.point :as gpt]))
|
||||
|
||||
(declare canvas-wrapper)
|
||||
|
||||
(mf/defc shape-wrapper
|
||||
{:wrap [mf/wrap-memo]}
|
||||
[{:keys [shape] :as props}]
|
||||
(when (and shape (not (:hidden shape)))
|
||||
(case (:type shape)
|
||||
:canvas [:& canvas-wrapper {:shape shape :childs []}]
|
||||
:curve [:& path/path-wrapper {:shape shape}]
|
||||
:text [:& text/text-wrapper {:shape shape}]
|
||||
:icon [:& icon/icon-wrapper {:shape shape}]
|
||||
:rect [:& rect/rect-wrapper {:shape shape}]
|
||||
:path [:& path/path-wrapper {:shape shape}]
|
||||
:image [:& image/image-wrapper {:shape shape}]
|
||||
:circle [:& circle/circle-wrapper {:shape shape}])))
|
||||
|
||||
(def canvas-default-props
|
||||
{:fill-color "#ffffff"})
|
||||
|
||||
(declare canvas-shape)
|
||||
|
||||
(mf/defc canvas-wrapper
|
||||
[{:keys [shape] :as props}]
|
||||
(let [selected (mf/deref refs/selected-shapes)
|
||||
selected? (contains? selected (:id shape))
|
||||
on-mouse-down #(common/on-mouse-down % shape selected)
|
||||
shape (merge canvas-default-props shape)]
|
||||
(letfn [(on-double-click [event]
|
||||
(dom/prevent-default event)
|
||||
(st/emit! dw/deselect-all
|
||||
(dw/select-shape (:id shape))))]
|
||||
[:g.shape {:class (when selected? "selected")
|
||||
:on-double-click on-double-click
|
||||
:on-mouse-down on-mouse-down}
|
||||
[:& rect-shape {:shape shape}]])))
|
||||
[{:keys [shape childs] :as props}]
|
||||
(when (and shape (not (:hidden shape)))
|
||||
(let [selected (mf/deref refs/selected-shapes)
|
||||
selected? (contains? selected (:id shape))
|
||||
on-mouse-down #(common/on-mouse-down % shape selected)
|
||||
shape (merge canvas-default-props shape)
|
||||
|
||||
on-double-click
|
||||
(fn [event]
|
||||
(dom/prevent-default event)
|
||||
(st/emit! dw/deselect-all
|
||||
(dw/select-shape (:id shape))))]
|
||||
[:g {:class (when selected? "selected")
|
||||
:on-double-click on-double-click
|
||||
:on-mouse-down on-mouse-down}
|
||||
[:& canvas-shape {:shape shape :childs childs}]])))
|
||||
|
||||
(defn- translate-to-canvas
|
||||
[shape canvas-ds-modifier pt]
|
||||
(let [rz-modifier (:resize-modifier shape)
|
||||
shape (cond-> shape
|
||||
(gmt/matrix? canvas-ds-modifier)
|
||||
(geom/transform canvas-ds-modifier)
|
||||
|
||||
(gmt/matrix? rz-modifier)
|
||||
(-> (geom/transform rz-modifier)
|
||||
(dissoc :resize-modifier)))]
|
||||
(geom/move shape pt)))
|
||||
|
||||
(mf/defc canvas-shape
|
||||
[{:keys [shape childs] :as props}]
|
||||
(let [rotation (:rotation shape)
|
||||
ds-modifier (:displacement-modifier shape)
|
||||
rz-modifier (:modifier-mtx shape)
|
||||
|
||||
shape (cond-> shape
|
||||
(gmt/matrix? rz-modifier) (geom/transform rz-modifier)
|
||||
(gmt/matrix? ds-modifier) (geom/transform ds-modifier))
|
||||
|
||||
{:keys [id x y width height]} shape
|
||||
|
||||
props (-> (attrs/extract-style-attrs shape)
|
||||
(assoc :x 0
|
||||
:y 0
|
||||
:id (str "shape-" id)
|
||||
:width width
|
||||
:height height
|
||||
))
|
||||
|
||||
translate #(translate-to-canvas % ds-modifier (gpt/point (- x) (- y)))]
|
||||
|
||||
[:svg {:x x :y y :width width :height height}
|
||||
[:& "rect" props]
|
||||
(for [item (map translate childs)]
|
||||
[:& shape-wrapper {:shape item :key (:id item)}])]))
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -32,28 +32,28 @@
|
|||
|
||||
(mf/defc circle-shape
|
||||
[{:keys [shape] :as props}]
|
||||
(let [{:keys [id rotation cx cy modifier-mtx]} shape
|
||||
|
||||
shape (cond
|
||||
(gmt/matrix? modifier-mtx) (geom/transform shape modifier-mtx)
|
||||
:else shape)
|
||||
(let [ds-modifier (:displacement-modifier shape)
|
||||
rz-modifier (:resize-modifier shape)
|
||||
|
||||
center (gpt/point (:cx shape)
|
||||
(:cy shape))
|
||||
shape (cond-> shape
|
||||
(gmt/matrix? rz-modifier) (geom/transform rz-modifier)
|
||||
(gmt/matrix? ds-modifier) (geom/transform ds-modifier))
|
||||
|
||||
rotation (or rotation 0)
|
||||
|
||||
moving? (boolean modifier-mtx)
|
||||
{:keys [id cx cy rx ry rotation]} shape
|
||||
|
||||
center (gpt/point cx cy)
|
||||
rotation (or rotation 0)
|
||||
transform (when (pos? rotation)
|
||||
(str (-> (gmt/matrix)
|
||||
(gmt/rotate rotation center))))
|
||||
|
||||
props {:id (str "shape-" id)
|
||||
:class (classnames :move-cursor moving?)
|
||||
:transform transform}
|
||||
|
||||
attrs (merge props
|
||||
(attrs/extract-style-attrs shape)
|
||||
(select-keys shape [:cx :cy :rx :ry]))]
|
||||
[:> :ellipse (normalize-props attrs)]))
|
||||
props (-> (attrs/extract-style-attrs shape)
|
||||
(assoc :cx cx
|
||||
:cy cy
|
||||
:rx rx
|
||||
:ry ry
|
||||
:transform transform
|
||||
:id (str "shape-" id)
|
||||
))]
|
||||
[:& "elipse" props]))
|
||||
|
|
|
@ -13,12 +13,15 @@
|
|||
(:require
|
||||
[potok.core :as ptk]
|
||||
[beicon.core :as rx]
|
||||
[uxbox.common.data :as d]
|
||||
[uxbox.common.spec :as us]
|
||||
[uxbox.main.data.workspace :as dw]
|
||||
[uxbox.main.refs :as refs]
|
||||
[uxbox.main.store :as st]
|
||||
[uxbox.main.ui.keyboard :as kbd]
|
||||
[uxbox.main.streams :as uws]
|
||||
[uxbox.main.workers :as uwrk]
|
||||
[uxbox.main.geom :as geom]
|
||||
[uxbox.util.geom.matrix :as gmt]
|
||||
[uxbox.util.geom.point :as gpt]
|
||||
[uxbox.util.dom :as dom]))
|
||||
|
@ -34,14 +37,93 @@
|
|||
stoper (rx/filter uws/mouse-up? stream)
|
||||
position @uws/mouse-position]
|
||||
(rx/concat
|
||||
;; (when (refs/alignment-activated? flags)
|
||||
;; (rx/of (dw/initial-selection-align selected)))
|
||||
(->> (uws/mouse-position-deltas position)
|
||||
(rx/map #(dw/apply-temporal-displacement-in-bulk selected %))
|
||||
(rx/map #(dw/apply-displacement-in-bulk selected %))
|
||||
(rx/take-until stoper))
|
||||
(rx/of (dw/materialize-temporal-modifier-in-bulk selected)
|
||||
(rx/of (dw/materialize-displacement-in-bulk selected)
|
||||
::dw/page-data-update))))))
|
||||
|
||||
;; (defn apply-canvas-displacement
|
||||
;; "Apply the same displacement delta to all shapes identified by the
|
||||
;; set if ids."
|
||||
;; [id delta]
|
||||
;; (us/verify ::us/uuid id)
|
||||
;; (us/verify gpt/point? delta)
|
||||
;; (ptk/reify ::apply-temporal-displacement-in-bulk
|
||||
;; ptk/UpdateEvent
|
||||
;; (update [_ state]
|
||||
;; (let [shape (get-in state [:workspace-data :shapes-by-id id])
|
||||
;; prev-xfmt (:displacement-modifier shape (gmt/matrix))
|
||||
;; xfmt (gmt/translate prev-xfmt delta)]
|
||||
;; (->> (assoc shape :displacement-modifier xfmt)
|
||||
;; (assoc-in state [:workspace-data :shapes-by-id id]))))))
|
||||
|
||||
;; (defn materialize-canvas-displacement
|
||||
;; [id]
|
||||
;; (us/verify ::us/uuid id)
|
||||
;; (ptk/reify ::materialize-temporal-modifier
|
||||
;; dw/IBatchedChange
|
||||
;; ptk/UpdateEvent
|
||||
;; (update [_ state]
|
||||
;; (let [data (:workspace-data state)
|
||||
;; shapes-map (:shapes-by-id data)
|
||||
|
||||
;; canvas (get shapes-map id)
|
||||
|
||||
;; xfmt (or (:displacement-modifier canvas) (gmt/matrix))
|
||||
|
||||
;; canvas (-> canvas
|
||||
;; (dissoc :displacement-modifier)
|
||||
;; (geom/transform xfmt))
|
||||
|
||||
;; shapes (->> (:shapes data [])
|
||||
;; (map #(get shapes-map %))
|
||||
;; (filter #(= (:canvas %) id))
|
||||
;; (map #(geom/transform % xfmt)))
|
||||
|
||||
;; shapes (d/index-by :id shapes)
|
||||
;; shapes (assoc shapes (:id canvas) canvas)]
|
||||
|
||||
;; (update-in state [:workspace-data :shapes-by-id] merge shapes)))))
|
||||
|
||||
;; (defn- move-canvas
|
||||
;; [id delta]
|
||||
;; (ptk/reify ::move-canvas
|
||||
;; ptk/UpdateEvent
|
||||
;; (update [_ state]
|
||||
;; (let [data (:workspace-data state)
|
||||
;; shapes-map (:shapes-by-id data)
|
||||
|
||||
;; canvas (-> (get shapes-map id)
|
||||
;; (geom/move delta))
|
||||
|
||||
;; shapes (->> (:shapes data [])
|
||||
;; (map #(get shapes-map %))
|
||||
;; (filter #(= (:canvas %) id))
|
||||
;; (map #(geom/move % delta)))
|
||||
|
||||
;; shapes (d/index-by :id shapes)
|
||||
;; shapes (assoc shapes (:id canvas) canvas)]
|
||||
|
||||
;; (update-in state [:workspace-data :shapes-by-id] merge shapes)))))
|
||||
|
||||
|
||||
(def start-move-canvas
|
||||
(ptk/reify ::start-move-selected
|
||||
ptk/WatchEvent
|
||||
(watch [_ state stream]
|
||||
(let [flags (get-in state [:workspace-local :flags])
|
||||
selected (get-in state [:workspace-local :selected])
|
||||
stoper (rx/filter uws/mouse-up? stream)
|
||||
canvas-id (first selected)
|
||||
position @uws/mouse-position]
|
||||
|
||||
(rx/concat
|
||||
(->> (uws/mouse-position-deltas position)
|
||||
(rx/map #(dw/apply-canvas-displacement canvas-id %))
|
||||
(rx/take-until stoper))
|
||||
(rx/of (dw/materialize-canvas-displacement canvas-id)))))))
|
||||
|
||||
(defn on-mouse-down
|
||||
[event {:keys [id type] :as shape} selected]
|
||||
(let [selected? (contains? selected id)
|
||||
|
@ -54,7 +136,7 @@
|
|||
(= type :canvas)
|
||||
(when selected?
|
||||
(dom/stop-propagation event)
|
||||
(st/emit! start-move-selected))
|
||||
(st/emit! start-move-canvas))
|
||||
|
||||
(and (not selected?) (empty? selected))
|
||||
(do
|
||||
|
|
|
@ -34,13 +34,14 @@
|
|||
|
||||
(mf/defc icon-shape
|
||||
[{:keys [shape] :as props}]
|
||||
(let [{:keys [id content metadata rotation modifier-mtx]} shape
|
||||
(let [ds-modifier (:displacement-modifier shape)
|
||||
rz-modifier (:resize-modifier shape)
|
||||
|
||||
shape (cond
|
||||
(gmt/matrix? modifier-mtx) (geom/transform shape modifier-mtx)
|
||||
:else shape)
|
||||
shape (cond-> shape
|
||||
(gmt/matrix? rz-modifier) (geom/transform rz-modifier)
|
||||
(gmt/matrix? ds-modifier) (geom/transform ds-modifier))
|
||||
|
||||
{:keys [x y width height] :as shape} shape
|
||||
{:keys [id x y width height metadata rotation content] :as shape} shape
|
||||
|
||||
transform (when (and rotation (pos? rotation))
|
||||
(str/format "rotate(%s %s %s)"
|
||||
|
@ -48,7 +49,6 @@
|
|||
(+ x (/ width 2))
|
||||
(+ y (/ height 2))))
|
||||
|
||||
|
||||
view-box (apply str (interpose " " (:view-box metadata)))
|
||||
|
||||
props (-> (attrs/extract-style-attrs shape)
|
||||
|
|
|
@ -33,13 +33,14 @@
|
|||
|
||||
(mf/defc image-shape
|
||||
[{:keys [shape] :as props}]
|
||||
(let [{:keys [id rotation modifier-mtx metadata]} shape
|
||||
(let [ds-modifier (:displacement-modifier shape)
|
||||
rz-modifier (:resize-modifier shape)
|
||||
|
||||
shape (cond
|
||||
(gmt/matrix? modifier-mtx) (geom/transform shape modifier-mtx)
|
||||
:else shape)
|
||||
shape (cond-> shape
|
||||
(gmt/matrix? rz-modifier) (geom/transform rz-modifier)
|
||||
(gmt/matrix? ds-modifier) (geom/transform ds-modifier))
|
||||
|
||||
{:keys [x y width height]} shape
|
||||
{:keys [id x y width height rotation metadata]} shape
|
||||
|
||||
transform (when (and rotation (pos? rotation))
|
||||
(str/format "rotate(%s %s %s)"
|
||||
|
|
|
@ -61,14 +61,14 @@
|
|||
|
||||
(mf/defc path-shape
|
||||
[{:keys [shape background?] :as props}]
|
||||
(let [modifier-mtx (:modifier-mtx shape)
|
||||
rotation (:rotation shape)
|
||||
(let [ds-modifier (:displacement-modifier shape)
|
||||
rz-modifier (:resize-modifier shape)
|
||||
|
||||
shape (cond
|
||||
(gmt/matrix? modifier-mtx) (geom/transform shape modifier-mtx)
|
||||
:else shape)
|
||||
shape (cond-> shape
|
||||
(gmt/matrix? rz-modifier) (geom/transform rz-modifier)
|
||||
(gmt/matrix? ds-modifier) (geom/transform ds-modifier))
|
||||
|
||||
{:keys [id x y width height]} (geom/shape->rect-shape shape)
|
||||
{:keys [id x y width height rotation]} (geom/shape->rect-shape shape)
|
||||
|
||||
transform (when (and rotation (pos? rotation))
|
||||
(str/format "rotate(%s %s %s)"
|
||||
|
|
|
@ -34,13 +34,14 @@
|
|||
|
||||
(mf/defc rect-shape
|
||||
[{:keys [shape] :as props}]
|
||||
(let [{:keys [id rotation modifier-mtx]} shape
|
||||
(let [ds-modifier (:displacement-modifier shape)
|
||||
rz-modifier (:resize-modifier shape)
|
||||
|
||||
shape (cond
|
||||
(gmt/matrix? modifier-mtx) (geom/transform shape modifier-mtx)
|
||||
:else shape)
|
||||
shape (cond-> shape
|
||||
(gmt/matrix? rz-modifier) (geom/transform rz-modifier)
|
||||
(gmt/matrix? ds-modifier) (geom/transform ds-modifier))
|
||||
|
||||
{:keys [x y width height]} shape
|
||||
{:keys [id x y width height rotation]} shape
|
||||
|
||||
transform (when (and rotation (pos? rotation))
|
||||
(str/format "rotate(%s %s %s)"
|
||||
|
|
|
@ -120,7 +120,7 @@
|
|||
result (geom/resize-shape :bottom-right shape' point lock?)
|
||||
scale (geom/calculate-scale-ratio shape' result)
|
||||
mtx (geom/generate-resize-matrix :bottom-right shape' scale)]
|
||||
(assoc shape :modifier-mtx mtx)))
|
||||
(assoc shape :resize-modifier mtx)))
|
||||
|
||||
(update-drawing [state point lock?]
|
||||
(update-in state [:workspace-local :drawing] resize-shape point lock?))]
|
||||
|
@ -273,11 +273,11 @@
|
|||
(rx/concat
|
||||
(rx/of dw/clear-drawing)
|
||||
(when (::initialized? shape)
|
||||
(let [modifier-mtx (:modifier-mtx shape)
|
||||
shape (if (gmt/matrix? modifier-mtx)
|
||||
(geom/transform shape modifier-mtx)
|
||||
(let [modifier (:resize-modifier shape)
|
||||
shape (if (gmt/matrix? modifier)
|
||||
(geom/transform shape modifier)
|
||||
shape)
|
||||
shape (dissoc shape ::initialized? :modifier-mtx)]
|
||||
shape (dissoc shape ::initialized? :resize-modifier)]
|
||||
;; Add & select the created shape to the workspace
|
||||
(rx/of dw/deselect-all
|
||||
(if (= :canvas (:type shape))
|
||||
|
|
|
@ -35,7 +35,7 @@
|
|||
(let [result (geom/resize-shape vid shape point lock?)
|
||||
scale (geom/calculate-scale-ratio shape result)
|
||||
mtx (geom/generate-resize-matrix vid shape scale)]
|
||||
(rx/of (dw/assoc-temporal-modifier-in-bulk ids mtx))))
|
||||
(rx/of (dw/assoc-resize-modifier-in-bulk ids mtx))))
|
||||
|
||||
;; Unifies the instantaneous proportion lock modifier
|
||||
;; activated by Ctrl key and the shapes own proportion
|
||||
|
@ -64,8 +64,7 @@
|
|||
(rx/map normalize-proportion-lock)
|
||||
(rx/mapcat (partial resize shape))
|
||||
(rx/take-until stoper))
|
||||
(rx/of (dw/materialize-temporal-modifier-in-bulk ids)
|
||||
::dw/page-data-update)))))))
|
||||
(rx/of (dw/materialize-resize-modifier-in-bulk ids))))))))
|
||||
|
||||
(defn start-rotate
|
||||
[shape]
|
||||
|
@ -261,9 +260,13 @@
|
|||
(st/emit! (start-resize %1 #{(:id shape)} shape)))
|
||||
on-rotate #(do (dom/stop-propagation %)
|
||||
(st/emit! (start-rotate shape)))
|
||||
modifier (:modifier-mtx shape)
|
||||
shape (-> (geom/shape->rect-shape shape)
|
||||
(geom/transform (or modifier (gmt/matrix))))]
|
||||
|
||||
ds-modifier (:displacement-modifier shape)
|
||||
rz-modifier (:resize-modifier shape)
|
||||
shape (cond-> (geom/shape->rect-shape shape)
|
||||
(gmt/matrix? rz-modifier) (geom/transform rz-modifier)
|
||||
(gmt/matrix? ds-modifier) (geom/transform ds-modifier))]
|
||||
|
||||
[:& controls {:shape shape
|
||||
:zoom zoom
|
||||
:on-rotate on-rotate
|
||||
|
|
|
@ -23,7 +23,7 @@
|
|||
[uxbox.main.ui.workspace.ruler :refer [ruler]]
|
||||
[uxbox.main.ui.workspace.drawarea :refer [start-drawing]]
|
||||
|
||||
[uxbox.main.ui.shapes :refer [shape-wrapper]]
|
||||
[uxbox.main.ui.shapes :refer [shape-wrapper canvas-wrapper]]
|
||||
[uxbox.main.ui.workspace.drawarea :refer [draw-area]]
|
||||
[uxbox.main.ui.workspace.selection :refer [selection-handlers]]
|
||||
|
||||
|
@ -149,11 +149,14 @@
|
|||
(let [data (mf/deref refs/workspace-data)
|
||||
shapes-by-id (:shapes-by-id data)
|
||||
shapes (map #(get shapes-by-id %) (:shapes data []))
|
||||
canvas (map #(get shapes-by-id %) (:canvas data []))]
|
||||
canvas (map #(get shapes-by-id %) (:canvas data []))
|
||||
unassinged (filter #(nil? (:canvas %)) shapes)]
|
||||
[:g.shapes
|
||||
(for [item canvas]
|
||||
[:& shape-wrapper {:shape item :key (:id item)}])
|
||||
(for [item shapes]
|
||||
(let [shapes (filter #(= (:canvas %) (:id item)) shapes)]
|
||||
[:& canvas-wrapper {:shape item :key (:id item)
|
||||
:childs shapes}]))
|
||||
(for [item unassinged]
|
||||
[:& shape-wrapper {:shape item :key (:id item)}])]))
|
||||
|
||||
(mf/defc viewport
|
||||
|
|
Loading…
Add table
Reference in a new issue