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/UpdateEvent (ptk/reify ::initialize
(update [_ state] ptk/UpdateEvent
(assoc-in state [:dashboard :icons] {:selected #{}}))) (update [_ state]
(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,48 +70,37 @@
;; --- Collection Created ;; --- Collection Created
(defrecord CollectionCreated [item]
ptk/UpdateEvent
(update [_ state]
(let [{:keys [id] :as item} (assoc item :type :own)]
(update state :icons-collections assoc id item)))
ptk/WatchEvent
(watch [_ state stream]
(rx/of (select-collection :own (:id item)))))
(defn collection-created (defn collection-created
[item] [item]
(CollectionCreated. item)) (ptk/reify ::collection-created
ptk/UpdateEvent
(update [_ state]
(let [{:keys [id] :as item} (assoc item :type :own)]
(update state :icons-collections assoc id item)))
ptk/WatchEvent
(watch [_ state stream]
(rx/of (select-collection :own (:id item))))))
;; --- Create Collection ;; --- Create Collection
(defrecord CreateCollection [] (def create-collection
ptk/WatchEvent (ptk/reify ::create-collection
(watch [_ state s] ptk/WatchEvent
(let [name (tr "ds.default-library-title" (gensym "c")) (watch [_ state s]
data {:name name}] (let [name (tr "ds.default-library-title" (gensym "c"))
(->> (rp/mutation! :create-icons-collection data) data {:name name}]
(rx/map collection-created))))) (->> (rp/mutation! :create-icons-collection data)
(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
ptk/UpdateEvent
(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))))))
(defrecord DeselectAll [] ptk/WatchEvent
ptk/UpdateEvent (watch [_ state s]
(update [_ state] (prn "select-shape$watch" id)
(let [pid (get-in state [:workspace :current])] (rx/of (activate-flag :element-options)))))
(update-in state [:workspace pid] #(-> %
(assoc :selected #{})
(dissoc :selected-canvas))))))
(defn deselect-all (def deselect-all
"Clear all possible state of drawing, edition "Clear all possible state of drawing, edition
or any similar action taken by the user." or any similar action taken by the user."
[] (ptk/reify ::deselect-all
(DeselectAll.)) ptk/UpdateEvent
(update [_ state]
(prn "deselect-all")
(let [pid (get-in state [:workspace :current])]
(update-in state [:workspace pid] #(-> %
(assoc :selected #{})
(dissoc :selected-canvas)))))))
;; --- 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,26 +18,29 @@
[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)))))))
(defn on-mouse-down (defn on-mouse-down
[event {:keys [id type] :as shape} selected] [event {:keys [id type] :as shape} 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?)