|
|
@@ -0,0 +1,116 @@ |
|
|
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); |