diff --git a/crates/eframe/src/web/app_runner.rs b/crates/eframe/src/web/app_runner.rs index 31f6e79c0..620fe86fd 100644 --- a/crates/eframe/src/web/app_runner.rs +++ b/crates/eframe/src/web/app_runner.rs @@ -60,7 +60,9 @@ impl AppRunner { super::storage::load_memory(&egui_ctx); egui_ctx.options_mut(|o| { - // On web, the browser controls the zoom factor: + // On web by default egui follows the zoom factor of the browser, + // and lets the browser handle the zoom shortscuts. + // A user can still zoom egui separately by calling [`egui::Context::set_zoom_factor`]. o.zoom_with_keyboard = false; o.zoom_factor = 1.0; }); @@ -183,7 +185,7 @@ impl AppRunner { /// The result can be painted later with a call to [`Self::run_and_paint`] or [`Self::paint`]. pub fn logic(&mut self) { super::resize_canvas_to_screen_size(self.canvas(), self.web_options.max_size_points); - let canvas_size = super::canvas_size_in_points(self.canvas()); + let canvas_size = super::canvas_size_in_points(self.canvas(), self.egui_ctx()); let raw_input = self.input.new_frame(canvas_size); let full_output = self.egui_ctx.run(raw_input, |egui_ctx| { diff --git a/crates/eframe/src/web/events.rs b/crates/eframe/src/web/events.rs index c6737f6e7..224ae3ac0 100644 --- a/crates/eframe/src/web/events.rs +++ b/crates/eframe/src/web/events.rs @@ -297,7 +297,7 @@ pub(crate) fn install_canvas_events(runner_ref: &WebRunner) -> Result<(), JsValu let modifiers = modifiers_from_mouse_event(&event); runner.input.raw.modifiers = modifiers; if let Some(button) = button_from_mouse_event(&event) { - let pos = pos_from_mouse_event(runner.canvas(), &event); + let pos = pos_from_mouse_event(runner.canvas(), &event, runner.egui_ctx()); let modifiers = runner.input.raw.modifiers; runner.input.raw.events.push(egui::Event::PointerButton { pos, @@ -324,7 +324,7 @@ pub(crate) fn install_canvas_events(runner_ref: &WebRunner) -> Result<(), JsValu |event: web_sys::MouseEvent, runner| { let modifiers = modifiers_from_mouse_event(&event); runner.input.raw.modifiers = modifiers; - let pos = pos_from_mouse_event(runner.canvas(), &event); + let pos = pos_from_mouse_event(runner.canvas(), &event, runner.egui_ctx()); runner.input.raw.events.push(egui::Event::PointerMoved(pos)); runner.needs_repaint.repaint_asap(); event.stop_propagation(); @@ -336,7 +336,7 @@ pub(crate) fn install_canvas_events(runner_ref: &WebRunner) -> Result<(), JsValu let modifiers = modifiers_from_mouse_event(&event); runner.input.raw.modifiers = modifiers; if let Some(button) = button_from_mouse_event(&event) { - let pos = pos_from_mouse_event(runner.canvas(), &event); + let pos = pos_from_mouse_event(runner.canvas(), &event, runner.egui_ctx()); let modifiers = runner.input.raw.modifiers; runner.input.raw.events.push(egui::Event::PointerButton { pos, @@ -374,7 +374,12 @@ pub(crate) fn install_canvas_events(runner_ref: &WebRunner) -> Result<(), JsValu "touchstart", |event: web_sys::TouchEvent, runner| { let mut latest_touch_pos_id = runner.input.latest_touch_pos_id; - let pos = pos_from_touch_event(runner.canvas(), &event, &mut latest_touch_pos_id); + let pos = pos_from_touch_event( + runner.canvas(), + &event, + &mut latest_touch_pos_id, + runner.egui_ctx(), + ); runner.input.latest_touch_pos_id = latest_touch_pos_id; runner.input.latest_touch_pos = Some(pos); let modifiers = runner.input.raw.modifiers; @@ -397,7 +402,12 @@ pub(crate) fn install_canvas_events(runner_ref: &WebRunner) -> Result<(), JsValu "touchmove", |event: web_sys::TouchEvent, runner| { let mut latest_touch_pos_id = runner.input.latest_touch_pos_id; - let pos = pos_from_touch_event(runner.canvas(), &event, &mut latest_touch_pos_id); + let pos = pos_from_touch_event( + runner.canvas(), + &event, + &mut latest_touch_pos_id, + runner.egui_ctx(), + ); runner.input.latest_touch_pos_id = latest_touch_pos_id; runner.input.latest_touch_pos = Some(pos); runner.input.raw.events.push(egui::Event::PointerMoved(pos)); @@ -460,7 +470,9 @@ pub(crate) fn install_canvas_events(runner_ref: &WebRunner) -> Result<(), JsValu }); let scroll_multiplier = match unit { - egui::MouseWheelUnit::Page => canvas_size_in_points(runner.canvas()).y, + egui::MouseWheelUnit::Page => { + canvas_size_in_points(runner.canvas(), runner.egui_ctx()).y + } egui::MouseWheelUnit::Line => { #[allow(clippy::let_and_return)] let points_per_scroll_line = 8.0; // Note that this is intentionally different from what we use in winit. diff --git a/crates/eframe/src/web/input.rs b/crates/eframe/src/web/input.rs index 4ed022773..361e8031d 100644 --- a/crates/eframe/src/web/input.rs +++ b/crates/eframe/src/web/input.rs @@ -3,11 +3,13 @@ use super::{canvas_origin, AppRunner}; pub fn pos_from_mouse_event( canvas: &web_sys::HtmlCanvasElement, event: &web_sys::MouseEvent, + ctx: &egui::Context, ) -> egui::Pos2 { let rect = canvas.get_bounding_client_rect(); + let zoom_factor = ctx.zoom_factor(); egui::Pos2 { - x: event.client_x() as f32 - rect.left() as f32, - y: event.client_y() as f32 - rect.top() as f32, + x: (event.client_x() as f32 - rect.left() as f32) / zoom_factor, + y: (event.client_y() as f32 - rect.top() as f32) / zoom_factor, } } @@ -32,6 +34,7 @@ pub fn pos_from_touch_event( canvas: &web_sys::HtmlCanvasElement, event: &web_sys::TouchEvent, touch_id_for_pos: &mut Option, + egui_ctx: &egui::Context, ) -> egui::Pos2 { let touch_for_pos = if let Some(touch_id_for_pos) = touch_id_for_pos { // search for the touch we previously used for the position @@ -49,14 +52,19 @@ pub fn pos_from_touch_event( .or_else(|| event.touches().get(0)) .map_or(Default::default(), |touch| { *touch_id_for_pos = Some(egui::TouchId::from(touch.identifier())); - pos_from_touch(canvas_origin(canvas), &touch) + pos_from_touch(canvas_origin(canvas), &touch, egui_ctx) }) } -fn pos_from_touch(canvas_origin: egui::Pos2, touch: &web_sys::Touch) -> egui::Pos2 { +fn pos_from_touch( + canvas_origin: egui::Pos2, + touch: &web_sys::Touch, + egui_ctx: &egui::Context, +) -> egui::Pos2 { + let zoom_factor = egui_ctx.zoom_factor(); egui::Pos2 { - x: touch.page_x() as f32 - canvas_origin.x, - y: touch.page_y() as f32 - canvas_origin.y, + x: (touch.page_x() as f32 - canvas_origin.x) / zoom_factor, + y: (touch.page_y() as f32 - canvas_origin.y) / zoom_factor, } } @@ -68,7 +76,7 @@ pub fn push_touches(runner: &mut AppRunner, phase: egui::TouchPhase, event: &web device_id: egui::TouchDeviceId(0), id: egui::TouchId::from(touch.identifier()), phase, - pos: pos_from_touch(canvas_origin, &touch), + pos: pos_from_touch(canvas_origin, &touch, runner.egui_ctx()), force: Some(touch.force()), }); } diff --git a/crates/eframe/src/web/mod.rs b/crates/eframe/src/web/mod.rs index d88e94229..a322a530a 100644 --- a/crates/eframe/src/web/mod.rs +++ b/crates/eframe/src/web/mod.rs @@ -116,8 +116,8 @@ fn canvas_origin(canvas: &web_sys::HtmlCanvasElement) -> egui::Pos2 { egui::pos2(rect.left() as f32, rect.top() as f32) } -fn canvas_size_in_points(canvas: &web_sys::HtmlCanvasElement) -> egui::Vec2 { - let pixels_per_point = native_pixels_per_point(); +fn canvas_size_in_points(canvas: &web_sys::HtmlCanvasElement, ctx: &egui::Context) -> egui::Vec2 { + let pixels_per_point = ctx.pixels_per_point(); egui::vec2( canvas.width() as f32 / pixels_per_point, canvas.height() as f32 / pixels_per_point, diff --git a/crates/egui/src/memory.rs b/crates/egui/src/memory.rs index b84308283..7d61acd96 100644 --- a/crates/egui/src/memory.rs +++ b/crates/egui/src/memory.rs @@ -185,6 +185,12 @@ pub struct Options { /// presses Cmd+Plus, Cmd+Minus or Cmd+0, just like in a browser. /// /// This is `true` by default. + /// + /// On the web-backend of `eframe` this is set to false by default, + /// so that the zoom shortcuts are handled exclusively by the browser, + /// which will change the `native_pixels_per_point` (`devicePixelRatio`). + /// You can still zoom egui independently by calling [`crate::Context::set_zoom_factor`], + /// which will be applied on top of the browsers global zoom. #[cfg_attr(feature = "serde", serde(skip))] pub zoom_with_keyboard: bool,