mirror of
https://github.com/penpot/penpot.git
synced 2025-05-24 00:46:10 +02:00
🚧 Experimenting with some performance improvements.
This commit is contained in:
parent
31ffa73bda
commit
4cf7a48567
16 changed files with 299 additions and 267 deletions
|
@ -10,8 +10,8 @@
|
||||||
funcool/beicon {:mvn/version "5.1.0"}
|
funcool/beicon {:mvn/version "5.1.0"}
|
||||||
funcool/cuerdas {:mvn/version "2.2.0"}
|
funcool/cuerdas {:mvn/version "2.2.0"}
|
||||||
funcool/lentes {:mvn/version "1.3.0-SNAPSHOT"}
|
funcool/lentes {:mvn/version "1.3.0-SNAPSHOT"}
|
||||||
funcool/potok {:mvn/version "2.5.0"}
|
funcool/potok {:mvn/version "2.6.0"}
|
||||||
funcool/promesa {:mvn/version "3.0.0-SNAPSHOT"}
|
funcool/promesa {:mvn/version "4.0.0-SNAPSHOT"}
|
||||||
funcool/rumext {:mvn/version "2.0.0-SNAPSHOT"}
|
funcool/rumext {:mvn/version "2.0.0-SNAPSHOT"}
|
||||||
}
|
}
|
||||||
:paths ["src" "vendor" "resources"]
|
:paths ["src" "vendor" "resources"]
|
||||||
|
|
|
@ -27,10 +27,7 @@
|
||||||
|
|
||||||
(defn logged-in
|
(defn logged-in
|
||||||
[data]
|
[data]
|
||||||
(reify
|
(ptk/reify ::logged-in
|
||||||
ptk/EventType
|
|
||||||
(type [_] ::logged-in)
|
|
||||||
|
|
||||||
ptk/UpdateEvent
|
ptk/UpdateEvent
|
||||||
(update [this state]
|
(update [this state]
|
||||||
(assoc state :auth data))
|
(assoc state :auth data))
|
||||||
|
|
|
@ -153,13 +153,10 @@
|
||||||
[id pages]
|
[id pages]
|
||||||
(s/assert ::us/uuid id)
|
(s/assert ::us/uuid id)
|
||||||
(s/assert ::us/coll pages)
|
(s/assert ::us/coll pages)
|
||||||
(reify
|
(ptk/reify ::page-fetched
|
||||||
IDeref
|
IDeref
|
||||||
(-deref [_] (list id pages))
|
(-deref [_] (list id pages))
|
||||||
|
|
||||||
ptk/EventType
|
|
||||||
(type [_] ::page-fetched)
|
|
||||||
|
|
||||||
ptk/UpdateEvent
|
ptk/UpdateEvent
|
||||||
(update [_ state]
|
(update [_ state]
|
||||||
(let [get-order #(get-in % [:metadata :order])
|
(let [get-order #(get-in % [:metadata :order])
|
||||||
|
@ -262,13 +259,10 @@
|
||||||
(defn page-persisted
|
(defn page-persisted
|
||||||
[data]
|
[data]
|
||||||
(s/assert ::server-page data)
|
(s/assert ::server-page data)
|
||||||
(reify
|
(ptk/reify ::page-persisted
|
||||||
cljs.core/IDeref
|
cljs.core/IDeref
|
||||||
(-deref [_] data)
|
(-deref [_] data)
|
||||||
|
|
||||||
ptk/EventType
|
|
||||||
(type [_] ::page-persisted)
|
|
||||||
|
|
||||||
ptk/UpdateEvent
|
ptk/UpdateEvent
|
||||||
(update [_ state]
|
(update [_ state]
|
||||||
(let [{:keys [id version]} data]
|
(let [{:keys [id version]} data]
|
||||||
|
@ -283,24 +277,19 @@
|
||||||
;; --- Persist Page
|
;; --- Persist Page
|
||||||
|
|
||||||
(defn persist-page
|
(defn persist-page
|
||||||
([id] (persist-page id identity))
|
[id]
|
||||||
([id on-success]
|
(s/assert ::us/uuid id)
|
||||||
(assert (uuid? id))
|
(ptk/reify ::persist-page
|
||||||
(reify
|
ptk/WatchEvent
|
||||||
ptk/EventType
|
(watch [this state s]
|
||||||
(type [_] ::persist-page)
|
(let [page (get-in state [:pages id])]
|
||||||
|
(if (:history page)
|
||||||
ptk/WatchEvent
|
(rx/empty)
|
||||||
(watch [this state s]
|
(let [page (pack-page state id)]
|
||||||
(let [page (get-in state [:pages id])]
|
(->> (rp/req :update/page page)
|
||||||
(if (:history page)
|
(rx/map :payload)
|
||||||
(rx/empty)
|
(rx/map page-persisted)
|
||||||
(let [page (pack-page state id)]
|
(rx/catch (fn [err] (rx/of ::page-persist-error))))))))))
|
||||||
(->> (rp/req :update/page page)
|
|
||||||
(rx/map :payload)
|
|
||||||
(rx/map page-persisted)
|
|
||||||
(rx/catch (fn [err] (rx/of ::page-persist-error)))))))))))
|
|
||||||
|
|
||||||
|
|
||||||
(defn persist-page?
|
(defn persist-page?
|
||||||
[v]
|
[v]
|
||||||
|
@ -314,10 +303,7 @@
|
||||||
(defn metadata-persisted
|
(defn metadata-persisted
|
||||||
[{:keys [id] :as data}]
|
[{:keys [id] :as data}]
|
||||||
(s/assert ::metadata-persisted-params data)
|
(s/assert ::metadata-persisted-params data)
|
||||||
(reify
|
(ptk/reify ::metadata-persisted
|
||||||
ptk/EventType
|
|
||||||
(type [_] ::metadata-persisted)
|
|
||||||
|
|
||||||
ptk/UpdateEvent
|
ptk/UpdateEvent
|
||||||
(update [_ state]
|
(update [_ state]
|
||||||
(assoc-in state [:pages id :version] (:version data)))))
|
(assoc-in state [:pages id :version] (:version data)))))
|
||||||
|
@ -335,8 +321,8 @@
|
||||||
|
|
||||||
(defn persist-metadata
|
(defn persist-metadata
|
||||||
[id]
|
[id]
|
||||||
{:pre [(uuid? id)]}
|
(s/assert ::us/uuid id)
|
||||||
(reify
|
(ptk/reify ::persist-metadata
|
||||||
ptk/WatchEvent
|
ptk/WatchEvent
|
||||||
(watch [_ state stream]
|
(watch [_ state stream]
|
||||||
(let [page (get-in state [:pages id])]
|
(let [page (get-in state [:pages id])]
|
||||||
|
@ -349,7 +335,7 @@
|
||||||
(defn update-page-attrs
|
(defn update-page-attrs
|
||||||
[{:keys [id] :as data}]
|
[{:keys [id] :as data}]
|
||||||
(s/assert ::page-entity data)
|
(s/assert ::page-entity data)
|
||||||
(reify
|
(ptk/reify
|
||||||
IPageUpdate
|
IPageUpdate
|
||||||
ptk/UpdateEvent
|
ptk/UpdateEvent
|
||||||
(update [_ state]
|
(update [_ state]
|
||||||
|
@ -446,6 +432,5 @@
|
||||||
(->> (rx/filter metadata-persisted? stream)
|
(->> (rx/filter metadata-persisted? stream)
|
||||||
(rx/take 1)
|
(rx/take 1)
|
||||||
(rx/ignore))))))
|
(rx/ignore))))))
|
||||||
(rx/take-until stopper)
|
(rx/take-until stopper))))))
|
||||||
(rx/retry 10000))))))
|
|
||||||
|
|
||||||
|
|
|
@ -188,31 +188,16 @@
|
||||||
(defn dissoc-from-index
|
(defn dissoc-from-index
|
||||||
"A function that dissoc shape from the indexed
|
"A function that dissoc shape from the indexed
|
||||||
data structure of shapes from the state."
|
data structure of shapes from the state."
|
||||||
[state {:keys [id type] :as shape}]
|
[state shape]
|
||||||
(if (= :group type)
|
(update state :shapes dissoc (:id shape)))
|
||||||
(let [items (map #(get-in state [:shapes %]) (:items shape))]
|
|
||||||
(as-> state $
|
|
||||||
(update-in $ [:shapes] dissoc id)
|
|
||||||
(reduce dissoc-from-index $ items)))
|
|
||||||
(update-in state [:shapes] dissoc id)))
|
|
||||||
|
|
||||||
(defn dissoc-from-page
|
(defn dissoc-from-page
|
||||||
"Given a shape, try to remove its reference from the
|
"Given a shape, try to remove its reference from the
|
||||||
corresponding page."
|
corresponding page."
|
||||||
[state {:keys [id page] :as shape}]
|
[state {:keys [id page] :as shape}]
|
||||||
(as-> (get-in state [:pages page :shapes]) $
|
;; TODO: handle canvas special case
|
||||||
(into [] (remove #(= % id) $))
|
(update-in state [:pages page :shapes]
|
||||||
(assoc-in state [:pages page :shapes] $)))
|
(fn [items] (vec (remove #(= % id) items)))))
|
||||||
|
|
||||||
(defn dissoc-from-group
|
|
||||||
"Given a shape, try to remove its reference from the
|
|
||||||
corresponding group (only if it belongs to one group)."
|
|
||||||
[state {:keys [id group] :as shape}]
|
|
||||||
(if-let [group' (get-in state [:shapes group])]
|
|
||||||
(as-> (:items group') $
|
|
||||||
(into [] (remove #(= % id) $))
|
|
||||||
(assoc-in state [:shapes group :items] $))
|
|
||||||
state))
|
|
||||||
|
|
||||||
(declare dissoc-shape)
|
(declare dissoc-shape)
|
||||||
|
|
||||||
|
@ -234,11 +219,9 @@
|
||||||
(defn dissoc-shape
|
(defn dissoc-shape
|
||||||
"Given a shape, removes it from the state."
|
"Given a shape, removes it from the state."
|
||||||
[state shape]
|
[state shape]
|
||||||
(as-> state $
|
(-> state
|
||||||
(dissoc-from-page $ shape)
|
(dissoc-from-page shape)
|
||||||
(dissoc-from-group $ shape)
|
(dissoc-from-index shape)))
|
||||||
(dissoc-from-index $ shape)
|
|
||||||
(clear-empty-groups $ shape)))
|
|
||||||
|
|
||||||
;; --- Shape Movements
|
;; --- Shape Movements
|
||||||
|
|
||||||
|
@ -265,8 +248,7 @@
|
||||||
:last (- (count shapes) 1))
|
:last (- (count shapes) 1))
|
||||||
|
|
||||||
state (-> state
|
state (-> state
|
||||||
(dissoc-from-page shape)
|
(dissoc-from-page shape))
|
||||||
(dissoc-from-group shape))
|
|
||||||
|
|
||||||
shapes (if group
|
shapes (if group
|
||||||
(get-in state [:shapes group :items])
|
(get-in state [:shapes group :items])
|
||||||
|
@ -293,8 +275,7 @@
|
||||||
source (get-in state [:shapes sid])
|
source (get-in state [:shapes sid])
|
||||||
|
|
||||||
state (-> state
|
state (-> state
|
||||||
(dissoc-from-page source)
|
(dissoc-from-page source))
|
||||||
(dissoc-from-group source))
|
|
||||||
|
|
||||||
shapes (if group
|
shapes (if group
|
||||||
(get-in state [:shapes group :items])
|
(get-in state [:shapes group :items])
|
||||||
|
@ -323,8 +304,7 @@
|
||||||
{:pre [(not= tid sid)]}
|
{:pre [(not= tid sid)]}
|
||||||
(let [source (get-in state [:shapes sid])
|
(let [source (get-in state [:shapes sid])
|
||||||
state (-> state
|
state (-> state
|
||||||
(dissoc-from-page source)
|
(dissoc-from-page source))
|
||||||
(dissoc-from-group source))
|
|
||||||
shapes (get-in state [:shapes tid :items])]
|
shapes (get-in state [:shapes tid :items])]
|
||||||
(if (seq shapes)
|
(if (seq shapes)
|
||||||
(as-> state $
|
(as-> state $
|
||||||
|
|
|
@ -25,9 +25,13 @@
|
||||||
[uxbox.util.geom.point :as gpt]
|
[uxbox.util.geom.point :as gpt]
|
||||||
[uxbox.util.math :as mth]
|
[uxbox.util.math :as mth]
|
||||||
[uxbox.util.spec :as us]
|
[uxbox.util.spec :as us]
|
||||||
|
[uxbox.util.perf :as perf]
|
||||||
[uxbox.util.time :as dt]
|
[uxbox.util.time :as dt]
|
||||||
[uxbox.util.uuid :as uuid]))
|
[uxbox.util.uuid :as uuid]))
|
||||||
|
|
||||||
|
(s/def ::set-of-uuid
|
||||||
|
(s/every ::us/uuid :kind set?))
|
||||||
|
|
||||||
;; --- Expose inner functions
|
;; --- Expose inner functions
|
||||||
|
|
||||||
(def start-ruler nil)
|
(def start-ruler nil)
|
||||||
|
@ -338,6 +342,8 @@
|
||||||
;; Shapes events
|
;; Shapes events
|
||||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||||
|
|
||||||
|
;; TODO: add spec
|
||||||
|
|
||||||
(defn add-shape
|
(defn add-shape
|
||||||
[data]
|
[data]
|
||||||
(reify
|
(reify
|
||||||
|
@ -352,14 +358,24 @@
|
||||||
|
|
||||||
(defn delete-shape
|
(defn delete-shape
|
||||||
[id]
|
[id]
|
||||||
{:pre [(uuid? id)]}
|
(s/assert ::us/uuid id)
|
||||||
(reify
|
(ptk/reify ::delete-shape
|
||||||
udp/IPageUpdate
|
udp/IPageUpdate
|
||||||
ptk/UpdateEvent
|
ptk/UpdateEvent
|
||||||
(update [_ state]
|
(update [_ state]
|
||||||
(let [shape (get-in state [:shapes id])]
|
(let [shape (get-in state [:shapes id])]
|
||||||
(ds/dissoc-shape state shape)))))
|
(ds/dissoc-shape state shape)))))
|
||||||
|
|
||||||
|
(defn delete-many-shapes
|
||||||
|
[ids]
|
||||||
|
(s/assert ::us/set ids)
|
||||||
|
(ptk/reify ::delete-many-shapes
|
||||||
|
udp/IPageUpdate
|
||||||
|
ptk/UpdateEvent
|
||||||
|
(update [_ state]
|
||||||
|
(reduce ds/dissoc-shape state
|
||||||
|
(map #(get-in state [:shapes %]) ids)))))
|
||||||
|
|
||||||
(defrecord SelectShape [id]
|
(defrecord SelectShape [id]
|
||||||
ptk/UpdateEvent
|
ptk/UpdateEvent
|
||||||
(update [_ state]
|
(update [_ state]
|
||||||
|
@ -385,10 +401,7 @@
|
||||||
(let [pid (get-in state [:workspace :current])]
|
(let [pid (get-in state [:workspace :current])]
|
||||||
(update-in state [:workspace pid] #(-> %
|
(update-in state [:workspace pid] #(-> %
|
||||||
(assoc :selected #{})
|
(assoc :selected #{})
|
||||||
(dissoc :selected-canvas)))))
|
(dissoc :selected-canvas))))))
|
||||||
ptk/WatchEvent
|
|
||||||
(watch [_ state stream]
|
|
||||||
(rx/just :interrupt)))
|
|
||||||
|
|
||||||
(defn deselect-all
|
(defn deselect-all
|
||||||
"Clear all possible state of drawing, edition
|
"Clear all possible state of drawing, edition
|
||||||
|
@ -398,22 +411,18 @@
|
||||||
|
|
||||||
;; --- Select First Shape
|
;; --- Select First Shape
|
||||||
|
|
||||||
(deftype SelectFirstShape []
|
(def select-first-shape
|
||||||
ptk/UpdateEvent
|
(ptk/reify ::select-first-shape
|
||||||
(update [_ state]
|
ptk/UpdateEvent
|
||||||
(let [pid (get-in state [:workspace :current])
|
(update [_ state]
|
||||||
sid (first (get-in state [:pages pid :shapes]))]
|
(let [pid (get-in state [:workspace :current])
|
||||||
(assoc-in state [:workspace pid :selected] #{sid}))))
|
sid (first (get-in state [:pages pid :shapes]))]
|
||||||
|
(assoc-in state [:workspace pid :selected] #{sid})))))
|
||||||
(defn select-first-shape
|
|
||||||
"Mark a shape selected for drawing."
|
|
||||||
[]
|
|
||||||
(SelectFirstShape.))
|
|
||||||
|
|
||||||
;; --- Select Shapes (By selrect)
|
;; --- Select Shapes (By selrect)
|
||||||
|
|
||||||
(def select-shapes-by-current-selrect
|
(def select-shapes-by-current-selrect
|
||||||
(reify
|
(ptk/reify ::select-shapes-by-current-selrect
|
||||||
ptk/UpdateEvent
|
ptk/UpdateEvent
|
||||||
(update [_ state]
|
(update [_ state]
|
||||||
(let [pid (get-in state [:workspace :current])
|
(let [pid (get-in state [:workspace :current])
|
||||||
|
@ -471,11 +480,9 @@
|
||||||
:fast (gpt/point (if align? (* 3 gx) 10)
|
:fast (gpt/point (if align? (* 3 gx) 10)
|
||||||
(if align? (* 3 gy) 10))}))
|
(if align? (* 3 gy) 10))}))
|
||||||
|
|
||||||
(declare initial-shape-align)
|
(declare initial-selection-align)
|
||||||
(declare apply-displacement)
|
(declare materialize-current-modifier-in-bulk)
|
||||||
(declare assoc-temporal-modifier)
|
(declare apply-temporal-displacement-in-bulk)
|
||||||
(declare materialize-current-modifier)
|
|
||||||
(declare apply-temporal-displacement)
|
|
||||||
|
|
||||||
(s/def ::direction #{:up :down :right :left})
|
(s/def ::direction #{:up :down :right :left})
|
||||||
(s/def ::speed #{:std :fast})
|
(s/def ::speed #{:std :fast})
|
||||||
|
@ -497,11 +504,9 @@
|
||||||
displacement (get-displacement direction speed distance)]
|
displacement (get-displacement direction speed distance)]
|
||||||
(rx/concat
|
(rx/concat
|
||||||
(when align?
|
(when align?
|
||||||
(rx/concat
|
(rx/of (initial-selection-align selected)))
|
||||||
(rx/from-coll (map initial-shape-align selected))
|
(rx/of (apply-temporal-displacement-in-bulk selected displacement))
|
||||||
(rx/from-coll (map apply-displacement selected))))
|
(rx/of (materialize-current-modifier-in-bulk selected)))))))
|
||||||
(rx/from-coll (map #(apply-temporal-displacement % displacement) selected))
|
|
||||||
(rx/from-coll (map materialize-current-modifier selected)))))))
|
|
||||||
|
|
||||||
;; --- Move Selected Layer
|
;; --- Move Selected Layer
|
||||||
|
|
||||||
|
@ -539,8 +544,7 @@
|
||||||
(watch [_ state stream]
|
(watch [_ state stream]
|
||||||
(let [id (get-in state [:workspace :current])
|
(let [id (get-in state [:workspace :current])
|
||||||
selected (get-in state [:workspace id :selected])]
|
selected (get-in state [:workspace id :selected])]
|
||||||
(rx/from-coll
|
(rx/of (delete-many-shapes selected))))))
|
||||||
(into [(deselect-all)] (map #(delete-shape %) selected)))))))
|
|
||||||
|
|
||||||
;; --- Rename Shape
|
;; --- Rename Shape
|
||||||
|
|
||||||
|
@ -584,56 +588,71 @@
|
||||||
canvas (vec (concat before [id] after))]
|
canvas (vec (concat before [id] after))]
|
||||||
(assoc-in state [:pages page-id :canvas] canvas)))))
|
(assoc-in state [:pages page-id :canvas] canvas)))))
|
||||||
|
|
||||||
;; --- Shape Transformations
|
;; --- Shape / Selection Alignment
|
||||||
|
|
||||||
(defn initial-shape-align
|
(defn initial-selection-align
|
||||||
[id]
|
"Align the selection of shapes."
|
||||||
{:pre [(uuid? id)]}
|
[ids]
|
||||||
(reify
|
(s/assert ::set-of-uuid ids)
|
||||||
ptk/WatchEvent
|
(ptk/reify ::initialize-shapes-align-in-bulk
|
||||||
(watch [_ state s]
|
|
||||||
(let [{:keys [x1 y1] :as shape} (->> (get-in state [:shapes id])
|
|
||||||
(geom/shape->rect-shape state))
|
|
||||||
point (gpt/point x1 y1)]
|
|
||||||
(->> (uwrk/align-point point)
|
|
||||||
(rx/map (fn [{:keys [x y] :as pt}]
|
|
||||||
(apply-temporal-displacement id (gpt/subtract pt point)))))))))
|
|
||||||
|
|
||||||
|
|
||||||
;; --- Apply Temporal Displacement
|
|
||||||
|
|
||||||
(defn apply-temporal-displacement
|
|
||||||
[id delta]
|
|
||||||
{:pre [(uuid? id) (gpt/point? delta)]}
|
|
||||||
(reify
|
|
||||||
ptk/WatchEvent
|
ptk/WatchEvent
|
||||||
(watch [_ state stream]
|
(watch [_ state stream]
|
||||||
(let [prev (get-in state [:shapes id :modifier-mtx] (gmt/matrix))
|
(let [shapes-by-id (:shapes state)
|
||||||
curr (gmt/translate prev delta)]
|
shapes (mapv #(get shapes-by-id %) ids)
|
||||||
(rx/of (assoc-temporal-modifier id curr))))))
|
sshape (geom/shapes->rect-shape shapes)
|
||||||
|
point (gpt/point (:x1 sshape)
|
||||||
|
(:y1 sshape))]
|
||||||
|
(->> (uwrk/align-point point)
|
||||||
|
(rx/map (fn [{:keys [x y] :as pt}]
|
||||||
|
(apply-temporal-displacement-in-bulk ids (gpt/subtract pt point)))))))))
|
||||||
|
|
||||||
|
;; --- Temportal displacement for Shape / Selection
|
||||||
|
|
||||||
|
;; TODO: this can be done in more performant way using transients
|
||||||
|
|
||||||
|
(defn apply-temporal-displacement-in-bulk
|
||||||
|
"Apply the same displacement delta to all shapes identified by the
|
||||||
|
set if ids."
|
||||||
|
[ids delta]
|
||||||
|
(s/assert ::set-of-uuid ids)
|
||||||
|
(s/assert gpt/point? delta)
|
||||||
|
(letfn [(process-shape [state id]
|
||||||
|
(let [prev (get-in state [:shapes id :modifier-mtx] (gmt/matrix))
|
||||||
|
xfmt (gmt/translate prev delta)]
|
||||||
|
(assoc-in state [:shapes id :modifier-mtx] xfmt)))]
|
||||||
|
(ptk/reify ::apply-temporal-displacement-in-bulk
|
||||||
|
ptk/UpdateEvent
|
||||||
|
(update [_ state]
|
||||||
|
(perf/with-measure ::apply-temporal-displacement-in-bulk
|
||||||
|
(reduce process-shape state ids))))))
|
||||||
|
|
||||||
;; --- Modifiers
|
;; --- Modifiers
|
||||||
|
|
||||||
(defn assoc-temporal-modifier
|
(defn assoc-temporal-modifier-in-bulk
|
||||||
[id xfmt]
|
[ids xfmt]
|
||||||
{:pre [(uuid? id)
|
(s/assert ::set-of-uuid ids)
|
||||||
(gmt/matrix? xfmt)]}
|
(s/assert gmt/matrix? xfmt)
|
||||||
(reify
|
(ptk/reify ::assoc-temporal-modifier-in-bulk
|
||||||
ptk/UpdateEvent
|
ptk/UpdateEvent
|
||||||
(update [_ state]
|
(update [_ state]
|
||||||
(assoc-in state [:shapes id :modifier-mtx] xfmt))))
|
(reduce #(assoc-in %1 [:shapes %2 :modifier-mtx] xfmt) state ids))))
|
||||||
|
|
||||||
(defn materialize-current-modifier
|
(defn materialize-current-modifier-in-bulk
|
||||||
[id]
|
[ids]
|
||||||
{:pre [(uuid? id)]}
|
(s/assert ::us/set ids)
|
||||||
(reify
|
(letfn [(process-shape [state id]
|
||||||
ptk/WatchEvent
|
(let [xfmt (get-in state [:shapes id :modifier-mtx])]
|
||||||
(watch [_ state stream]
|
(if (gmt/matrix? xfmt)
|
||||||
(let [xfmt (get-in state [:shapes id :modifier-mtx])]
|
(-> state
|
||||||
(when (gmt/matrix? xfmt)
|
(update-in [:shapes id] geom/transform xfmt)
|
||||||
(rx/of #(update-in % [:shapes id] geom/transform xfmt)
|
(update-in [:shapes id] dissoc :modifier-mtx))
|
||||||
#(update-in % [:shapes id] dissoc :modifier-mtx)
|
state)))]
|
||||||
::udp/page-update))))))
|
(ptk/reify ::materialize-current-modifier-in-bulk
|
||||||
|
udp/IPageUpdate
|
||||||
|
ptk/UpdateEvent
|
||||||
|
(update [_ state]
|
||||||
|
(perf/with-measure ::materialize-current-modifier-in-bulk
|
||||||
|
(reduce process-shape state ids))))))
|
||||||
|
|
||||||
(defn rehash-shape-relationship
|
(defn rehash-shape-relationship
|
||||||
"Checks shape overlaping with existing canvas, if one or more
|
"Checks shape overlaping with existing canvas, if one or more
|
||||||
|
@ -644,10 +663,7 @@
|
||||||
(let [shape1 (geom/shape->rect-shape canvas)
|
(let [shape1 (geom/shape->rect-shape canvas)
|
||||||
shape2 (geom/shape->rect-shape shape)]
|
shape2 (geom/shape->rect-shape shape)]
|
||||||
(geom/overlaps? shape1 shape2)))]
|
(geom/overlaps? shape1 shape2)))]
|
||||||
(reify
|
(ptk/reify ::rehash-shape-relationship
|
||||||
ptk/EventType
|
|
||||||
(type [_] ::rehash-shape-relationship)
|
|
||||||
|
|
||||||
ptk/UpdateEvent
|
ptk/UpdateEvent
|
||||||
(update [_ state]
|
(update [_ state]
|
||||||
(let [shape (get-in state [:shapes id])
|
(let [shape (get-in state [:shapes id])
|
||||||
|
@ -945,38 +961,36 @@
|
||||||
;; Canvas Interactions
|
;; Canvas Interactions
|
||||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||||
|
|
||||||
;; ;; --- Group Collapsing
|
|
||||||
|
|
||||||
;; (deftype CollapseGroupShape [id]
|
|
||||||
;; udp/IPageUpdate
|
|
||||||
;; ptk/UpdateEvent
|
|
||||||
;; (update [_ state]
|
|
||||||
;; (update-in state [:shapes id] assoc :collapsed true)))
|
|
||||||
|
|
||||||
;; (defn collapse-shape
|
|
||||||
;; [id]
|
|
||||||
;; {:pre [(uuid? id)]}
|
|
||||||
;; (CollapseGroupShape. id))
|
|
||||||
|
|
||||||
;; (deftype UncollapseGroupShape [id]
|
|
||||||
;; udp/IPageUpdate
|
|
||||||
;; ptk/UpdateEvent
|
|
||||||
;; (update [_ state]
|
|
||||||
;; (update-in state [:shapes id] assoc :collapsed false)))
|
|
||||||
|
|
||||||
;; (defn uncollapse-shape
|
|
||||||
;; [id]
|
|
||||||
;; {:pre [(uuid? id)]}
|
|
||||||
;; (UncollapseGroupShape. id))
|
|
||||||
|
|
||||||
(defn select-canvas
|
(defn select-canvas
|
||||||
[id]
|
[id]
|
||||||
(reify
|
(s/assert ::us/uuid id)
|
||||||
|
(ptk/reify ::select-canvas
|
||||||
ptk/UpdateEvent
|
ptk/UpdateEvent
|
||||||
(update [_ state]
|
(update [_ state]
|
||||||
(let [pid (get-in state [:workspace :current])]
|
(let [pid (get-in state [:workspace :current])]
|
||||||
(update-in state [:workspace pid] assoc :selected-canvas id)))))
|
(update-in state [:workspace pid] assoc :selected-canvas id)))))
|
||||||
|
|
||||||
|
;; (defn watch-page-changes
|
||||||
|
;; [id]
|
||||||
|
;; (s/assert ::us/uuid id)
|
||||||
|
;; (ptk/reify ::watch-page-changes
|
||||||
|
;; ptk/WatchEvent
|
||||||
|
;; (watch [_ state stream]
|
||||||
|
;; (let [stopper (rx/filter #(= % ::stop-page-watcher) stream)]
|
||||||
|
;; (->> (rx/merge
|
||||||
|
;; (->> stream
|
||||||
|
;; (rx/filter #(or (satisfies? IPageUpdate %)
|
||||||
|
;; (= ::page-update %)))
|
||||||
|
;; (rx/map #(rehash-shape-relationship
|
||||||
|
;; (->> stream
|
||||||
|
;; (rx/filter #(satisfies? IMetadataUpdate %))
|
||||||
|
;; (rx/debounce 1000)
|
||||||
|
;; (rx/mapcat #(rx/merge (rx/of (persist-metadata id))
|
||||||
|
;; (->> (rx/filter metadata-persisted? stream)
|
||||||
|
;; (rx/take 1)
|
||||||
|
;; (rx/ignore))))))
|
||||||
|
;; (rx/take-until stopper))))))
|
||||||
|
|
||||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||||
;; Server Interactions
|
;; Server Interactions
|
||||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||||
|
|
|
@ -456,31 +456,50 @@
|
||||||
|
|
||||||
(defn shape->rect-shape
|
(defn shape->rect-shape
|
||||||
"Coerce shape to rect like shape."
|
"Coerce shape to rect like shape."
|
||||||
([shape] (shape->rect-shape @st/state shape))
|
[{:keys [type] :as shape}]
|
||||||
([state {:keys [type] :as shape}]
|
(case type
|
||||||
(case type
|
:circle (circle->rect-shape shape)
|
||||||
:circle (circle->rect-shape state shape)
|
:path (path->rect-shape shape)
|
||||||
:path (path->rect-shape state shape)
|
:curve (path->rect-shape shape)
|
||||||
:curve (path->rect-shape state shape)
|
shape))
|
||||||
shape)))
|
|
||||||
|
|
||||||
(defn shapes->rect-shape
|
(defn shapes->rect-shape
|
||||||
([shapes] (shapes->rect-shape @st/state shapes))
|
[shapes]
|
||||||
([state [shape :as shapes]]
|
(let [shapes (mapv shape->rect-shape shapes)
|
||||||
{:pre [(seq shapes)]}
|
minx (apply js/Math.min (mapv :x1 shapes))
|
||||||
(let [shapes (map shape->rect-shape shapes)
|
miny (apply js/Math.min (mapv :y1 shapes))
|
||||||
minx (apply min (map :x1 shapes))
|
maxx (apply js/Math.max (mapv :x2 shapes))
|
||||||
miny (apply min (map :y1 shapes))
|
maxy (apply js/Math.max (mapv :y2 shapes))]
|
||||||
maxx (apply max (map :x2 shapes))
|
{:x1 minx
|
||||||
maxy (apply max (map :y2 shapes))]
|
:y1 miny
|
||||||
{:x1 minx
|
:x2 maxx
|
||||||
:y1 miny
|
:y2 maxy
|
||||||
:x2 maxx
|
:type :rect}))
|
||||||
:y2 maxy
|
|
||||||
:type :rect})))
|
(defn shapes->rect-shape'
|
||||||
|
[shapes]
|
||||||
|
(let [shapes (mapv shape->rect-shape shapes)
|
||||||
|
total (count shapes)]
|
||||||
|
(loop [idx (int 0)
|
||||||
|
minx js/Number.POSITIVE_INFINITY
|
||||||
|
miny js/Number.POSITIVE_INFINITY
|
||||||
|
maxx js/Number.NEGATIVE_INFINITY
|
||||||
|
maxy js/Number.NEGATIVE_INFINITY]
|
||||||
|
(if (> total idx)
|
||||||
|
(let [{:keys [x1 y1 x2 y2]} (nth shapes idx)]
|
||||||
|
(recur (inc idx)
|
||||||
|
(min minx x1)
|
||||||
|
(min miny y1)
|
||||||
|
(max maxx x2)
|
||||||
|
(max maxy y2)))
|
||||||
|
{:x1 minx
|
||||||
|
:y1 miny
|
||||||
|
:x2 maxx
|
||||||
|
:y2 maxy
|
||||||
|
:type :rect}))))
|
||||||
|
|
||||||
(defn- path->rect-shape
|
(defn- path->rect-shape
|
||||||
[state {:keys [segments] :as shape}]
|
[{:keys [segments] :as shape}]
|
||||||
(let [minx (apply min (map :x segments))
|
(let [minx (apply min (map :x segments))
|
||||||
miny (apply min (map :y segments))
|
miny (apply min (map :y segments))
|
||||||
maxx (apply max (map :x segments))
|
maxx (apply max (map :x segments))
|
||||||
|
@ -492,7 +511,7 @@
|
||||||
:y2 maxy)))
|
:y2 maxy)))
|
||||||
|
|
||||||
(defn- circle->rect-shape
|
(defn- circle->rect-shape
|
||||||
[state {:keys [cx cy rx ry] :as shape}]
|
[{:keys [cx cy rx ry] :as shape}]
|
||||||
(let [width (* rx 2)
|
(let [width (* rx 2)
|
||||||
height (* ry 2)
|
height (* ry 2)
|
||||||
x1 (- cx rx)
|
x1 (- cx rx)
|
||||||
|
|
|
@ -20,6 +20,24 @@
|
||||||
(defonce store (ptk/store {:on-error #(*on-error* %)}))
|
(defonce store (ptk/store {:on-error #(*on-error* %)}))
|
||||||
(defonce stream (ptk/input-stream store))
|
(defonce stream (ptk/input-stream store))
|
||||||
|
|
||||||
|
;; (defn repr-event
|
||||||
|
;; [event]
|
||||||
|
;; (cond
|
||||||
|
;; (satisfies? ptk/Event event)
|
||||||
|
;; (str "typ: " (pr-str (ptk/type event)))
|
||||||
|
|
||||||
|
;; (and (fn? event)
|
||||||
|
;; (pos? (count (.-name event))))
|
||||||
|
;; (str "fn: " (demunge (.-name event)))
|
||||||
|
|
||||||
|
;; :else
|
||||||
|
;; (str "unk: " (pr-str event))))
|
||||||
|
|
||||||
|
;; (defonce debug (as-> stream $
|
||||||
|
;; (rx/filter ptk/event? $)
|
||||||
|
;; (rx/subscribe $ (fn [event]
|
||||||
|
;; (println "[stream]: " (repr-event event))))))
|
||||||
|
|
||||||
(def auth-ref
|
(def auth-ref
|
||||||
(-> (l/key :auth)
|
(-> (l/key :auth)
|
||||||
(l/derive state)))
|
(l/derive state)))
|
||||||
|
|
|
@ -30,12 +30,39 @@
|
||||||
:image [:& image/image-component {:shape shape}]
|
:image [:& image/image-component {:shape shape}]
|
||||||
:circle [:& circle/circle-component {:shape shape}])))
|
:circle [:& circle/circle-component {:shape shape}])))
|
||||||
|
|
||||||
|
(mf/defc render-shape'
|
||||||
|
{:wrap [mf/wrap-memo]}
|
||||||
|
[{:keys [shape] :as props}]
|
||||||
|
(render-shape shape))
|
||||||
|
|
||||||
(mf/defc shape-component
|
(mf/defc shape-component
|
||||||
{:wrap [mf/wrap-memo]}
|
{:wrap [mf/wrap-memo]}
|
||||||
[{:keys [id] :as props}]
|
[{:keys [id] :as props}]
|
||||||
(let [shape-iref (mf/use-memo {:deps #js [id]
|
(uxbox.util.perf/with-measure ::foobar
|
||||||
:fn #(-> (l/in [:shapes id])
|
(let [shape-iref (mf/use-memo {:deps #js [id]
|
||||||
(l/derive st/state))})]
|
:fn #(-> (l/in [:shapes id])
|
||||||
(when-let [shape (mf/deref shape-iref)]
|
(l/derive st/state))})]
|
||||||
(when-not (:hidden shape)
|
(when-let [shape (mf/deref shape-iref)]
|
||||||
(render-shape shape)))))
|
(when-not (:hidden shape)
|
||||||
|
(mf/html
|
||||||
|
[:& render-shape' {:shape shape}]))))))
|
||||||
|
|
||||||
|
(mf/defc shape-component'
|
||||||
|
{:wrap [mf/wrap-memo]}
|
||||||
|
[{:keys [shape] :as props}]
|
||||||
|
(when (and shape (not (:hidden shape)))
|
||||||
|
[:& render-shape' {:shape shape}]))
|
||||||
|
|
||||||
|
(def ^:private shapes-iref
|
||||||
|
(-> (l/key :shapes)
|
||||||
|
(l/derive st/state)))
|
||||||
|
|
||||||
|
(mf/defc all-shapes
|
||||||
|
{:wrap [mf/wrap-memo]}
|
||||||
|
[{:keys [page] :as props}]
|
||||||
|
(let [shapes-by-id (mf/deref shapes-iref)
|
||||||
|
shapes (map #(get shapes-by-id %) (:shapes page))]
|
||||||
|
[:*
|
||||||
|
(for [item shapes]
|
||||||
|
[:& shape-component' {:shape item :key (:id item)}])]))
|
||||||
|
|
||||||
|
|
|
@ -18,31 +18,21 @@
|
||||||
|
|
||||||
;; --- Shape Movement (by mouse)
|
;; --- Shape Movement (by mouse)
|
||||||
|
|
||||||
(defn start-move
|
|
||||||
[id]
|
|
||||||
{:pre [(uuid? id)]}
|
|
||||||
(reify
|
|
||||||
ptk/WatchEvent
|
|
||||||
(watch [_ state stream]
|
|
||||||
(let [pid (get-in state [:workspace :current])
|
|
||||||
flags (get-in state [:workspace pid :flags])
|
|
||||||
stoper (rx/filter uws/mouse-up? stream)]
|
|
||||||
(rx/concat
|
|
||||||
(when (refs/alignment-activated? flags)
|
|
||||||
(rx/of (dw/initial-shape-align id)))
|
|
||||||
(->> uws/mouse-position-deltas
|
|
||||||
(rx/map #(dw/apply-temporal-displacement id %))
|
|
||||||
(rx/take-until stoper))
|
|
||||||
(rx/of (dw/materialize-current-modifier id)
|
|
||||||
(dw/rehash-shape-relationship id)))))))
|
|
||||||
|
|
||||||
(def start-move-selected
|
(def start-move-selected
|
||||||
(reify
|
(reify
|
||||||
ptk/WatchEvent
|
ptk/WatchEvent
|
||||||
(watch [_ state stream]
|
(watch [_ state stream]
|
||||||
(let [pid (get-in state [:workspace :current])
|
(let [pid (get-in state [:workspace :current])
|
||||||
selected (get-in state [:workspace pid :selected])]
|
flags (get-in state [:workspace pid :flags])
|
||||||
(rx/from-coll (map start-move selected))))))
|
selected (get-in state [:workspace pid :selected])
|
||||||
|
stoper (rx/filter uws/mouse-up? stream)]
|
||||||
|
(rx/concat
|
||||||
|
(when (refs/alignment-activated? flags)
|
||||||
|
(rx/of (dw/initial-selection-align selected)))
|
||||||
|
(->> uws/mouse-position-deltas
|
||||||
|
(rx/map #(dw/apply-temporal-displacement-in-bulk selected %))
|
||||||
|
(rx/take-until stoper))
|
||||||
|
(rx/of (dw/materialize-current-modifier-in-bulk selected)))))))
|
||||||
|
|
||||||
(defn on-mouse-down
|
(defn on-mouse-down
|
||||||
[event {:keys [id type] :as shape} selected]
|
[event {:keys [id type] :as shape} selected]
|
||||||
|
|
|
@ -55,9 +55,9 @@
|
||||||
|
|
||||||
props {:x x1 :y y1
|
props {:x x1 :y y1
|
||||||
:id (str "shape-" id)
|
:id (str "shape-" id)
|
||||||
:class-name (classnames :move-cursor moving?)
|
:className (classnames :move-cursor moving?)
|
||||||
:width width
|
:width width
|
||||||
:height height
|
:height height
|
||||||
:transform transform}
|
:transform transform}
|
||||||
attrs (merge (attrs/extract-style-attrs shape) props)]
|
attrs (merge (attrs/extract-style-attrs shape) props)]
|
||||||
[:> :rect (normalize-props attrs)]))
|
[:& "rect" attrs]))
|
||||||
|
|
|
@ -36,27 +36,6 @@
|
||||||
(declare handle-finish-drawing)
|
(declare handle-finish-drawing)
|
||||||
(declare conditional-align)
|
(declare conditional-align)
|
||||||
|
|
||||||
(defn start-drawing
|
|
||||||
[type]
|
|
||||||
{:pre [(keyword? type)]}
|
|
||||||
(let [id (gensym "drawing")]
|
|
||||||
(reify
|
|
||||||
ptk/UpdateEvent
|
|
||||||
(update [_ state]
|
|
||||||
(update-in state [:workspace :drawing-lock] #(if (nil? %) id %)))
|
|
||||||
|
|
||||||
ptk/WatchEvent
|
|
||||||
(watch [_ state stream]
|
|
||||||
(let [pid (get-in state [:workspace :current])
|
|
||||||
lock (get-in state [:workspace :drawing-lock])]
|
|
||||||
(if (= lock id)
|
|
||||||
(rx/merge
|
|
||||||
(->> (rx/filter #(= % handle-finish-drawing) stream)
|
|
||||||
(rx/take 1)
|
|
||||||
(rx/map (fn [_] #(update % :workspace dissoc :drawing-lock))))
|
|
||||||
(rx/of (handle-drawing type)))
|
|
||||||
(rx/empty)))))))
|
|
||||||
|
|
||||||
(def ^:private minimal-shapes
|
(def ^:private minimal-shapes
|
||||||
[{:type :rect
|
[{:type :rect
|
||||||
:name "Rect"
|
:name "Rect"
|
||||||
|
@ -87,6 +66,27 @@
|
||||||
:name "Text"
|
:name "Text"
|
||||||
:content "Type your text here"}])
|
:content "Type your text here"}])
|
||||||
|
|
||||||
|
(defn start-drawing
|
||||||
|
[type]
|
||||||
|
{:pre [(keyword? type)]}
|
||||||
|
(let [id (gensym "drawing")]
|
||||||
|
(ptk/reify ::start-drawing
|
||||||
|
ptk/UpdateEvent
|
||||||
|
(update [_ state]
|
||||||
|
(update-in state [:workspace :drawing-lock] #(if (nil? %) id %)))
|
||||||
|
|
||||||
|
ptk/WatchEvent
|
||||||
|
(watch [_ state stream]
|
||||||
|
(let [pid (get-in state [:workspace :current])
|
||||||
|
lock (get-in state [:workspace :drawing-lock])]
|
||||||
|
(if (= lock id)
|
||||||
|
(rx/merge
|
||||||
|
(->> (rx/filter #(= % handle-finish-drawing) stream)
|
||||||
|
(rx/take 1)
|
||||||
|
(rx/map (fn [_] #(update % :workspace dissoc :drawing-lock))))
|
||||||
|
(rx/of (handle-drawing type)))
|
||||||
|
(rx/empty)))))))
|
||||||
|
|
||||||
(defn- make-minimal-shape
|
(defn- make-minimal-shape
|
||||||
[type]
|
[type]
|
||||||
(let [tool (seek #(= type (:type %)) minimal-shapes)]
|
(let [tool (seek #(= type (:type %)) minimal-shapes)]
|
||||||
|
@ -95,7 +95,7 @@
|
||||||
|
|
||||||
(defn handle-drawing
|
(defn handle-drawing
|
||||||
[type]
|
[type]
|
||||||
(reify
|
(ptk/reify ::handle-drawing
|
||||||
ptk/UpdateEvent
|
ptk/UpdateEvent
|
||||||
(update [_ state]
|
(update [_ state]
|
||||||
(let [pid (get-in state [:workspace :current])
|
(let [pid (get-in state [:workspace :current])
|
||||||
|
@ -131,7 +131,7 @@
|
||||||
(let [pid (get-in state [:workspace :current])]
|
(let [pid (get-in state [:workspace :current])]
|
||||||
(update-in state [:workspace pid :drawing] resize-shape point lock?)))]
|
(update-in state [:workspace pid :drawing] resize-shape point lock?)))]
|
||||||
|
|
||||||
(reify
|
(ptk/reify ::handle-drawing-generic
|
||||||
ptk/WatchEvent
|
ptk/WatchEvent
|
||||||
(watch [_ state stream]
|
(watch [_ state stream]
|
||||||
(let [pid (get-in state [:workspace :current])
|
(let [pid (get-in state [:workspace :current])
|
||||||
|
@ -184,7 +184,7 @@
|
||||||
(remove-dangling-segmnet [state]
|
(remove-dangling-segmnet [state]
|
||||||
(let [pid (get-in state [:workspace :current])]
|
(let [pid (get-in state [:workspace :current])]
|
||||||
(update-in state [:workspace pid :drawing :segments] #(vec (butlast %)))))]
|
(update-in state [:workspace pid :drawing :segments] #(vec (butlast %)))))]
|
||||||
(reify
|
(ptk/reify ::handle-drawing-path
|
||||||
ptk/WatchEvent
|
ptk/WatchEvent
|
||||||
(watch [_ state stream]
|
(watch [_ state stream]
|
||||||
(let [pid (get-in state [:workspace :current])
|
(let [pid (get-in state [:workspace :current])
|
||||||
|
@ -262,7 +262,8 @@
|
||||||
(simplify-drawing-path [state tolerance]
|
(simplify-drawing-path [state tolerance]
|
||||||
(let [pid (get-in state [:workspace :current])]
|
(let [pid (get-in state [:workspace :current])]
|
||||||
(update-in state [:workspace pid :drawing :segments] path/simplify tolerance)))]
|
(update-in state [:workspace pid :drawing :segments] path/simplify tolerance)))]
|
||||||
(reify
|
|
||||||
|
(ptk/reify ::handle-drawing-curve
|
||||||
ptk/WatchEvent
|
ptk/WatchEvent
|
||||||
(watch [_ state stream]
|
(watch [_ state stream]
|
||||||
(let [pid (get-in state [:workspace :current])
|
(let [pid (get-in state [:workspace :current])
|
||||||
|
@ -283,7 +284,7 @@
|
||||||
handle-finish-drawing)))))))
|
handle-finish-drawing)))))))
|
||||||
|
|
||||||
(def handle-finish-drawing
|
(def handle-finish-drawing
|
||||||
(reify
|
(ptk/reify ::handle-finish-drawing
|
||||||
ptk/WatchEvent
|
ptk/WatchEvent
|
||||||
(watch [_ state stream]
|
(watch [_ state stream]
|
||||||
(let [pid (get-in state [:workspace :current])
|
(let [pid (get-in state [:workspace :current])
|
||||||
|
@ -298,10 +299,10 @@
|
||||||
shape (dissoc shape ::initialized? :modifier-mtx)]
|
shape (dissoc shape ::initialized? :modifier-mtx)]
|
||||||
;; Add & select the cred shape to the workspace
|
;; Add & select the cred shape to the workspace
|
||||||
(rx/of (dw/add-shape shape)
|
(rx/of (dw/add-shape shape)
|
||||||
(dw/select-first-shape)))))))))
|
dw/select-first-shape))))))))
|
||||||
|
|
||||||
(def close-drawing-path
|
(def close-drawing-path
|
||||||
(reify
|
(ptk/reify ::close-drawing-path
|
||||||
ptk/UpdateEvent
|
ptk/UpdateEvent
|
||||||
(update [_ state]
|
(update [_ state]
|
||||||
(let [pid (get-in state [:workspace :current])]
|
(let [pid (get-in state [:workspace :current])]
|
||||||
|
|
|
@ -39,7 +39,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)]
|
||||||
(apply rx/of (map #(dw/assoc-temporal-modifier % mtx) ids))))
|
(rx/of (dw/assoc-temporal-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
|
||||||
|
@ -72,9 +72,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/from-coll (map dw/materialize-current-modifier ids))))))))
|
(rx/of (dw/materialize-current-modifier-in-bulk ids))))))))
|
||||||
|
|
||||||
;; (rx/subscribe stream (partial on-resize shape) nil on-end))))
|
|
||||||
|
|
||||||
;; --- Controls (Component)
|
;; --- Controls (Component)
|
||||||
|
|
||||||
|
@ -188,14 +186,16 @@
|
||||||
:stroke "#28c4d4"
|
:stroke "#28c4d4"
|
||||||
:style {:cursor "pointer"}}])])))
|
:style {:cursor "pointer"}}])])))
|
||||||
|
|
||||||
|
;; TODO: add specs for clarity
|
||||||
|
|
||||||
(mf/defc multiple-selection-handlers
|
(mf/defc multiple-selection-handlers
|
||||||
[{:keys [shapes zoom] :as props}]
|
[{:keys [shapes selected zoom] :as props}]
|
||||||
(let [shape (->> shapes
|
(let [shape (->> shapes
|
||||||
(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-click #(do (dom/stop-propagation %2)
|
||||||
(st/emit! (start-resize %1 (mapv :id shapes) shape)))]
|
(st/emit! (start-resize %1 selected shape)))]
|
||||||
[:& controls {:shape shape
|
[:& controls {:shape shape
|
||||||
:zoom zoom
|
:zoom zoom
|
||||||
:on-click on-click}]))
|
:on-click on-click}]))
|
||||||
|
@ -239,6 +239,7 @@
|
||||||
|
|
||||||
(> num 1)
|
(> num 1)
|
||||||
[:& multiple-selection-handlers {:shapes shapes
|
[:& multiple-selection-handlers {:shapes shapes
|
||||||
|
:selected (:selected wst)
|
||||||
:zoom zoom}]
|
:zoom zoom}]
|
||||||
|
|
||||||
(and (= type :text)
|
(and (= type :text)
|
||||||
|
|
|
@ -85,10 +85,11 @@
|
||||||
(clear-state [state]
|
(clear-state [state]
|
||||||
(let [id (get-in state [:workspace :current])]
|
(let [id (get-in state [:workspace :current])]
|
||||||
(update-in state [:workspace id] dissoc :selrect)))]
|
(update-in state [:workspace id] dissoc :selrect)))]
|
||||||
(reify
|
(ptk/reify ::handle-selrect
|
||||||
ptk/WatchEvent
|
ptk/WatchEvent
|
||||||
(watch [_ state stream]
|
(watch [_ state stream]
|
||||||
(let [stoper (rx/filter #(or (dw/interrupt? %) (uws/mouse-up? %)) stream)]
|
(let [stoper (->> (rx/filter #(or (dw/interrupt? %) (uws/mouse-up? %)) stream)
|
||||||
|
(rx/pr-log "handle-selrect|stoper:"))]
|
||||||
(rx/concat
|
(rx/concat
|
||||||
(rx/of (dw/deselect-all))
|
(rx/of (dw/deselect-all))
|
||||||
(->> uws/mouse-position
|
(->> uws/mouse-position
|
||||||
|
@ -118,7 +119,7 @@
|
||||||
cy (.-scrollTop dom)]
|
cy (.-scrollTop dom)]
|
||||||
(set! (.-scrollLeft dom) (- cx x))
|
(set! (.-scrollLeft dom) (- cx x))
|
||||||
(set! (.-scrollTop dom) (- cy y))))]
|
(set! (.-scrollTop dom) (- cy y))))]
|
||||||
(reify
|
(ptk/reify ::handle-viewport-positioning
|
||||||
ptk/EffectEvent
|
ptk/EffectEvent
|
||||||
(effect [_ state stream]
|
(effect [_ state stream]
|
||||||
(let [stoper (rx/filter #(= ::finish-positioning %) stream)
|
(let [stoper (rx/filter #(= ::finish-positioning %) stream)
|
||||||
|
@ -145,7 +146,7 @@
|
||||||
(when (not edition)
|
(when (not edition)
|
||||||
(if drawing-tool
|
(if drawing-tool
|
||||||
(st/emit! (start-drawing drawing-tool))
|
(st/emit! (start-drawing drawing-tool))
|
||||||
(st/emit! :interrupt handle-selrect))))
|
(st/emit! handle-selrect))))
|
||||||
|
|
||||||
(on-context-menu [event]
|
(on-context-menu [event]
|
||||||
(dom/prevent-default event)
|
(dom/prevent-default event)
|
||||||
|
@ -249,8 +250,9 @@
|
||||||
(for [id (reverse (:canvas page))]
|
(for [id (reverse (:canvas page))]
|
||||||
[:& uus/shape-component {:id id :key id}])
|
[:& uus/shape-component {:id id :key id}])
|
||||||
|
|
||||||
(for [id (reverse (:shapes page))]
|
#_(for [id (reverse (:shapes page))]
|
||||||
[:& uus/shape-component {:id id :key id}])
|
[:& uus/shape-component {:id id :key id}])
|
||||||
|
[:& uus/all-shapes {:page page}]
|
||||||
|
|
||||||
(when (seq (:selected wst))
|
(when (seq (:selected wst))
|
||||||
[:& selection-handlers {:wst wst}])
|
[:& selection-handlers {:wst wst}])
|
||||||
|
|
|
@ -56,10 +56,7 @@
|
||||||
|
|
||||||
(defn show
|
(defn show
|
||||||
[data]
|
[data]
|
||||||
(reify
|
(ptk/reify ::show
|
||||||
ptk/EventType
|
|
||||||
(type [_] ::show)
|
|
||||||
|
|
||||||
ptk/UpdateEvent
|
ptk/UpdateEvent
|
||||||
(update [_ state]
|
(update [_ state]
|
||||||
(let [message (assoc data :state :visible)]
|
(let [message (assoc data :state :visible)]
|
||||||
|
|
|
@ -54,6 +54,7 @@
|
||||||
(s/def ::inst inst?)
|
(s/def ::inst inst?)
|
||||||
(s/def ::keyword keyword?)
|
(s/def ::keyword keyword?)
|
||||||
(s/def ::fn fn?)
|
(s/def ::fn fn?)
|
||||||
|
(s/def ::set set?)
|
||||||
(s/def ::coll coll?)
|
(s/def ::coll coll?)
|
||||||
|
|
||||||
(s/def ::not-empty-string
|
(s/def ::not-empty-string
|
||||||
|
|
|
@ -23,6 +23,6 @@
|
||||||
[{:keys [sender point] :as message}]
|
[{:keys [sender point] :as message}]
|
||||||
(let [point [(:x point) (:y point)]
|
(let [point [(:x point) (:y point)]
|
||||||
results (kd/nearest tree point 1)
|
results (kd/nearest tree point 1)
|
||||||
[[x y] d] (first results)
|
[x y] (ffirst results)
|
||||||
result (gpt/point x y)]
|
result (gpt/point x y)]
|
||||||
(impl/reply! sender {:point (gpt/point x y)})))
|
(impl/reply! sender {:point (gpt/point x y)})))
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue