JSFiddle - React, Tailwind, and code Playground
HTML
<div class="block" id="wave">
<span class="line" id="lines">-</span>
<span class="line">-</span>
<span class="line">-</span>
<span class="line">-</span>
<span class="line">-</span>
<span class="line">
<a href="#" class="circle" title="Подсказка"></a>
</span>
<span class="line">-</span>
<span class="line">-</span>
<span class="line">-</span>
<span class="line">-</span>
</div>
CSS
body {
background-color: rgba(0, 0, 0, .3);
height: 200vh;
}
.block {
background-color: rgba(0, 0, 0, .7);
width: 200px;
display: flex;
align-items: center;
justify-content: center;
flex-direction: column;
position: relative;
}
.line {
color: white;
display: block;
font-size: 18px;
text-align: center;
transform: translate(0px);
width: 18px;
transition: transform 100ms linear;
}
.circle {
width: 15px;
height: 15px;
border-radius: 50%;
border: 1px solid #ff9c5d;
display: inline-block;
transition: .3s linear;
}
.circle:hover {
background-color: #ff9c5d;
}
JavaScript
(function() {
let wave = document.querySelector('#wave');
let waveRect = wave.getBoundingClientRect();
let lines = document.querySelectorAll('.line');
let linesRect = [...lines].map(line => {
let rect = line.getBoundingClientRect();
return [rect.top, rect.bottom];
});
wave.addEventListener('mousemove', function(e) {
let mouseX = e.clientX;
let mouseY = e.clientY;
let maxX = mouseX - waveRect.left - waveRect.width/2;
//+ waveRect.width/2
let targetLineIndex = linesRect.findIndex(cur => mouseY >= cur[0] && mouseY <= cur[1]);
let targetLine = lines[targetLineIndex];
targetLine.style.transform = `translateX(${maxX}px)`;
let next = targetLine.nextElementSibling;
let nextXRad = Math.PI / 2;
let nextXMult = 1;
let nextXPos;
while (next) {
nextXRad -= Math.PI * 0.15;
nextXMult *= 0.85;
nextXPos = (Math.sin(nextXRad) * maxX * nextXMult).toFixed(3);
next.style.transform = `translateX(${nextXPos}px)`;
next = next.nextElementSibling;
}
let prev = targetLine.previousElementSibling;
let prevXRad = Math.PI / 2;
let prevXMult = 1;
let prevXPos;
while (prev) {
prevXRad += Math.PI * 0.15;
prevXMult *= 0.85;
prevXPos = (Math.sin(prevXRad) * maxX * prevXMult).toFixed(3);
prev.style.transform = `translateX(${prevXPos}px)`;
prev = prev.previousElementSibling;
}
});
wave.addEventListener('mouseleave', function(e) {
[...lines].forEach(line => line.style.transform = '');
});
})();