Skip to content

Commit acbefda

Browse files
avoid initial translation jump in plot demo
1 parent b38e225 commit acbefda

File tree

4 files changed

+61
-20
lines changed

4 files changed

+61
-20
lines changed

egui/src/data/input.rs

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -338,3 +338,21 @@ pub enum TouchPhase {
338338
/// been intended by the user)
339339
Cancel,
340340
}
341+
342+
impl From<u64> for TouchId {
343+
fn from(id: u64) -> Self {
344+
Self(id)
345+
}
346+
}
347+
348+
impl From<i32> for TouchId {
349+
fn from(id: i32) -> Self {
350+
Self(id as u64)
351+
}
352+
}
353+
354+
impl From<u32> for TouchId {
355+
fn from(id: u32) -> Self {
356+
Self(id as u64)
357+
}
358+
}

egui_glium/src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -204,7 +204,7 @@ pub fn input_to_egui(
204204
touch.device_id.hash(&mut hasher);
205205
input_state.raw.events.push(Event::Touch {
206206
device_id: TouchDeviceId(hasher.finish()),
207-
id: TouchId(touch.id),
207+
id: TouchId::from(touch.id),
208208
phase: match touch.phase {
209209
glutin::event::TouchPhase::Started => egui::TouchPhase::Start,
210210
glutin::event::TouchPhase::Moved => egui::TouchPhase::Move,

egui_web/src/backend.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,9 @@ pub struct WebInput {
8484
/// Required because we don't get a position on touched
8585
pub latest_touch_pos: Option<egui::Pos2>,
8686

87+
/// Required to maintain a stable touch position for multi-touch gestures.
88+
pub latest_touch_pos_id: Option<egui::TouchId>,
89+
8790
pub raw: egui::RawInput,
8891
}
8992

egui_web/src/lib.rs

Lines changed: 39 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -114,23 +114,37 @@ pub fn button_from_mouse_event(event: &web_sys::MouseEvent) -> Option<egui::Poin
114114
}
115115
}
116116

117-
pub fn pos_from_touch_event(canvas_id: &str, event: &web_sys::TouchEvent) -> egui::Pos2 {
118-
// TO BE CLARIFIED: For some types of touch events (e.g. `touchcancel`) it may be necessary to
119-
// change the return type to an `Option<Pos2>` – but this would be an incompatible change. Can
120-
// we do this?
121-
122-
// Calculate the average of all touch positions:
123-
let mut accu = egui::Vec2::ZERO;
124-
let touch_count = event.touches().length();
125-
if touch_count > 0 {
126-
let canvas_origin = canvas_origin(canvas_id);
127-
for touch_idx in 0..touch_count {
128-
let touch = event.touches().get(touch_idx).unwrap();
129-
accu += pos_from_touch(canvas_origin, &touch).to_vec2();
130-
}
131-
accu = accu / touch_count as f32;
117+
/// A single touch is translated to a pointer movement. When a second touch is added, the pointer
118+
/// should not jump to a different position. Therefore, we do not calculate the average position
119+
/// of all touches, but we keep using the same touch as long as it is available.
120+
///
121+
/// `touch_id_for_pos` is the `TouchId` of the `Touch` we previously used to determine the
122+
/// pointer position.
123+
pub fn pos_from_touch_event(
124+
canvas_id: &str,
125+
event: &web_sys::TouchEvent,
126+
touch_id_for_pos: &mut Option<egui::TouchId>,
127+
) -> egui::Pos2 {
128+
let touch_for_pos;
129+
if let Some(touch_id_for_pos) = touch_id_for_pos {
130+
// search for the touch we previously used for the position
131+
// (unfortunately, `event.touches()` is not a rust collection):
132+
touch_for_pos = (0..event.touches().length())
133+
.into_iter()
134+
.map(|i| event.touches().get(i).unwrap())
135+
.find(|touch| egui::TouchId::from(touch.identifier()) == *touch_id_for_pos);
136+
} else {
137+
touch_for_pos = None;
132138
}
133-
egui::Pos2::ZERO + accu
139+
// Use the touch found above or pick the first, or return a default position if there is no
140+
// touch at all. (The latter is not expected as the current method is only called when there is
141+
// at least one touch.)
142+
touch_for_pos
143+
.or_else(|| event.touches().get(0))
144+
.map_or(Default::default(), |touch| {
145+
*touch_id_for_pos = Some(egui::TouchId::from(touch.identifier()));
146+
pos_from_touch(canvas_origin(canvas_id), &touch)
147+
})
134148
}
135149

136150
fn pos_from_touch(canvas_origin: egui::Pos2, touch: &web_sys::Touch) -> egui::Pos2 {
@@ -153,7 +167,7 @@ fn push_touches(runner: &mut AppRunner, phase: egui::TouchPhase, event: &web_sys
153167
if let Some(touch) = event.changed_touches().item(touch_idx) {
154168
runner.input.raw.events.push(egui::Event::Touch {
155169
device_id: egui::TouchDeviceId(0),
156-
id: egui::TouchId(touch.identifier() as u64),
170+
id: egui::TouchId::from(touch.identifier()),
157171
phase,
158172
pos: pos_from_touch(canvas_origin, &touch),
159173
force: touch.force(),
@@ -914,7 +928,10 @@ fn install_canvas_events(runner_ref: &AppRunnerRef) -> Result<(), JsValue> {
914928
let runner_ref = runner_ref.clone();
915929
let closure = Closure::wrap(Box::new(move |event: web_sys::TouchEvent| {
916930
let mut runner_lock = runner_ref.0.lock();
917-
let pos = pos_from_touch_event(runner_lock.canvas_id(), &event);
931+
let mut latest_touch_pos_id = runner_lock.input.latest_touch_pos_id;
932+
let pos =
933+
pos_from_touch_event(runner_lock.canvas_id(), &event, &mut latest_touch_pos_id);
934+
runner_lock.input.latest_touch_pos_id = latest_touch_pos_id;
918935
runner_lock.input.latest_touch_pos = Some(pos);
919936
runner_lock.input.is_touch = true;
920937
let modifiers = runner_lock.input.raw.modifiers;
@@ -943,7 +960,10 @@ fn install_canvas_events(runner_ref: &AppRunnerRef) -> Result<(), JsValue> {
943960
let runner_ref = runner_ref.clone();
944961
let closure = Closure::wrap(Box::new(move |event: web_sys::TouchEvent| {
945962
let mut runner_lock = runner_ref.0.lock();
946-
let pos = pos_from_touch_event(runner_lock.canvas_id(), &event);
963+
let mut latest_touch_pos_id = runner_lock.input.latest_touch_pos_id;
964+
let pos =
965+
pos_from_touch_event(runner_lock.canvas_id(), &event, &mut latest_touch_pos_id);
966+
runner_lock.input.latest_touch_pos_id = latest_touch_pos_id;
947967
runner_lock.input.latest_touch_pos = Some(pos);
948968
runner_lock.input.is_touch = true;
949969
runner_lock

0 commit comments

Comments
 (0)