I am trying to animate a line using canvas. I want to use TimelineLite to handle the animation. How would I do this? I know that in TimelineLite, the Timelines look like this:
var timeline = new TimelineLite();
timeline.to(target, duration, vars, position);
The points exist in a JSON file, and the file is correctly being brought in with AJAX. I want the line to start at the points x1 & y1, keep x2, as the same value, and animate it to the y2 position. So I basically want it to grow from x1-y1 to x2-y2.
JS
function animateLines(name, stroke, width, x1, y1, x2, y2){
ctx.beginPath();
ctx.moveTo(x1, y1);
ctx.lineWidth = width;
ctx.strokeStyle = stroke;
ctx.stroke;
console.log(x2);
}
for(var i = 0; i < animated_lines.length; i++){
animateLines(animated_lines[i].name, animated_lines[i].stroke, animated_lines[i].width, animated_lines[i].x1, animated_lines[i].y1, animated_lines[i].x2, animated_lines[i].y2);
}
JSON
"animated_lines": [
{
"name": "Test",
"stroke": "red",
"width": 3,
"x1": 0,
"y1": 0,
"x2": 0,
"y2": 50
}
]
So my question is really a multi-part one. How do I go about animating the line using canvas? How do I animate the line based on the name
in the animateLine()
function?
TimelineLite
uses the element
to transform the targeted values of that element.
You can watch the update progress of the transform using onUpdate
over time and animate your line based on that value.
timeline.eventCallback('onUpdate',function(data){
var progress = this.progress();
// Do animation calls here!
});
Here is a working example code snippet
I am transitioning the canvas opacity during the timeline and animating the canvas.
var timeline = new TimelineLite();
var mainCanvas = document.getElementById("ctx");
var ctx = mainCanvas.getContext("2d");
var temp = document.createElement('div');
var animated_lines = [{
"name": "Red",
"stroke": "#ff0000",
"width": 3,
"x1": 50,
"y1": 50,
"x2": 100,
"y2": 100
},{
"name": "Green",
"stroke": "#00ff00",
"width": 2,
"x1": 50,
"y1": 20,
"x2": 100,
"y2": 100
}];
function createLine(line, progress) {
ctx.lineWidth = line.width;
ctx.strokeStyle = line.stroke;
ctx.beginPath();
ctx.moveTo(line.x1, line.y1);
ctx.lineTo(line.x2, line.y2*progress);
ctx.stroke();
}
console.log('ctx', ctx);
timeline.from('#ctx', 10, { opacity: 0 });
timeline.eventCallback('onUpdate',function(){
var progress = this.progress();
//console.log(progress);
ctx.clearRect ( 0 , 0 , mainCanvas.width, mainCanvas.height );
for (var i = 0; i < animated_lines.length; i++) {
createLine(animated_lines[i], progress);
}
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.0/jquery.min.js"></script>
<script src="http://cdnjs.cloudflare.com/ajax/libs/gsap/latest/TweenMax.min.js"></script>
<canvas id="ctx" />
Is this the kind of effect you were looking to produce or something similar?
JS of which is as belows:
var width,height,centerX,centerY,canvas,context;
var delayFactor=.06,duration=1.2,ease=Elastic.easeOut,destIncrement=200,strokeWidth=2;
var timeline=new TimelineMax({paused:true,repeat:-1,yoyo:true,repeatDelay:duration*.5});
var animatedLines=[
{name:'Test',stroke:'red',width:strokeWidth,x1:0,y1:0,x2:0,y2:destIncrement},
{name:'Test',stroke:'green',width:strokeWidth,x1:0,y1:0,x2:destIncrement*.5,y2:destIncrement*.5},
{name:'Test',stroke:'blue',width:strokeWidth,x1:0,y1:0,x2:destIncrement,y2:0},
{name:'Test',stroke:'red',width:strokeWidth,x1:0,y1:0,x2:destIncrement*.5,y2:-destIncrement*.5},
{name:'Test',stroke:'green',width:strokeWidth,x1:0,y1:0,x2:0,y2:-destIncrement},
{name:'Test',stroke:'blue',width:strokeWidth,x1:0,y1:0,x2:-destIncrement*.5,y2:-destIncrement*.5},
{name:'Test',stroke:'red',width:strokeWidth,x1:0,y1:0,x2:-destIncrement,y2:0},
{name:'Test',stroke:'green',width:strokeWidth,x1:0,y1:0,x2:-destIncrement*.5,y2:destIncrement*.5}
];
function init(){
initCanvas();
initLines();
populateTimeline();
timeline.play();
TweenLite.ticker.addEventListener('tick',render);
}
function populateTimeline(){
var length=animatedLines.length,currentLine;
for(var i=0; i<length; i+=1){
currentLine=animatedLines[i];
timeline.to(currentLine,duration,{destX:currentLine.x2,destY:currentLine.y2,ease:ease},i*delayFactor);
}
}
function initLines(){
var length=animatedLines.length,currentLine;
for(var i=0; i<length; i+=1){
currentLine=animatedLines[i];
currentLine.destX=currentLine.x1;
currentLine.destY=currentLine.y1;
}
}
function initCanvas(){
canvas=document.querySelector('canvas');
context=canvas.getContext('2d');
width=canvas.width=window.innerWidth;
height=canvas.height=window.innerHeight;
centerX=width*.5;
centerY=height*.5;
}
function drawLine(currentLine){
context.lineWidth=currentLine.width;
context.strokeStyle=currentLine.stroke;
context.beginPath();
context.moveTo(centerX+currentLine.x1,centerY+currentLine.y1);
context.lineTo(centerX+currentLine.destX,centerY+currentLine.destY);
context.stroke();
}
function render(){
var length=animatedLines.length;
context.clearRect(0,0,width,height);
for(var i=0; i<length; i+=1){ drawLine(animatedLines[i]); }
}
init();
The trick is to introduce two new variables into each Line of your animatedLines
, namely destX
and destY
, and set their initial values to that of your x1
and y1
respectively, defined under the initLines();
function. And then make them increment towards your x2
and y2
values using TimelineMax
which happens in the populateTimeline();
function.
Go ahead and take a look at the jsFiddle to take it further.
Hope this is helpful to you in some way.