5

I was trying to implement kinetic scrolling (whether that's a good idea or not is not the question) and experienced some "strange" behavior.

function scroll(timestamp){
    var deltaTime = timestamp - this.scrollLastTime;
    this.scrollLastTime = timestamp;
    console.log(deltaTime);
    var newPosition = this.scrollTop + this.scrollSpeed*deltaTime;
    if(newPosition <= 0){
      this.scrollTop = 0;
      this.scrolling = false;
      return;
    }else if(newPosition > this.scrollHeight-this.clientHeight){
      this.scrollTop = this.scrollHeight-this.clientHeight;
      this.scrolling = false;
    }else{
      this.scrollTop = newPosition;
      var newSpeed = this.scrollSpeed + Math.sign(this.scrollSpeed) * this.scrollAcceleration*deltaTime;
      if(this.scrollSpeed < 0 && newSpeed >= 0){
        this.scrolling = false;
      }else if(this.scrollSpeed >0 && newSpeed <= 0){
        this.scrolling = false;
      }else{
        this.scrollSpeed = newSpeed;
        window.requestAnimationFrame(this.scrollCallback);
      }
    }
  }
  document.getElementById("0").addEventListener('wheel',
        function(e){
            this.scrollSpeed = e.wheelDelta/100;
            if(!this.scrolling){
              this.scrolling = true;
              this.scrollLastTime = performance.now();
              this.scrollAcceleration = -0.01;
              if(!this.scrollCallback)this.scrollCallback = scroll.bind(this);
              window.requestAnimationFrame(this.scrollCallback);
            }
            e.preventDefault();
        });

The problem is that often the deltaTime becomes negative, what am I missing?

Edit: I am using Chromium Version 51.0.2704.79 Ubuntu 14.04 (64-bit) if that helps.

Adam
  • 1,342
  • 7
  • 15
  • 3
    Basically, the rAF timestamp isn't very reliable. It seems to snap to the nearest frame time rather than the time the code is actually run. Never got the bottom of it, but [I've been having the same issue](http://stackoverflow.com/questions/38360250/requestanimationframe-now-vs-performance-now-time-discrepancy). I resorted to just using `performance.now()` each frame instead of relying on the rAF timestamp. – Whothehellisthat Aug 09 '16 at 11:04

1 Answers1

1

As @Whothehellisthat has already pointed out in his comment:

the rAF timestamp isn't very reliable

Here is an little example to proove that:

document.getElementById("button").addEventListener('click', function(e){
        this.valueOfPerformanceNow = performance.now();
        if(!this.clickCallback)this.clickCallback = printTime.bind(this);
        window.requestAnimationFrame(this.clickCallback);
});

function printTime(timestamp){
  $("#perfromanceNow").val(this.valueOfPerformanceNow);
  $("#delta").val(timestamp-this.valueOfPerformanceNow);
  $("#timestamp").val(timestamp);
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div>
  <input type="submit" id="button" value="print current time"><br>
  <label>performance.now():</label>
  <input type="text" id="perfromanceNow" readonly><br>
  <label>timestamp:</label>
  <input type="text" id="timestamp" readonly><br>
   <label>delta:</label>
  <input type="text" id="delta" readonly>
<div>

There is a simple workaround. You can use var timestamp = performance.now(); at the beginning of you method instead of getting you timestamp via the rAF time.

Heres a working example:

document.getElementById("button").addEventListener('click', function(e){
        this.valueOfPerformanceNow = performance.now();
        if(!this.clickCallback)this.clickCallback = printTime.bind(this);
        window.requestAnimationFrame(this.clickCallback);
});

function printTime(){
  var timestamp = performance.now();
  $("#perfromanceNow").val(this.valueOfPerformanceNow);
  $("#delta").val(timestamp-this.valueOfPerformanceNow);
  $("#timestamp").val(timestamp);
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div>
  <input type="submit" id="button" value="print current time with new timestamp initialization"><br>
  <label>performance.now():</label>
  <input type="text" id="perfromanceNow" readonly><br>
  <label>timestamp:</label>
  <input type="text" id="timestamp" readonly><br>
   <label>delta:</label>
  <input type="text" id="delta" readonly>
<div>
Yannick Huber
  • 607
  • 2
  • 16
  • 35