From f166f4a4d1fd015591a53adff2c6e5b0a427d081 Mon Sep 17 00:00:00 2001 From: vinono Date: Sun, 12 Oct 2025 01:02:45 +0800 Subject: [PATCH] Fix issue 8139: Update mouseX/mouseY on window resize - Add _updateMouseCoordsFromWindowPosition() method to recalculate coordinates - Add resize event listener to trigger updates automatically - Add unit tests and manual test example - Fixes mouseX/mouseY freezing when DevTools/fullscreen/resize happens - Maintains backward compatibility and minimal performance impact --- src/core/main.js | 12 +++ src/events/mouse.js | 27 ++++++ .../canvas-resize-mouse-coords/README.md | 36 ++++++++ .../canvas-resize-mouse-coords/index.html | 21 +++++ .../canvas-resize-mouse-coords/sketch.js | 49 ++++++++++ test/unit/events/mouse.js | 91 +++++++++++++++++++ 6 files changed, 236 insertions(+) create mode 100644 test/manual-test-examples/mouse-events/canvas-resize-mouse-coords/README.md create mode 100644 test/manual-test-examples/mouse-events/canvas-resize-mouse-coords/index.html create mode 100644 test/manual-test-examples/mouse-events/canvas-resize-mouse-coords/sketch.js diff --git a/src/core/main.js b/src/core/main.js index 0e19d75ec1..fec0961198 100644 --- a/src/core/main.js +++ b/src/core/main.js @@ -722,9 +722,21 @@ class p5 { }; window.addEventListener('focus', focusHandler); window.addEventListener('blur', blurHandler); + + // Add resize handler to update mouse coordinates when canvas position changes + // (e.g., when dev tools open/close, fullscreen toggle, or window resize) + // This fixes issue #8139 + const resizeHandler = () => { + if (typeof this._updateMouseCoordsFromWindowPosition !== 'undefined') { + this._updateMouseCoordsFromWindowPosition(); + } + }; + window.addEventListener('resize', resizeHandler); + this.registerMethod('remove', () => { window.removeEventListener('focus', focusHandler); window.removeEventListener('blur', blurHandler); + window.removeEventListener('resize', resizeHandler); }); if (document.readyState === 'complete') { diff --git a/src/events/mouse.js b/src/events/mouse.js index 7d83626962..42ce2aee40 100644 --- a/src/events/mouse.js +++ b/src/events/mouse.js @@ -862,6 +862,33 @@ p5.prototype._updateMouseCoords = function() { this._setProperty('_pmouseWheelDeltaY', this._mouseWheelDeltaY); }; +/** + * Recalculates mouse coordinates relative to the canvas when the canvas + * position changes (e.g., due to window resize, fullscreen, dev tools). + * This uses the last known window mouse coordinates (winMouseX, winMouseY). + * @private + */ +p5.prototype._updateMouseCoordsFromWindowPosition = function() { + if (this._curElement !== null && this._hasMouseInteracted) { + // Create a synthetic event object with the last known window coordinates + const syntheticEvent = { + clientX: this.winMouseX, + clientY: this.winMouseY + }; + + const mousePos = getMousePos( + this._curElement.elt, + this.width, + this.height, + syntheticEvent + ); + + this._setProperty('mouseX', mousePos.x); + this._setProperty('mouseY', mousePos.y); + // winMouseX and winMouseY remain unchanged as the mouse hasn't actually moved + } +}; + function getMousePos(canvas, w, h, evt) { if (evt && !evt.clientX) { // use touches if touch and not mouse diff --git a/test/manual-test-examples/mouse-events/canvas-resize-mouse-coords/README.md b/test/manual-test-examples/mouse-events/canvas-resize-mouse-coords/README.md new file mode 100644 index 0000000000..1ab147aa5b --- /dev/null +++ b/test/manual-test-examples/mouse-events/canvas-resize-mouse-coords/README.md @@ -0,0 +1,36 @@ +# Test for Issue #8139: mouseX/mouseY not updated on canvas resize + +## Bug Description +When the canvas position changes (e.g., opening/closing dev tools with F12, toggling fullscreen with F11, or resizing the browser window), the `mouseX` and `mouseY` values would freeze at their old values until the user physically moved the mouse. + +## Expected Behavior +When the canvas position changes, `mouseX` and `mouseY` should automatically update to reflect the mouse's new position relative to the canvas, even if the mouse hasn't moved. + +## Test Instructions + +1. Open `index.html` in a web browser +2. Move your mouse onto the canvas and note the displayed `mouseX` and `mouseY` values +3. **Keep your mouse completely still** +4. Press F12 to open/close the browser developer tools +5. Observe that `mouseX` and `mouseY` values update automatically to reflect the new canvas position +6. Alternatively, press F11 to toggle fullscreen and observe the same behavior + +## What to Look For + +### Before the fix: +- `mouseX` and `mouseY` would stay frozen at old values +- The red circle indicator would appear in the wrong position +- Values would only update after the mouse was physically moved + +### After the fix: +- `mouseX` and `mouseY` update immediately when canvas position changes +- The red circle indicator stays at the correct mouse position +- `winMouseX` and `winMouseY` remain constant (as they should) + +## Technical Details + +The fix adds a `resize` event listener that recalculates mouse coordinates relative to the canvas when the window is resized. It uses the stored `winMouseX` and `winMouseY` values (which represent the mouse position in window coordinates) and calls `getBoundingClientRect()` to get the updated canvas position. + +### Modified Files: +- `src/events/mouse.js` - Added `_updateMouseCoordsFromWindowPosition()` method +- `src/core/main.js` - Added `resize` event listener that calls the new method diff --git a/test/manual-test-examples/mouse-events/canvas-resize-mouse-coords/index.html b/test/manual-test-examples/mouse-events/canvas-resize-mouse-coords/index.html new file mode 100644 index 0000000000..fcab83dd24 --- /dev/null +++ b/test/manual-test-examples/mouse-events/canvas-resize-mouse-coords/index.html @@ -0,0 +1,21 @@ + + + + + Canvas Resize Mouse Coords Test + + + + +

