Skip to content

Instantly share code, notes, and snippets.

@AnoRebel
Forked from Usman2k19/index.html
Created January 31, 2025 10:16
Show Gist options
  • Save AnoRebel/1a33c80cdce1fb71937f93f53d0d790d to your computer and use it in GitHub Desktop.
Save AnoRebel/1a33c80cdce1fb71937f93f53d0d790d to your computer and use it in GitHub Desktop.
Mouse hover water effect
<canvas id="canvas"></canvas>
<div id="wrapper">
</div>

Mouse hover water effect

Within Oasen we experimented with a water ripple effect on mouse over as a small tweak within our website, our developer Marnix tried all the different movements and timings. You can check the end result on http://oasen.nl

A Pen by Usman2k19 on CodePen.

License.

const rippleSettings = {
maxSize: 100,
animationSpeed: 5,
strokeColor: [148, 217, 255],
};
const canvasSettings = {
blur: 8,
ratio: 1,
};
function Coords(x, y) {
this.x = x || null;
this.y = y || null;
}
const Ripple = function Ripple(x, y, circleSize, ctx) {
this.position = new Coords(x, y);
this.circleSize = circleSize;
this.maxSize = rippleSettings.maxSize;
this.opacity = 1;
this.ctx = ctx;
this.strokeColor = `rgba(${Math.floor(rippleSettings.strokeColor[0])},
${Math.floor(rippleSettings.strokeColor[1])},
${Math.floor(rippleSettings.strokeColor[2])},
${this.opacity})`;
this.animationSpeed = rippleSettings.animationSpeed;
this.opacityStep = (this.animationSpeed / (this.maxSize - circleSize)) / 2;
};
Ripple.prototype = {
update: function update() {
this.circleSize = this.circleSize + this.animationSpeed;
this.opacity = this.opacity - this.opacityStep;
this.strokeColor = `rgba(${Math.floor(rippleSettings.strokeColor[0])},
${Math.floor(rippleSettings.strokeColor[1])},
${Math.floor(rippleSettings.strokeColor[2])},
${this.opacity})`;
},
draw: function draw() {
this.ctx.beginPath();
this.ctx.strokeStyle = this.strokeColor;
this.ctx.arc(this.position.x, this.position.y, this.circleSize, 0,
2 * Math.PI);
this.ctx.stroke();
},
setStatus: function setStatus(status) {
this.status = status;
},
};
const canvas = document.querySelector('#canvas');
const ctx = canvas.getContext('2d');
const ripples = [];
const height = document.body.clientHeight;
const width = document.body.clientWidth;
const rippleStartStatus = 'start';
const isIE11 = !!window.MSInputMethodContext && !!document.documentMode;
canvas.style.filter = `blur(${canvasSettings.blur}px)`;
canvas.width = width * canvasSettings.ratio;
canvas.height = height * canvasSettings.ratio;
canvas.style.width = `${width}px`;
canvas.style.height = `${height}px`;
let animationFrame;
// Add GUI settings
const addGuiSettings = () => {
const gui = new dat.GUI();
gui.add(rippleSettings, 'maxSize', 0, 1000).step(1);
gui.add(rippleSettings, 'animationSpeed', 1, 30).step(1);
gui.addColor(rippleSettings, 'strokeColor');
const blur = gui.add(canvasSettings, 'blur', 0, 20).step(1);
blur.onChange((value) => {
canvas.style.filter = `blur(${value}px)`;
});
};
addGuiSettings();
// Function which is executed on mouse hover on canvas
const canvasMouseOver = (e) => {
const x = e.clientX * canvasSettings.ratio;
const y = e.clientY * canvasSettings.ratio;
ripples.unshift(new Ripple(x, y, 2, ctx));
};
const animation = () => {
ctx.clearRect(0, 0, canvas.width, canvas.height);
const length = ripples.length;
for (let i = length - 1; i >= 0; i -= 1) {
const r = ripples[i];
r.update();
r.draw();
if (r.opacity <= 0) {
ripples[i] = null;
delete ripples[i];
ripples.pop();
}
}
animationFrame = window.requestAnimationFrame(animation);
};
animation();
canvas.addEventListener('mousemove', canvasMouseOver);
<script src="https://cdnjs.cloudflare.com/ajax/libs/dat-gui/0.6.2/dat.gui.min.js"></script>
html, body, #canvas {
width: 100%;
height: 100%;
margin: 0;
}
body {
background-color: #26b4f4;
}
#wrapper {
position: absolute;
top: 0;
width: 100%;
height: 100%;
pointer-events: none;
}
#menu {
width: 100%;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment