Tuesday, October 8, 2024
HomeCSSjavascript - Why is my order of transformation utilized affecting the best...

javascript – Why is my order of transformation utilized affecting the best way my code behaves?


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.

RELATED ARTICLES

LEAVE A REPLY

Please enter your comment!
Please enter your name here

Most Popular

Recent Comments