Remove unexpected lag on moving shape.

The lag happens when the shape is not initially selected.
This commit is contained in:
Andrey Antukh 2019-11-26 10:55:38 +01:00
parent 1357fed067
commit 792303a833
15 changed files with 106 additions and 121 deletions

View file

@ -6,6 +6,7 @@
(ns ^:figwheel-hooks uxbox.main (ns ^:figwheel-hooks uxbox.main
(:require (:require
[cljs.spec.alpha :as s]
[rumext.alpha :as mf] [rumext.alpha :as mf]
[uxbox.main.data.auth :refer [logout]] [uxbox.main.data.auth :refer [logout]]
[uxbox.main.data.users :as udu] [uxbox.main.data.users :as udu]
@ -27,6 +28,7 @@
;; --- i18n ;; --- i18n
(declare reinit) (declare reinit)
(s/check-asserts true)
(i18n/update-locales! (fn [locales] (i18n/update-locales! (fn [locales]
(-> locales (-> locales

View file

@ -20,29 +20,23 @@
;; --- Initialize ;; --- Initialize
(defrecord Initialize [] (def initialize
(ptk/reify ::initialize
ptk/UpdateEvent ptk/UpdateEvent
(update [_ state] (update [_ state]
(assoc-in state [:dashboard :icons] {:selected #{}}))) (assoc-in state [:dashboard :icons] {:selected #{}}))))
(defn initialize
[]
(Initialize.))
;; --- Select a Collection ;; --- Select a Collection
(defrecord SelectCollection [type id]
ptk/WatchEvent
(watch [_ state stream]
(rx/of (r/navigate :dashboard/icons
{:type type :id id}))))
(defn select-collection (defn select-collection
([type] ([type]
(select-collection type nil)) (select-collection type nil))
([type id] ([type id]
{:pre [(keyword? type)]} {:pre [(keyword? type)]}
(SelectCollection. type id))) (ptk/reify ::select-collection
ptk/WatchEvent
(watch [_ state stream]
(rx/of (r/navigate :dashboard/icons {:type type :id id}))))))
;; --- Collections Fetched ;; --- Collections Fetched
@ -61,6 +55,10 @@
state state
items)))) items))))
(defn collections-fetched?
[v]
(= ::collections-fetched (ptk/type v)))
;; --- Fetch Collections ;; --- Fetch Collections
(def fetch-collections (def fetch-collections
@ -72,7 +70,9 @@
;; --- Collection Created ;; --- Collection Created
(defrecord CollectionCreated [item] (defn collection-created
[item]
(ptk/reify ::collection-created
ptk/UpdateEvent ptk/UpdateEvent
(update [_ state] (update [_ state]
(let [{:keys [id] :as item} (assoc item :type :own)] (let [{:keys [id] :as item} (assoc item :type :own)]
@ -80,40 +80,27 @@
ptk/WatchEvent ptk/WatchEvent
(watch [_ state stream] (watch [_ state stream]
(rx/of (select-collection :own (:id item))))) (rx/of (select-collection :own (:id item))))))
(defn collection-created
[item]
(CollectionCreated. item))
;; --- Create Collection ;; --- Create Collection
(defrecord CreateCollection [] (def create-collection
(ptk/reify ::create-collection
ptk/WatchEvent ptk/WatchEvent
(watch [_ state s] (watch [_ state s]
(let [name (tr "ds.default-library-title" (gensym "c")) (let [name (tr "ds.default-library-title" (gensym "c"))
data {:name name}] data {:name name}]
(->> (rp/mutation! :create-icons-collection data) (->> (rp/mutation! :create-icons-collection data)
(rx/map collection-created))))) (rx/map collection-created))))))
(defn create-collection
[]
(CreateCollection.))
(defn collections-fetched?
[v]
(= ::collections-fetched (ptk/type v)))
;; --- Collection Updated ;; --- Collection Updated
(defrecord CollectionUpdated [item]
ptk/UpdateEvent
(update [_ state]
(update-in state [:icons-collections (:id item)] merge item)))
(defn collection-updated (defn collection-updated
[item] [item]
(CollectionUpdated. item)) (ptk/reify ::collection-updated
ptk/UpdateEvent
(update [_ state]
(update-in state [:icons-collections (:id item)] merge item))))
;; --- Update Collection ;; --- Update Collection

View file

@ -245,31 +245,17 @@
{:pre [(or (uuid? id) (nil? id)) (fn? on-uploaded)]} {:pre [(or (uuid? id) (nil? id)) (fn? on-uploaded)]}
(CreateImages. id files on-uploaded))) (CreateImages. id files on-uploaded)))
;; --- Image Updated
(defrecord ImagePersisted [id data]
ptk/UpdateEvent
(update [_ state]
(assoc-in state [:images id] data)))
(defn image-persisted
[{:keys [id] :as data}]
{:pre [(map? data) (uuid? id)]}
(ImagePersisted. id data))
;; --- Update Image ;; --- Update Image
(defrecord PersistImage [id]
ptk/WatchEvent
(watch [_ state stream]
(let [data (get-in state [:images id])]
(->> (rp/mutation! :update-image data)
(rx/map image-persisted)))))
(defn persist-image (defn persist-image
[id] [id]
{:pre [(uuid? id)]} {:pre [(uuid? id)]}
(PersistImage. id)) (ptk/reify ::persist-image
ptk/WatchEvent
(watch [_ state stream]
(let [data (get-in state [:images id])]
(->> (rp/mutation! :update-image data)
(rx/ignore))))))
;; --- Images Fetched ;; --- Images Fetched

View file

@ -378,38 +378,38 @@
(reduce ds/dissoc-shape state (reduce ds/dissoc-shape state
(map #(get-in state [:shapes %]) ids))))) (map #(get-in state [:shapes %]) ids)))))
(defrecord SelectShape [id]
ptk/UpdateEvent
(update [_ state]
(let [pid (get-in state [:workspace :current])
selected (get-in state [:workspace pid :selected])]
(if (contains? selected id)
(update-in state [:workspace pid :selected] disj id)
(update-in state [:workspace pid :selected] conj id))))
ptk/WatchEvent
(watch [_ state s]
(rx/of (activate-flag :element-options))))
(defn select-shape (defn select-shape
"Mark a shape selected for drawing." "Mark a shape selected for drawing."
[id] [id]
{:pre [(uuid? id)]} (s/assert ::us/uuid id)
(SelectShape. id)) (ptk/reify ::select-shape
(defrecord DeselectAll []
ptk/UpdateEvent ptk/UpdateEvent
(update [_ state] (update [_ state]
(prn "select-shape$update" id)
(let [pid (get-in state [:workspace :current])
selected (get-in state [:workspace pid :selected])]
(update-in state [:workspace pid :selected]
(fn [selected]
(if (contains? selected id)
(disj selected id)
(conj selected id))))))
ptk/WatchEvent
(watch [_ state s]
(prn "select-shape$watch" id)
(rx/of (activate-flag :element-options)))))
(def deselect-all
"Clear all possible state of drawing, edition
or any similar action taken by the user."
(ptk/reify ::deselect-all
ptk/UpdateEvent
(update [_ state]
(prn "deselect-all")
(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)))))))
(defn deselect-all
"Clear all possible state of drawing, edition
or any similar action taken by the user."
[]
(DeselectAll.))
;; --- Select First Shape ;; --- Select First Shape
@ -1030,7 +1030,7 @@
(rx/buffer-time 300) (rx/buffer-time 300)
(rx/map #(into* #{} %)) (rx/map #(into* #{} %))
(rx/filter (complement empty?)) (rx/filter (complement empty?))
(rx/tap #(prn "changed" %)) ;; (rx/tap #(prn "changed" %))
(rx/mapcat (fn [items] (rx/from-coll (rx/mapcat (fn [items] (rx/from-coll
(map rehash-shape-relationship items)))) (map rehash-shape-relationship items))))
(rx/take-until stoper))))))) (rx/take-until stoper)))))))

View file

@ -425,7 +425,7 @@
:else (first colls)) :else (first colls))
id (:id selected-coll)] id (:id selected-coll)]
(mf/use-effect #(st/emit! di/fetch-collections)) (mf/use-effect #(st/emit! di/fetch-collections))
(mf/use-effect {:fn #(st/emit! (di/initialize) (mf/use-effect {:fn #(st/emit! di/initialize
(di/fetch-icons id)) (di/fetch-icons id))
:deps #js [id type]}) :deps #js [id type]})

View file

@ -32,7 +32,7 @@
shape (merge canvas-default-props shape)] shape (merge canvas-default-props shape)]
(letfn [(on-double-click [event] (letfn [(on-double-click [event]
(dom/prevent-default event) (dom/prevent-default event)
(st/emit! (dw/deselect-all) (st/emit! dw/deselect-all
(dw/select-shape (:id shape))))] (dw/select-shape (:id shape))))]
[:g.shape {:class (when selected? "selected") [:g.shape {:class (when selected? "selected")
:on-double-click on-double-click :on-double-click on-double-click

View file

@ -4,6 +4,11 @@
;; ;;
;; Copyright (c) 2016-2019 Andrey Antukh <niwi@niwi.nz> ;; Copyright (c) 2016-2019 Andrey Antukh <niwi@niwi.nz>
;; TODO: we need to consider moving this under uxbox.ui.workspace
;; namespace because this is logic only related to workspace
;; manipulation. Staying here causes a lot of confusion and finding
;; this code is also very difficult.
(ns uxbox.main.ui.shapes.common (ns uxbox.main.ui.shapes.common
(:require (:require
[potok.core :as ptk] [potok.core :as ptk]
@ -13,23 +18,26 @@
[uxbox.main.store :as st] [uxbox.main.store :as st]
[uxbox.main.ui.keyboard :as kbd] [uxbox.main.ui.keyboard :as kbd]
[uxbox.main.ui.workspace.streams :as uws] [uxbox.main.ui.workspace.streams :as uws]
[uxbox.main.workers :as uwrk]
[uxbox.util.geom.matrix :as gmt] [uxbox.util.geom.matrix :as gmt]
[uxbox.util.geom.point :as gpt]
[uxbox.util.dom :as dom])) [uxbox.util.dom :as dom]))
;; --- Shape Movement (by mouse) ;; --- Shape Movement (by mouse)
(def start-move-selected (def start-move-selected
(reify (ptk/reify ::start-move-selected
ptk/WatchEvent ptk/WatchEvent
(watch [_ state stream] (watch [_ state stream]
(let [pid (get-in state [:workspace :current]) (let [pid (get-in state [:workspace :current])
flags (get-in state [:workspace pid :flags]) flags (get-in state [:workspace pid :flags])
selected (get-in state [:workspace pid :selected]) selected (get-in state [:workspace pid :selected])
stoper (rx/filter uws/mouse-up? stream)] stoper (rx/filter uws/mouse-up? stream)
position @uws/mouse-position]
(rx/concat (rx/concat
(when (refs/alignment-activated? flags) (when (refs/alignment-activated? flags)
(rx/of (dw/initial-selection-align selected))) (rx/of (dw/initial-selection-align selected)))
(->> uws/mouse-position-deltas (->> (uws/mouse-position-deltas position)
(rx/map #(dw/apply-temporal-displacement-in-bulk selected %)) (rx/map #(dw/apply-temporal-displacement-in-bulk selected %))
(rx/take-until stoper)) (rx/take-until stoper))
(rx/of (dw/materialize-current-modifier-in-bulk selected))))))) (rx/of (dw/materialize-current-modifier-in-bulk selected)))))))
@ -51,7 +59,7 @@
(and (not selected?) (empty? selected)) (and (not selected?) (empty? selected))
(do (do
(dom/stop-propagation event) (dom/stop-propagation event)
(st/emit! (dw/deselect-all) (st/emit! dw/deselect-all
(dw/select-shape id) (dw/select-shape id)
start-move-selected)) start-move-selected))
@ -60,7 +68,7 @@
(dom/stop-propagation event) (dom/stop-propagation event)
(if (kbd/shift? event) (if (kbd/shift? event)
(st/emit! (dw/select-shape id)) (st/emit! (dw/select-shape id))
(st/emit! (dw/deselect-all) (st/emit! dw/deselect-all
(dw/select-shape id) (dw/select-shape id)
start-move-selected))) start-move-selected)))
:else :else

View file

@ -154,10 +154,10 @@
[{:keys [shape modifiers zoom] :as props}] [{:keys [shape modifiers zoom] :as props}]
(letfn [(on-mouse-down [event index] (letfn [(on-mouse-down [event index]
(dom/stop-propagation event) (dom/stop-propagation event)
;; TODO: this need code ux refactor ;; TODO: this need code ux refactor
(let [stoper (get-edition-stream-stoper) (let [stoper (get-edition-stream-stoper)
stream (rx/take-until stoper ws/mouse-position-deltas)] stream (->> (ws/mouse-position-deltas @ws/mouse-position)
(rx/take-until stoper))]
(when @refs/selected-alignment (when @refs/selected-alignment
(st/emit! (dw/initial-path-point-align (:id shape) index))) (st/emit! (dw/initial-path-point-align (:id shape) index)))
(rx/subscribe stream #(on-handler-move % index)))) (rx/subscribe stream #(on-handler-move % index))))

View file

@ -39,7 +39,7 @@
:ctrl+b #(st/emit! (dw/select-for-drawing :rect)) :ctrl+b #(st/emit! (dw/select-for-drawing :rect))
:ctrl+e #(st/emit! (dw/select-for-drawing :circle)) :ctrl+e #(st/emit! (dw/select-for-drawing :circle))
:ctrl+t #(st/emit! (dw/select-for-drawing :text)) :ctrl+t #(st/emit! (dw/select-for-drawing :text))
:esc #(st/emit! (dw/deselect-all)) :esc #(st/emit! dw/deselect-all)
:delete #(st/emit! dw/delete-selected) :delete #(st/emit! dw/delete-selected)
:ctrl+up #(st/emit! (dw/order-selected-shapes :up)) :ctrl+up #(st/emit! (dw/order-selected-shapes :up))
:ctrl+down #(st/emit! (dw/order-selected-shapes :down)) :ctrl+down #(st/emit! (dw/order-selected-shapes :down))

View file

@ -57,7 +57,7 @@
(dw/select-for-drawing tool))) (dw/select-for-drawing tool)))
(toggle-ruler [event] (toggle-ruler [event]
(st/emit! (dw/select-for-drawing nil) (st/emit! (dw/select-for-drawing nil)
(dw/deselect-all) dw/deselect-all
(dw/toggle-ruler)))] (dw/toggle-ruler)))]
(let [selected (mf/deref refs/selected-drawing-tool) (let [selected (mf/deref refs/selected-drawing-tool)

View file

@ -100,10 +100,10 @@
(st/emit! (dw/select-shape id)) (st/emit! (dw/select-shape id))
(> (count selected) 1) (> (count selected) 1)
(st/emit! (dw/deselect-all) (st/emit! dw/deselect-all
(dw/select-shape id)) (dw/select-shape id))
:else :else
(st/emit! (dw/deselect-all) (st/emit! dw/deselect-all
(dw/select-shape id))))) (dw/select-shape id)))))
(on-drop [item monitor] (on-drop [item monitor]
@ -161,10 +161,10 @@
(st/emit! (dw/select-shape id)) (st/emit! (dw/select-shape id))
(> (count selected) 1) (> (count selected) 1)
(st/emit! (dw/deselect-all) (st/emit! dw/deselect-all
(dw/select-shape id)) (dw/select-shape id))
:else :else
(st/emit! (dw/deselect-all) (st/emit! dw/deselect-all
(dw/select-shape id))))) (dw/select-shape id)))))
(on-drop [item monitor] (on-drop [item monitor]

View file

@ -92,7 +92,6 @@
(mf/defc sitemap-toolbox (mf/defc sitemap-toolbox
[{:keys [project-id current-page-id] :as props}] [{:keys [project-id current-page-id] :as props}]
(prn "sitemap-toolbox" props)
(let [project-iref (mf/use-memo {:deps #js [project-id] (let [project-iref (mf/use-memo {:deps #js [project-id]
:fn #(-> (l/in [:projects project-id]) :fn #(-> (l/in [:projects project-id])
(l/derive st/state))}) (l/derive st/state))})

View file

@ -94,9 +94,11 @@
(rx/subscribe-with ob sub) (rx/subscribe-with ob sub)
sub)) sub))
(defonce mouse-position-deltas
(->> mouse-position (defn mouse-position-deltas
(rx/sample 10) [current]
(->> (rx/concat (rx/of current)
(rx/sample 10 mouse-position))
(rx/map #(gpt/divide % @refs/selected-zoom)) (rx/map #(gpt/divide % @refs/selected-zoom))
(rx/mapcat (fn [point] (rx/mapcat (fn [point]
(if @refs/selected-alignment (if @refs/selected-alignment
@ -104,8 +106,7 @@
(rx/of point)))) (rx/of point))))
(rx/buffer 2 1) (rx/buffer 2 1)
(rx/map (fn [[old new]] (rx/map (fn [[old new]]
(gpt/subtract new old))) (gpt/subtract new old)))))
(rx/share)))
(defonce viewport-scroll (defonce viewport-scroll
(let [sub (rx/behavior-subject nil) (let [sub (rx/behavior-subject nil)

View file

@ -90,7 +90,7 @@
(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/concat (rx/concat
(rx/of (dw/deselect-all)) (rx/of dw/deselect-all)
(->> uws/mouse-position (->> uws/mouse-position
(rx/map (fn [pos] #(update-state % pos))) (rx/map (fn [pos] #(update-state % pos)))
(rx/take-until stoper)) (rx/take-until stoper))

View file

@ -50,7 +50,6 @@
(s/def ::email email?) (s/def ::email email?)
(s/def ::color color?) (s/def ::color color?)
(s/def ::string string?) (s/def ::string string?)
(s/def ::number number?)
(s/def ::positive pos?) (s/def ::positive pos?)
(s/def ::inst inst?) (s/def ::inst inst?)
(s/def ::keyword keyword?) (s/def ::keyword keyword?)
@ -62,15 +61,18 @@
(s/and string? #(not (str/empty? %)))) (s/and string? #(not (str/empty? %))))
(defn- conform-number-str (defn- conform-number
[v] [v]
(cond (cond
(re-matches number-rx v) (js/parseFloat v)
(number? v) v (number? v) v
(re-matches number-rx v) (js/parseFloat v)
:else ::s/invalid)) :else ::s/invalid))
(s/def ::number-str (s/def ::number
(s/conformer conform-number-str str)) (s/conformer conform-number str))
;; NOTE: backward compatibility (revisit the code and remove)
(s/def ::number-str ::number)
(s/def ::color color?) (s/def ::color color?)