Test Issue #8139: mouseX/mouseY not updated when canvas changes

+

Instructions:

+ +

Current behavior: mouseX/mouseY freeze until mouse moves

+

Expected behavior: mouseX/mouseY should update to reflect new canvas position

+ + diff --git a/test/manual-test-examples/mouse-events/canvas-resize-mouse-coords/sketch.js b/test/manual-test-examples/mouse-events/canvas-resize-mouse-coords/sketch.js new file mode 100644 index 0000000000..4ce507c0d8 --- /dev/null +++ b/test/manual-test-examples/mouse-events/canvas-resize-mouse-coords/sketch.js @@ -0,0 +1,49 @@ +// Test for issue #8139 +// mouseX and mouseY not updated when canvas changes until mouse moves + +function setup() { + createCanvas(800, 800); + textAlign(LEFT, TOP); + textSize(20); +} + +function draw() { + background(220); + + // Display mouseX and mouseY coordinates + fill(0); + text('mouseX: ' + mouseX, 20, 20); + text('mouseY: ' + mouseY, 20, 50); + text('pmouseX: ' + pmouseX, 20, 80); + text('pmouseY: ' + pmouseY, 20, 110); + + // Display window coordinates (these should stay constant) + text('winMouseX: ' + winMouseX, 20, 140); + text('winMouseY: ' + winMouseY, 20, 170); + + // Visual indicator - draw a circle at mouse position + fill(255, 0, 0, 150); + noStroke(); + circle(mouseX, mouseY, 30); + + // Instructions + fill(0, 150, 0); + textSize(16); + text('TEST INSTRUCTIONS:', 20, 220); + text('1. Place mouse at a specific location on canvas', 20, 245); + text('2. Keep mouse COMPLETELY STILL', 20, 265); + text('3. Press F12 to open/close dev tools', 20, 285); + text('4. Or press F11 to toggle fullscreen', 20, 305); + text('5. Watch mouseX/mouseY values update automatically!', 20, 325); + + fill(0, 0, 150); + text('EXPECTED: mouseX/mouseY update without mouse movement', 20, 360); + text('PREVIOUS BUG: coordinates would freeze', 20, 380); + + // Show canvas size for debugging + fill(0); + textSize(14); + text('Canvas: ' + width + ' x ' + height, 20, 420); + text('Window: ' + windowWidth + ' x ' + windowHeight, 20, 440); + text('Frame: ' + frameCount, 20, 460); +} diff --git a/test/unit/events/mouse.js b/test/unit/events/mouse.js index fd3003ce02..1bdddc8154 100644 --- a/test/unit/events/mouse.js +++ b/test/unit/events/mouse.js @@ -484,4 +484,95 @@ suite('Mouse Events', function() { assert.deepEqual(counts, [1, 1]); }); }); + + // Test for issue #8139: mouseX/mouseY not updated on canvas resize + suite('mouseX/mouseY update on window resize', function() { + test('mouseX and mouseY should update when window is resized without mouse movement', function() { + // First, trigger a mouse event to set initial coordinates + const initialMouseEvent = new MouseEvent('mousemove', { + clientX: 150, + clientY: 150 + }); + window.dispatchEvent(initialMouseEvent); + + // Verify winMouseX/winMouseY are set correctly + assert.strictEqual(myp5.winMouseX, 150); + assert.strictEqual(myp5.winMouseY, 150); + + // Simulate a window resize event (which changes canvas position) + // This should trigger _updateMouseCoordsFromWindowPosition + window.dispatchEvent(new Event('resize')); + + // After resize, mouseX/mouseY should be recalculated based on the new canvas position + // Since we can't easily change the actual canvas position in this test, + // we verify that the function exists and can be called + assert.isFunction(myp5._updateMouseCoordsFromWindowPosition); + + // Manually call the update function to verify it works + myp5._updateMouseCoordsFromWindowPosition(); + + // mouseX/mouseY should still be numbers after the update + assert.isNumber(myp5.mouseX); + assert.isNumber(myp5.mouseY); + + // winMouseX/winMouseY should remain unchanged (no actual mouse movement) + assert.strictEqual(myp5.winMouseX, 150); + assert.strictEqual(myp5.winMouseY, 150); + }); + + test('_updateMouseCoordsFromWindowPosition should not run before mouse interaction', function() { + // Create a fresh p5 instance + let testP5; + new p5(function(p) { + p.setup = function() { + testP5 = p; + }; + }); + + // Before any mouse interaction, _hasMouseInteracted should be false + assert.strictEqual(testP5._hasMouseInteracted, false); + + // Call the update function - it should do nothing since no interaction yet + if (typeof testP5._updateMouseCoordsFromWindowPosition !== 'undefined') { + testP5._updateMouseCoordsFromWindowPosition(); + } + + // mouseX and mouseY should still be at their initial values (0) + assert.strictEqual(testP5.mouseX, 0); + assert.strictEqual(testP5.mouseY, 0); + + // Clean up + testP5.remove(); + }); + + test('_updateMouseCoordsFromWindowPosition should recalculate coordinates after mouse interaction', function() { + // Trigger initial mouse event + const mouseEvent = new MouseEvent('mousemove', { + clientX: 100, + clientY: 100 + }); + window.dispatchEvent(mouseEvent); + + // Store current canvas bounding rect + const initialRect = canvas.getBoundingClientRect(); + const initialMouseX = (100 - initialRect.left) / sx; + const initialMouseY = (100 - initialRect.top) / sy; + + // Verify initial calculation + assert.strictEqual(myp5.mouseX, initialMouseX); + assert.strictEqual(myp5.mouseY, initialMouseY); + + // Call the update function + myp5._updateMouseCoordsFromWindowPosition(); + + // Get the new rect (in real scenario this would be different after resize) + const newRect = canvas.getBoundingClientRect(); + const expectedMouseX = (100 - newRect.left) / sx; + const expectedMouseY = (100 - newRect.top) / sy; + + // mouseX/mouseY should be recalculated based on current canvas position + assert.strictEqual(myp5.mouseX, expectedMouseX); + assert.strictEqual(myp5.mouseY, expectedMouseY); + }); + }); });