Skip to content

Commit d1eb0b7

Browse files
justusdieckmannemilk
authored andcommitted
Add web support for zoom_factor (emilk#4260)
Before, when setting the `zoom_factor`, the website was already enlarged, but the zoom was ignored when calculating the logical window size and mouse position, causing an offset between the actual cursor and selected elements. That is addressed here --------- Co-authored-by: Emil Ernerfeldt <emil.ernerfeldt@gmail.com>
1 parent 878244b commit d1eb0b7

File tree

5 files changed

+45
-17
lines changed

5 files changed

+45
-17
lines changed

crates/eframe/src/web/app_runner.rs

+4-2
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,9 @@ impl AppRunner {
6060
super::storage::load_memory(&egui_ctx);
6161

6262
egui_ctx.options_mut(|o| {
63-
// On web, the browser controls the zoom factor:
63+
// On web by default egui follows the zoom factor of the browser,
64+
// and lets the browser handle the zoom shortscuts.
65+
// A user can still zoom egui separately by calling [`egui::Context::set_zoom_factor`].
6466
o.zoom_with_keyboard = false;
6567
o.zoom_factor = 1.0;
6668
});
@@ -183,7 +185,7 @@ impl AppRunner {
183185
/// The result can be painted later with a call to [`Self::run_and_paint`] or [`Self::paint`].
184186
pub fn logic(&mut self) {
185187
super::resize_canvas_to_screen_size(self.canvas(), self.web_options.max_size_points);
186-
let canvas_size = super::canvas_size_in_points(self.canvas());
188+
let canvas_size = super::canvas_size_in_points(self.canvas(), self.egui_ctx());
187189
let raw_input = self.input.new_frame(canvas_size);
188190

189191
let full_output = self.egui_ctx.run(raw_input, |egui_ctx| {

crates/eframe/src/web/events.rs

+18-6
Original file line numberDiff line numberDiff line change
@@ -297,7 +297,7 @@ pub(crate) fn install_canvas_events(runner_ref: &WebRunner) -> Result<(), JsValu
297297
let modifiers = modifiers_from_mouse_event(&event);
298298
runner.input.raw.modifiers = modifiers;
299299
if let Some(button) = button_from_mouse_event(&event) {
300-
let pos = pos_from_mouse_event(runner.canvas(), &event);
300+
let pos = pos_from_mouse_event(runner.canvas(), &event, runner.egui_ctx());
301301
let modifiers = runner.input.raw.modifiers;
302302
runner.input.raw.events.push(egui::Event::PointerButton {
303303
pos,
@@ -324,7 +324,7 @@ pub(crate) fn install_canvas_events(runner_ref: &WebRunner) -> Result<(), JsValu
324324
|event: web_sys::MouseEvent, runner| {
325325
let modifiers = modifiers_from_mouse_event(&event);
326326
runner.input.raw.modifiers = modifiers;
327-
let pos = pos_from_mouse_event(runner.canvas(), &event);
327+
let pos = pos_from_mouse_event(runner.canvas(), &event, runner.egui_ctx());
328328
runner.input.raw.events.push(egui::Event::PointerMoved(pos));
329329
runner.needs_repaint.repaint_asap();
330330
event.stop_propagation();
@@ -336,7 +336,7 @@ pub(crate) fn install_canvas_events(runner_ref: &WebRunner) -> Result<(), JsValu
336336
let modifiers = modifiers_from_mouse_event(&event);
337337
runner.input.raw.modifiers = modifiers;
338338
if let Some(button) = button_from_mouse_event(&event) {
339-
let pos = pos_from_mouse_event(runner.canvas(), &event);
339+
let pos = pos_from_mouse_event(runner.canvas(), &event, runner.egui_ctx());
340340
let modifiers = runner.input.raw.modifiers;
341341
runner.input.raw.events.push(egui::Event::PointerButton {
342342
pos,
@@ -374,7 +374,12 @@ pub(crate) fn install_canvas_events(runner_ref: &WebRunner) -> Result<(), JsValu
374374
"touchstart",
375375
|event: web_sys::TouchEvent, runner| {
376376
let mut latest_touch_pos_id = runner.input.latest_touch_pos_id;
377-
let pos = pos_from_touch_event(runner.canvas(), &event, &mut latest_touch_pos_id);
377+
let pos = pos_from_touch_event(
378+
runner.canvas(),
379+
&event,
380+
&mut latest_touch_pos_id,
381+
runner.egui_ctx(),
382+
);
378383
runner.input.latest_touch_pos_id = latest_touch_pos_id;
379384
runner.input.latest_touch_pos = Some(pos);
380385
let modifiers = runner.input.raw.modifiers;
@@ -397,7 +402,12 @@ pub(crate) fn install_canvas_events(runner_ref: &WebRunner) -> Result<(), JsValu
397402
"touchmove",
398403
|event: web_sys::TouchEvent, runner| {
399404
let mut latest_touch_pos_id = runner.input.latest_touch_pos_id;
400-
let pos = pos_from_touch_event(runner.canvas(), &event, &mut latest_touch_pos_id);
405+
let pos = pos_from_touch_event(
406+
runner.canvas(),
407+
&event,
408+
&mut latest_touch_pos_id,
409+
runner.egui_ctx(),
410+
);
401411
runner.input.latest_touch_pos_id = latest_touch_pos_id;
402412
runner.input.latest_touch_pos = Some(pos);
403413
runner.input.raw.events.push(egui::Event::PointerMoved(pos));
@@ -460,7 +470,9 @@ pub(crate) fn install_canvas_events(runner_ref: &WebRunner) -> Result<(), JsValu
460470
});
461471

462472
let scroll_multiplier = match unit {
463-
egui::MouseWheelUnit::Page => canvas_size_in_points(runner.canvas()).y,
473+
egui::MouseWheelUnit::Page => {
474+
canvas_size_in_points(runner.canvas(), runner.egui_ctx()).y
475+
}
464476
egui::MouseWheelUnit::Line => {
465477
#[allow(clippy::let_and_return)]
466478
let points_per_scroll_line = 8.0; // Note that this is intentionally different from what we use in winit.

crates/eframe/src/web/input.rs

+15-7
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,13 @@ use super::{canvas_origin, AppRunner};
33
pub fn pos_from_mouse_event(
44
canvas: &web_sys::HtmlCanvasElement,
55
event: &web_sys::MouseEvent,
6+
ctx: &egui::Context,
67
) -> egui::Pos2 {
78
let rect = canvas.get_bounding_client_rect();
9+
let zoom_factor = ctx.zoom_factor();
810
egui::Pos2 {
9-
x: event.client_x() as f32 - rect.left() as f32,
10-
y: event.client_y() as f32 - rect.top() as f32,
11+
x: (event.client_x() as f32 - rect.left() as f32) / zoom_factor,
12+
y: (event.client_y() as f32 - rect.top() as f32) / zoom_factor,
1113
}
1214
}
1315

@@ -32,6 +34,7 @@ pub fn pos_from_touch_event(
3234
canvas: &web_sys::HtmlCanvasElement,
3335
event: &web_sys::TouchEvent,
3436
touch_id_for_pos: &mut Option<egui::TouchId>,
37+
egui_ctx: &egui::Context,
3538
) -> egui::Pos2 {
3639
let touch_for_pos = if let Some(touch_id_for_pos) = touch_id_for_pos {
3740
// search for the touch we previously used for the position
@@ -49,14 +52,19 @@ pub fn pos_from_touch_event(
4952
.or_else(|| event.touches().get(0))
5053
.map_or(Default::default(), |touch| {
5154
*touch_id_for_pos = Some(egui::TouchId::from(touch.identifier()));
52-
pos_from_touch(canvas_origin(canvas), &touch)
55+
pos_from_touch(canvas_origin(canvas), &touch, egui_ctx)
5356
})
5457
}
5558

56-
fn pos_from_touch(canvas_origin: egui::Pos2, touch: &web_sys::Touch) -> egui::Pos2 {
59+
fn pos_from_touch(
60+
canvas_origin: egui::Pos2,
61+
touch: &web_sys::Touch,
62+
egui_ctx: &egui::Context,
63+
) -> egui::Pos2 {
64+
let zoom_factor = egui_ctx.zoom_factor();
5765
egui::Pos2 {
58-
x: touch.page_x() as f32 - canvas_origin.x,
59-
y: touch.page_y() as f32 - canvas_origin.y,
66+
x: (touch.page_x() as f32 - canvas_origin.x) / zoom_factor,
67+
y: (touch.page_y() as f32 - canvas_origin.y) / zoom_factor,
6068
}
6169
}
6270

@@ -68,7 +76,7 @@ pub fn push_touches(runner: &mut AppRunner, phase: egui::TouchPhase, event: &web
6876
device_id: egui::TouchDeviceId(0),
6977
id: egui::TouchId::from(touch.identifier()),
7078
phase,
71-
pos: pos_from_touch(canvas_origin, &touch),
79+
pos: pos_from_touch(canvas_origin, &touch, runner.egui_ctx()),
7280
force: Some(touch.force()),
7381
});
7482
}

crates/eframe/src/web/mod.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -116,8 +116,8 @@ fn canvas_origin(canvas: &web_sys::HtmlCanvasElement) -> egui::Pos2 {
116116
egui::pos2(rect.left() as f32, rect.top() as f32)
117117
}
118118

119-
fn canvas_size_in_points(canvas: &web_sys::HtmlCanvasElement) -> egui::Vec2 {
120-
let pixels_per_point = native_pixels_per_point();
119+
fn canvas_size_in_points(canvas: &web_sys::HtmlCanvasElement, ctx: &egui::Context) -> egui::Vec2 {
120+
let pixels_per_point = ctx.pixels_per_point();
121121
egui::vec2(
122122
canvas.width() as f32 / pixels_per_point,
123123
canvas.height() as f32 / pixels_per_point,

crates/egui/src/memory.rs

+6
Original file line numberDiff line numberDiff line change
@@ -185,6 +185,12 @@ pub struct Options {
185185
/// presses Cmd+Plus, Cmd+Minus or Cmd+0, just like in a browser.
186186
///
187187
/// This is `true` by default.
188+
///
189+
/// On the web-backend of `eframe` this is set to false by default,
190+
/// so that the zoom shortcuts are handled exclusively by the browser,
191+
/// which will change the `native_pixels_per_point` (`devicePixelRatio`).
192+
/// You can still zoom egui independently by calling [`crate::Context::set_zoom_factor`],
193+
/// which will be applied on top of the browsers global zoom.
188194
#[cfg_attr(feature = "serde", serde(skip))]
189195
pub zoom_with_keyboard: bool,
190196

0 commit comments

Comments
 (0)