<p class="text">serendipity</p>
<svg id="svg" width="400" height="300" viewbox="0 0 400 300" id="svg">
<path id="curve" d="M10,150 Q200,150 390,150"
fill="none" stroke="#f52e6d" stroke-width="6"/>
</svg>
#svg {
position: absolute;
margin-left: -200px;
margin-top: -150px;
left: 50%;
top: 50%;
z-index: 10;
cursor: arrow;
}
.text {
width: 380px;
height: 260px;
position: absolute;
margin-left: -190px;
margin-top: -150px;
left: 50%;
top: 50%;
font-size: 78px;
line-height: 228px;
pointer-events: none;
z-index: 0;
}
var svgElemnt, path;
var connected, tweening, tween;
var mousePos = {}, svgTop;
function init() {
svgElement = document.getElementById('svg');
path = document.getElementById('curve');
setSVGTop();
addListeners();
loop();
}
function setSVGTop() {
svgTop = svgElement.getBoundingClientRect().top;
}
function addListeners() {
window.addEventListener('mousemove', function(e) {
// storing the y position of the mouse - we want the y pos relative to the SVG container so we'll subtract the container top from clientY.
mousePos.y = e.clientY - svgTop;
});
window.addEventListener('resize', setSVGTop);
path.addEventListener('mouseover', function() {
// if we haven't connected yet and we're not tweening back to center, bgin connection
if (!connected && !tweening) {
connected = true;
svgElement.style.cursor = 'pointer';
}
});
}
function updateCurve() {
var y = mousePos.y;
y = mousePos.y - (150-mousePos.y)*1.1;
if (Math.abs(150-y) > 100) {
connected = false;
tweening = true;
svgElement.style.cursor = 'default';
snapBack(y);
} else {
path.setAttribute('d', 'M10,150 Q200,'+y+' 390,150');
}
}
function snapBack(y) {
tween = new TWEEN.Tween({ y: y })
.to({ y: 150 }, 800)
.easing( TWEEN.Easing.Elastic.Out )
.onUpdate( function () {
updatePath(this.y);
}).onComplete(function() {
tweening = false;
}).start();
}
function updatePath(y) {
// update SVG path control point
path.setAttribute('d', 'M10,150 Q200,'+y+' 390,150');
}
function loop(time) {
if (connected) updateCurve();
TWEEN.update(time);
requestAnimationFrame(loop);
}
window.onload = init;
This Pen doesn't use any external CSS resources.