DEV Community

Jared Becker
Jared Becker

Posted on

Rainbow Slinky

So I have seen lots of posts about people sharing fun little projects they have made so I would like to share my Rainbow slinky with you guys. Please go easy on me. This is my first post so I'm not entirely sure what I'm doing but anyways, lets get into it!๐Ÿ˜

The way this will work is by creating a bunch of empty div elements. On the mousemove event we will pull the X and Y coordinates of the mouse and then incrementally update the div's to move to that location on the screen creating a really cool slinky effect.

HTML

To begin we will need create our markup. This will be very simple. It will consist of 2 div's, 1 that we will use as our cursor because we will hide the default mouse cursor and then another div to contain all the rings of our slinky.

<div id="ring_container"></div>
<div class="dot mouse_el"></div>
Enter fullscreen mode Exit fullscreen mode

CSS

We can now add our CSS. This will remove the cursor from the page, give our rings a default style and also style the dot which will become our new cursor

* {
    cursor: none !important;
}
html,
body {
    height: 100vh;
    overflow: hidden;
    background-color: #000;
}      
.mouse_el {
    border-radius: 50%;
    position: absolute;
    top: 50%;
    left: 50%;
}
.ring {
    border: 5px solid #fff;
}
.dot {
    height: 10px;
    width: 10px;
    background-color: #fff;
}
Enter fullscreen mode Exit fullscreen mode

Javascript

Now that our HTML and CSS is pretty much done we can get onto the logic behind the slinky. First we need to define some global variables. The rings variable will store our collection of rings so we can use it in multiple functions. The dot is our cursor and the colors will be the colors we loop through when creating our div's, in this case the colors of the rainbow but these can be changed.

let rings;
let dot = document.querySelector('.dot');
let colors = ['#9400D3', '#4B0082', '#0000FF', '#00FF00', '#FFFF00', '#FF7F00', '#FF0000'];
Enter fullscreen mode Exit fullscreen mode

We now need to create the div's and append them to the rings container. Once all the rings are created we will then set the colors of the div's

function createRings(numRings) {
    if (numRings > 0) {
        for (let i = 0; i <= numRings; i++) {
            const div = document.createElement('div');
            div.classList.add('mouse_el', 'ring');
            document.getElementById('ring_container').appendChild(div);
        }
        setColors();
    }

}
function setColors() {
    let index = 0;
    const dimensions = 60;
    rings = document.querySelectorAll('.ring');

    rings.forEach((el) => {
        index = index < colors.length ? index : 0;
        el.style.borderColor = colors[index];
        el.style.width = dimensions + 'px';
        el.style.height = dimensions + 'px';
        index++;
    })
}
Enter fullscreen mode Exit fullscreen mode

Now we need to create the function that will update the X and Y coordinates of all the div's. Here we will need to get the size of the border because we will need to take this into account when trying to calculate the center of the rings for the cursor.

function updateCursor(eventObj) {
    let lag = 50;
    const x = eventObj.clientX;
    const y = eventObj.clientY;
    let ringBorderSize = parseInt(window.getComputedStyle(rings[0]).getPropertyValue('border-top-width'));

    calcPosition(dot, x, y, ringBorderSize);

    rings.forEach((el, i) => {
        lag += 50;
        setTimeout(() => { calcPosition(el, x, y) }, lag + 50);
    })
}
Enter fullscreen mode Exit fullscreen mode

Now its time for some quick math. We need to check if the ringBorderSize > 0 because then we know that we are trying to calculate the position for the cursor in which case we will need to take the size of the borders into account or else the dot won't sit perfectly in the center of the rings.

function calcPosition(el, x, y, border_size = 0) {
    if (border_size <= 0) {
        el.style.left = x - (el.clientWidth / 2) + 'px';
        el.style.top = y - (el.clientHeight / 2) + 'px';
    } else {
        el.style.left = x - ((el.clientWidth / 2) - border_size) + 'px';
        el.style.top = y - ((el.clientHeight / 2) - border_size) + 'px';
    }
}
Enter fullscreen mode Exit fullscreen mode

The last step is to setup the eventListener and call the createRings function. If you find it lagging a bit, try reduce the number passed to create rings and see what works best for you

window.addEventListener('mousemove', (e) => { updateCursor(e) });

createRings(75);
Enter fullscreen mode Exit fullscreen mode

I hope you guys have as much fun with this as I've had!๐Ÿฅณ

Top comments (2)

Collapse
 
lifeskills profile image
Adam

This is very cool and fun, I love it.

Collapse
 
jaredcodesalot profile image
Jared Becker

Thanks Adam! Glad you like it๐Ÿ˜