0
Fork 0
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:
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) (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

View file

@ -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

View file

@ -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

View file

@ -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}])])))))

View file

@ -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)

View file

@ -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")]

View file

@ -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]

View file

@ -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))