Rotating and animating in HTML5 Canvas

By Ben

In my mission to reproduce the interactive banner on our services banner, I came across the need to animate arrows around the edge of an outer circle. Having previously animated circles around the edge of another circle, I thought it would be easy - oh how I was wrong.

My first step was to implement the same code I used for the circles, which worked great, however the circles did not rotate and follow the path as intended.

I then decided to use the .rotate() method when drawing the arrows - however as I was rotating the canvas, the starting co-ordinates for the arrow had therefore shifted and also everything drawn afterwards would also be rotated, resulting in a very interesting result when running the code:

It took some head-bashing, but I finally realised that I would need to use a few more methods to get the result I wanted:

  1. .save() & .restore() - before doing anything, I decided to save the state of the canvas so that I can restore it after drawing the arrows, and mean that everything drawn afterwards would be as intended.
  2. .translate() - before rotating the canvas, I realised that I should shift the starting point of the canvas to the point at which I want to draw the arrow. That way after I rotate the canvas, I can just draw it at 0, 0 and the arrow will be in the correct place.

My resulting code is below, which you can see a running demo of here.

topArrowX = tmpService.x + ((tmpService.radius + tmpService.hoverInnerRadius) * Math.cos(tmpService.arrowAngle*(Math.PI/180)));
topArrowY = tmpService.y + ((tmpService.radius + tmpService.hoverInnerRadius) * Math.sin(tmpService.arrowAngle*(Math.PI/180)));

context.save();
context.translate(topArrowX, topArrowY);
context.rotate(tmpService.arrowRotation*(Math.PI/180));
drawArrow(0, 0);
context.restore();

bottomArrowX = tmpService.x + ((tmpService.radius + tmpService.hoverInnerRadius) * Math.cos((tmpService.arrowAngle + 180)*(Math.PI/180)));
bottomArrowY = tmpService.y + ((tmpService.radius + tmpService.hoverInnerRadius) * Math.sin((tmpService.arrowAngle + 180)*(Math.PI/180)));

context.save();
context.translate(bottomArrowX, bottomArrowY);
context.rotate((tmpService.arrowRotation + 180)*(Math.PI/180));
drawArrow(0, 0);
context.restore();

Related posts