mirror of
https://github.com/penpot/penpot.git
synced 2025-03-05 20:31:20 -05:00
♻️ Refactor panning/zoom rendering
This commit is contained in:
parent
a5b2f0e4c3
commit
10b32de447
7 changed files with 70 additions and 23 deletions
|
@ -292,19 +292,23 @@
|
||||||
(when @canvas-init?
|
(when @canvas-init?
|
||||||
(wasm.api/resize-viewbox (:width vport) (:height vport))))
|
(wasm.api/resize-viewbox (:width vport) (:height vport))))
|
||||||
|
|
||||||
(mf/with-effect [base-objects @canvas-init?]
|
(mf/with-effect [@canvas-init? base-objects]
|
||||||
(when @canvas-init?
|
(when @canvas-init?
|
||||||
(wasm.api/set-objects base-objects)))
|
(wasm.api/set-objects base-objects)))
|
||||||
|
|
||||||
(mf/with-effect [preview-blend @canvas-init?]
|
(mf/with-effect [@canvas-init? preview-blend]
|
||||||
(when (and @canvas-init? preview-blend)
|
(when (and @canvas-init? preview-blend)
|
||||||
(wasm.api/request-render)))
|
(wasm.api/request-render "with-effect")))
|
||||||
|
|
||||||
(mf/with-effect [vbox @canvas-init?]
|
(mf/with-effect [@canvas-init? vbox]
|
||||||
(when @canvas-init?
|
(when @canvas-init?
|
||||||
(wasm.api/set-view zoom vbox)))
|
(wasm.api/set-view-zoom zoom vbox)))
|
||||||
|
|
||||||
(mf/with-effect [background]
|
(mf/with-effect [@canvas-init? vbox]
|
||||||
|
(when @canvas-init?
|
||||||
|
(wasm.api/set-view-box zoom vbox)))
|
||||||
|
|
||||||
|
(mf/with-effect [@canvas-init? background]
|
||||||
(when @canvas-init?
|
(when @canvas-init?
|
||||||
(wasm.api/set-canvas-background background)))
|
(wasm.api/set-canvas-background background)))
|
||||||
|
|
||||||
|
|
|
@ -61,15 +61,16 @@
|
||||||
[r g b a]))
|
[r g b a]))
|
||||||
|
|
||||||
(defn cancel-render
|
(defn cancel-render
|
||||||
[]
|
[_]
|
||||||
(when internal-frame-id
|
(when internal-frame-id
|
||||||
(js/cancelAnimationFrame internal-frame-id)
|
(js/cancelAnimationFrame internal-frame-id)
|
||||||
(set! internal-frame-id nil)))
|
(set! internal-frame-id nil)))
|
||||||
|
|
||||||
(defn request-render
|
(defn request-render
|
||||||
[]
|
[requester]
|
||||||
(when internal-frame-id (cancel-render))
|
(when internal-frame-id (cancel-render requester))
|
||||||
(set! internal-frame-id (js/requestAnimationFrame render)))
|
(let [frame-id (js/requestAnimationFrame render)]
|
||||||
|
(set! internal-frame-id frame-id)))
|
||||||
|
|
||||||
(defn use-shape
|
(defn use-shape
|
||||||
[id]
|
[id]
|
||||||
|
@ -378,10 +379,15 @@
|
||||||
|
|
||||||
(def debounce-render-without-cache (fns/debounce render-without-cache 100))
|
(def debounce-render-without-cache (fns/debounce render-without-cache 100))
|
||||||
|
|
||||||
(defn set-view
|
(defn set-view-box
|
||||||
[zoom vbox]
|
[zoom vbox]
|
||||||
(h/call internal-module "_set_view" zoom (- (:x vbox)) (- (:y vbox)))
|
(h/call internal-module "_set_view" zoom (- (:x vbox)) (- (:y vbox)))
|
||||||
(h/call internal-module "_navigate")
|
(h/call internal-module "_pan"))
|
||||||
|
|
||||||
|
(defn set-view-zoom
|
||||||
|
[zoom vbox]
|
||||||
|
(h/call internal-module "_set_view" zoom (- (:x vbox)) (- (:y vbox)))
|
||||||
|
(h/call internal-module "_zoom")
|
||||||
(debounce-render-without-cache))
|
(debounce-render-without-cache))
|
||||||
|
|
||||||
(defn set-objects
|
(defn set-objects
|
||||||
|
@ -427,7 +433,7 @@
|
||||||
(let [pending' (concat (set-shape-fills fills) (set-shape-strokes strokes))]
|
(let [pending' (concat (set-shape-fills fills) (set-shape-strokes strokes))]
|
||||||
(recur (inc index) (into pending pending'))))
|
(recur (inc index) (into pending pending'))))
|
||||||
pending))]
|
pending))]
|
||||||
(request-render)
|
(request-render "set-objects")
|
||||||
(when-let [pending (seq pending)]
|
(when-let [pending (seq pending)]
|
||||||
(->> (rx/from pending)
|
(->> (rx/from pending)
|
||||||
(rx/mapcat identity)
|
(rx/mapcat identity)
|
||||||
|
|
|
@ -130,7 +130,7 @@
|
||||||
;; when something synced with wasm
|
;; when something synced with wasm
|
||||||
;; is modified, we need to request
|
;; is modified, we need to request
|
||||||
;; a new render.
|
;; a new render.
|
||||||
(api/request-render)))
|
(api/request-render "set-wasm-attrs")))
|
||||||
|
|
||||||
(defn- impl-assoc
|
(defn- impl-assoc
|
||||||
[self k v]
|
[self k v]
|
||||||
|
|
|
@ -69,9 +69,16 @@ pub unsafe extern "C" fn render_without_cache() {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub unsafe extern "C" fn navigate() {
|
pub unsafe extern "C" fn zoom() {
|
||||||
|
let state: &mut Box<State<'_>> =
|
||||||
|
unsafe { STATE.as_mut() }.expect("got an invalid state pointer");
|
||||||
|
state.zoom();
|
||||||
|
}
|
||||||
|
|
||||||
|
#[no_mangle]
|
||||||
|
pub unsafe extern "C" fn pan() {
|
||||||
let state = unsafe { STATE.as_mut() }.expect("got an invalid state pointer");
|
let state = unsafe { STATE.as_mut() }.expect("got an invalid state pointer");
|
||||||
state.navigate();
|
state.pan();
|
||||||
}
|
}
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
|
|
|
@ -36,9 +36,13 @@ pub(crate) struct CachedSurfaceImage {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl CachedSurfaceImage {
|
impl CachedSurfaceImage {
|
||||||
fn is_dirty(&self, viewbox: &Viewbox) -> bool {
|
fn is_dirty_for_zooming(&mut self, viewbox: &Viewbox) -> bool {
|
||||||
!self.has_all_shapes && !self.viewbox.area.contains(viewbox.area)
|
!self.has_all_shapes && !self.viewbox.area.contains(viewbox.area)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn is_dirty_for_panning(&mut self, _viewbox: &Viewbox) -> bool {
|
||||||
|
!self.has_all_shapes
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) struct RenderState {
|
pub(crate) struct RenderState {
|
||||||
|
@ -168,9 +172,23 @@ impl RenderState {
|
||||||
.clear(skia::Color::TRANSPARENT);
|
.clear(skia::Color::TRANSPARENT);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn navigate(&mut self, tree: &HashMap<Uuid, impl Renderable>) -> Result<(), String> {
|
pub fn zoom(&mut self, tree: &HashMap<Uuid, impl Renderable>) -> Result<(), String> {
|
||||||
if let Some(cached_surface_image) = self.cached_surface_image.as_ref() {
|
if let Some(cached_surface_image) = self.cached_surface_image.as_mut() {
|
||||||
if cached_surface_image.is_dirty(&self.viewbox) {
|
let is_dirty = cached_surface_image.is_dirty_for_zooming(&self.viewbox);
|
||||||
|
if is_dirty {
|
||||||
|
self.render_all(tree, true);
|
||||||
|
} else {
|
||||||
|
self.render_all_from_cache()?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn pan(&mut self, tree: &HashMap<Uuid, impl Renderable>) -> Result<(), String> {
|
||||||
|
if let Some(cached_surface_image) = self.cached_surface_image.as_mut() {
|
||||||
|
let is_dirty = cached_surface_image.is_dirty_for_panning(&self.viewbox);
|
||||||
|
if is_dirty {
|
||||||
self.render_all(tree, true);
|
self.render_all(tree, true);
|
||||||
} else {
|
} else {
|
||||||
self.render_all_from_cache()?;
|
self.render_all_from_cache()?;
|
||||||
|
@ -192,6 +210,7 @@ impl RenderState {
|
||||||
);
|
);
|
||||||
self.translate(self.viewbox.pan_x, self.viewbox.pan_y);
|
self.translate(self.viewbox.pan_x, self.viewbox.pan_y);
|
||||||
|
|
||||||
|
// Reset shape tree
|
||||||
let is_complete = self.render_shape_tree(&Uuid::nil(), tree);
|
let is_complete = self.render_shape_tree(&Uuid::nil(), tree);
|
||||||
if generate_cached_surface_image || self.cached_surface_image.is_none() {
|
if generate_cached_surface_image || self.cached_surface_image.is_none() {
|
||||||
self.cached_surface_image = Some(CachedSurfaceImage {
|
self.cached_surface_image = Some(CachedSurfaceImage {
|
||||||
|
@ -299,7 +318,7 @@ impl RenderState {
|
||||||
if !root_id.is_nil() {
|
if !root_id.is_nil() {
|
||||||
if !element.bounds().intersects(self.viewbox.area) || element.hidden() {
|
if !element.bounds().intersects(self.viewbox.area) || element.hidden() {
|
||||||
self.render_debug_element(element, false);
|
self.render_debug_element(element, false);
|
||||||
// TODO: This means that not all the shapes are renderer so we
|
// TODO: This means that not all the shapes are rendered so we
|
||||||
// need to call a render_all on the zoom out.
|
// need to call a render_all on the zoom out.
|
||||||
return is_complete; // TODO return is_complete or return false??
|
return is_complete; // TODO return is_complete or return false??
|
||||||
} else {
|
} else {
|
||||||
|
|
6
render-wasm/src/shapes/rects.rs
Normal file
6
render-wasm/src/shapes/rects.rs
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
use crate::math::Point;
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, PartialEq)]
|
||||||
|
pub struct Rect {
|
||||||
|
|
||||||
|
}
|
|
@ -36,9 +36,14 @@ impl<'a> State<'a> {
|
||||||
&mut self.render_state
|
&mut self.render_state
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn navigate(&mut self) {
|
pub fn pan(&mut self) {
|
||||||
// TODO: propagate error to main fn
|
// TODO: propagate error to main fn
|
||||||
let _ = self.render_state.navigate(&self.shapes).unwrap();
|
let _ = self.render_state.pan(&self.shapes).unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn zoom(&mut self) {
|
||||||
|
// TODO: propagate error to main fn
|
||||||
|
let _ = self.render_state.zoom(&self.shapes).unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn render_all(&mut self, generate_cached_surface_image: bool) {
|
pub fn render_all(&mut self, generate_cached_surface_image: bool) {
|
||||||
|
|
Loading…
Add table
Reference in a new issue