<h1>Pointer Lock - 🐭 Acceleration Sample</h1>
<button id="firstRequestPointerLockButton">
request pointer lock
</button>
<button id="secondRequestPointerLockButton" autofocus>
request pointer lock with "unadjustedMovement"
</button>
<button id="clearButton">
clear
</button>
<pre id="mouseLog">movementX: - max: - min: - </pre>
<pre id="unadjustedMouseLog">movementX: - max: - min: - </pre>
<hr />
<div id="log"></div>
<canvas id="canvas"></canvas>
html {
height: 100%;
}
body {
font-family: helvetica, arial, sans-serif;
margin: 2em;
}
h2 {
margin-top: 2em;
text-align: right;
}
button {
margin-bottom: 0.5em;
}
#log,
pre {
margin: 1em 0 0 0;
white-space: pre-wrap;
word-break: break-all;
text-shadow: 1px 1px 0 white, -1px -1px 0 white, 2px 2px 0 white,
-2px -2px 0 white;
}
#unadjustedMouseLog {
margin: 0 0 1em 0;
}
#unadjustedMouseLog::after {
content: " (without acceleration)";
white-space: nowrap;
}
#mouseLog::after {
content: " (with acceleration, by default)";
white-space: nowrap;
}
canvas {
z-index: -1;
width: 100%;
height: 100%;
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
}
@media screen and (min-width: 640px) {
body {
margin: 2em auto;
max-width: calc(640px - 2em);
}
}
console.log = (text) => {
log.textContent += `${text}\r\n`;
};
const myTargetElement = document.body;
let isLockedWithUnadjustedMovement = false;
// Request pointer lock.
firstRequestPointerLockButton.onclick = requestPointerLockWithoutUnadjustedMovement;
function requestPointerLockWithoutUnadjustedMovement() {
const promise = myTargetElement.requestPointerLock({
unadjustedMovement: false
});
isLockedWithUnadjustedMovement = false;
if (!promise) return;
return promise
.then(() => console.log("pointer is locked without unadjusted movement"))
.catch((error) => {
console.log(
`pointer can't be locked without unadjusted movement: "${error.message}"`
);
});
}
document.addEventListener("pointerlockchange", () => {
if (document.pointerLockElement) {
console.log(`pointer is locked on ${document.pointerLockElement.id}`);
} else {
console.log("pointer is unlocked");
}
});
document.addEventListener("pointerlockerror", () => {
console.log("pointer lock error");
});
// Disable mouse acceleration.
secondRequestPointerLockButton.onclick = requestPointerLockWithUnadjustedMovement;
function requestPointerLockWithUnadjustedMovement() {
const promise = myTargetElement.requestPointerLock({
unadjustedMovement: true
});
if (!promise) {
isLockedWithUnadjustedMovement = false;
console.log("disabling mouse acceleration not supported");
return;
}
return promise
.then(() => {
isLockedWithUnadjustedMovement = true;
console.log("pointer is locked with unadjusted movement");
})
.catch((error) => {
console.log(
`pointer can't be locked with unadjusted movement: "${error.message}"`
);
if (error.name === "NotSupportedError") {
// Some platforms may not support unadjusted movement.
// You can request again a regular pointer lock.
return requestPointerLockWithoutUnadjustedMovement();
}
});
}
// Clear data.
clearButton.onclick = (_) => {
maxMovementX = 0;
maxUnadjustedMovementX = 0;
minMovementX = 0;
minUnadjustedMovementX = 0;
mouseLog.textContent = "movementX: - max: - min: - ";
unadjustedMouseLog.textContent = "movementX: - max: - min: - ";
mouseMoveData = [];
};
// Mouse move events handling.
let maxMovementX = 0;
let maxUnadjustedMovementX = 0;
let minMovementX = 0;
let minUnadjustedMovementX = 0;
document.onmousemove = (event) => {
const unadjusted =
document.pointerLockElement && isLockedWithUnadjustedMovement;
if (!unadjusted) {
maxMovementX = Math.max(event.movementX, maxMovementX);
minMovementX = Math.min(event.movementX, minMovementX);
mouseLog.textContent = `movementX: ${event.movementX
.toString()
.padEnd(5)} max: ${maxMovementX
.toString()
.padEnd(5)} min: ${minMovementX.toString().padEnd(5)}`;
} else {
maxUnadjustedMovementX = Math.max(event.movementX, maxUnadjustedMovementX);
minUnadjustedMovementX = Math.min(event.movementX, minUnadjustedMovementX);
unadjustedMouseLog.textContent = `movementX: ${event.movementX
.toString()
.padEnd(5)} max: ${maxUnadjustedMovementX
.toString()
.padEnd(5)} min: ${minUnadjustedMovementX.toString().padEnd(5)}`;
}
mouseMoveData.push({ x: event.movementX, unadjusted });
};
let mouseMoveData = [];
(function draw() {
canvas.width = innerWidth * devicePixelRatio;
canvas.height = innerHeight * devicePixelRatio;
mouseMoveData
.filter((mouseMove, index) => mouseMoveData.length - index < canvas.width)
.forEach((mouseMove, index) => {
const x = index;
const y = canvas.height;
const w = 1;
const h = -Math.abs(mouseMove.x) * devicePixelRatio;
const context = canvas.getContext("2d");
context.fillStyle = mouseMove.unadjusted ? "#ccc" : "#888";
context.fillRect(x, y, w, h);
});
requestAnimationFrame(draw);
})();
This Pen doesn't use any external CSS resources.
This Pen doesn't use any external JavaScript resources.