I created this easy cursor for enjoyable, it is a circle div that follows the mouse with some bounciness (spring and damping). I additionally needed it to stretch and squeeze primarily based on the speed of the mouse so I added that as properly, and each works. Now I additionally added rotation primarily based on the speed path of the mouse, now that works too (individually). nevertheless after I put all of them collectively it does not work as anticipated, for instance:
if I put the ultimate rework like so :
circle.model.rework = `${translateElement} ${scaleElement} ${rotateElement}`;
all the pieces technically works, however the stretch and squeeze is utilized on the identical axis after the rotation which implies it is at all times squeezing from prime to backside (visually) and stretching from proper to left (once more visually). So it does not appear to be it is being stretched in direction of the mouse, which was the specified impact I used to be going for
now if I put the rework like this : circle.model.rework = `${translateElement} ${rotateElement} ${scaleElement}`;
the circle div doesn’t transfer or scale in any respect (principally the code just isn’t working with out console error), Can anybody assist me work out why?
const circle = doc.querySelector('.circle');
const mousePos = { x: 0, y: 0 };
const prevMousePos = { x: 0, y: 0 };
let mouseSpeed = 0;
const circlePos = { x: 0, y: 0 };
const circleVelocity = { x: 0, y: 0 };
const spring = 0.025;
const damping = 0.845;
const maxSqueeze = 0.5;
const maxStretch = 1.5;
const maxMouseSpeed = 5;
let lowSpeedStartTime = 0;
let lowSpeedDuration = 0;
const lowSpeedThreshold = 0.5; // 0.5 seconds
doc.addEventListener('mousemove', (e) => {
const currentMousePos = { x: e.clientX, y: e.clientY };
const dx = currentMousePos.x - prevMousePos.x;
const dy = currentMousePos.y - prevMousePos.y;
// Calculate the pace because the magnitude of the speed vector
mouseSpeed = Math.sqrt(dx * dx + dy * dy);
// Replace earlier mouse place
prevMousePos.x = currentMousePos.x;
prevMousePos.y = currentMousePos.y;
// Replace the present mouse place
mousePos.x = currentMousePos.x;
mousePos.y = currentMousePos.y;
});
operate animate() {
const ax = (mousePos.x - circlePos.x) * spring;
const ay = (mousePos.y - circlePos.y) * spring;
circleVelocity.x += ax;
circleVelocity.y += ay;
circleVelocity.x *= damping;
circleVelocity.y *= damping;
circlePos.x += circleVelocity.x;
circlePos.y += circleVelocity.y;
// calculate rotation angle
const angle = Math.atan2(circleVelocity.y, circleVelocity.x) * 180 / Math.PI;
// Calculate the normalized mouse pace
const normalizedSpeed = Math.min(mouseSpeed, maxMouseSpeed) / maxMouseSpeed;
// Calculate stretch and squeeze components
const scaleFactor = 1 + (maxStretch - 1) * normalizedSpeed;
const squeezeFactor = 1 - (1 - maxSqueeze) * normalizedSpeed;
if (mouseSpeed <= 1) {
if (lowSpeedStartTime === 0) {
lowSpeedStartTime = efficiency.now();
}
lowSpeedDuration = (efficiency.now() - lowSpeedStartTime) / 1000; // in seconds
} else {
lowSpeedStartTime = 0;
lowSpeedDuration = 0;
}
// Apply squeeze/stretch impact
let scaleX = scaleFactor; // Stretch
let scaleY = squeezeFactor; // Squeeze
if (lowSpeedDuration > lowSpeedThreshold) {
scaleX = 1.0; // Squeeze
scaleY = 1.0; // Stretch
}
const translateElement = `translate(${circlePos.x}px, ${circlePos.y}px)`;
const rotateElement = `rotate(${angle}deg`;
const scaleElement = `scale(${scaleX}, ${scaleY})`;
circle.model.rework = `${translateElement} ${rotateElement} ${scaleElement}`;
requestAnimationFrame(animate);
}
animate();
doc.addEventListener('mouseleave', () => {
circle.model.opacity = '0'; // Make cursor disappear
});
doc.addEventListener('mouseenter', () => {
circle.model.opacity = '1'; // Make cursor reappear when mouse enters the doc once more
});
physique {
background-color: #1d1f22;
}
.circle {
--circle-size: 30px;
place: mounted;
prime: calc(var(--circle-size) / 2 * -1);
left: calc(var(--circle-size) / 2 * -1);
pointer-events: none;
box-sizing: border-box;
width: var(--circle-size);
peak: var(--circle-size);
/* border: 2px strong #c1bb98; */
background-color: #c1bb98;
mix-blend-mode: distinction;
border-radius: 100%;
rework: rotate(45deg);
transition: opacity 0.15s ease-out;
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta identify="viewport" content material="width=device-width, initial-scale=1.0">
<hyperlink rel="stylesheet" href="https://stackoverflow.com/questions/78975340/model.css">
<title>Doc</title>
</head>
<physique>
<div class="circle"></div>
<script src="script.js"></script>
</physique>
</html>
I attempted altering the form of the div to examine if the rotation is definitely being utilized on the primary order of transforms and it does work, so there’s something unsuitable with the 2nd order of rework which isn’t working.
Observe: the 2nd order of rework is legitimate in CSS, I’ve used it earlier than and it really works, it simply doesn’t work on this explicit situation and I do not perceive why.