I created a canvas animation in which lines warp when hovering over the canvas. 1 point is pulled toward the mouse and the other is pushed away.
There are a few aspects of the animation I'm struggling with, I would like to animate the lines being pulled toward the mouse, right now it's just very instant and vice versa for the mouse leaving the canvas, they just receive their initial coördinates which makes it very instant. I tried this by using gsap.to but I can't seem to figure out how to use this to set two seperate points in a line.
One more thing I would like to add is that the further away the mouse is from a certain line, the shorter I would like the line to be. Right now all the lines are equal in length once the mouse hovers the canvas.
$(document).ready(function () {
initContainerCanvas();
});
$(window).resize(function () {
initContainerCanvas();
});
function initContainerCanvas() {
var canvas = document.querySelector('.container-animation');
canvas.setAttribute('width', window.getComputedStyle(canvas, null).getPropertyValue("width"));
canvas.setAttribute('height', window.getComputedStyle(canvas, null).getPropertyValue("height"));
var Line = function() {
this.point1x = 0;
this.point1y = 0;
this.point2x = 0;
this.point2y = 0;
this.initialpoint1x = 0;
this.initialpoint1y = 0;
this.initialpoint2x = 0;
this.initialpoint2y = 0;
this.lineWidth = 0;
this.color = 0;
};
Line.prototype.draw = function (context) {
context.save();
context.beginPath();
context.moveTo(this.point1x, this.point1y);
context.lineTo(this.point2x, this.point2y);
context.strokeStyle = this.color;
context.lineWidth = this.lineWidth;
context.lineCap = "round";
context.stroke();
context.closePath();
context.restore();
};
var context = canvas.getContext('2d');
var lines = [];
var mouse = {x: 0, y: 0};
var mouseOver = false;
var mouseMoved = false;
var column = 4;
for ( var i = 1; i < 10; i++) {
lines[i] = [];
var xa = 0;
var ya = 0;
for ( var j = 0; j < column; j++ ) {
xa += 20;
ya = (i * 20);
var line = new Line();
line.point1x = xa;
line.point1y = ya;
line.initialpoint1x = xa;
line.initialpoint1y = ya;
line.point2x = xa;
line.point2y = ya;
line.initialpoint2x = xa;
line.initialpoint2y = ya;
line.color = '#19FDB7';
line.lineWidth = 10;
lines[i][j] = line;
}
column++;
}
console.log(lines);
gsap.ticker.add(draw);
function draw() {
context.clearRect(0, 0, canvas.width, canvas.height);
if(mouseOver && mouseMoved){
calculateLinePosition();
mouseMoved = false;
}
var column = 4;
for (var i = 1; i < 10; i++) {
for (var j = 0; j < column; j++) {
var line = lines[i][j];
line.draw(context);
}
column++;
}
}
function calculateLinePosition() {
var column = 4;
for (var i = 1; i < 10; i++) {
for (var j = 0; j < column; j++) {
var line = lines[i][j];
var radius = 20;
var dx = mouse.x - line.initialpoint1x;
var dy = mouse.y - line.initialpoint1y;
var dist = Math.sqrt(dx * dx + dy * dy) || 1;
var angle = Math.atan2(dy, dx);
line.point1x = line.initialpoint1x - Math.cos(angle) * radius;
line.point1y = line.initialpoint1y - Math.sin(angle) * radius;
line.point2x = line.initialpoint2x + Math.cos(angle) * radius;
line.point2y = line.initialpoint2y + Math.sin(angle) * radius;
}
column++;
}
}
$(canvas).mousemove(function (e) {
var rect = canvas.getBoundingClientRect();
mouse.x = e.clientX - rect.left;
mouse.y = e.clientY - rect.top;
mouseMoved = true;
});
$(canvas).mouseenter(function () {
mouseOver = true;
});
$(canvas).mouseleave(function () {
mouseOver = false;
var column = 4;
for (var i = 1; i < 10; i++) {
for (var j = 0; j < column; j++) {
var line = lines[i][j];
line.point1x = line.initialpoint1x;
line.point1y = line.initialpoint1y;
line.point2x = line.initialpoint2x;
line.point2y = line.initialpoint2y;
}
column++;
}
});
}
Here's what I have so far: https://codepen.io/geordi-feijens/pen/abOMKKY
The key is using tweens inside of your draw and mouseleave functions instead of just setting the value. Make sure that you set overwrite
to true
or auto
because the default value of false
will not be buggy.
For example this is how you'd set it up in the draw function:
gsap.to(line, {
duration: 0.2,
overwrite: 'auto',
point1x: line.initialpoint1x - Math.cos(angle) * radius,
point1y: line.initialpoint1y - Math.sin(angle) * radius,
point2x: line.initialpoint2x + Math.cos(angle) * radius,
point2y: line.initialpoint2y + Math.sin(angle) * radius
});
https://codepen.io/GreenSock/pen/oNXOvoy?editors=0010
There's no need for jQuery :)
Side note about performance: loops are pretty slow. It's usually not a big deal but when you're looping through a lot of elements every tick it can start to hurt your performance. For more feedback on how to improve performance, check out CodeReview.SE - some really helpful people answer questions there.
By the way, if you post GSAP questions like this on the GreenSock forums you'll likely get a response faster and from more people.
There's also a bunch of existing threads like this one which does very similar things to what you're wanting.