Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions src/core/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -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') {
Expand Down
27 changes: 27 additions & 0 deletions src/events/mouse.js
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
Original file line number Diff line number Diff line change
@@ -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
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Canvas Resize Mouse Coords Test</title>
<script src="../../../../lib/p5.js"></script>
<script src="sketch.js"></script>
</head>
<body>
<h3>Test Issue #8139: mouseX/mouseY not updated when canvas changes</h3>
<p>Instructions:</p>
<ul>
<li>Keep your mouse still on the canvas</li>
<li>Press F12 to open/close dev tools (or manually resize the browser window)</li>
<li>Press F11 to toggle fullscreen</li>
<li>Watch the mouseX and mouseY values - they should stay updated even without moving the mouse</li>
</ul>
<p>Current behavior: mouseX/mouseY freeze until mouse moves</p>
<p>Expected behavior: mouseX/mouseY should update to reflect new canvas position</p>
</body>
</html>
Original file line number Diff line number Diff line change
@@ -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);
}
91 changes: 91 additions & 0 deletions test/unit/events/mouse.js
Original file line number Diff line number Diff line change
Expand Up @@ -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);
});
});
});