Pan a color highlight across a series of elements

Experimenting with update/render loop and delta ms to calculate state then render color animation from it

by sfoster

HTML

<div id="strip">
  <div class="led"></div>
  <div class="led"></div>
  <div class="led"></div>
  <div class="led"></div>
  <div class="led"></div>
  <div class="led"></div>
  <div class="led"></div>
</div>
<div id="message"></div>
<button>Stop</button>

CSS

.led {
  display: inline-block;
  width: 40px;
  height: 40px;
  outline: 1px dotted #999;
}

JavaScript

// library stuff
function Color(r,g,b) {
  this.r = r;
  this.g = g;
  this.b = b;
}
Color.prototype = Object.prototype;

function msg(str) {
  document.getElementById("message").textContent = str;
}

function setPixelColor(node, color) {
  var colorStr = 'rgb('+color.r.toFixed(0)+','+color.g.toFixed(0)+','+color.b.toFixed(0)+')';
  node.style.backgroundColor = colorStr;
}

function render() {
  var nodes = container.children;
  for(i=0; i<pixels.length; i++) {
    setPixelColor(nodes[i], pixels[i]);
  }
}

// runtime state
var container = document.getElementById("strip");
var pixels = Array.map(container.children, function() {
  return new Color(0,0,0);
});
var currentColor = new Color(0,0,0);
var currentPosition = 0;
var speed = 1000/7;

var startTime = Date.now();
var prevTime = startTime;
var lastFrame = startTime;
var animateFn = null;

// the animation-specific update function
function panHighlight(delta) {
  var distance;
  if (Date.now() - lastFrame >= speed) {
    for(var i=0; i<pixels.length; i++) {
      distance = 1+Math.abs(i - currentPosition);
      //msg(distance);
      pixels[i] = new Color(150,
                            255 - (150 * distance/pixels.length),
                            255);
    }
    currentPosition = (currentPosition+1) % (pixels.length);
    lastFrame = Date.now();
  }
}
// the animation loop
function startAnimation() {
	function onFrame() {
    if (!animateFn) {
      return;
    }
    var now = Date.now();
    animateFn(now - prevTime);
    render();
    prevTime = now;
    window.requestAnimationFrame(onFrame);
  }
	window.requestAnimationFrame(onFrame);
}
function stopAnimation() {
	animateFn = null;
}
// the init
animateFn = panHighlight;
startAnimation();
document.querySelector("button").onclick = stopAnimation;