🐛 Fix problem with component thumbnails

This commit is contained in:
alonso.torres 2026-04-10 11:51:40 +02:00 committed by Alonso Torres
parent f07b954b7e
commit 1d8299a919
3 changed files with 79 additions and 28 deletions

View File

@ -411,9 +411,16 @@
(when id-ref
(reset! id-ref component-id))
(when-not (empty? (:redo-changes changes))
(rx/of (dch/commit-changes changes)
(dws/select-shapes (d/ordered-set (:id root)))
(ptk/data-event :layout/update {:ids parents}))))))))))
(rx/concat
(rx/of (dch/commit-changes changes)
(dws/select-shapes (d/ordered-set (:id root)))
(ptk/data-event :layout/update {:ids parents}))
;; When activated the wasm rendering we need to recreate its thumbnail on creation
(if (features/active-feature? state "render-wasm/v1")
(rx/of (dwt.wasm/render-thumbnail file-id page-id (:id root))
(dwt.wasm/persist-thumbnail file-id page-id (:id root)))
(rx/empty)))))))))))
(defn add-component
"Add a new component to current file library, from the currently selected shapes.

View File

@ -15,11 +15,15 @@
- persist-thumbnail: pushes current data-uri to the server (debounced)"
(:require
[app.common.data.macros :as dm]
[app.common.files.helpers :as cfh]
[app.common.logging :as l]
[app.common.math :as mth]
[app.common.thumbnails :as thc]
[app.common.time :as ct]
[app.main.data.helpers :as dsh]
[app.main.data.workspace.thumbnails :as dwt]
[app.main.repo :as rp]
[app.main.store :as st]
[app.render-wasm.api :as wasm.api]
[app.util.webapi :as wapi]
[beicon.v2.core :as rx]
@ -41,27 +45,38 @@
(fn [e] (reject e)))
(.readAsDataURL reader blob)))))
;; This constant stores the target thumbnail minimum max-size so
;; the images doesn't lose quality when rendered
(def target-size 200)
(defn- render-component-pixels
"Renders a component frame using the workspace WASM context.
Returns an observable that emits a data-uri string.
Deferred by one animation frame so that process-shape-changes!
has time to sync all child shapes to WASM memory first."
[frame-id]
[file-id page-id frame-id]
(rx/create
(fn [subs]
(js/requestAnimationFrame
(fn [_]
(try
(let [png-bytes (wasm.api/render-shape-pixels frame-id 1)]
(let [objects (dsh/lookup-page-objects @st/state file-id page-id)
frame (get objects frame-id)
{:keys [width height]} (:selrect frame)
max-size (mth/max width height)
scale (mth/max 1 (/ target-size max-size))
png-bytes (wasm.api/render-shape-pixels frame-id scale)]
(if (or (nil? png-bytes) (zero? (.-length png-bytes)))
(do (js/console.error "[thumbnails] render-shape-pixels returned empty for" (str frame-id))
(rx/end! subs))
(.then (png-bytes->data-uri png-bytes)
(fn [data-uri]
(rx/push! subs data-uri)
(rx/end! subs))
(fn [err]
(rx/error! subs err)))))
(do
(js/console.error "[thumbnails] render-shape-pixels returned empty for" (str frame-id))
(rx/end! subs))
(.then
(png-bytes->data-uri png-bytes)
(fn [data-uri]
(rx/push! subs data-uri)
(rx/end! subs))
(fn [err]
(rx/error! subs err)))))
(catch :default err
(rx/error! subs err)))))
nil)))
@ -71,29 +86,57 @@
Does NOT persist to the server — persistence is handled separately
by `persist-thumbnail` on a debounced schedule."
[file-id page-id frame-id]
(let [object-id (thc/fmt-object-id file-id page-id frame-id "component")]
(ptk/reify ::render-thumbnail
cljs.core/IDeref
(-deref [_] object-id)
ptk/WatchEvent
(watch [_ _ stream]
(let [tp (ct/tpoint-ms)]
(->> (render-component-pixels frame-id)
(rx/map
(fn [data-uri]
(l/dbg :hint "component thumbnail rendered (wasm)"
:elapsed (dm/str (tp) "ms"))
(dwt/assoc-thumbnail object-id data-uri)))
(watch [_ state stream]
;; When the component is removed it can arrived a render
;; request with frame-id=null
(when (some? frame-id)
(letfn [(load-objects-stream
[]
(rx/create
(fn [subs]
(let [objects (dsh/lookup-page-objects state file-id page-id)
(rx/catch (fn [err]
(js/console.error "[thumbnails] error rendering component thumbnail" err)
(rx/empty)))
;; retrieves a subtree with only the id and its children
;; to be loaded before rendering the thumbnail
subtree
(into {}
(map #(vector (:id %) %))
(cfh/get-children-with-self objects frame-id))]
(try
(wasm.api/set-objects subtree #(rx/push! subs %))
(catch :default err
(rx/error! subs err)))))))
(rx/take-until
(->> stream
(rx/filter (ptk/type? ::dwt/clear-thumbnail))
(rx/filter #(= (deref %) object-id))))))))))
(do-render-thumbnail
[]
(let [tp (ct/tpoint-ms)]
(->> (render-component-pixels file-id page-id frame-id)
(rx/map
(fn [data-uri]
(l/dbg :hint "component thumbnail rendered (wasm)"
:elapsed (dm/str (tp) "ms"))
(dwt/assoc-thumbnail object-id data-uri)))
(rx/catch (fn [err]
(js/console.error "[thumbnails] error rendering component thumbnail" err)
(rx/empty)))
(rx/take-until
(->> stream
(rx/filter (ptk/type? ::dwt/clear-thumbnail))
(rx/filter #(= (deref %) object-id)))))))]
(if (not= page-id (:current-page-id state))
(->> (load-objects-stream)
(rx/mapcat do-render-thumbnail))
(do-render-thumbnail))))))))
(defn persist-thumbnail
"Persists the current component thumbnail data-uri to the server.

View File

@ -24,6 +24,7 @@
cause-sym (gensym "cause")]
`(let [~fn-sym (cljs.core/unchecked-get ~module ~name)]
(try
;; (prn ~name ~@params)
(~fn-sym ~@params)
(catch :default ~cause-sym
(let [read-code-fn# (cljs.core/unchecked-get ~module "_read_error_code")