0
Fork 0
mirror of https://github.com/penpot/penpot.git synced 2025-01-25 07:58:49 -05:00

Merge pull request #1428 from penpot/performance

 Improved thumbnails handling
This commit is contained in:
Andrey Antukh 2021-12-29 11:33:39 +01:00 committed by GitHub
commit d3a83142ae
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
8 changed files with 124 additions and 97 deletions

View file

@ -81,32 +81,32 @@
(obj/set! js/window "onbeforeunload" nil)
(st/emit! (update-persistence-status {:status :saved})))]
(->> (rx/merge
(->> stream
(rx/filter dch/commit-changes?)
(rx/map deref)
(rx/filter local-file?)
(rx/tap on-dirty)
(rx/buffer-until notifier)
(rx/filter (complement empty?))
(rx/map (fn [buf]
(->> (into [] (comp (map #(assoc % :id (uuid/next)))
(map #(assoc % :file-id file-id)))
buf)
(persist-changes file-id))))
(rx/tap on-saving)
(rx/take-until (rx/delay 100 stoper)))
(->> stream
(rx/filter dch/commit-changes?)
(rx/map deref)
(rx/filter library-file?)
(rx/filter (complement #(empty? (:changes %))))
(rx/map persist-synchronous-changes)
(rx/take-until (rx/delay 100 stoper)))
(->> stream
(rx/filter (ptk/type? ::changes-persisted))
(rx/tap on-saved)
(rx/ignore)
(rx/take-until stoper)))
(->> stream
(rx/filter dch/commit-changes?)
(rx/map deref)
(rx/filter local-file?)
(rx/tap on-dirty)
(rx/buffer-until notifier)
(rx/filter (complement empty?))
(rx/map (fn [buf]
(->> (into [] (comp (map #(assoc % :id (uuid/next)))
(map #(assoc % :file-id file-id)))
buf)
(persist-changes file-id))))
(rx/tap on-saving)
(rx/take-until (rx/delay 100 stoper)))
(->> stream
(rx/filter dch/commit-changes?)
(rx/map deref)
(rx/filter library-file?)
(rx/filter (complement #(empty? (:changes %))))
(rx/map persist-synchronous-changes)
(rx/take-until (rx/delay 100 stoper)))
(->> stream
(rx/filter (ptk/type? ::changes-persisted))
(rx/tap on-saved)
(rx/ignore)
(rx/take-until stoper)))
(rx/subs #(st/emit! %)
(constantly nil)
(fn []
@ -520,25 +520,25 @@
(defn clone-media-object
[{:keys [file-id object-id] :as params}]
(us/assert ::clone-media-objects-params params)
(ptk/reify ::clone-media-objects
ptk/WatchEvent
(watch [_ _ _]
(let [{:keys [on-success on-error]
:or {on-success identity
on-error identity}} (meta params)
params {:is-local true
:file-id file-id
:id object-id}]
(ptk/reify ::clone-media-objects
ptk/WatchEvent
(watch [_ _ _]
(let [{:keys [on-success on-error]
:or {on-success identity
on-error identity}} (meta params)
params {:is-local true
:file-id file-id
:id object-id}]
(rx/concat
(rx/of (dm/show {:content (tr "media.loading")
:type :info
:timeout nil
:tag :media-loading}))
(->> (rp/mutation! :clone-file-media-object params)
(rx/do on-success)
(rx/catch on-error)
(rx/finalize #(st/emit! (dm/hide-tag :media-loading)))))))))
(rx/concat
(rx/of (dm/show {:content (tr "media.loading")
:type :info
:timeout nil
:tag :media-loading}))
(->> (rp/mutation! :clone-file-media-object params)
(rx/do on-success)
(rx/catch on-error)
(rx/finalize #(st/emit! (dm/hide-tag :media-loading)))))))))
;; --- Helpers
@ -555,12 +555,17 @@
[ids]
(ptk/reify ::remove-thumbnails
ptk/WatchEvent
(watch [_ _ _]
(watch [_ state _]
;; Removes the thumbnail while it's regenerated
(rx/of (dch/update-shapes
ids
#(dissoc % :thumbnail)
{:save-undo? false})))))
(let [moving? (= :move (get-in state [:workspace-local :transform]))
selected? (wsh/lookup-selected state)
;; When we're moving the current frame it's safe to keep the thumbnail
;; 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
[frame-id]
@ -607,7 +612,8 @@
xform (comp (mapcat extract-ids)
(map get-frame-id)
(remove nil?)
(filter #(not= uuid/zero %)))]
(filter #(not= uuid/zero %))
(filter #(contains? new-objects %)))]
(into #{} xform changes)))
@ -647,7 +653,8 @@
(rx/filter dch/commit-changes?)
(rx/filter (comp not thumbnail-change?))
(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)
no-thumb-frames (->> frames

View file

@ -449,7 +449,7 @@
(ptk/reify ::duplicate-selected
ptk/WatchEvent
(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)
objects (wsh/lookup-page-objects state page-id)
selected (wsh/lookup-selected state)
@ -475,10 +475,10 @@
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
:origin it})
(select-shapes selected)
(memorize-duplicated id-original id-duplicated)))))))
(defn change-hover-state

View file

@ -510,6 +510,11 @@
(defn- start-move-duplicate
[from-position]
(ptk/reify ::start-move-duplicate
ptk/UpdateEvent
(update [_ state]
(-> state
(assoc-in [:workspace-local :transform] :move)))
ptk/WatchEvent
(watch [_ _ stream]
(->> stream

View file

@ -90,41 +90,46 @@
(mf/create-element component 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]
(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/wrap [#(mf/memo' % check-frame-props) custom-deferred]
{::mf/wrap [#(mf/memo' % check-frame-props)]
::mf/wrap-props false}
[props]
(let [shape (unchecked-get props "shape")
objects (unchecked-get props "objects")
thumbnail? (unchecked-get props "thumbnail?")
children (-> (mapv (d/getf objects) (:shapes shape))
(hooks/use-equal-memo))
(let [shape (unchecked-get props "shape")
objects (unchecked-get props "objects")
thumbnail? (unchecked-get props "thumbnail?")
all-children (-> (cp/get-children-objects (:id shape) objects)
(hooks/use-equal-memo))
children (-> (mapv (d/getf objects) (:shapes shape))
(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)))
on-dom
(mf/use-callback
(fn [node]
(ts/schedule-on-idle #(reset! rendered? (some? node)))))]
show-thumbnail? (and thumbnail? (some? (:thumbnail shape)))]
(when (some? shape)
[:g.frame-wrapper {:display (when (:hidden shape) "none")}
(when-not show-thumbnail?
[:> shape-container {:shape shape :ref on-dom}
[:& ff/fontfaces-style {:shapes all-children}]
[:& frame-shape {:shape shape
:childs children}]])
(when (or (not @rendered?) show-thumbnail?)
[:& thumbnail {:shape shape}])])))))
[:> shape-container {:shape shape}
[:& ff/fontfaces-style {:shapes all-children}]
(if show-thumbnail?
[:& thumbnail {:shape shape}]
[:& deferred-frame-shape
{:shape shape
:childs children}])]])))))

View file

@ -28,10 +28,14 @@
(when node
(let [img-node (mf/ref-val thumbnail-img)]
(timers/schedule-on-idle
#(let [frame-node (dom/get-element (str "shape-" (:id shape)))
loading-node (when frame-node
(dom/query frame-node "[data-loading=\"true\"]"))]
(if (and (some? frame-node) (not (some? loading-node)))
#(let [frame-node (dom/get-element (str "shape-" (:id shape)))
thumb-node (dom/query frame-node ".frame-thumbnail")
loading-node (dom/query frame-node "[data-loading=\"true\"]")]
(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.)
(.serializeToString frame-node))
@ -125,7 +129,9 @@
;; after a time
(reset! shape-id nil)
(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/deps render-frame)

View file

@ -52,17 +52,16 @@
;; When the shape is a frame we maybe need to move its thumbnail
thumb-node (when frame? (dom/get-element (str "thumbnail-" id)))]
(cond
(some? thumb-node)
[(.-parentNode thumb-node)]
(and (some? shape-node) frame?)
[(dom/query shape-node ".frame-background")
(cond
frame?
[thumb-node
(dom/query shape-node ".frame-background")
(dom/query shape-node ".frame-clip")]
;; For groups we don't want to transform the whole group but only
;; its filters/masks
(and (some? shape-node) mask?)
mask?
[(dom/query shape-node ".mask-clip-path")
(dom/query shape-node ".mask-shape")]

View file

@ -186,7 +186,8 @@
(defn query
[el query]
(.querySelector el query))
(when (some? el)
(.querySelector el query)))
(defn get-client-position
[event]

View file

@ -44,11 +44,15 @@
(def ^:private cancel-idle-callback #(js/clearTimeout %))))
(defn schedule-on-idle
[func]
(let [sem (request-idle-callback #(func))]
(reify rx/IDisposable
(-dispose [_]
(cancel-idle-callback sem)))))
([ms func]
;; Schedule on idle after `ms` time
(schedule ms #(schedule-on-idle func)))
([func]
(let [sem (request-idle-callback #(func))]
(reify rx/IDisposable
(-dispose [_]
(cancel-idle-callback sem))))))
(def ^:private request-animation-frame
(or (and (exists? js/window) (.-requestAnimationFrame js/window))