i am bad at coding
i am bad at coding

Reputation: 705

How to make html element lerp towards cursor in vanilla Javascript?

I'm trying to recreate the button effect on this website: https://advanced.team/team

Scroll down until you see this enter image description here

You can move your mouse around the div, even outside of the div itself a little bit and it will lerp towards the cursor.

I'm trying to recreate this effect and it's pretty close, except, it's much more "glitchy". You can see the movements are not smooth and it jumps around frequently. I assume this is because I'm not using a lerp function. How would I recreate the effect on that site? Thanks in advance.

const hoverElement = document.querySelector(".svg-container");

//My lerp function
function lerp(start, end, amt) {
    return (1 - amt) * start + amt * end;
}

//Get bounds of my element + or - 10 pixels so it activates outside of the div
let leftBound = hoverElement.getBoundingClientRect().left - 10;
let rightBound =
    hoverElement.getBoundingClientRect().left +
    hoverElement.getBoundingClientRect().width +
    10;
let topBound = hoverElement.getBoundingClientRect().top - 10;
let bottomBound =
    hoverElement.getBoundingClientRect().top +
    hoverElement.getBoundingClientRect().height +
    10;

window.addEventListener("mousemove", (e) => {
//If the mouse is in the Bounds, translate the div, otherwise reset the translation
    if (
        leftBound <= e.clientX &&
        e.clientX <= rightBound &&
        topBound <= e.clientY &&
        e.clientY <= bottomBound
    ) {
       //Set the position so the center of the image is 0,0 instead of top-left corner
        let elementX =
            e.clientX -
            hoverElement.getBoundingClientRect().left -
            hoverElement.getBoundingClientRect().width / 2;
        let elementY =
            e.clientY -
            hoverElement.getBoundingClientRect().top -
            hoverElement.getBoundingClientRect().height / 2;
        hoverElement.style.transform = `translate(${elementX}px, ${elementY}px)`;
    } else {
        hoverElement.style.transform = `translate(${0}px, ${0}px)`;
    }

});
* {
    margin: 0;
    padding: 0;
    box-sizing: border-box;
}

body {
    background-color: black;
}

.formatting {
    display: flex;
    justify-content: center;
    align-items: center;
    height: 100vh;
}

.svg-container {
    border-radius: 50%;
    position: relative;
    border: 1px solid white;
    display: flex;
    justify-content: center;
    align-items: center;
    padding: 40px;
    cursor: pointer;
    transition: all 0.55s;
}

.svg-container::before {
    content: "";
    background-color: none;
    position: absolute;
    border-radius: 50%;
    width: 0%;
    z-index: -4;
    height: 0%;
    transition: all 0.55s ease-in-out;
}

.svg-container:hover::before,
.svg-container:focus::before {
    height: 100%;
    width: 100%;
    background-color: white;
    transition: height 0.55s ease-in-out, width 0.55s ease-in-out;
}

.svg-actual {
    position: absolute;
    display: flex;
    justify-content: center;
    align-items: center;
    z-index: 50;
    mix-blend-mode: difference;
}

path {
    transition: all 0.5s ease-in-out;
}
.svg-container:hover path {
    /* fill: white; */
    transition: all 0.5s ease-in-out;
}
    
    <div class="formatting">
        <div class="svg-container">
            <div class="svg-actual">
                <svg width="27" height="15" viewBox="0 0 280 184" fill="none" xmlns="http://www.w3.org/2000/svg">
                    <path id="arrow" d="M259.585 97.2345L180.703 176.117L187.96 183.375L279.22 92.115L187.955 0.850169L180.707 8.09801L259.577 86.9878L0.129355 86.9758V97.2345L259.585 97.2345Z" fill="#ffffff"/>
                </svg>
                <!-- <div class="text">
                    Read More   Read More   Read More   Read More   Read More
                </div> -->
            </div>
        </div>
    </div>

Upvotes: 2

Views: 1051

Answers (1)

user17881346
user17881346

Reputation: 13

If you can add a link to your project, I might be more helpful. Anyway, this is the way to achieve the effect.

  1. The element contains a container and inside of it theres the circle element , which means when you hover it, youalso hover the empty edges and not on the circle itself (important).
  2. Set a boundaries variable (they use 40px/45px)
  3. Add "mousemove" event on the square container(again, no the circle itself). When you hover it with the mouse, calculate the distance between the mouse and the origin center of the container ((x or y) + ((width or height) / 2)) and store it as a value when the page loads), this is the amount of pixels you need to translate.
  4. Check your pixels translate value do not cross the boundaries (you can use Math.max). make sure you calculate it correct when its less than 0.
  5. Now the tricky part, use Math.sqrt(value * newX/newY) to create some sort of an ease (theres probably some better ways, thats how I managed to do it).
  6. Apply the translate, and add "mouseleave" event to translate the circle to (0,0), so it get back to place when you're not hovering anymore.
  7. Now the container should follow your mouse.

Upvotes: 1

Related Questions