mirror of
https://github.com/penpot/penpot.git
synced 2025-02-13 10:38:13 -05:00
Merge pull request #3665 from penpot/niwinz-develop-workspace-thumbnails
♻️ Add another refactor iteration on workspace thumbnails
This commit is contained in:
commit
6e8cfa7be4
16 changed files with 367 additions and 334 deletions
|
@ -15,7 +15,6 @@
|
|||
[app.main.data.websocket :as ws]
|
||||
[app.main.errors]
|
||||
[app.main.features :as feat]
|
||||
[app.main.imposters :as imp]
|
||||
[app.main.rasterizer :as thr]
|
||||
[app.main.store :as st]
|
||||
[app.main.ui :as ui]
|
||||
|
@ -114,7 +113,6 @@
|
|||
(theme/init! cf/themes)
|
||||
(cur/init-styles)
|
||||
(thr/init!)
|
||||
(imp/init!)
|
||||
(init-ui)
|
||||
(st/emit! (initialize)))
|
||||
|
||||
|
|
|
@ -385,9 +385,10 @@
|
|||
;; we only need to proceed when page-index is properly loaded
|
||||
(when-let [pindex (-> state :workspace-data :pages-index)]
|
||||
(if (contains? pindex page-id)
|
||||
(rx/of (preload-data-uris page-id)
|
||||
(dwth/watch-state-changes)
|
||||
(dwl/watch-component-changes))
|
||||
(let [file-id (:current-file-id state)]
|
||||
(rx/of (preload-data-uris page-id)
|
||||
(dwth/watch-state-changes file-id page-id)
|
||||
(dwl/watch-component-changes)))
|
||||
(let [page-id (dm/get-in state [:workspace-data :pages 0])]
|
||||
(rx/of (go-to-page page-id))))))))
|
||||
|
||||
|
|
|
@ -13,7 +13,7 @@
|
|||
[app.common.types.shape-tree :as ctst]
|
||||
[app.common.uuid :as uuid]
|
||||
[app.main.data.workspace.changes :as dch]
|
||||
;; [app.main.data.workspace.thumbnails :as dwt]
|
||||
[app.main.data.workspace.thumbnails :as dwt]
|
||||
[app.main.features :as features]
|
||||
[app.main.repo :as rp]
|
||||
[app.main.store :as st]
|
||||
|
@ -156,10 +156,9 @@
|
|||
(->> (rp/cmd! :update-file params)
|
||||
(rx/mapcat (fn [lagged]
|
||||
(log/debug :hint "changes persisted" :lagged (count lagged))
|
||||
(let [
|
||||
;; frame-updates
|
||||
;; (-> (group-by :page-id changes)
|
||||
;; (update-vals #(into #{} (mapcat :frames) %)))
|
||||
(let [frame-updates
|
||||
(-> (group-by :page-id changes)
|
||||
(update-vals #(into #{} (mapcat :frames) %)))
|
||||
|
||||
commits
|
||||
(->> @pending-commits
|
||||
|
@ -167,10 +166,11 @@
|
|||
|
||||
(rx/concat
|
||||
(rx/merge
|
||||
#_(->> (rx/from frame-updates)
|
||||
(rx/mapcat (fn [[page-id frames]]
|
||||
(->> frames (map #(vector page-id %)))))
|
||||
(rx/map (fn [[_ frame-id]] (dwt/update-thumbnail frame-id))))
|
||||
(->> (rx/from frame-updates)
|
||||
(rx/mapcat (fn [[page-id frames]]
|
||||
(->> frames (map (fn [frame-id] [file-id page-id frame-id])))))
|
||||
(rx/map (fn [data]
|
||||
(ptk/data-event ::dwt/update data))))
|
||||
|
||||
(->> (rx/from (concat lagged commits))
|
||||
(rx/merge-map
|
||||
|
|
|
@ -7,67 +7,92 @@
|
|||
(ns app.main.data.workspace.thumbnails
|
||||
(:require
|
||||
[app.common.data.macros :as dm]
|
||||
[app.common.logging :as log]
|
||||
;; [app.common.pages.helpers :as cph]
|
||||
;; [app.common.uuid :as uuid]
|
||||
;; [app.main.data.workspace.changes :as dch]
|
||||
;; [app.main.data.workspace.state-helpers :as wsh]
|
||||
[app.common.logging :as l]
|
||||
[app.common.pages.helpers :as cph]
|
||||
[app.common.uuid :as uuid]
|
||||
[app.main.data.workspace.changes :as dch]
|
||||
[app.main.data.workspace.notifications :as-alias wnt]
|
||||
[app.main.data.workspace.state-helpers :as wsh]
|
||||
[app.main.rasterizer :as thr]
|
||||
;; [app.main.refs :as refs]
|
||||
[app.main.refs :as refs]
|
||||
[app.main.render :as render]
|
||||
[app.main.repo :as rp]
|
||||
;; [app.main.store :as st]
|
||||
[app.util.http :as http]
|
||||
[app.util.imposters :as imps]
|
||||
[app.util.time :as tp]
|
||||
[app.util.timers :as tm]
|
||||
[app.util.webapi :as wapi]
|
||||
[beicon.core :as rx]
|
||||
[cuerdas.core :as str]
|
||||
[potok.core :as ptk]))
|
||||
|
||||
(log/set-level! :debug)
|
||||
(l/set-level! :info)
|
||||
|
||||
(declare set-workspace-thumbnail)
|
||||
(defn fmt-object-id
|
||||
[file-id page-id frame-id]
|
||||
(str/ffmt "%/%/%" file-id page-id frame-id))
|
||||
|
||||
(defn get-thumbnail
|
||||
[id]
|
||||
(let [object-id (dm/str id)
|
||||
tp (tp/tpoint-ms)]
|
||||
(->> (rx/of id)
|
||||
(rx/mapcat @imps/render-fn)
|
||||
(rx/filter #(= object-id (unchecked-get % "id")))
|
||||
[state file-id page-id frame-id & {:keys [object-id]}]
|
||||
|
||||
(let [object-id (or object-id (fmt-object-id file-id page-id frame-id))
|
||||
tp (tp/tpoint-ms)
|
||||
objects (wsh/lookup-page-objects state page-id)
|
||||
shape (get objects frame-id)]
|
||||
|
||||
(->> (render/render-frame objects shape object-id)
|
||||
(rx/take 1)
|
||||
(rx/map (fn [imposter]
|
||||
{:data (unchecked-get imposter "data")
|
||||
:styles (unchecked-get imposter "styles")
|
||||
:width (unchecked-get imposter "width")}))
|
||||
(rx/filter some?)
|
||||
(rx/mapcat thr/render)
|
||||
(rx/map (fn [blob] (wapi/create-uri blob)))
|
||||
(rx/tap #(log/debug :hint "generated thumbnail" :elapsed (dm/str (tp) "ms"))))))
|
||||
(rx/tap #(l/dbg :hint "thumbnail rendered"
|
||||
:elapsed (dm/str (tp) "ms"))))))
|
||||
|
||||
(defn clear-thumbnail
|
||||
[frame-id]
|
||||
(ptk/reify ::clear-thumbnail
|
||||
ptk/UpdateEvent
|
||||
(update [_ state]
|
||||
(let [object-id (dm/str frame-id)]
|
||||
(when-let [uri (dm/get-in state [:workspace-thumbnails object-id])]
|
||||
(tm/schedule-on-idle (partial wapi/revoke-uri uri)))
|
||||
(update state :workspace-thumbnails dissoc object-id)))))
|
||||
(defn- clear-thumbnail
|
||||
([file-id page-id frame-id]
|
||||
(clear-thumbnail file-id (fmt-object-id file-id page-id frame-id)))
|
||||
([file-id object-id]
|
||||
(let [emit-rpc? (volatile! false)]
|
||||
(ptk/reify ::clear-thumbnail
|
||||
cljs.core/IDeref
|
||||
(-deref [_] object-id)
|
||||
|
||||
(defn set-workspace-thumbnail
|
||||
[id uri]
|
||||
ptk/UpdateEvent
|
||||
(update [_ state]
|
||||
(let [uri (dm/get-in state [:workspace-thumbnails object-id])]
|
||||
(if (some? uri)
|
||||
(do
|
||||
(l/dbg :hint "clear thumbnail" :object-id object-id)
|
||||
(vreset! emit-rpc? true)
|
||||
(tm/schedule-on-idle (partial wapi/revoke-uri uri))
|
||||
(update state :workspace-thumbnails dissoc object-id))
|
||||
|
||||
state)))
|
||||
|
||||
ptk/WatchEvent
|
||||
(watch [_ _ _]
|
||||
(when ^boolean @emit-rpc?
|
||||
(->> (rp/cmd! :delete-file-object-thumbnail {:file-id file-id :object-id object-id})
|
||||
(rx/catch rx/empty)
|
||||
(rx/ignore))))))))
|
||||
|
||||
(defn- assoc-thumbnail
|
||||
[object-id uri]
|
||||
(let [prev-uri* (volatile! nil)]
|
||||
(ptk/reify ::set-workspace-thumbnail
|
||||
(ptk/reify ::assoc-thumbnail
|
||||
ptk/UpdateEvent
|
||||
(update [_ state]
|
||||
(let [object-id (dm/str id)
|
||||
prev-uri (dm/get-in state [:workspace-thumbnails object-id])]
|
||||
(let [prev-uri (dm/get-in state [:workspace-thumbnails object-id])]
|
||||
(some->> prev-uri (vreset! prev-uri*))
|
||||
(l/trc :hint "assoc thumbnail" :object-id object-id :uri uri)
|
||||
|
||||
(update state :workspace-thumbnails assoc object-id uri)))
|
||||
|
||||
ptk/EffectEvent
|
||||
(effect [_ _ _]
|
||||
(tm/schedule-on-idle #(some-> ^boolean @prev-uri* wapi/revoke-uri))))))
|
||||
(tm/schedule-on-idle
|
||||
(fn []
|
||||
(when-let [uri (deref prev-uri*)]
|
||||
(wapi/revoke-uri uri))))))))
|
||||
|
||||
(defn duplicate-thumbnail
|
||||
[old-id new-id]
|
||||
|
@ -81,42 +106,45 @@
|
|||
|
||||
(defn update-thumbnail
|
||||
"Updates the thumbnail information for the given frame `id`"
|
||||
([id]
|
||||
(ptk/reify ::update-thumbnail
|
||||
ptk/WatchEvent
|
||||
(watch [_ state _]
|
||||
(let [object-id (dm/str id)
|
||||
file-id (:current-file-id state)]
|
||||
(rx/concat
|
||||
;; Delete the thumbnail first so if we interrupt we can regenerate after
|
||||
(->> (rp/cmd! :delete-file-object-thumbnail {:file-id file-id :object-id object-id})
|
||||
(rx/catch rx/empty))
|
||||
|
||||
;; Send the update to the back-end
|
||||
(->> (get-thumbnail id)
|
||||
(rx/filter (fn [data] (and (some? data) (some? file-id))))
|
||||
(rx/merge-map
|
||||
(fn [uri]
|
||||
(rx/merge
|
||||
(rx/of (set-workspace-thumbnail object-id uri))
|
||||
[file-id page-id frame-id]
|
||||
(let [object-id (fmt-object-id file-id page-id frame-id)]
|
||||
(ptk/reify ::update-thumbnail
|
||||
cljs.core/IDeref
|
||||
(-deref [_] object-id)
|
||||
|
||||
(->> (http/send! {:uri uri :response-type :blob :method :get})
|
||||
(rx/map :body)
|
||||
(rx/mapcat (fn [blob]
|
||||
;; Send the data to backend
|
||||
(let [params {:file-id file-id
|
||||
:object-id object-id
|
||||
:media blob}]
|
||||
(rp/cmd! :create-file-object-thumbnail params))))
|
||||
(rx/catch rx/empty)
|
||||
(rx/ignore)))))
|
||||
ptk/WatchEvent
|
||||
(watch [_ state stream]
|
||||
(l/dbg :hint "update thumbnail" :object-id object-id)
|
||||
;; Send the update to the back-end
|
||||
(->> (get-thumbnail state file-id page-id frame-id {:object-id object-id})
|
||||
(rx/mapcat (fn [uri]
|
||||
(rx/merge
|
||||
(rx/of (assoc-thumbnail object-id uri))
|
||||
(->> (http/send! {:uri uri :response-type :blob :method :get})
|
||||
(rx/map :body)
|
||||
(rx/mapcat (fn [blob]
|
||||
;; Send the data to backend
|
||||
(let [params {:file-id file-id
|
||||
:object-id object-id
|
||||
:media blob}]
|
||||
(rp/cmd! :create-file-object-thumbnail params))))
|
||||
(rx/catch rx/empty)
|
||||
(rx/ignore)))))
|
||||
(rx/catch (fn [cause]
|
||||
(.error js/console cause)
|
||||
(rx/empty)))
|
||||
|
||||
(rx/catch #(do (.error js/console %)
|
||||
(rx/empty))))))))))
|
||||
;; We cancel all the stream if user starts editing while
|
||||
;; thumbnail is generating
|
||||
(rx/take-until
|
||||
(->> stream
|
||||
(rx/filter (ptk/type? ::clear-thumbnail))
|
||||
(rx/filter #(= (deref %) object-id)))))))))
|
||||
|
||||
#_(defn- extract-frame-changes
|
||||
(defn- extract-frame-changes
|
||||
"Process a changes set in a commit to extract the frames that are changing"
|
||||
[[event [old-data new-data]]]
|
||||
[page-id [event [old-data new-data]]]
|
||||
(let [changes (-> event deref :changes)
|
||||
|
||||
extract-ids
|
||||
|
@ -129,40 +157,42 @@
|
|||
[]))
|
||||
|
||||
get-frame-id
|
||||
(fn [[page-id id]]
|
||||
(let [old-objects (wsh/lookup-data-objects old-data page-id)
|
||||
new-objects (wsh/lookup-data-objects new-data page-id)
|
||||
(fn [[_ id]]
|
||||
(let [old-objects (wsh/lookup-data-objects old-data page-id)
|
||||
new-objects (wsh/lookup-data-objects new-data page-id)
|
||||
|
||||
new-shape (get new-objects id)
|
||||
old-shape (get old-objects id)
|
||||
new-shape (get new-objects id)
|
||||
old-shape (get old-objects id)
|
||||
|
||||
old-frame-id (if (cph/frame-shape? old-shape) id (:frame-id old-shape))
|
||||
new-frame-id (if (cph/frame-shape? new-shape) id (:frame-id new-shape))]
|
||||
|
||||
(cond-> #{}
|
||||
(and old-frame-id (not= uuid/zero old-frame-id))
|
||||
(conj [page-id old-frame-id])
|
||||
(and (some? old-frame-id) (not= uuid/zero old-frame-id))
|
||||
(conj old-frame-id)
|
||||
|
||||
(and new-frame-id (not= uuid/zero new-frame-id))
|
||||
(conj [page-id new-frame-id]))))]
|
||||
(and (some? new-frame-id) (not= uuid/zero new-frame-id))
|
||||
(conj new-frame-id))))]
|
||||
|
||||
(into #{}
|
||||
(comp (mapcat extract-ids)
|
||||
(filter (fn [[page-id']] (= page-id page-id')))
|
||||
(mapcat get-frame-id))
|
||||
changes)))
|
||||
|
||||
(defn watch-state-changes
|
||||
"Watch the state for changes inside frames. If a change is detected will force a rendering
|
||||
of the frame data so the thumbnail can be updated."
|
||||
[]
|
||||
[file-id page-id]
|
||||
(ptk/reify ::watch-state-changes
|
||||
ptk/WatchEvent
|
||||
(watch [_ _ _stream]
|
||||
#_(let [
|
||||
stopper
|
||||
(->> stream
|
||||
(rx/filter #(or (= :app.main.data.workspace/finalize-page (ptk/type %))
|
||||
(= ::watch-state-changes (ptk/type %)))))
|
||||
(watch [_ _ stream]
|
||||
(let [stopper-s (rx/filter
|
||||
(fn [event]
|
||||
(as-> (ptk/type event) type
|
||||
(or (= :app.main.data.workspace/finalize-page type)
|
||||
(= ::watch-state-changes type))))
|
||||
stream)
|
||||
|
||||
workspace-data-s
|
||||
(->> (rx/concat
|
||||
|
@ -170,27 +200,60 @@
|
|||
(rx/from-atom refs/workspace-data {:emit-current-value? true}))
|
||||
;; We need to keep the old-objects so we can check the frame for the
|
||||
;; deleted objects
|
||||
(rx/buffer 2 1))
|
||||
|
||||
change-s
|
||||
(->> stream
|
||||
(rx/filter #(or (dch/commit-changes? %)
|
||||
(= (ptk/type %) :app.main.data.workspace.notifications/handle-file-change)))
|
||||
(rx/observe-on :async))
|
||||
|
||||
frame-changes-s
|
||||
(->> change-s
|
||||
(rx/with-latest-from workspace-data-s)
|
||||
(rx/flat-map extract-frame-changes)
|
||||
(rx/buffer 2 1)
|
||||
(rx/share))
|
||||
]
|
||||
|
||||
changes-s
|
||||
(->> (rx/merge
|
||||
;; LOCAL CHANGES
|
||||
(->> stream
|
||||
(rx/filter dch/commit-changes?)
|
||||
(rx/observe-on :async)
|
||||
(rx/with-latest-from workspace-data-s)
|
||||
(rx/flat-map (partial extract-frame-changes page-id))
|
||||
(rx/tap #(l/trc :hint "inconming change" :origin "local" :frame-id (dm/str %))))
|
||||
|
||||
;; NOTIFICATIONS CHANGES
|
||||
(->> stream
|
||||
(rx/filter (ptk/type? ::wnt/handle-file-change))
|
||||
(rx/observe-on :async)
|
||||
(rx/with-latest-from workspace-data-s)
|
||||
(rx/flat-map (partial extract-frame-changes page-id))
|
||||
(rx/tap #(l/trc :hint "inconming change" :origin "notifications" :frame-id (dm/str %))))
|
||||
|
||||
;; PERSISTENCE CHANGES
|
||||
(->> stream
|
||||
(rx/filter (ptk/type? ::update))
|
||||
(rx/map deref)
|
||||
(rx/filter (fn [[file-id page-id]]
|
||||
(and (= file-id file-id)
|
||||
(= page-id page-id))))
|
||||
(rx/map (fn [[_ _ frame-id]] frame-id))
|
||||
(rx/tap #(l/trc :hint "inconming change" :origin "persistence" :frame-id (dm/str %)))))
|
||||
|
||||
(rx/share))
|
||||
|
||||
;; BUFFER NOTIFIER (window of 5s of inactivity)
|
||||
notifier-s
|
||||
(->> changes-s
|
||||
(rx/debounce 5000)
|
||||
(rx/tap #(l/trc :hint "buffer initialized")))]
|
||||
|
||||
(->> (rx/merge
|
||||
(->> frame-changes-s
|
||||
(rx/filter (fn [[page-id _]] (not= page-id (:current-page-id @st/state))))
|
||||
(rx/map (fn [[_ frame-id]] (clear-thumbnail frame-id))))
|
||||
;; Perform instant thumbnail cleaning of affected frames
|
||||
;; and interrupt any ongoing update-thumbnail process
|
||||
;; related to current frame-id
|
||||
(->> changes-s
|
||||
(rx/map (fn [frame-id]
|
||||
(clear-thumbnail file-id page-id frame-id))))
|
||||
|
||||
;; Generate thumbnails in batchs, once user becomes
|
||||
;; inactive for some instant
|
||||
(->> changes-s
|
||||
(rx/buffer-until notifier-s)
|
||||
(rx/mapcat #(into #{} %))
|
||||
(rx/map (fn [frame-id]
|
||||
(update-thumbnail file-id page-id frame-id)))))
|
||||
|
||||
(rx/take-until stopper-s))))))
|
||||
|
||||
(->> frame-changes-s
|
||||
(rx/filter (fn [[page-id _]] (= page-id (:current-page-id @st/state))))
|
||||
(rx/map (fn [[_ frame-id]] (update-thumbnail frame-id)))))
|
||||
(rx/take-until stopper))))))
|
||||
|
|
|
@ -1,77 +0,0 @@
|
|||
;; This Source Code Form is subject to the terms of the Mozilla Public
|
||||
;; License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
;; file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
;;
|
||||
;; Copyright (c) KALEIDOS INC
|
||||
|
||||
(ns app.main.imposters
|
||||
(:require ["react-dom/server" :as rds]
|
||||
[app.common.data.macros :as dm]
|
||||
[app.common.geom.rect :as grc]
|
||||
[app.common.geom.shapes :as gsh]
|
||||
[app.main.data.workspace.state-helpers :as wsh]
|
||||
[app.main.fonts :as fonts]
|
||||
[app.main.refs :as refs]
|
||||
[app.main.render :as render]
|
||||
[app.main.store :as st]
|
||||
[app.main.ui.shapes.text.fontfaces :as ff]
|
||||
[app.util.imposters :as imps]
|
||||
[app.util.thumbnails :as th]
|
||||
[beicon.core :as rx]
|
||||
[rumext.v2 :as mf]))
|
||||
|
||||
(defn render
|
||||
"Render the frame and store it in the imposter map"
|
||||
([id shape objects]
|
||||
(render id shape objects nil))
|
||||
([id shape objects fonts]
|
||||
(let [object-id (dm/str id)
|
||||
shape (if (nil? shape) (get objects id) shape)
|
||||
fonts (if (nil? fonts) (ff/shape->fonts shape objects) fonts)
|
||||
|
||||
all-children (deref (refs/all-children-objects id))
|
||||
|
||||
bounds
|
||||
(if (:show-content shape)
|
||||
(gsh/shapes->rect (cons shape all-children))
|
||||
(-> shape :points grc/points->rect))
|
||||
|
||||
x (dm/get-prop bounds :x)
|
||||
y (dm/get-prop bounds :y)
|
||||
width (dm/get-prop bounds :width)
|
||||
height (dm/get-prop bounds :height)
|
||||
|
||||
viewbox (dm/fmt "% % % %" x y width height)
|
||||
|
||||
[fixed-width fixed-height] (th/get-proportional-size width height)
|
||||
|
||||
data (rds/renderToStaticMarkup
|
||||
(mf/element render/frame-imposter-svg
|
||||
{:objects objects
|
||||
:frame shape
|
||||
:vbox viewbox
|
||||
:width width
|
||||
:height height
|
||||
:show-thumbnails? false}))]
|
||||
(->> (fonts/render-font-styles-cached fonts)
|
||||
(rx/catch rx/empty)
|
||||
(rx/map (fn [styles] #js {:id object-id
|
||||
:data data
|
||||
:viewbox viewbox
|
||||
:width fixed-width
|
||||
:height fixed-height
|
||||
:styles styles}))))))
|
||||
|
||||
(defn render-by-id
|
||||
"Render the shape by its id (IMPORTANT! id as uuid, not string)"
|
||||
[id]
|
||||
(dm/assert! "expected uuid" (uuid? id))
|
||||
(let [objects (wsh/lookup-page-objects @st/state)
|
||||
shape (get objects id)
|
||||
fonts (ff/shape->fonts shape objects)]
|
||||
(render id shape objects fonts)))
|
||||
|
||||
(defn init!
|
||||
"Initializes the render function"
|
||||
[]
|
||||
(imps/init! render-by-id))
|
|
@ -475,15 +475,12 @@
|
|||
(dm/get-in state [:viewer-local :zoom-type]))
|
||||
st/state))
|
||||
|
||||
(def thumbnail-data
|
||||
(l/derived #(get % :workspace-thumbnails {}) st/state))
|
||||
|
||||
(defn thumbnail-frame-data
|
||||
[frame-id]
|
||||
(defn workspace-thumbnail-by-id
|
||||
[object-id]
|
||||
(l/derived
|
||||
(fn [thumbnails]
|
||||
(get thumbnails (dm/str frame-id)))
|
||||
thumbnail-data))
|
||||
(fn [state]
|
||||
(dm/get-in state [:workspace-thumbnails object-id]))
|
||||
st/state))
|
||||
|
||||
(def workspace-text-modifier
|
||||
(l/derived :workspace-text-modifier st/state))
|
||||
|
|
|
@ -14,11 +14,13 @@
|
|||
(:require
|
||||
["react-dom/server" :as rds]
|
||||
[app.common.colors :as clr]
|
||||
[app.common.data :as d]
|
||||
[app.common.data.macros :as dm]
|
||||
[app.common.geom.point :as gpt]
|
||||
[app.common.geom.rect :as grc]
|
||||
[app.common.geom.shapes :as gsh]
|
||||
[app.common.geom.shapes.bounds :as gsb]
|
||||
[app.common.logging :as l]
|
||||
[app.common.math :as mth]
|
||||
[app.common.pages.helpers :as cph]
|
||||
[app.common.types.file :as ctf]
|
||||
|
@ -43,6 +45,7 @@
|
|||
[app.util.http :as http]
|
||||
[app.util.object :as obj]
|
||||
[app.util.strings :as ust]
|
||||
[app.util.thumbnails :as th]
|
||||
[app.util.timers :as ts]
|
||||
[beicon.core :as rx]
|
||||
[clojure.set :as set]
|
||||
|
@ -229,17 +232,11 @@
|
|||
[:& shape-wrapper {:shape item
|
||||
:key (:id item)}])]]]]))
|
||||
|
||||
;; Component that serves for render frame thumbnails, mainly used in
|
||||
;; the viewer and inspector
|
||||
(mf/defc frame-imposter-svg
|
||||
{::mf/wrap [mf/memo]}
|
||||
[{:keys [objects frame vbox width height show-thumbnails?] :as props}]
|
||||
(let [shape-wrapper
|
||||
(mf/use-memo
|
||||
(mf/deps objects)
|
||||
#(shape-wrapper-factory objects))]
|
||||
|
||||
[:& (mf/provider muc/render-thumbnails) {:value show-thumbnails?}
|
||||
(mf/defc frame-imposter
|
||||
{::mf/wrap-props false}
|
||||
[{:keys [objects frame vbox width height]}]
|
||||
(let [shape-wrapper (shape-wrapper-factory objects)]
|
||||
[:& (mf/provider muc/render-thumbnails) {:value false}
|
||||
[:svg {:view-box vbox
|
||||
:width (ust/format-precision width viewbox-decimal-precision)
|
||||
:height (ust/format-precision height viewbox-decimal-precision)
|
||||
|
@ -538,3 +535,45 @@
|
|||
#js {:data data :render-embed? true :include-metadata? true
|
||||
:source (name source)})]
|
||||
(rds/renderToStaticMarkup elem))))))))
|
||||
|
||||
(defn render-frame
|
||||
[objects shape object-id]
|
||||
(let [shape-id (dm/get-prop shape :id)
|
||||
fonts (ff/shape->fonts shape objects)
|
||||
|
||||
bounds (if (:show-content shape)
|
||||
(let [ids (cph/get-children-ids objects shape-id)
|
||||
children (sequence (keep (d/getf objects)) ids)]
|
||||
(gsh/shapes->rect (cons shape children)))
|
||||
(-> shape :points grc/points->rect))
|
||||
|
||||
x (dm/get-prop bounds :x)
|
||||
y (dm/get-prop bounds :y)
|
||||
width (dm/get-prop bounds :width)
|
||||
height (dm/get-prop bounds :height)
|
||||
|
||||
viewbox (str/ffmt "% % % %" x y width height)
|
||||
|
||||
[fixed-width
|
||||
fixed-height] (th/get-proportional-size width height)
|
||||
|
||||
data (rds/renderToStaticMarkup
|
||||
(mf/element frame-imposter
|
||||
#js {:objects objects
|
||||
:frame shape
|
||||
:vbox viewbox
|
||||
:width width
|
||||
:height height}))]
|
||||
|
||||
(->> (fonts/render-font-styles-cached fonts)
|
||||
(rx/catch (fn [cause]
|
||||
(l/err :hint "unexpected error on rendering imposter"
|
||||
:cause cause)
|
||||
(rx/empty)))
|
||||
(rx/map (fn [styles]
|
||||
{:id object-id
|
||||
:data data
|
||||
:viewbox viewbox
|
||||
:width fixed-width
|
||||
:height fixed-height
|
||||
:styles styles})))))
|
||||
|
|
|
@ -87,7 +87,7 @@
|
|||
cap-end (:stroke-cap-end stroke)
|
||||
|
||||
color (if (some? gradient)
|
||||
(str/ffmt "url(#stroke-color-gradient_%s_%s)" render-id index)
|
||||
(str/ffmt "url(#stroke-color-gradient-%s-%s)" render-id index)
|
||||
(:stroke-color stroke))
|
||||
|
||||
opacity (when-not (some? gradient)
|
||||
|
@ -198,7 +198,7 @@
|
|||
alignment (:stroke-alignment stroke :center)
|
||||
width (:stroke-width stroke 0)
|
||||
|
||||
props #js {:id (dm/str "stroke-color-gradient_" render-id "_" index)
|
||||
props #js {:id (dm/str "stroke-color-gradient-" render-id "-" index)
|
||||
:gradient gradient
|
||||
:shape shape}]
|
||||
[:*
|
||||
|
@ -391,7 +391,7 @@
|
|||
props
|
||||
(if (or (some? (->> shape-shadow (remove :hidden) seq))
|
||||
(not ^boolean (:hidden shape-blur)))
|
||||
(obj/set! props "filter" (dm/fmt "url(#filter_%)" render-id))
|
||||
(obj/set! props "filter" (dm/fmt "url(#filter-%)" render-id))
|
||||
props))
|
||||
|
||||
svg-attrs (attrs/get-svg-props shape render-id)
|
||||
|
@ -494,11 +494,11 @@
|
|||
(cond
|
||||
(and (some? shape-blur)
|
||||
(not ^boolean (:hidden shape-blur)))
|
||||
(obj/set! props "filter" (dm/fmt "url(#filter_blur_%)" render-id))
|
||||
(obj/set! props "filter" (dm/fmt "url(#filter-blur-%)" render-id))
|
||||
|
||||
(and (empty? shape-fills)
|
||||
(some? (->> shape-shadow (remove :hidden) seq)))
|
||||
(obj/set! props "filter" (dm/fmt "url(#filter_%)" render-id))))]
|
||||
(obj/set! props "filter" (dm/fmt "url(#filter-%)" render-id))))]
|
||||
|
||||
|
||||
(when (d/not-empty? shape-strokes)
|
||||
|
|
|
@ -15,14 +15,13 @@
|
|||
[rumext.v2 :as mf]))
|
||||
|
||||
(defn get-filter-id []
|
||||
(str "filter_" (uuid/next)))
|
||||
(dm/str "filter-" (uuid/next)))
|
||||
|
||||
(defn filter-str
|
||||
[filter-id shape]
|
||||
|
||||
(when (or (seq (->> (:shadow shape) (remove :hidden)))
|
||||
(and (:blur shape) (-> shape :blur :hidden not)))
|
||||
(str/fmt "url(#$0)" [filter-id])))
|
||||
(str/ffmt "url(#%)" filter-id)))
|
||||
|
||||
(mf/defc color-matrix
|
||||
[{:keys [color]}]
|
||||
|
@ -31,7 +30,7 @@
|
|||
[r g b] [(/ r 255) (/ g 255) (/ b 255)]]
|
||||
[:feColorMatrix
|
||||
{:type "matrix"
|
||||
:values (str/fmt "0 0 0 0 $0 0 0 0 0 $1 0 0 0 0 $2 0 0 0 $3 0" [r g b a])}]))
|
||||
:values (str/ffmt "0 0 0 0 % 0 0 0 0 % 0 0 0 0 % 0 0 0 % 0" r g b a)}]))
|
||||
|
||||
(mf/defc drop-shadow-filter
|
||||
[{:keys [filter-in filter-id params]}]
|
||||
|
|
|
@ -66,7 +66,7 @@
|
|||
|
||||
type (dm/get-prop shape :type)
|
||||
render-id (h/use-render-id)
|
||||
filter-id (dm/str "filter_" render-id)
|
||||
filter-id (dm/str "filter-" render-id)
|
||||
styles (-> (obj/create)
|
||||
(obj/set! "pointerEvents" pointer-events)
|
||||
(cond-> (and blend-mode (not= blend-mode :normal))
|
||||
|
@ -116,8 +116,8 @@
|
|||
[:defs
|
||||
[:& defs/svg-defs {:shape shape :render-id render-id}]
|
||||
[:& filters/filters {:shape shape :filter-id filter-id}]
|
||||
[:& filters/filters {:shape shape-without-blur :filter-id (dm/fmt "filter_shadow_%" render-id)}]
|
||||
[:& filters/filters {:shape shape-without-shadows :filter-id (dm/fmt "filter_blur_%" render-id)}]
|
||||
[:& filters/filters {:shape shape-without-blur :filter-id (dm/fmt "filter-shadow-%" render-id)}]
|
||||
[:& filters/filters {:shape shape-without-shadows :filter-id (dm/fmt "filter-blur-%" render-id)}]
|
||||
[:& fills/fills {:shape shape :render-id render-id}]
|
||||
[:& frame/frame-clip-def {:shape shape :render-id render-id}]]
|
||||
|
||||
|
|
|
@ -74,6 +74,7 @@
|
|||
(if ^boolean (cph/frame-shape? shape)
|
||||
[:& root-frame-wrapper
|
||||
{:shape shape
|
||||
:objects objects
|
||||
:thumbnail? (not (contains? active-frames (dm/get-prop shape :id)))}]
|
||||
[:& shape-wrapper {:shape shape}])])]]]))
|
||||
|
||||
|
|
|
@ -6,20 +6,23 @@
|
|||
|
||||
(ns app.main.ui.workspace.shapes.frame
|
||||
(:require
|
||||
[app.common.data :as d]
|
||||
[app.common.data.macros :as dm]
|
||||
;; [app.common.geom.rect :as grc]
|
||||
;; [app.common.geom.shapes :as gsh]
|
||||
[app.common.geom.rect :as grc]
|
||||
[app.common.geom.shapes :as gsh]
|
||||
[app.common.pages.helpers :as cph]
|
||||
[app.main.data.workspace.state-helpers :as wsh]
|
||||
;; [app.main.data.workspace.thumbnails :as dwt]
|
||||
[app.main.data.workspace.thumbnails :as dwt]
|
||||
[app.main.refs :as refs]
|
||||
[app.main.store :as st]
|
||||
[app.main.ui.context :as ctx]
|
||||
[app.main.ui.shapes.embed :as embed]
|
||||
[app.main.ui.shapes.frame :as frame]
|
||||
[app.main.ui.shapes.shape :refer [shape-container]]
|
||||
[app.main.ui.workspace.shapes.common :refer [check-shape-props]]
|
||||
[app.main.ui.workspace.shapes.frame.dynamic-modifiers :as fdm]
|
||||
;; [app.util.debug :as dbg]
|
||||
[app.util.debug :as dbg]
|
||||
[app.util.timers :as tm]
|
||||
[rumext.v2 :as mf]))
|
||||
|
||||
(defn frame-shape-factory
|
||||
|
@ -46,6 +49,12 @@
|
|||
[new-props old-props]
|
||||
(and (= (unchecked-get new-props "thumbnail?")
|
||||
(unchecked-get old-props "thumbnail?"))
|
||||
|
||||
(identical?
|
||||
(unchecked-get new-props "objects")
|
||||
(unchecked-get old-props "objects"))
|
||||
|
||||
^boolean
|
||||
(check-shape-props new-props old-props)))
|
||||
|
||||
(defn nested-frame-wrapper-factory
|
||||
|
@ -69,54 +78,54 @@
|
|||
(fdm/use-dynamic-modifiers objects (mf/ref-val node-ref) modifiers)
|
||||
[:& frame-shape {:shape shape :ref node-ref}]))))
|
||||
|
||||
|
||||
(defn root-frame-wrapper-factory
|
||||
[shape-wrapper]
|
||||
|
||||
(let [frame-shape (frame-shape-factory shape-wrapper)]
|
||||
(mf/fnc frame-wrapper
|
||||
{::mf/wrap [#(mf/memo' % check-props)]
|
||||
::mf/wrap-props false}
|
||||
[props]
|
||||
|
||||
(let [shape (unchecked-get props "shape")
|
||||
;; thumbnail? (unchecked-get props "thumbnail?")
|
||||
(let [shape (unchecked-get props "shape")
|
||||
thumbnail? (unchecked-get props "thumbnail?")
|
||||
objects (unchecked-get props "objects")
|
||||
|
||||
;; page-id (mf/use-ctx ctx/current-page-id)
|
||||
frame-id (:id shape)
|
||||
file-id (mf/use-ctx ctx/current-file-id)
|
||||
page-id (mf/use-ctx ctx/current-page-id)
|
||||
frame-id (dm/get-prop shape :id)
|
||||
|
||||
objects (wsh/lookup-page-objects @st/state)
|
||||
container-ref (mf/use-ref nil)
|
||||
content-ref (mf/use-ref nil)
|
||||
|
||||
container-ref (mf/use-ref nil)
|
||||
content-ref (mf/use-ref nil)
|
||||
;; FIXME: apply specific rendering optimizations separating to a component
|
||||
bounds (if (:show-content shape)
|
||||
(let [ids (cph/get-children-ids objects frame-id)
|
||||
children (sequence (keep (d/getf objects)) ids)]
|
||||
(gsh/shapes->rect (cons shape children)))
|
||||
(-> shape :points grc/points->rect))
|
||||
|
||||
;; all-children-ref (mf/with-memo [frame-id]
|
||||
;; (refs/all-children-objects frame-id))
|
||||
;; all-children (mf/deref all-children-ref)
|
||||
x (dm/get-prop bounds :x)
|
||||
y (dm/get-prop bounds :y)
|
||||
width (dm/get-prop bounds :width)
|
||||
height (dm/get-prop bounds :height)
|
||||
|
||||
;; bounds
|
||||
;; (if (:show-content shape)
|
||||
;; (gsh/shapes->rect (cons shape all-children))
|
||||
;; (-> shape :points grc/points->rect))
|
||||
thumbnail-uri* (mf/with-memo [file-id page-id frame-id]
|
||||
(let [object-id (dwt/fmt-object-id file-id page-id frame-id)]
|
||||
(refs/workspace-thumbnail-by-id object-id)))
|
||||
thumbnail-uri (mf/deref thumbnail-uri*)
|
||||
|
||||
;; x (dm/get-prop bounds :x)
|
||||
;; y (dm/get-prop bounds :y)
|
||||
;; width (dm/get-prop bounds :width)
|
||||
;; height (dm/get-prop bounds :height)
|
||||
modifiers-ref (mf/with-memo [frame-id]
|
||||
(refs/workspace-modifiers-by-frame-id frame-id))
|
||||
modifiers (mf/deref modifiers-ref)
|
||||
|
||||
;; thumbnail-uri* (mf/with-memo [frame-id]
|
||||
;; (refs/thumbnail-frame-data frame-id))
|
||||
;; thumbnail-uri (mf/deref thumbnail-uri*)
|
||||
hidden? (true? (:hidden shape))]
|
||||
|
||||
modifiers-ref (mf/with-memo [frame-id]
|
||||
(refs/workspace-modifiers-by-frame-id frame-id))
|
||||
modifiers (mf/deref modifiers-ref)
|
||||
|
||||
;; debug? (dbg/enabled? :thumbnails)
|
||||
]
|
||||
|
||||
#_(when-not (some? thumbnail-uri)
|
||||
(st/emit! (dwt/update-thumbnail frame-id)))
|
||||
;; NOTE: we don't add deps because we want this to be executed
|
||||
;; once on mount with only referenced the initial data
|
||||
(mf/with-effect []
|
||||
(when-not (some? thumbnail-uri)
|
||||
(tm/schedule-on-idle
|
||||
#(st/emit! (dwt/update-thumbnail file-id page-id frame-id)))))
|
||||
|
||||
(fdm/use-dynamic-modifiers objects (mf/ref-val content-ref) modifiers)
|
||||
|
||||
|
@ -124,24 +133,20 @@
|
|||
[:g.frame-container
|
||||
{:id (dm/str "frame-container-" frame-id)
|
||||
:key "frame-container"
|
||||
;; :ref on-container-ref
|
||||
:opacity (when (:hidden shape) 0)}
|
||||
:opacity (when ^boolean hidden? 0)}
|
||||
|
||||
;; When thumbnail is enabled.
|
||||
#_[:g.frame-imposter
|
||||
;; Render thumbnail image.
|
||||
[:g.frame-imposter
|
||||
[:image.thumbnail-bitmap
|
||||
{;; :ref on-imposter-ref
|
||||
:x x
|
||||
{:x x
|
||||
:y y
|
||||
:width width
|
||||
:height height
|
||||
:href thumbnail-uri
|
||||
:style {:display (when-not thumbnail? "none")}}]
|
||||
:style {:display (when-not ^boolean thumbnail? "none")}}]
|
||||
|
||||
;; Render border around image when we are debugging
|
||||
;; thumbnails.
|
||||
(when ^boolean debug?
|
||||
(when (dbg/enabled? :thumbnails)
|
||||
[:rect {:x (+ x 2)
|
||||
:y (+ y 2)
|
||||
:width (- width 4)
|
||||
|
@ -150,8 +155,10 @@
|
|||
:stroke-width 2}])]
|
||||
|
||||
;; When thumbnail is disabled.
|
||||
(when-not false #_thumbnail?
|
||||
(when (or (not ^boolean thumbnail?)
|
||||
(not ^boolean thumbnail-uri))
|
||||
[:g.frame-content
|
||||
{:id (dm/str "frame-content-" frame-id)
|
||||
:ref container-ref}
|
||||
[:& frame-shape {:shape shape :ref content-ref}]])]]))))
|
||||
|
||||
|
|
|
@ -173,13 +173,13 @@
|
|||
(fn [] (rx/dispose! subs)))))
|
||||
[:g.gradient-handlers
|
||||
[:defs
|
||||
[:& gradient-line-drop-shadow-filter {:id "gradient_line_drop_shadow" :from-p from-p :to-p to-p :zoom zoom}]
|
||||
[:& gradient-line-drop-shadow-filter {:id "gradient_width_line_drop_shadow" :from-p from-p :to-p width-p :zoom zoom}]
|
||||
[:& gradient-square-drop-shadow-filter {:id "gradient_square_from_drop_shadow" :point from-p :zoom zoom}]
|
||||
[:& gradient-square-drop-shadow-filter {:id "gradient_square_to_drop_shadow" :point to-p :zoom zoom}]
|
||||
[:& gradient-width-handler-shadow-filter {:id "gradient_width_handler_drop_shadow" :point width-p :zoom zoom}]]
|
||||
[:& gradient-line-drop-shadow-filter {:id "gradient-line-drop-shadow" :from-p from-p :to-p to-p :zoom zoom}]
|
||||
[:& gradient-line-drop-shadow-filter {:id "gradient-width-line-drop-shadow" :from-p from-p :to-p width-p :zoom zoom}]
|
||||
[:& gradient-square-drop-shadow-filter {:id "gradient-square-from-drop-shadow" :point from-p :zoom zoom}]
|
||||
[:& gradient-square-drop-shadow-filter {:id "gradient-square-to-drop-shadow" :point to-p :zoom zoom}]
|
||||
[:& gradient-width-handler-shadow-filter {:id "gradient-width-handler-drop-shadow" :point width-p :zoom zoom}]]
|
||||
|
||||
[:g {:filter "url(#gradient_line_drop_shadow)"}
|
||||
[:g {:filter "url(#gradient-line-drop-shadow)"}
|
||||
[:line {:x1 (:x from-p)
|
||||
:y1 (:y from-p)
|
||||
:x2 (:x to-p)
|
||||
|
@ -188,7 +188,7 @@
|
|||
:stroke-width (/ gradient-line-stroke-width zoom)}]]
|
||||
|
||||
(when width-p
|
||||
[:g {:filter "url(#gradient_width_line_drop_shadow)"}
|
||||
[:g {:filter "url(#gradient-width-line-drop-shadow)"}
|
||||
[:line {:x1 (:x from-p)
|
||||
:y1 (:y from-p)
|
||||
:x2 (:x width-p)
|
||||
|
@ -197,7 +197,7 @@
|
|||
:stroke-width (/ gradient-line-stroke-width zoom)}]])
|
||||
|
||||
(when width-p
|
||||
[:g {:filter "url(#gradient_width_handler_drop_shadow)"}
|
||||
[:g {:filter "url(#gradient-width-handler-drop-shadow)"}
|
||||
[:circle {:data-allow-click-modal "colorpicker"
|
||||
:cx (:x width-p)
|
||||
:cy (:y width-p)
|
||||
|
@ -208,7 +208,7 @@
|
|||
|
||||
[:& gradient-color-handler
|
||||
{:selected (or (not editing) (= editing 0))
|
||||
:filter-id "gradient_square_from_drop_shadow"
|
||||
:filter-id "gradient-square-from-drop-shadow"
|
||||
:zoom zoom
|
||||
:point from-p
|
||||
:color from-color
|
||||
|
@ -219,7 +219,7 @@
|
|||
|
||||
[:& gradient-color-handler
|
||||
{:selected (= editing 1)
|
||||
:filter-id "gradient_square_to_drop_shadow"
|
||||
:filter-id "gradient-square-to-drop-shadow"
|
||||
:zoom zoom
|
||||
:point to-p
|
||||
:color to-color
|
||||
|
|
|
@ -240,9 +240,10 @@
|
|||
|
||||
dest-shape-id (:id dest-shape)
|
||||
|
||||
;; FIXME: broken
|
||||
thumbnail-data-ref (mf/use-memo
|
||||
(mf/deps page-id dest-shape-id)
|
||||
#(refs/thumbnail-frame-data dest-shape-id))
|
||||
#(refs/workspace-thumbnail-by-id dest-shape-id))
|
||||
thumbnail-data (mf/deref thumbnail-data-ref)
|
||||
|
||||
dest-shape (cond-> dest-shape
|
||||
|
|
|
@ -132,7 +132,8 @@
|
|||
(and (>= s1c1 s2c1) (<= s1c1 s2c2))
|
||||
(and (>= s1c2 s2c1) (<= s1c2 s2c2)))))
|
||||
|
||||
(defn calculate-segments [coord selrect lt-shapes gt-shapes]
|
||||
(defn calculate-segments
|
||||
[coord selrect lt-shapes gt-shapes]
|
||||
(let [distance-to-selrect
|
||||
(fn [shape]
|
||||
(let [sr (:selrect shape)]
|
||||
|
@ -158,10 +159,13 @@
|
|||
;; Left/Top shapes and right/bottom shapes (depends on `coord` parameter)
|
||||
|
||||
;; Gets the distance to the current selection
|
||||
distances-xf (comp (map distance-to-selrect) (filter pos?))
|
||||
distances-xf (comp (filter some?)
|
||||
(map distance-to-selrect)
|
||||
(filter pos?))
|
||||
|
||||
lt-distances (into #{} distances-xf lt-shapes)
|
||||
gt-distances (into #{} distances-xf gt-shapes)
|
||||
distances (set/union lt-distances gt-distances)
|
||||
distances (set/union lt-distances gt-distances)
|
||||
|
||||
;; We'll show the distances that match a distance from the selrect
|
||||
show-candidate? #(check-in-set % distances)
|
||||
|
@ -202,6 +206,26 @@
|
|||
|
||||
segments-to-display))
|
||||
|
||||
(defn- query-worker
|
||||
[page-id coord [selrect selected frame]]
|
||||
(let [lt-side (if (= coord :x) :left :top)
|
||||
gt-side (if (= coord :x) :right :bottom)
|
||||
|
||||
vbox (deref refs/vbox)
|
||||
areas (gsh/get-areas
|
||||
(or (grc/clip-rect (dm/get-prop frame :selrect) vbox) vbox)
|
||||
selrect)
|
||||
|
||||
query-side
|
||||
(fn [side]
|
||||
(let [rect (get areas side)]
|
||||
(if (and (> (:width rect) 0) (> (:height rect) 0))
|
||||
(ams/select-shapes-area page-id (:id frame) selected @refs/workspace-page-objects rect)
|
||||
(rx/of nil))))]
|
||||
|
||||
(rx/combine-latest (query-side lt-side)
|
||||
(query-side gt-side))))
|
||||
|
||||
(mf/defc shape-distance
|
||||
{::mf/wrap-props false}
|
||||
[props]
|
||||
|
@ -213,51 +237,46 @@
|
|||
selected (unchecked-get props "selected")
|
||||
|
||||
subject (mf/use-memo #(rx/subject))
|
||||
to-measure (mf/use-state [])
|
||||
|
||||
query-worker
|
||||
(fn [[selrect selected frame]]
|
||||
(let [lt-side (if (= coord :x) :left :top)
|
||||
gt-side (if (= coord :x) :right :bottom)
|
||||
|
||||
vbox (deref refs/vbox)
|
||||
areas (gsh/get-areas
|
||||
(or (grc/clip-rect (dm/get-prop frame :selrect) vbox) vbox)
|
||||
selrect)
|
||||
lt-shapes* (mf/use-state nil)
|
||||
lt-shapes (deref lt-shapes*)
|
||||
|
||||
query-side (fn [side]
|
||||
(let [rect (get areas side)]
|
||||
(if (and (> (:width rect) 0) (> (:height rect) 0))
|
||||
(ams/select-shapes-area page-id (:id frame) selected @refs/workspace-page-objects rect)
|
||||
(rx/of nil))))]
|
||||
(rx/combine-latest (query-side lt-side)
|
||||
(query-side gt-side))))
|
||||
gt-shapes* (mf/use-state nil)
|
||||
gt-shapes (deref gt-shapes*)
|
||||
|
||||
[lt-shapes gt-shapes] @to-measure
|
||||
segments-to-display
|
||||
(mf/with-memo [lt-shapes gt-shapes selrect]
|
||||
(calculate-segments coord selrect lt-shapes gt-shapes))]
|
||||
|
||||
segments-to-display (mf/use-memo
|
||||
(mf/deps @to-measure)
|
||||
#(calculate-segments coord selrect lt-shapes gt-shapes))]
|
||||
|
||||
(mf/use-effect
|
||||
(fn []
|
||||
(let [sub (->> subject
|
||||
(rx/throttle 100)
|
||||
(rx/switch-map query-worker)
|
||||
(rx/subs #(reset! to-measure %)))]
|
||||
;; On unmount dispose
|
||||
#(rx/dispose! sub))))
|
||||
(mf/with-effect [page-id]
|
||||
(let [sub (->> subject
|
||||
(rx/throttle 100)
|
||||
;; NOTE: we don't put coord on deps because we
|
||||
;; know it is a static value and will not go to
|
||||
;; change
|
||||
(rx/switch-map (partial query-worker page-id coord))
|
||||
(rx/subs (fn [[lt-shapes gt-shapes]]
|
||||
(reset! lt-shapes* lt-shapes)
|
||||
(reset! gt-shapes* gt-shapes))))]
|
||||
;; On unmount dispose
|
||||
#(rx/dispose! sub)))
|
||||
|
||||
(mf/use-effect
|
||||
(mf/deps selrect)
|
||||
#(rx/push! subject [selrect selected frame]))
|
||||
|
||||
(for [[sr1 sr2] segments-to-display]
|
||||
[:& shape-distance-segment {:key (str/join "-" [(:x sr1) (:y sr1) (:x sr2) (:y sr2)])
|
||||
:sr1 sr1
|
||||
:sr2 sr2
|
||||
:coord coord
|
||||
:zoom zoom}])))
|
||||
[:& shape-distance-segment
|
||||
{:key (str/ffmt "%-%-%-%"
|
||||
(dm/get-prop sr1 :x)
|
||||
(dm/get-prop sr1 :y)
|
||||
(dm/get-prop sr2 :x)
|
||||
(dm/get-prop sr2 :y))
|
||||
:sr1 sr1
|
||||
:sr2 sr2
|
||||
:coord coord
|
||||
:zoom zoom}])))
|
||||
|
||||
(mf/defc snap-distances
|
||||
{::mf/wrap-props false}
|
||||
|
|
|
@ -1,15 +0,0 @@
|
|||
;; This Source Code Form is subject to the terms of the Mozilla Public
|
||||
;; License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
;; file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
;;
|
||||
;; Copyright (c) KALEIDOS INC
|
||||
|
||||
(ns app.util.imposters)
|
||||
|
||||
;; This is needed to avoid a circular dependency between
|
||||
;; app.main.ui.workspace.shapes.frame and app.util.imposters
|
||||
(defonce render-fn (atom nil))
|
||||
|
||||
(defn init!
|
||||
[fn]
|
||||
(reset! render-fn fn))
|
Loading…
Add table
Reference in a new issue