fix: made view port reactive with scaling
This commit is contained in:
parent
b361460485
commit
8201092703
1 changed files with 66 additions and 41 deletions
|
|
@ -106,10 +106,11 @@ pub fn RealmSceneViewer(
|
||||||
let outer_container_ref = NodeRef::<leptos::html::Div>::new();
|
let outer_container_ref = NodeRef::<leptos::html::Div>::new();
|
||||||
|
|
||||||
// Store scale factors for coordinate conversion (shared between both canvases)
|
// Store scale factors for coordinate conversion (shared between both canvases)
|
||||||
let scale_x = StoredValue::new(1.0_f64);
|
// Using RwSignal for reactivity - derived signals will recompute on resize
|
||||||
let scale_y = StoredValue::new(1.0_f64);
|
let (scale_x, set_scale_x) = signal(1.0_f64);
|
||||||
let offset_x = StoredValue::new(0.0_f64);
|
let (scale_y, set_scale_y) = signal(1.0_f64);
|
||||||
let offset_y = StoredValue::new(0.0_f64);
|
let (offset_x, set_offset_x) = signal(0.0_f64);
|
||||||
|
let (offset_y, set_offset_y) = signal(0.0_f64);
|
||||||
|
|
||||||
// Signal to track when scale factors have been properly calculated
|
// Signal to track when scale factors have been properly calculated
|
||||||
let (scales_ready, set_scales_ready) = signal(false);
|
let (scales_ready, set_scales_ready) = signal(false);
|
||||||
|
|
@ -129,10 +130,10 @@ pub fn RealmSceneViewer(
|
||||||
let click_x = ev.client_x() as f64 - rect.left();
|
let click_x = ev.client_x() as f64 - rect.left();
|
||||||
let click_y = ev.client_y() as f64 - rect.top();
|
let click_y = ev.client_y() as f64 - rect.top();
|
||||||
|
|
||||||
let sx = scale_x.get_value();
|
let sx = scale_x.get();
|
||||||
let sy = scale_y.get_value();
|
let sy = scale_y.get();
|
||||||
let ox = offset_x.get_value();
|
let ox = offset_x.get();
|
||||||
let oy = offset_y.get_value();
|
let oy = offset_y.get();
|
||||||
|
|
||||||
if sx > 0.0 && sy > 0.0 {
|
if sx > 0.0 && sy > 0.0 {
|
||||||
let scene_x = (click_x - ox) / sx;
|
let scene_x = (click_x - ox) / sx;
|
||||||
|
|
@ -176,7 +177,7 @@ pub fn RealmSceneViewer(
|
||||||
|
|
||||||
// =========================================================
|
// =========================================================
|
||||||
// Viewport Dimensions Effect - tracks outer container size
|
// Viewport Dimensions Effect - tracks outer container size
|
||||||
// Uses setTimeout to ensure DOM is ready after mount
|
// Uses window resize event to detect size changes
|
||||||
// =========================================================
|
// =========================================================
|
||||||
Effect::new(move |_| {
|
Effect::new(move |_| {
|
||||||
// Track pan mode to re-run when it changes (affects container layout)
|
// Track pan mode to re-run when it changes (affects container layout)
|
||||||
|
|
@ -188,46 +189,69 @@ pub fn RealmSceneViewer(
|
||||||
|
|
||||||
let container_el: web_sys::HtmlElement = container.into();
|
let container_el: web_sys::HtmlElement = container.into();
|
||||||
|
|
||||||
// Use setTimeout to ensure DOM has settled after any layout changes
|
// Measure and update dimensions
|
||||||
let update_dimensions = Closure::once(Box::new(move || {
|
let measure_container = {
|
||||||
let width = container_el.client_width() as f64;
|
let container_el = container_el.clone();
|
||||||
let height = container_el.client_height() as f64;
|
move || {
|
||||||
|
let width = container_el.client_width() as f64;
|
||||||
if width > 0.0 && height > 0.0 {
|
let height = container_el.client_height() as f64;
|
||||||
set_viewport_dimensions.set((width, height));
|
if width > 0.0 && height > 0.0 {
|
||||||
|
set_viewport_dimensions.set((width, height));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}) as Box<dyn FnOnce()>);
|
};
|
||||||
|
|
||||||
|
// Measure immediately
|
||||||
|
measure_container();
|
||||||
|
|
||||||
|
// Also measure on window resize
|
||||||
|
let resize_handler = Closure::wrap(Box::new({
|
||||||
|
let container_el = container_el.clone();
|
||||||
|
move |_: web_sys::Event| {
|
||||||
|
let width = container_el.client_width() as f64;
|
||||||
|
let height = container_el.client_height() as f64;
|
||||||
|
if width > 0.0 && height > 0.0 {
|
||||||
|
set_viewport_dimensions.set((width, height));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}) as Box<dyn Fn(web_sys::Event)>);
|
||||||
|
|
||||||
let window = web_sys::window().unwrap();
|
let window = web_sys::window().unwrap();
|
||||||
let _ = window.set_timeout_with_callback_and_timeout_and_arguments_0(
|
let _ = window.add_event_listener_with_callback(
|
||||||
update_dimensions.as_ref().unchecked_ref(),
|
"resize",
|
||||||
150, // Slightly longer delay to ensure DOM settles
|
resize_handler.as_ref().unchecked_ref(),
|
||||||
);
|
);
|
||||||
update_dimensions.forget();
|
|
||||||
|
// Keep the closure alive
|
||||||
|
resize_handler.forget();
|
||||||
});
|
});
|
||||||
|
|
||||||
// Track the last settings to detect changes
|
// Track the last settings to detect changes
|
||||||
let last_pan_mode = Rc::new(RefCell::new(None::<bool>));
|
let last_pan_mode = Rc::new(RefCell::new(None::<bool>));
|
||||||
let last_zoom = Rc::new(RefCell::new(None::<f64>));
|
let last_zoom = Rc::new(RefCell::new(None::<f64>));
|
||||||
|
let last_viewport = Rc::new(RefCell::new(None::<(f64, f64)>));
|
||||||
|
|
||||||
// =========================================================
|
// =========================================================
|
||||||
// Background Effect - redraws when settings change
|
// Background Effect - redraws when settings or viewport change
|
||||||
// =========================================================
|
// =========================================================
|
||||||
Effect::new(move |_| {
|
Effect::new(move |_| {
|
||||||
// Track settings signals - this Effect reruns when they change
|
// Track settings signals - this Effect reruns when they change
|
||||||
let current_pan_mode = is_pan_mode.get();
|
let current_pan_mode = is_pan_mode.get();
|
||||||
let current_zoom = zoom_level.get();
|
let current_zoom = zoom_level.get();
|
||||||
|
let current_viewport = viewport_dimensions.get();
|
||||||
|
|
||||||
let Some(canvas) = bg_canvas_ref.get() else {
|
let Some(canvas) = bg_canvas_ref.get() else {
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
|
|
||||||
// Check if we need to redraw (settings changed or first render)
|
// Check if we need to redraw (settings or viewport changed, or first render)
|
||||||
let needs_redraw = {
|
let needs_redraw = {
|
||||||
let last_pan = *last_pan_mode.borrow();
|
let last_pan = *last_pan_mode.borrow();
|
||||||
let last_z = *last_zoom.borrow();
|
let last_z = *last_zoom.borrow();
|
||||||
|
let last_vp = *last_viewport.borrow();
|
||||||
last_pan != Some(current_pan_mode)
|
last_pan != Some(current_pan_mode)
|
||||||
|| (current_pan_mode && last_z != Some(current_zoom))
|
|| (current_pan_mode && last_z != Some(current_zoom))
|
||||||
|
|| (!current_pan_mode && last_vp != Some(current_viewport))
|
||||||
};
|
};
|
||||||
|
|
||||||
if !needs_redraw {
|
if !needs_redraw {
|
||||||
|
|
@ -237,6 +261,7 @@ pub fn RealmSceneViewer(
|
||||||
// Update last values
|
// Update last values
|
||||||
*last_pan_mode.borrow_mut() = Some(current_pan_mode);
|
*last_pan_mode.borrow_mut() = Some(current_pan_mode);
|
||||||
*last_zoom.borrow_mut() = Some(current_zoom);
|
*last_zoom.borrow_mut() = Some(current_zoom);
|
||||||
|
*last_viewport.borrow_mut() = Some(current_viewport);
|
||||||
|
|
||||||
let canvas_el: &web_sys::HtmlCanvasElement = &canvas;
|
let canvas_el: &web_sys::HtmlCanvasElement = &canvas;
|
||||||
let canvas_el = canvas_el.clone();
|
let canvas_el = canvas_el.clone();
|
||||||
|
|
@ -254,10 +279,10 @@ pub fn RealmSceneViewer(
|
||||||
canvas_el.set_height(canvas_height);
|
canvas_el.set_height(canvas_height);
|
||||||
|
|
||||||
// Store scale factors (zoom level, no offset)
|
// Store scale factors (zoom level, no offset)
|
||||||
scale_x.set_value(current_zoom);
|
set_scale_x.set(current_zoom);
|
||||||
scale_y.set_value(current_zoom);
|
set_scale_y.set(current_zoom);
|
||||||
offset_x.set_value(0.0);
|
set_offset_x.set(0.0);
|
||||||
offset_y.set_value(0.0);
|
set_offset_y.set(0.0);
|
||||||
|
|
||||||
// Signal that scale factors are ready
|
// Signal that scale factors are ready
|
||||||
set_scales_ready.set(true);
|
set_scales_ready.set(true);
|
||||||
|
|
@ -323,10 +348,10 @@ pub fn RealmSceneViewer(
|
||||||
// Store scale factors
|
// Store scale factors
|
||||||
let sx = draw_width / scene_width_f;
|
let sx = draw_width / scene_width_f;
|
||||||
let sy = draw_height / scene_height_f;
|
let sy = draw_height / scene_height_f;
|
||||||
scale_x.set_value(sx);
|
set_scale_x.set(sx);
|
||||||
scale_y.set_value(sy);
|
set_scale_y.set(sy);
|
||||||
offset_x.set_value(draw_x);
|
set_offset_x.set(draw_x);
|
||||||
offset_y.set_value(draw_y);
|
set_offset_y.set(draw_y);
|
||||||
|
|
||||||
// Signal that scale factors are ready
|
// Signal that scale factors are ready
|
||||||
set_scales_ready.set(true);
|
set_scales_ready.set(true);
|
||||||
|
|
@ -410,10 +435,10 @@ pub fn RealmSceneViewer(
|
||||||
ctx.clear_rect(0.0, 0.0, canvas_width as f64, canvas_height as f64);
|
ctx.clear_rect(0.0, 0.0, canvas_width as f64, canvas_height as f64);
|
||||||
|
|
||||||
// Get stored scale factors
|
// Get stored scale factors
|
||||||
let sx = scale_x.get_value();
|
let sx = scale_x.get();
|
||||||
let sy = scale_y.get_value();
|
let sy = scale_y.get();
|
||||||
let ox = offset_x.get_value();
|
let ox = offset_x.get();
|
||||||
let oy = offset_y.get_value();
|
let oy = offset_y.get();
|
||||||
|
|
||||||
// Calculate prop size based on mode
|
// Calculate prop size based on mode
|
||||||
let prop_size = calculate_prop_size(
|
let prop_size = calculate_prop_size(
|
||||||
|
|
@ -715,8 +740,8 @@ pub fn RealmSceneViewer(
|
||||||
let current_pan_mode = is_pan_mode.get();
|
let current_pan_mode = is_pan_mode.get();
|
||||||
let current_zoom = zoom_level.get();
|
let current_zoom = zoom_level.get();
|
||||||
let current_enlarge = enlarge_props.get();
|
let current_enlarge = enlarge_props.get();
|
||||||
let sx = scale_x.get_value();
|
let sx = scale_x.get();
|
||||||
let sy = scale_y.get_value();
|
let sy = scale_y.get();
|
||||||
|
|
||||||
// Reference scale factor for "enlarge props" mode
|
// Reference scale factor for "enlarge props" mode
|
||||||
let ref_scale = (scene_width_f / REFERENCE_WIDTH).max(scene_height_f / REFERENCE_HEIGHT);
|
let ref_scale = (scene_width_f / REFERENCE_WIDTH).max(scene_height_f / REFERENCE_HEIGHT);
|
||||||
|
|
@ -738,10 +763,10 @@ pub fn RealmSceneViewer(
|
||||||
let text_em_size = Signal::derive(move || settings.get().text_em_size);
|
let text_em_size = Signal::derive(move || settings.get().text_em_size);
|
||||||
|
|
||||||
// Create signals for scale/offset values to pass to AvatarCanvas
|
// Create signals for scale/offset values to pass to AvatarCanvas
|
||||||
let scale_x_signal = Signal::derive(move || scale_x.get_value());
|
let scale_x_signal = Signal::derive(move || scale_x.get());
|
||||||
let scale_y_signal = Signal::derive(move || scale_y.get_value());
|
let scale_y_signal = Signal::derive(move || scale_y.get());
|
||||||
let offset_x_signal = Signal::derive(move || offset_x.get_value());
|
let offset_x_signal = Signal::derive(move || offset_x.get());
|
||||||
let offset_y_signal = Signal::derive(move || offset_y.get_value());
|
let offset_y_signal = Signal::derive(move || offset_y.get());
|
||||||
|
|
||||||
// Create a map of members by key for efficient lookup
|
// Create a map of members by key for efficient lookup
|
||||||
let members_by_key = Signal::derive(move || {
|
let members_by_key = Signal::derive(move || {
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue