Merge pull request #3628 from penpot/niwinz-develop-bugfixes-4

 Don't render not visible shapes on workspace
This commit is contained in:
Alejandro 2023-09-15 11:11:05 +02:00 committed by GitHub
commit aa62b9d248
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
9 changed files with 119 additions and 107 deletions

View file

@ -275,21 +275,19 @@
[a b] [a b]
(mth/almost-zero? (- a b))) (mth/almost-zero? (- a b)))
;; FIXME: performance
(defn overlaps-rects? (defn overlaps-rects?
"Check for two rects to overlap. Rects won't overlap only if "Check for two rects to overlap. Rects won't overlap only if
one of them is fully to the left or the top" one of them is fully to the left or the top"
[rect-a rect-b] [rect-a rect-b]
(let [x1a (dm/get-prop rect-a :x)
y1a (dm/get-prop rect-a :y)
x2a (+ x1a (dm/get-prop rect-a :width))
y2a (+ y1a (dm/get-prop rect-a :height))
(let [x1a (:x rect-a) x1b (dm/get-prop rect-b :x)
y1a (:y rect-a) y1b (dm/get-prop rect-b :y)
x2a (+ (:x rect-a) (:width rect-a)) x2b (+ x1b (dm/get-prop rect-b :width))
y2a (+ (:y rect-a) (:height rect-a)) y2b (+ y1b (dm/get-prop rect-b :height))]
x1b (:x rect-b)
y1b (:y rect-b)
x2b (+ (:x rect-b) (:width rect-b))
y2b (+ (:y rect-b) (:height rect-b))]
(and (or (> x2a x1b) (s= x2a x1b)) (and (or (> x2a x1b) (s= x2a x1b))
(or (>= x2b x1a) (s= x2b x1a)) (or (>= x2b x1a) (s= x2b x1a))

View file

@ -307,12 +307,12 @@
(defn overlaps? (defn overlaps?
"General case to check for overlapping between shapes and a rectangle" "General case to check for overlapping between shapes and a rectangle"
[shape rect] [shape rect]
(let [stroke-width (/ (or (:stroke-width shape) 0) 2) (let [swidth (/ (or (:stroke-width shape) 0) 2)
rect (-> rect rect (-> rect
(update :x - stroke-width) (update :x - swidth)
(update :y - stroke-width) (update :y - swidth)
(update :width + (* 2 stroke-width)) (update :width + (* 2 swidth))
(update :height + (* 2 stroke-width)))] (update :height + (* 2 swidth)))]
(or (not shape) (or (not shape)
(cond (cond
(cph/path-shape? shape) (cph/path-shape? shape)

View file

@ -16,6 +16,7 @@
(def current-project-id (mf/create-context nil)) (def current-project-id (mf/create-context nil))
(def current-page-id (mf/create-context nil)) (def current-page-id (mf/create-context nil))
(def current-file-id (mf/create-context nil)) (def current-file-id (mf/create-context nil))
(def current-vbox (mf/create-context nil))
(def active-frames (mf/create-context nil)) (def active-frames (mf/create-context nil))
(def render-thumbnails (mf/create-context nil)) (def render-thumbnails (mf/create-context nil))

View file

@ -13,6 +13,7 @@
common." common."
(:require (:require
[app.common.data.macros :as dm] [app.common.data.macros :as dm]
[app.common.geom.rect :as grc]
[app.common.pages.helpers :as cph] [app.common.pages.helpers :as cph]
[app.common.uuid :as uuid] [app.common.uuid :as uuid]
[app.main.ui.context :as ctx] [app.main.ui.context :as ctx]
@ -49,15 +50,14 @@
(let [objects (obj/get props "objects") (let [objects (obj/get props "objects")
active-frames (obj/get props "active-frames") active-frames (obj/get props "active-frames")
shapes (cph/get-immediate-children objects) shapes (cph/get-immediate-children objects)
vbox (mf/use-ctx ctx/current-vbox)
;; vbox (mf/use-ctx ctx/current-vbox) shapes (mf/with-memo [shapes vbox]
;; shapes (mf/with-memo [shapes vbox] (if (some? vbox)
;; (if (some? vbox) (filter (fn [shape]
;; (filter (fn [shape] (grc/overlaps-rects? vbox (dm/get-prop shape :selrect)))
;; (grc/overlaps-rects? vbox (dm/get-prop shape :selrect))) shapes)
;; shapes) shapes))]
;; shapes))
]
[:g {:id (dm/str "shape-" uuid/zero)} [:g {:id (dm/str "shape-" uuid/zero)}
[:& (mf/provider ctx/active-frames) {:value active-frames} [:& (mf/provider ctx/active-frames) {:value active-frames}

View file

@ -73,6 +73,7 @@
(fdm/use-dynamic-modifiers objects (mf/ref-val node-ref) modifiers) (fdm/use-dynamic-modifiers objects (mf/ref-val node-ref) modifiers)
[:& frame-shape {:shape shape :ref node-ref}])))) [:& frame-shape {:shape shape :ref node-ref}]))))
(defn root-frame-wrapper-factory (defn root-frame-wrapper-factory
[shape-wrapper] [shape-wrapper]
@ -86,9 +87,9 @@
thumbnail? (unchecked-get props "thumbnail?") thumbnail? (unchecked-get props "thumbnail?")
page-id (mf/use-ctx ctx/current-page-id) page-id (mf/use-ctx ctx/current-page-id)
frame-id (:id shape) frame-id (dm/get-prop shape :id)
objects (wsh/lookup-page-objects @st/state) objects (wsh/lookup-page-objects @st/state page-id)
node-ref (mf/use-ref nil) node-ref (mf/use-ref nil)
root-ref (mf/use-ref nil) root-ref (mf/use-ref nil)
@ -114,6 +115,7 @@
on-frame-load on-frame-load
(fns/use-node-store node-ref rendered-ref thumbnail? render-frame?) (fns/use-node-store node-ref rendered-ref thumbnail? render-frame?)
] ]
(fdm/use-dynamic-modifiers objects (mf/ref-val node-ref) modifiers) (fdm/use-dynamic-modifiers objects (mf/ref-val node-ref) modifiers)

View file

@ -225,8 +225,8 @@
:spell-check false :spell-check false
:on-change on-filter-change}] :on-change on-filter-change}]
(when (and recent-fonts show-recent) (when (and recent-fonts show-recent)
[:*
[:hr] [:hr]
[*
[:p.title (tr "workspace.options.recent-fonts")] [:p.title (tr "workspace.options.recent-fonts")]
(for [[idx font] (d/enumerate recent-fonts)] (for [[idx font] (d/enumerate recent-fonts)]
[:& font-item {:key (dm/str "font-" idx) [:& font-item {:key (dm/str "font-" idx)

View file

@ -88,6 +88,8 @@
show-distances? show-distances?
picking-color?]} wglobal picking-color?]} wglobal
vbox' (mf/use-debounce 100 vbox)
;; CONTEXT ;; CONTEXT
page-id (mf/use-ctx ctx/current-page-id) page-id (mf/use-ctx ctx/current-page-id)
@ -323,12 +325,13 @@
:y (:y vbox 0) :y (:y vbox 0)
:fill background}] :fill background}]
[:& (mf/provider ctx/current-vbox) {:value vbox'}
[:& (mf/provider use/include-metadata-ctx) {:value (debug? :show-export-metadata)} [:& (mf/provider use/include-metadata-ctx) {:value (debug? :show-export-metadata)}
[:& (mf/provider embed/context) {:value true} [:& (mf/provider embed/context) {:value true}
;; Render root shape ;; Render root shape
[:& shapes/root-shape {:key page-id [:& shapes/root-shape {:key page-id
:objects base-objects :objects base-objects
:active-frames @active-frames}]]]] :active-frames @active-frames}]]]]]
[:svg.viewport-controls [:svg.viewport-controls
{:xmlns "http://www.w3.org/2000/svg" {:xmlns "http://www.w3.org/2000/svg"

View file

@ -409,16 +409,25 @@
(defn bounding-rect->rect (defn bounding-rect->rect
[rect] [rect]
(when (some? rect) (when (some? rect)
{:x (or (.-left rect) (:left rect) 0) (grc/make-rect
:y (or (.-top rect) (:top rect) 0) (or (.-left rect) (:left rect) 0)
:width (or (.-width rect) (:width rect) 1) (or (.-top rect) (:top rect) 0)
:height (or (.-height rect) (:height rect) 1)})) (or (.-width rect) (:width rect) 1)
(or (.-height rect) (:height rect) 1))))
(defn get-window-size (defn get-window-size
[] []
{:width (.-innerWidth ^js js/window) {:width (.-innerWidth ^js js/window)
:height (.-innerHeight ^js js/window)}) :height (.-innerHeight ^js js/window)})
(defn get-computed-styles
[node]
(js/getComputedStyle node))
(defn get-property-value
[o prop]
(.getPropertyValue ^js o prop))
(defn focus! (defn focus!
[^js node] [^js node]
(when (some? node) (when (some? node)

View file

@ -12,20 +12,19 @@
[app.main.fonts :as fonts] [app.main.fonts :as fonts]
[app.util.dom :as dom] [app.util.dom :as dom]
[app.util.text-position-data :as tpd] [app.util.text-position-data :as tpd]
[cuerdas.core :as str]
[promesa.core :as p])) [promesa.core :as p]))
(defn parse-text-nodes (defn parse-text-nodes
"Given a text node retrieves the rectangles for everyone of its paragraphs and its text." "Given a text node retrieves the rectangles for everyone of its paragraphs and its text."
[parent-node direction text-node text-align] [parent-node direction text-node text-align]
(letfn [(parse-entry [^js entry] (letfn [(parse-entry [^js entry]
(when (some? (.-position entry)) (when (some? (.-position entry))
{:node (.-node entry) {:node (.-node entry)
:position (dom/bounding-rect->rect (.-position entry)) :position (dom/bounding-rect->rect (.-position entry))
:text (.-text entry) :text (.-text entry)
:direction direction}))] :direction direction}))]
(into (into []
[]
(keep parse-entry) (keep parse-entry)
(tpd/parse-text-nodes parent-node text-node text-align)))) (tpd/parse-text-nodes parent-node text-node text-align))))
@ -40,76 +39,76 @@
load-promise))) load-promise)))
(defn resolve-font (defn resolve-font
[^js node] [node]
(let [styles (dom/get-computed-styles node)
(let [styles (js/getComputedStyle node) font (dom/get-property-value styles "font")
font (.getPropertyValue styles "font")
font (if (or (not font) (empty? font)) font (if (or (not font) (empty? font))
;; Firefox 95 won't return the font correctly. ;; Firefox 95 won't return the font correctly.
;; We can get the font shorthand with the font-size + font-family ;; We can get the font shorthand with the font-size + font-family
(dm/str (.getPropertyValue styles "font-size") (str/ffmt "% %"
" " (dom/get-property-value styles "font-size")
(.getPropertyValue styles "font-family")) (dom/get-property-value styles "font-family"))
font) font)
font-id (.getPropertyValue styles "--font-id")] font-id (dom/get-property-value styles "--font-id")]
(-> (fonts/ensure-loaded! font-id) (->> (fonts/ensure-loaded! font-id)
(p/then #(when (not (dom/check-font? font)) (p/fmap (fn []
(load-font font))) (when-not ^boolean (dom/check-font? font)
(p/catch #(.error js/console (dm/str "Cannot load font " font-id) %))))) (load-font font))))
(p/merr (fn [_cause]
(js/console.error (str/ffmt "Cannot load font %" font-id))
(p/resolved nil))))))
(defn- process-text-node
[parent-node]
(let [root (dom/get-parent-with-selector parent-node ".text-node-html")
paragraph (dom/get-parent-with-selector parent-node ".paragraph")
shape-x (d/parse-double (dom/get-attribute root "data-x"))
shape-y (d/parse-double (dom/get-attribute root "data-y"))
direction (.-direction ^js (dom/get-computed-styles parent-node))
text-align (.-textAlign ^js (dom/get-computed-styles paragraph))]
(sequence
(comp
(mapcat #(parse-text-nodes parent-node direction % text-align))
(map #(-> %
(update-in [:position :x] + shape-x)
(update-in [:position :y] + shape-y))))
(seq (.-childNodes parent-node)))))
(defn- calc-text-node-positions (defn- calc-text-node-positions
[shape-id] [shape-id]
(when (some? shape-id)
(let [text-nodes (-> (dom/query (dm/fmt "#html-text-node-%" shape-id)) (let [text-nodes (-> (dom/query (dm/fmt "#html-text-node-%" shape-id))
(dom/query-all ".text-node")) (dom/query-all ".text-node"))]
load-fonts (->> text-nodes (map resolve-font)) (->> (p/all (map resolve-font text-nodes))
(p/fmap #(mapcat process-text-node text-nodes)))))
process-text-node
(fn [parent-node]
(let [root (dom/get-parent-with-selector parent-node ".text-node-html")
paragraph (dom/get-parent-with-selector parent-node ".paragraph")
shape-x (-> (dom/get-attribute root "data-x") d/parse-double)
shape-y (-> (dom/get-attribute root "data-y") d/parse-double)
direction (.-direction (js/getComputedStyle parent-node))
text-align (.-textAlign (js/getComputedStyle paragraph))]
(->> (.-childNodes parent-node)
(mapcat #(parse-text-nodes parent-node direction % text-align))
(mapv #(-> %
(update-in [:position :x] + shape-x)
(update-in [:position :y] + shape-y))))))]
(-> (p/all load-fonts)
(p/then
(fn []
(->> text-nodes (mapcat process-text-node))))))))
(defn calc-position-data (defn calc-position-data
[shape-id] [shape-id]
(when (some? shape-id) (letfn [(get-prop [styles prop]
(p/let [text-data (calc-text-node-positions shape-id)]
(->> text-data
(mapv (fn [{:keys [node position text direction]}]
(let [{:keys [x y width height]} position
styles (js/getComputedStyle ^js node)
get (fn [prop]
(let [value (.getPropertyValue styles prop)] (let [value (.getPropertyValue styles prop)]
(when (and value (not= value "")) (when (and (some? value) (not= value ""))
value)))] value)))
(d/without-nils
{:x x (transform-data [{:keys [node position text direction]}]
:y (+ y height) (let [styles (dom/get-computed-styles node)
:width width position (assoc position :y (+ (dm/get-prop position :y)
:height height (dm/get-prop position :height)))]
:direction direction (into position (filter val)
:font-family (str (get "font-family")) {:direction direction
:font-size (str (get "font-size")) :font-family (dm/str (get-prop styles "font-family"))
:font-weight (str (get "font-weight")) :font-size (dm/str (get-prop styles "font-size"))
:text-transform (str (get "text-transform")) :font-weight (dm/str (get-prop styles "font-weight"))
:text-decoration (str (get "text-decoration")) :text-transform (dm/str (get-prop styles "text-transform"))
:letter-spacing (str (get "letter-spacing")) :text-decoration (dm/str (get-prop styles "text-decoration"))
:font-style (str (get "font-style")) :letter-spacing (dm/str (get-prop styles "letter-spacing"))
:fills (transit/decode-str (get "--fills")) :font-style (dm/str (get-prop styles "font-style"))
:text text})))))))) :fills (transit/decode-str (get-prop styles "--fills"))
:text text})))]
(when (some? shape-id)
(->> (calc-text-node-positions shape-id)
(p/fmap (fn [text-data]
(mapv transform-data text-data)))))))