0
Fork 0
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:
Andrey Antukh 2020-02-18 17:11:17 +01:00
parent 63a339dd31
commit 86ba4fd083
12 changed files with 442 additions and 152 deletions

View file

@ -960,28 +960,107 @@
(let [shape (get-in state [:workspace-data :shapes-by-id id])] (let [shape (get-in state [:workspace-data :shapes-by-id id])]
(assoc shape :id (uuid/next)))) (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 (def duplicate-selected
(ptk/reify ::duplicate-selected (ptk/reify ::duplicate-selected
ptk/WatchEvent ptk/WatchEvent
(watch [_ state stream] (watch [_ state stream]
(let [selected (get-in state [:workspace-local :selected]) (let [selected (get-in state [:workspace-local :selected])
duplicate (partial impl-duplicate-shape state) dup #(-> (get-in state [:workspace-data :shapes-by-id %])
shapes (map duplicate selected) (assoc :id (uuid/next)))
sid (:session-id state) shapes (map dup selected)
changes (mapv (fn [shape] shape? #(not= (:type %) :canvas)]
{:type :add-shape (cond
:id (:id shape) (and (= (count shapes) 1)
:shape shape (= (:type (first shapes)) :canvas))
:session-id sid}) (rx/of (duplicate-canvas (first shapes) (first selected)))
shapes)
uchanges (mapv (fn [shape] (and (pos? (count shapes))
{:type :del-shape (every? shape? shapes))
:id (:id shape) (rx/of (duplicate-shapes shapes))
:session-id sid})
shapes)] :else
(rx/merge (rx/empty))))))
(rx/from (map (fn [s] #(impl-assoc-shape % s)) shapes))
(rx/of (commit-changes changes uchanges)))))))
;; --- Toggle shape's selection status (selected or deselected) ;; --- Toggle shape's selection status (selected or deselected)
@ -1080,8 +1159,6 @@
;; --- Shape Movement (using keyboard shorcuts) ;; --- Shape Movement (using keyboard shorcuts)
(declare initial-selection-align) (declare initial-selection-align)
(declare apply-temporal-displacement-in-bulk)
(declare materialize-temporal-modifier-in-bulk)
(defn- get-displacement-with-grid (defn- get-displacement-with-grid
"Retrieve the correct displacement delta point for the "Retrieve the correct displacement delta point for the
@ -1109,6 +1186,9 @@
(s/def ::direction #{:up :down :right :left}) (s/def ::direction #{:up :down :right :left})
(declare apply-displacement-in-bulk)
(declare materialize-displacement-in-bulk)
(defn move-selected (defn move-selected
[direction align?] [direction align?]
(us/verify ::direction direction) (us/verify ::direction direction)
@ -1124,8 +1204,8 @@
displacement (if align? displacement (if align?
(get-displacement-with-grid shape direction options) (get-displacement-with-grid shape direction options)
(get-displacement shape direction))] (get-displacement shape direction))]
(rx/of (apply-temporal-displacement-in-bulk selected displacement) (rx/of (apply-displacement-in-bulk selected displacement)
(materialize-temporal-modifier-in-bulk selected)))))) (materialize-displacement-in-bulk selected))))))
;; --- Delete Selected ;; --- Delete Selected
@ -1289,34 +1369,10 @@
(:y1 sshape))] (:y1 sshape))]
(->> (uwrk/align-point point) (->> (uwrk/align-point point)
(rx/map (fn [{:keys [x y] :as pt}] (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 ;; --- 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 (defn- recalculate-shape-canvas-relation
[state shape] [state shape]
(let [shape' (geom/shape->rect-shape shape) (let [shape' (geom/shape->rect-shape shape)
@ -1330,21 +1386,109 @@
(first))] (first))]
(assoc shape :canvas id))) (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] [ids]
(letfn [(process-shape [state id] (letfn [(process-shape [state id]
(let [shape (get-in state [:workspace-data :shapes-by-id id]) (let [shape (get-in state [:workspace-data :shapes-by-id id])
xfmt (or (:modifier-mtx shape) (gmt/matrix)) modifier (:resize-modifier shape (gmt/matrix))
shape-old (dissoc shape :modifier-mtx)
shape-new (geom/transform shape-old xfmt) shape (-> (dissoc shape :resize-modifier)
shape-new (recalculate-shape-canvas-relation state shape-new)] (geom/transform modifier))
(assoc-in state [:workspace-data :shapes-by-id id] shape-new)))] shape (recalculate-shape-canvas-relation state shape)]
(ptk/reify ::materialize-temporal-modifier-in-bulk (assoc-in state [:workspace-data :shapes-by-id id] shape)))]
(ptk/reify ::materialize-resize-modifier-in-bulk
IBatchedChange IBatchedChange
ptk/UpdateEvent ptk/UpdateEvent
(update [_ state] (update [_ state]
(reduce process-shape state ids))))) (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 (defn commit-changes
([changes undo-changes] (commit-changes changes undo-changes true)) ([changes undo-changes] (commit-changes changes undo-changes true))
([changes undo-changes save-undo?] ([changes undo-changes save-undo?]

View file

@ -2,7 +2,10 @@
;; License, v. 2.0. If a copy of the MPL was not distributed with this ;; 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/. ;; 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 (ns uxbox.main.ui.shapes
(:require (:require
@ -10,25 +13,7 @@
[rumext.alpha :as mf] [rumext.alpha :as mf]
[uxbox.main.refs :as refs] [uxbox.main.refs :as refs]
[uxbox.main.store :as st] [uxbox.main.store :as st]
[uxbox.main.ui.shapes.circle :as circle] [uxbox.main.ui.shapes.canvas :as canvas]))
[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}])))
(def shape-wrapper canvas/shape-wrapper)
(def canvas-wrapper canvas/canvas-wrapper)

View file

@ -2,8 +2,11 @@
;; License, v. 2.0. If a copy of the MPL was not distributed with this ;; 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/. ;; file, You can obtain one at http://mozilla.org/MPL/2.0/.
;; ;;
;; Copyright (c) 2015-2016 Andrey Antukh <niwi@niwi.nz> ;; This Source Code Form is "Incompatible With Secondary Licenses", as
;; Copyright (c) 2015-2016 Juan de la Cruz <delacruzgarciajuan@gmail.com> ;; 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 (ns uxbox.main.ui.shapes.canvas
(:require (:require
@ -13,29 +16,97 @@
[uxbox.main.data.workspace :as dw] [uxbox.main.data.workspace :as dw]
[uxbox.main.geom :as geom] [uxbox.main.geom :as geom]
[uxbox.main.refs :as refs] [uxbox.main.refs :as refs]
[uxbox.main.ui.shapes.common :as common]
[uxbox.main.store :as st] [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.data :refer [parse-int]]
[uxbox.util.dom :as dom] [uxbox.util.dom :as dom]
[uxbox.util.geom.matrix :as gmt]
[uxbox.util.geom.point :as gpt])) [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 (def canvas-default-props
{:fill-color "#ffffff"}) {:fill-color "#ffffff"})
(declare canvas-shape)
(mf/defc canvas-wrapper (mf/defc canvas-wrapper
[{:keys [shape] :as props}] [{:keys [shape childs] :as props}]
(let [selected (mf/deref refs/selected-shapes) (when (and shape (not (:hidden shape)))
selected? (contains? selected (:id shape)) (let [selected (mf/deref refs/selected-shapes)
on-mouse-down #(common/on-mouse-down % shape selected) selected? (contains? selected (:id shape))
shape (merge canvas-default-props shape)] on-mouse-down #(common/on-mouse-down % shape selected)
(letfn [(on-double-click [event] shape (merge canvas-default-props shape)
(dom/prevent-default event)
(st/emit! dw/deselect-all on-double-click
(dw/select-shape (:id shape))))] (fn [event]
[:g.shape {:class (when selected? "selected") (dom/prevent-default event)
:on-double-click on-double-click (st/emit! dw/deselect-all
:on-mouse-down on-mouse-down} (dw/select-shape (:id shape))))]
[:& rect-shape {:shape 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)}])]))

View file

@ -32,28 +32,28 @@
(mf/defc circle-shape (mf/defc circle-shape
[{:keys [shape] :as props}] [{:keys [shape] :as props}]
(let [{:keys [id rotation cx cy modifier-mtx]} shape
shape (cond (let [ds-modifier (:displacement-modifier shape)
(gmt/matrix? modifier-mtx) (geom/transform shape modifier-mtx) rz-modifier (:resize-modifier shape)
:else shape)
center (gpt/point (:cx shape) shape (cond-> shape
(:cy shape)) (gmt/matrix? rz-modifier) (geom/transform rz-modifier)
(gmt/matrix? ds-modifier) (geom/transform ds-modifier))
rotation (or rotation 0) {:keys [id cx cy rx ry rotation]} shape
moving? (boolean modifier-mtx)
center (gpt/point cx cy)
rotation (or rotation 0)
transform (when (pos? rotation) transform (when (pos? rotation)
(str (-> (gmt/matrix) (str (-> (gmt/matrix)
(gmt/rotate rotation center)))) (gmt/rotate rotation center))))
props {:id (str "shape-" id) props (-> (attrs/extract-style-attrs shape)
:class (classnames :move-cursor moving?) (assoc :cx cx
:transform transform} :cy cy
:rx rx
attrs (merge props :ry ry
(attrs/extract-style-attrs shape) :transform transform
(select-keys shape [:cx :cy :rx :ry]))] :id (str "shape-" id)
[:> :ellipse (normalize-props attrs)])) ))]
[:& "elipse" props]))

View file

@ -13,12 +13,15 @@
(:require (:require
[potok.core :as ptk] [potok.core :as ptk]
[beicon.core :as rx] [beicon.core :as rx]
[uxbox.common.data :as d]
[uxbox.common.spec :as us]
[uxbox.main.data.workspace :as dw] [uxbox.main.data.workspace :as dw]
[uxbox.main.refs :as refs] [uxbox.main.refs :as refs]
[uxbox.main.store :as st] [uxbox.main.store :as st]
[uxbox.main.ui.keyboard :as kbd] [uxbox.main.ui.keyboard :as kbd]
[uxbox.main.streams :as uws] [uxbox.main.streams :as uws]
[uxbox.main.workers :as uwrk] [uxbox.main.workers :as uwrk]
[uxbox.main.geom :as geom]
[uxbox.util.geom.matrix :as gmt] [uxbox.util.geom.matrix :as gmt]
[uxbox.util.geom.point :as gpt] [uxbox.util.geom.point :as gpt]
[uxbox.util.dom :as dom])) [uxbox.util.dom :as dom]))
@ -34,14 +37,93 @@
stoper (rx/filter uws/mouse-up? stream) stoper (rx/filter uws/mouse-up? stream)
position @uws/mouse-position] position @uws/mouse-position]
(rx/concat (rx/concat
;; (when (refs/alignment-activated? flags)
;; (rx/of (dw/initial-selection-align selected)))
(->> (uws/mouse-position-deltas position) (->> (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/take-until stoper))
(rx/of (dw/materialize-temporal-modifier-in-bulk selected) (rx/of (dw/materialize-displacement-in-bulk selected)
::dw/page-data-update)))))) ::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 (defn on-mouse-down
[event {:keys [id type] :as shape} selected] [event {:keys [id type] :as shape} selected]
(let [selected? (contains? selected id) (let [selected? (contains? selected id)
@ -54,7 +136,7 @@
(= type :canvas) (= type :canvas)
(when selected? (when selected?
(dom/stop-propagation event) (dom/stop-propagation event)
(st/emit! start-move-selected)) (st/emit! start-move-canvas))
(and (not selected?) (empty? selected)) (and (not selected?) (empty? selected))
(do (do

View file

@ -34,13 +34,14 @@
(mf/defc icon-shape (mf/defc icon-shape
[{:keys [shape] :as props}] [{: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 shape (cond-> shape
(gmt/matrix? modifier-mtx) (geom/transform shape modifier-mtx) (gmt/matrix? rz-modifier) (geom/transform rz-modifier)
:else shape) (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)) transform (when (and rotation (pos? rotation))
(str/format "rotate(%s %s %s)" (str/format "rotate(%s %s %s)"
@ -48,7 +49,6 @@
(+ x (/ width 2)) (+ x (/ width 2))
(+ y (/ height 2)))) (+ y (/ height 2))))
view-box (apply str (interpose " " (:view-box metadata))) view-box (apply str (interpose " " (:view-box metadata)))
props (-> (attrs/extract-style-attrs shape) props (-> (attrs/extract-style-attrs shape)

View file

@ -33,13 +33,14 @@
(mf/defc image-shape (mf/defc image-shape
[{:keys [shape] :as props}] [{: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 shape (cond-> shape
(gmt/matrix? modifier-mtx) (geom/transform shape modifier-mtx) (gmt/matrix? rz-modifier) (geom/transform rz-modifier)
:else shape) (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)) transform (when (and rotation (pos? rotation))
(str/format "rotate(%s %s %s)" (str/format "rotate(%s %s %s)"

View file

@ -61,14 +61,14 @@
(mf/defc path-shape (mf/defc path-shape
[{:keys [shape background?] :as props}] [{:keys [shape background?] :as props}]
(let [modifier-mtx (:modifier-mtx shape) (let [ds-modifier (:displacement-modifier shape)
rotation (:rotation shape) rz-modifier (:resize-modifier shape)
shape (cond shape (cond-> shape
(gmt/matrix? modifier-mtx) (geom/transform shape modifier-mtx) (gmt/matrix? rz-modifier) (geom/transform rz-modifier)
:else shape) (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)) transform (when (and rotation (pos? rotation))
(str/format "rotate(%s %s %s)" (str/format "rotate(%s %s %s)"

View file

@ -34,13 +34,14 @@
(mf/defc rect-shape (mf/defc rect-shape
[{:keys [shape] :as props}] [{:keys [shape] :as props}]
(let [{:keys [id rotation modifier-mtx]} shape (let [ds-modifier (:displacement-modifier shape)
rz-modifier (:resize-modifier shape)
shape (cond shape (cond-> shape
(gmt/matrix? modifier-mtx) (geom/transform shape modifier-mtx) (gmt/matrix? rz-modifier) (geom/transform rz-modifier)
:else shape) (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)) transform (when (and rotation (pos? rotation))
(str/format "rotate(%s %s %s)" (str/format "rotate(%s %s %s)"

View file

@ -120,7 +120,7 @@
result (geom/resize-shape :bottom-right shape' point lock?) result (geom/resize-shape :bottom-right shape' point lock?)
scale (geom/calculate-scale-ratio shape' result) scale (geom/calculate-scale-ratio shape' result)
mtx (geom/generate-resize-matrix :bottom-right shape' scale)] 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-drawing [state point lock?]
(update-in state [:workspace-local :drawing] resize-shape point lock?))] (update-in state [:workspace-local :drawing] resize-shape point lock?))]
@ -273,11 +273,11 @@
(rx/concat (rx/concat
(rx/of dw/clear-drawing) (rx/of dw/clear-drawing)
(when (::initialized? shape) (when (::initialized? shape)
(let [modifier-mtx (:modifier-mtx shape) (let [modifier (:resize-modifier shape)
shape (if (gmt/matrix? modifier-mtx) shape (if (gmt/matrix? modifier)
(geom/transform shape modifier-mtx) (geom/transform shape modifier)
shape) shape)
shape (dissoc shape ::initialized? :modifier-mtx)] shape (dissoc shape ::initialized? :resize-modifier)]
;; Add & select the created shape to the workspace ;; Add & select the created shape to the workspace
(rx/of dw/deselect-all (rx/of dw/deselect-all
(if (= :canvas (:type shape)) (if (= :canvas (:type shape))

View file

@ -35,7 +35,7 @@
(let [result (geom/resize-shape vid shape point lock?) (let [result (geom/resize-shape vid shape point lock?)
scale (geom/calculate-scale-ratio shape result) scale (geom/calculate-scale-ratio shape result)
mtx (geom/generate-resize-matrix vid shape scale)] 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 ;; Unifies the instantaneous proportion lock modifier
;; activated by Ctrl key and the shapes own proportion ;; activated by Ctrl key and the shapes own proportion
@ -64,8 +64,7 @@
(rx/map normalize-proportion-lock) (rx/map normalize-proportion-lock)
(rx/mapcat (partial resize shape)) (rx/mapcat (partial resize shape))
(rx/take-until stoper)) (rx/take-until stoper))
(rx/of (dw/materialize-temporal-modifier-in-bulk ids) (rx/of (dw/materialize-resize-modifier-in-bulk ids))))))))
::dw/page-data-update)))))))
(defn start-rotate (defn start-rotate
[shape] [shape]
@ -261,9 +260,13 @@
(st/emit! (start-resize %1 #{(:id shape)} shape))) (st/emit! (start-resize %1 #{(:id shape)} shape)))
on-rotate #(do (dom/stop-propagation %) on-rotate #(do (dom/stop-propagation %)
(st/emit! (start-rotate shape))) (st/emit! (start-rotate shape)))
modifier (:modifier-mtx shape)
shape (-> (geom/shape->rect-shape shape) ds-modifier (:displacement-modifier shape)
(geom/transform (or modifier (gmt/matrix))))] 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 [:& controls {:shape shape
:zoom zoom :zoom zoom
:on-rotate on-rotate :on-rotate on-rotate

View file

@ -23,7 +23,7 @@
[uxbox.main.ui.workspace.ruler :refer [ruler]] [uxbox.main.ui.workspace.ruler :refer [ruler]]
[uxbox.main.ui.workspace.drawarea :refer [start-drawing]] [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.drawarea :refer [draw-area]]
[uxbox.main.ui.workspace.selection :refer [selection-handlers]] [uxbox.main.ui.workspace.selection :refer [selection-handlers]]
@ -149,11 +149,14 @@
(let [data (mf/deref refs/workspace-data) (let [data (mf/deref refs/workspace-data)
shapes-by-id (:shapes-by-id data) shapes-by-id (:shapes-by-id data)
shapes (map #(get shapes-by-id %) (:shapes 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 [:g.shapes
(for [item canvas] (for [item canvas]
[:& shape-wrapper {:shape item :key (:id item)}]) (let [shapes (filter #(= (:canvas %) (:id item)) shapes)]
(for [item shapes] [:& canvas-wrapper {:shape item :key (:id item)
:childs shapes}]))
(for [item unassinged]
[:& shape-wrapper {:shape item :key (:id item)}])])) [:& shape-wrapper {:shape item :key (:id item)}])]))
(mf/defc viewport (mf/defc viewport