Rayroth Rayroth - 1 year ago 70
Javascript Question

canvas pendulum animation - canvas translating

I'm trying to make simple pendulum in HTML5 Canvas but I'm stuck. I want to swing it for 25 degrees to the left and to the right, so I calculated I should translate every frame about -3.5 px in y axis (and 3.5 px when swings to the right). I'm using below code

var rotation = Math.PI/180, //rotate about 1deg
translation = -3.5,
counter = 0; //count rotations

function draw() {
var element = document.getElementById('canvas');
var ctx = canvas.getContext('2d');

ctx.translate(0, translation);

//function draws all objects

if (counter == 25) {
rotation *= -1;
translation *= -1;
counter = -25;
counter += 1;


Everything looks good but when pendulum is changing direction then everything is translating in also x axis and after few seconds disappears from screen.. What is wrong in this code? Or maybe I was miss something in my calculations? My code here https://jsfiddle.net/qskxjzv9/2/

Thanks in advance for your answers.

Answer Source

The problem is that when there is rotation involved, then translation, the x and y's will be translated in a different direction than what may seem logic.

To get around this we don't actually have to involve translation more than using it for placing pivot (point of rotation) and then use absolute rotation based on a different way of calculating the pendulum movement.

For example, this will take care of both the translation problem as well as smoothing the pendulum movement:

  • Change the draw method to draw the pendulum with origin (0,0) - it's just a matter of changing the initial coordinates so they evolve around (0,0)
  • Translate to pivot point of screen - this is where the rotation will take place.
  • Rotate using sin() as a factor - this will create a smooth animation and look more like a pendulum and it will restrict the movement to angle as range is [-1,1]
  • Use counter to move sin() instead - this acts as a frequency-ish factor (you can later convert this into an actual frequency to say, have the pendulum move n number of times per minute etc.). To keep it simple I have just used the existing counter variable and reduced its step value.

The main code then:

var maxRot = 25 / 180 * Math.PI,    // max 25° in both directions
    counter = 0,

    // these are better off outside loop
    element = document.getElementById('canvas');
    ctx = element.getContext('2d');

function draw() {

  // reset transform using absolute transformation. Include x translation:

  // clear screen, compensate for initial translate

  // rotate using sin() with max angle
  ctx.rotate(Math.sin(counter) * maxRot);

  // draw at new orientation which now is pivot point
  objects(element, ctx);

  // move sin() using "frequency"-ish value
  counter += 0.05;