mirror of
https://github.com/penpot/penpot.git
synced 2025-01-26 08:29:42 -05:00
Merge pull request #1428 from penpot/performance
⚡ Improved thumbnails handling
This commit is contained in:
commit
d3a83142ae
8 changed files with 124 additions and 97 deletions
|
@ -81,32 +81,32 @@
|
||||||
(obj/set! js/window "onbeforeunload" nil)
|
(obj/set! js/window "onbeforeunload" nil)
|
||||||
(st/emit! (update-persistence-status {:status :saved})))]
|
(st/emit! (update-persistence-status {:status :saved})))]
|
||||||
(->> (rx/merge
|
(->> (rx/merge
|
||||||
(->> stream
|
(->> stream
|
||||||
(rx/filter dch/commit-changes?)
|
(rx/filter dch/commit-changes?)
|
||||||
(rx/map deref)
|
(rx/map deref)
|
||||||
(rx/filter local-file?)
|
(rx/filter local-file?)
|
||||||
(rx/tap on-dirty)
|
(rx/tap on-dirty)
|
||||||
(rx/buffer-until notifier)
|
(rx/buffer-until notifier)
|
||||||
(rx/filter (complement empty?))
|
(rx/filter (complement empty?))
|
||||||
(rx/map (fn [buf]
|
(rx/map (fn [buf]
|
||||||
(->> (into [] (comp (map #(assoc % :id (uuid/next)))
|
(->> (into [] (comp (map #(assoc % :id (uuid/next)))
|
||||||
(map #(assoc % :file-id file-id)))
|
(map #(assoc % :file-id file-id)))
|
||||||
buf)
|
buf)
|
||||||
(persist-changes file-id))))
|
(persist-changes file-id))))
|
||||||
(rx/tap on-saving)
|
(rx/tap on-saving)
|
||||||
(rx/take-until (rx/delay 100 stoper)))
|
(rx/take-until (rx/delay 100 stoper)))
|
||||||
(->> stream
|
(->> stream
|
||||||
(rx/filter dch/commit-changes?)
|
(rx/filter dch/commit-changes?)
|
||||||
(rx/map deref)
|
(rx/map deref)
|
||||||
(rx/filter library-file?)
|
(rx/filter library-file?)
|
||||||
(rx/filter (complement #(empty? (:changes %))))
|
(rx/filter (complement #(empty? (:changes %))))
|
||||||
(rx/map persist-synchronous-changes)
|
(rx/map persist-synchronous-changes)
|
||||||
(rx/take-until (rx/delay 100 stoper)))
|
(rx/take-until (rx/delay 100 stoper)))
|
||||||
(->> stream
|
(->> stream
|
||||||
(rx/filter (ptk/type? ::changes-persisted))
|
(rx/filter (ptk/type? ::changes-persisted))
|
||||||
(rx/tap on-saved)
|
(rx/tap on-saved)
|
||||||
(rx/ignore)
|
(rx/ignore)
|
||||||
(rx/take-until stoper)))
|
(rx/take-until stoper)))
|
||||||
(rx/subs #(st/emit! %)
|
(rx/subs #(st/emit! %)
|
||||||
(constantly nil)
|
(constantly nil)
|
||||||
(fn []
|
(fn []
|
||||||
|
@ -520,25 +520,25 @@
|
||||||
(defn clone-media-object
|
(defn clone-media-object
|
||||||
[{:keys [file-id object-id] :as params}]
|
[{:keys [file-id object-id] :as params}]
|
||||||
(us/assert ::clone-media-objects-params params)
|
(us/assert ::clone-media-objects-params params)
|
||||||
(ptk/reify ::clone-media-objects
|
(ptk/reify ::clone-media-objects
|
||||||
ptk/WatchEvent
|
ptk/WatchEvent
|
||||||
(watch [_ _ _]
|
(watch [_ _ _]
|
||||||
(let [{:keys [on-success on-error]
|
(let [{:keys [on-success on-error]
|
||||||
:or {on-success identity
|
:or {on-success identity
|
||||||
on-error identity}} (meta params)
|
on-error identity}} (meta params)
|
||||||
params {:is-local true
|
params {:is-local true
|
||||||
:file-id file-id
|
:file-id file-id
|
||||||
:id object-id}]
|
:id object-id}]
|
||||||
|
|
||||||
(rx/concat
|
(rx/concat
|
||||||
(rx/of (dm/show {:content (tr "media.loading")
|
(rx/of (dm/show {:content (tr "media.loading")
|
||||||
:type :info
|
:type :info
|
||||||
:timeout nil
|
:timeout nil
|
||||||
:tag :media-loading}))
|
:tag :media-loading}))
|
||||||
(->> (rp/mutation! :clone-file-media-object params)
|
(->> (rp/mutation! :clone-file-media-object params)
|
||||||
(rx/do on-success)
|
(rx/do on-success)
|
||||||
(rx/catch on-error)
|
(rx/catch on-error)
|
||||||
(rx/finalize #(st/emit! (dm/hide-tag :media-loading)))))))))
|
(rx/finalize #(st/emit! (dm/hide-tag :media-loading)))))))))
|
||||||
|
|
||||||
;; --- Helpers
|
;; --- Helpers
|
||||||
|
|
||||||
|
@ -555,12 +555,17 @@
|
||||||
[ids]
|
[ids]
|
||||||
(ptk/reify ::remove-thumbnails
|
(ptk/reify ::remove-thumbnails
|
||||||
ptk/WatchEvent
|
ptk/WatchEvent
|
||||||
(watch [_ _ _]
|
(watch [_ state _]
|
||||||
;; Removes the thumbnail while it's regenerated
|
;; Removes the thumbnail while it's regenerated
|
||||||
(rx/of (dch/update-shapes
|
(let [moving? (= :move (get-in state [:workspace-local :transform]))
|
||||||
ids
|
selected? (wsh/lookup-selected state)
|
||||||
#(dissoc % :thumbnail)
|
;; When we're moving the current frame it's safe to keep the thumbnail
|
||||||
{:save-undo? false})))))
|
;; if it's resize we need to remove it immeditely
|
||||||
|
ids (cond->> ids moving? (remove selected?))]
|
||||||
|
|
||||||
|
(if (empty? ids)
|
||||||
|
(rx/empty)
|
||||||
|
(rx/of (dch/update-shapes ids #(dissoc % :thumbnail) {:save-undo? false})))))))
|
||||||
|
|
||||||
(defn update-frame-thumbnail
|
(defn update-frame-thumbnail
|
||||||
[frame-id]
|
[frame-id]
|
||||||
|
@ -607,7 +612,8 @@
|
||||||
xform (comp (mapcat extract-ids)
|
xform (comp (mapcat extract-ids)
|
||||||
(map get-frame-id)
|
(map get-frame-id)
|
||||||
(remove nil?)
|
(remove nil?)
|
||||||
(filter #(not= uuid/zero %)))]
|
(filter #(not= uuid/zero %))
|
||||||
|
(filter #(contains? new-objects %)))]
|
||||||
|
|
||||||
(into #{} xform changes)))
|
(into #{} xform changes)))
|
||||||
|
|
||||||
|
@ -647,7 +653,8 @@
|
||||||
(rx/filter dch/commit-changes?)
|
(rx/filter dch/commit-changes?)
|
||||||
(rx/filter (comp not thumbnail-change?))
|
(rx/filter (comp not thumbnail-change?))
|
||||||
(rx/with-latest-from objects-stream)
|
(rx/with-latest-from objects-stream)
|
||||||
(rx/map extract-frame-changes))
|
(rx/map extract-frame-changes)
|
||||||
|
(rx/share))
|
||||||
|
|
||||||
frames (-> state wsh/lookup-page-objects cp/select-frames)
|
frames (-> state wsh/lookup-page-objects cp/select-frames)
|
||||||
no-thumb-frames (->> frames
|
no-thumb-frames (->> frames
|
||||||
|
|
|
@ -449,7 +449,7 @@
|
||||||
(ptk/reify ::duplicate-selected
|
(ptk/reify ::duplicate-selected
|
||||||
ptk/WatchEvent
|
ptk/WatchEvent
|
||||||
(watch [it state _]
|
(watch [it state _]
|
||||||
(when (nil? (get-in state [:workspace-local :transform]))
|
(when (or (not move-delta?) (nil? (get-in state [:workspace-local :transform])))
|
||||||
(let [page-id (:current-page-id state)
|
(let [page-id (:current-page-id state)
|
||||||
objects (wsh/lookup-page-objects state page-id)
|
objects (wsh/lookup-page-objects state page-id)
|
||||||
selected (wsh/lookup-selected state)
|
selected (wsh/lookup-selected state)
|
||||||
|
@ -475,10 +475,10 @@
|
||||||
|
|
||||||
id-duplicated (when (= (count selected) 1) (first selected))]
|
id-duplicated (when (= (count selected) 1) (first selected))]
|
||||||
|
|
||||||
(rx/of (dch/commit-changes {:redo-changes rchanges
|
(rx/of (select-shapes selected)
|
||||||
|
(dch/commit-changes {:redo-changes rchanges
|
||||||
:undo-changes uchanges
|
:undo-changes uchanges
|
||||||
:origin it})
|
:origin it})
|
||||||
(select-shapes selected)
|
|
||||||
(memorize-duplicated id-original id-duplicated)))))))
|
(memorize-duplicated id-original id-duplicated)))))))
|
||||||
|
|
||||||
(defn change-hover-state
|
(defn change-hover-state
|
||||||
|
|
|
@ -510,6 +510,11 @@
|
||||||
(defn- start-move-duplicate
|
(defn- start-move-duplicate
|
||||||
[from-position]
|
[from-position]
|
||||||
(ptk/reify ::start-move-duplicate
|
(ptk/reify ::start-move-duplicate
|
||||||
|
ptk/UpdateEvent
|
||||||
|
(update [_ state]
|
||||||
|
(-> state
|
||||||
|
(assoc-in [:workspace-local :transform] :move)))
|
||||||
|
|
||||||
ptk/WatchEvent
|
ptk/WatchEvent
|
||||||
(watch [_ _ stream]
|
(watch [_ _ stream]
|
||||||
(->> stream
|
(->> stream
|
||||||
|
|
|
@ -90,41 +90,46 @@
|
||||||
(mf/create-element component props)
|
(mf/create-element component props)
|
||||||
(mf/create-element frame-placeholder props)))))
|
(mf/create-element frame-placeholder props)))))
|
||||||
|
|
||||||
(defn frame-wrapper-factory
|
;; Draw the frame proper as a deferred component
|
||||||
|
(defn deferred-frame-shape-factory
|
||||||
[shape-wrapper]
|
[shape-wrapper]
|
||||||
(let [frame-shape (frame/frame-shape shape-wrapper)]
|
(let [frame-shape (frame/frame-shape shape-wrapper)]
|
||||||
|
(mf/fnc defered-frame-wrapper
|
||||||
|
{::mf/wrap-props false
|
||||||
|
::mf/wrap [#(mf/memo' % (mf/check-props ["shape" "childs"]))
|
||||||
|
custom-deferred]}
|
||||||
|
[props]
|
||||||
|
(let [shape (unchecked-get props "shape")
|
||||||
|
childs (unchecked-get props "childs")]
|
||||||
|
[:& frame-shape {:shape shape
|
||||||
|
:childs childs}]))))
|
||||||
|
|
||||||
|
(defn frame-wrapper-factory
|
||||||
|
[shape-wrapper]
|
||||||
|
(let [deferred-frame-shape (deferred-frame-shape-factory shape-wrapper)]
|
||||||
(mf/fnc frame-wrapper
|
(mf/fnc frame-wrapper
|
||||||
{::mf/wrap [#(mf/memo' % check-frame-props) custom-deferred]
|
{::mf/wrap [#(mf/memo' % check-frame-props)]
|
||||||
::mf/wrap-props false}
|
::mf/wrap-props false}
|
||||||
[props]
|
[props]
|
||||||
(let [shape (unchecked-get props "shape")
|
|
||||||
objects (unchecked-get props "objects")
|
|
||||||
thumbnail? (unchecked-get props "thumbnail?")
|
|
||||||
|
|
||||||
children (-> (mapv (d/getf objects) (:shapes shape))
|
(let [shape (unchecked-get props "shape")
|
||||||
(hooks/use-equal-memo))
|
objects (unchecked-get props "objects")
|
||||||
|
thumbnail? (unchecked-get props "thumbnail?")
|
||||||
|
|
||||||
all-children (-> (cp/get-children-objects (:id shape) objects)
|
children (-> (mapv (d/getf objects) (:shapes shape))
|
||||||
(hooks/use-equal-memo))
|
(hooks/use-equal-memo))
|
||||||
|
all-children (-> (cp/get-children-objects (:id shape) objects)
|
||||||
|
(hooks/use-equal-memo))
|
||||||
|
|
||||||
rendered? (mf/use-state false)
|
show-thumbnail? (and thumbnail? (some? (:thumbnail shape)))]
|
||||||
|
|
||||||
show-thumbnail? (and thumbnail? (some? (:thumbnail shape)))
|
|
||||||
|
|
||||||
on-dom
|
|
||||||
(mf/use-callback
|
|
||||||
(fn [node]
|
|
||||||
(ts/schedule-on-idle #(reset! rendered? (some? node)))))]
|
|
||||||
|
|
||||||
(when (some? shape)
|
(when (some? shape)
|
||||||
[:g.frame-wrapper {:display (when (:hidden shape) "none")}
|
[:g.frame-wrapper {:display (when (:hidden shape) "none")}
|
||||||
|
[:> shape-container {:shape shape}
|
||||||
(when-not show-thumbnail?
|
[:& ff/fontfaces-style {:shapes all-children}]
|
||||||
[:> shape-container {:shape shape :ref on-dom}
|
(if show-thumbnail?
|
||||||
[:& ff/fontfaces-style {:shapes all-children}]
|
[:& thumbnail {:shape shape}]
|
||||||
[:& frame-shape {:shape shape
|
[:& deferred-frame-shape
|
||||||
:childs children}]])
|
{:shape shape
|
||||||
|
:childs children}])]])))))
|
||||||
(when (or (not @rendered?) show-thumbnail?)
|
|
||||||
[:& thumbnail {:shape shape}])])))))
|
|
||||||
|
|
||||||
|
|
|
@ -28,10 +28,14 @@
|
||||||
(when node
|
(when node
|
||||||
(let [img-node (mf/ref-val thumbnail-img)]
|
(let [img-node (mf/ref-val thumbnail-img)]
|
||||||
(timers/schedule-on-idle
|
(timers/schedule-on-idle
|
||||||
#(let [frame-node (dom/get-element (str "shape-" (:id shape)))
|
#(let [frame-node (dom/get-element (str "shape-" (:id shape)))
|
||||||
loading-node (when frame-node
|
thumb-node (dom/query frame-node ".frame-thumbnail")
|
||||||
(dom/query frame-node "[data-loading=\"true\"]"))]
|
loading-node (dom/query frame-node "[data-loading=\"true\"]")]
|
||||||
(if (and (some? frame-node) (not (some? loading-node)))
|
(if (and (some? frame-node)
|
||||||
|
;; Not render if the thumbnail is in display
|
||||||
|
(nil? thumb-node)
|
||||||
|
;; Not render if some image is still loading
|
||||||
|
(nil? loading-node))
|
||||||
(let [frame-html (-> (js/XMLSerializer.)
|
(let [frame-html (-> (js/XMLSerializer.)
|
||||||
(.serializeToString frame-node))
|
(.serializeToString frame-node))
|
||||||
|
|
||||||
|
@ -125,7 +129,9 @@
|
||||||
;; after a time
|
;; after a time
|
||||||
(reset! shape-id nil)
|
(reset! shape-id nil)
|
||||||
(rx/push! next :next)
|
(rx/push! next :next)
|
||||||
(timers/schedule-on-idle (st/emitf (dwp/update-frame-thumbnail frame-id)))))]
|
(timers/schedule-on-idle
|
||||||
|
100
|
||||||
|
(st/emitf (dwp/update-frame-thumbnail frame-id)))))]
|
||||||
|
|
||||||
(mf/use-effect
|
(mf/use-effect
|
||||||
(mf/deps render-frame)
|
(mf/deps render-frame)
|
||||||
|
|
|
@ -52,17 +52,16 @@
|
||||||
|
|
||||||
;; When the shape is a frame we maybe need to move its thumbnail
|
;; When the shape is a frame we maybe need to move its thumbnail
|
||||||
thumb-node (when frame? (dom/get-element (str "thumbnail-" id)))]
|
thumb-node (when frame? (dom/get-element (str "thumbnail-" id)))]
|
||||||
(cond
|
|
||||||
(some? thumb-node)
|
|
||||||
[(.-parentNode thumb-node)]
|
|
||||||
|
|
||||||
(and (some? shape-node) frame?)
|
(cond
|
||||||
[(dom/query shape-node ".frame-background")
|
frame?
|
||||||
|
[thumb-node
|
||||||
|
(dom/query shape-node ".frame-background")
|
||||||
(dom/query shape-node ".frame-clip")]
|
(dom/query shape-node ".frame-clip")]
|
||||||
|
|
||||||
;; For groups we don't want to transform the whole group but only
|
;; For groups we don't want to transform the whole group but only
|
||||||
;; its filters/masks
|
;; its filters/masks
|
||||||
(and (some? shape-node) mask?)
|
mask?
|
||||||
[(dom/query shape-node ".mask-clip-path")
|
[(dom/query shape-node ".mask-clip-path")
|
||||||
(dom/query shape-node ".mask-shape")]
|
(dom/query shape-node ".mask-shape")]
|
||||||
|
|
||||||
|
|
|
@ -186,7 +186,8 @@
|
||||||
|
|
||||||
(defn query
|
(defn query
|
||||||
[el query]
|
[el query]
|
||||||
(.querySelector el query))
|
(when (some? el)
|
||||||
|
(.querySelector el query)))
|
||||||
|
|
||||||
(defn get-client-position
|
(defn get-client-position
|
||||||
[event]
|
[event]
|
||||||
|
|
|
@ -44,11 +44,15 @@
|
||||||
(def ^:private cancel-idle-callback #(js/clearTimeout %))))
|
(def ^:private cancel-idle-callback #(js/clearTimeout %))))
|
||||||
|
|
||||||
(defn schedule-on-idle
|
(defn schedule-on-idle
|
||||||
[func]
|
([ms func]
|
||||||
(let [sem (request-idle-callback #(func))]
|
;; Schedule on idle after `ms` time
|
||||||
(reify rx/IDisposable
|
(schedule ms #(schedule-on-idle func)))
|
||||||
(-dispose [_]
|
|
||||||
(cancel-idle-callback sem)))))
|
([func]
|
||||||
|
(let [sem (request-idle-callback #(func))]
|
||||||
|
(reify rx/IDisposable
|
||||||
|
(-dispose [_]
|
||||||
|
(cancel-idle-callback sem))))))
|
||||||
|
|
||||||
(def ^:private request-animation-frame
|
(def ^:private request-animation-frame
|
||||||
(or (and (exists? js/window) (.-requestAnimationFrame js/window))
|
(or (and (exists? js/window) (.-requestAnimationFrame js/window))
|
||||||
|
|
Loading…
Add table
Reference in a new issue