Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Touch events report coordinates relative to the phone screen itself in browser builds #9071

Open
dearlordylord opened this issue Jul 8, 2023 · 3 comments
Labels
A-Input Player input via keyboard, mouse, gamepad, and more C-Bug An unexpected or incorrect behavior O-Web Specific to web (WASM) builds

Comments

@dearlordylord
Copy link

dearlordylord commented Jul 8, 2023

Bevy version

0.10.1

What you did

Compiled into wasm / attached to a specific canvas (but I think no explicit canvas will do as well)

What went wrong

  • what were you expecting?

touch events are relative to the canvas

  • what actually happened?

touch events are reported relative to the screen (not even to the browser window!)

Other information that can be used to further reproduce or isolate the problem.

  • screencast
telegram-cloud-document-2-5282792564146056949.mp4
  • workarounds that you used

explicitly send canvas.getBoundingClientRect() and use this data in your system to calculate the actual touch coords

  • links to related bugs, PRs or discussions

probably #7528

  • reproduction case deployed

https://touchies.apps.loskutoff.com/

  • reproduction source code

https://github.com/Firfi/touchies

  • notes

please note that the touch is being reported not even related to the browser window (which I could've worked around giving the app its canvas coordinates) bit the phone screen itself, as shown in the attached screencast

for mouse event comparison, the example deployed also has mouse event system; click couple times (to focus the element first, then to emit the actuan event)

@dearlordylord dearlordylord added C-Bug An unexpected or incorrect behavior S-Needs-Triage This issue needs to be labelled labels Jul 8, 2023
@NiklasEi NiklasEi added A-Input Player input via keyboard, mouse, gamepad, and more O-Web Specific to web (WASM) builds and removed S-Needs-Triage This issue needs to be labelled labels Jul 8, 2023
@dearlordylord
Copy link
Author

dearlordylord commented Jul 9, 2023

workaround would be:

static mut outside_pos: Option<Vec2> = None;

#[wasm_bindgen]
pub fn report_canvas_screen_position(x: f32, y: f32) {
  let v = Vec2::new(x, y);
  unsafe {
    outside_pos = Some(v);
  }
}

fn outside_window_size_system(mut event_writer: EventWriter<OutsideWindowResize>, mut size: ResMut<OutsideWindowSize>) {
  unsafe {
    if let Some(op) = outside_pos {
      if op != size.0 {
        size.0 = op;
        event_writer.send(OutsideWindowResize(op));
      }
    }
  }
}

// then in ts, call report_canvas_screen_position with the results of `canvas.getBoundingClientRect()`

// I.e. React hook:

const useCanvasPositionRelativeToTheWholeScreen = (canvas: HTMLCanvasElement | null) => {
  const [position, setPosition] = useState({ x: 0, y: 0 });
  useEffect(() => {
    if (!canvas) return;
    const updatePosition = () => setPosition(getCanvasPositionRelativeToTheWholeScreen(canvas));
    updatePosition();
    window.addEventListener("resize", updatePosition);
    window.document.addEventListener("scroll", updatePosition);
    window.addEventListener("touchmove", updatePosition);
    window.addEventListener("touchend", updatePosition);
    // and also poll it every 100 ms
    const interval = setInterval(updatePosition, 100);
    return () => {
      window.removeEventListener("resize", updatePosition);
      window.document.removeEventListener("scroll", updatePosition);
      window.removeEventListener("touchmove", updatePosition);
      window.removeEventListener("touchend", updatePosition);
      clearInterval(interval);
    };
  }, [canvas]);
  return useMemo(() => position, [position.x, position.y]);
}

@bilowik
Copy link

bilowik commented Nov 2, 2023

In case someone else comes upon this, if you are utilizing web-sys in your bevy app, you can calculate the offset using something along the lines of:

#[derive(Resource, Default)]
pub struct TouchOffset(pub Vec2);

#[cfg(target_arch = "wasm32")]
pub fn update_touch_offset(
    mut touch_offset: ResMut<TouchOffset>,
) {
    if let Some(curr_offset) = web_sys::window()
        .and_then(|window| window.document())
        .and_then(|document| document.get_element_by_id("main-canvas")) // Assumes you set the id of the canvas to this
        .map(|element| element.get_bounding_client_rect())
        .map(|rect| Vec2::new(rect.left() as f32, rect.top() as f32)) {
        if curr_offset != touch_offset.0 {
            touch_offset.0 = curr_offset;
            info!("New touch offset calculated: {:?}", curr_offset);
        }
    }
    else {
        error!("Failed to get the canvas offset, touch inputs may be impacted");
    }
}

You would then subtract the TouchOffset from any touch coordinates you utilize.
This probably doesn't need to run every frame though. Also the conditional is also not really needed, but I wanted to log when it changes while I was testing, you could just as easily set it without checking it.

(Also be aware that that error will spam your console if the element-getting logic is not right, so make sure you assign an id to the canvas and ensure bevy is rendering to that specific canvas.) (Edit: I ended up creating a Local counter to stop reporting the error after some amount of reports within a given timeframe, so that's an option for that for completeness)

Edit: I wrote up a plugin to do this offsetting automatically for TouchEvent and Touches resource that can be utilized until a proper fix finds its way in if anyone wants/needs a quick drop-in fix. Since it modifies the events themselves, this also fixes the issue for touch inputs and bevy UI elements, which my above example cannot. https://github.com/bilowik/bevy_wasm_touch_fix, also published on crates.io under the same name.

@daxpedda
Copy link
Contributor

This should have been fixed by #10702.
Let me know if you still encounter this issue.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-Input Player input via keyboard, mouse, gamepad, and more C-Bug An unexpected or incorrect behavior O-Web Specific to web (WASM) builds
Projects
None yet
Development

No branches or pull requests

4 participants