简体   繁体   中英

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.clearRect(0,0,element.width,element.height);
    ctx.translate(0, translation);
    ctx.rotate(rotation);

    //function draws all objects
    objects(element,ctx);

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

    window.requestAnimationFrame(draw);
  }

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.

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:
  ctx.setTransform(1,0,0,1,element.width*0.5,0);

  // clear screen, compensate for initial translate
  ctx.clearRect(-element.width*0.5,0,element.width,element.height);

  // 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;

  window.requestAnimationFrame(draw);
}

Fiddle

Additional

Thanks to @Blindman67 for providing additional improvements:

To control frequency in terms of oscillations you could do some minor changes - first define frequency:

var FREQUENCY = 3;

Define a function that will do the conversion:

function sint(time) {
    return Math.sin(FREQUENCY * time * Math.PI * 0.002); // 0.002 allow time in ms
}

If you now change the draw() method to take a time parameter instead of the counter:

function draw(time) {
   ...
}

Then you can call rotation like this:

ctx.rotate(sint(time) * maxRot);

you need to translate the origin to the point you want to rotate around:

  ctx.translate(element.width / 2, 0);

Then, the rotation as you suggest:

  ctx.rotate(rotation);

And finally, translate back:

  ctx.translate(- element.width / 2, 0);

See this commented fork of your fiddle.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM