How to use requestAnimationFrame inside a Class object

你离开我真会死。 提交于 2020-05-15 02:00:11

问题


I have a class that takes some coordinate and duration data. I want to use it to animate an svg. In more explicit terms, I want to use that data to change svg attributes over a time frame.

I'm using a step function and requestAnimationFrame outside the class:

function step(timestamp) {
  if (!start) start = timestamp
  var progress =  timestamp - start;
  var currentX = parseInt(document.querySelector('#start').getAttribute('cx'));
  var moveX =  distancePerFrame(circleMove.totalFrames(), circleMove.xLine);

  document.querySelector('#start').setAttribute('cx', currentX + moveX);
  if (progress < circleMove.duration) {
    window.requestAnimationFrame(step);
  }
}

var circleMove = new SingleLineAnimation(3000, startXY, endXY)

var start = null

function runProgram() {
  window.requestAnimationFrame(step);
}

I can make it a method, replacing the circleLine with this. That works fine for the first run through, but when it calls the this.step callback a second time, well, we're in a callback black hole and the reference to this is broken. Doing the old self = this won't work either, once we jump into the callback this is undefined(I'm not sure why). Here it is as a method:

step(timestamp) {
  var self = this;

  if (!start) start = timestamp
  var progress =  timestamp - start;
  var currentX = parseInt(document.querySelector('#start').getAttribute('cx'));
  var moveX =  distancePerFrame(self.totalFrames(), self.xLine);

  document.querySelector('#start').setAttribute('cx', currentX + moveX);
  if (progress < self.duration) {
    window.requestAnimationFrame(self.step);
  }
}

Any ideas on how to keep the "wiring" inside the Object?

Here's the code that more or less works with the step function defined outside the class.

class SingleLineAnimation { 
  constructor(duration, startXY, endXY) {
    this.duration = duration;
    this.xLine = [ startXY[0], endXY[0] ];
    this.yLine = [ startXY[1], endXY[1] ];
  }

  totalFrames(framerate = 60) { // Default to 60htz ie, 60 frames per second
    return Math.floor(this.duration * framerate / 1000);
  } 

  frame(progress) {
    return this.totalFrames() - Math.floor((this.duration - progress) / 17 );
  } 
}

This will also be inserted into the Class, for now it's just a helper function:

function distancePerFrame(totalFrames, startEndPoints) {
  return totalFrames > 0 ? Math.floor(Math.abs(startEndPoints[0] - startEndPoints[1]) / totalFrames) : 0;
}

And click a button to...

function runProgram() {
  window.requestAnimationFrame(step);
}

回答1:


You need to bind the requestAnimationFrame callback function to a context. The canonical way of doing this is like this:

window.requestAnimationFrame(this.step.bind(this))

but it's not ideal because you're repeatedly calling .bind and creating a new function reference over and over, once per frame.

If you had a locally scoped variable set to this.step.bind(this) you could pass that and avoid that continual rebinding.

An alternative is this:

function animate() {

    var start = performance.now();
    el = document.querySelector('#start');

    // use var self = this if you need to refer to `this` inside `frame()`

    function frame(timestamp) {

        var progress =  timestamp - start;
        var currentX = parseInt(el.getAttribute('cx'));
        var moveX =  distancePerFrame(circleMove.totalFrames(), circleMove.xLine);
        el.setAttribute('cx', currentX + moveX);

        if (progress < circleMove.duration) {
            window.requestAnimationFrame(frame);
        }
    }

    window.requestAnimationFrame(frame);
}

i.e. you're setting up the initial state, and then doing the animation within a purely locally scoped function that's called pseudo-recursively by requestAnimationFrame.

NB: either version of the code will interact badly if you inadvertently call another function that initiates an animation at the same time.



来源:https://stackoverflow.com/questions/48816441/how-to-use-requestanimationframe-inside-a-class-object

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!