Trying to write javascript that fades into background color

advertisements

I'm trying to teach myself javascript and I'm, apparently, not fully understanding.

What I'm trying to get is a box that when you click it, the background color changes smoothly from black to some color. To do this, I've created a function that takes an HSV value and spits out a string in the #rrggbb format. Hence, to fade in I simply walk the V value from 0 to 100 in increments of 1 using a for loop.

What I've got is a box that when you click it, it pauses and changes to the background color I'm using. I'm also logging the output and that calculates and updates once at the end with the RGB hex values.

So, clearly, I'm not understanding whatever knowledge is required to refresh the DOM at the intermediate steps. All searches I get for this come up with solutions using jQuery or the like. That's well and good, I intend to work my way through jQuery et al, but first, I'd like to get some things like this to work so that I can get a more thorough understanding of what is going on under the hood.

The code is here: http://codepen.io/anon/pen/QbzQJG

The code:

HTML:

<title>Color test</title>

<body>
  <div id="colorbox" onclick="javascript:fadeIn()"></div>
  <div id="console"></div>
</body>

CSS:

  body {
    background: #000;
    color: #999;
  }

  #colorbox {
    background: #000;
    border: 1px solid #333;
    width: 250px;
    height: 250px;
    margin: 0 auto;
  }

Javascript:

var c = function() {
  return ({
    log: function(msg) {
      consoleDiv = document.getElementById('console');
      para = document.createElement('p');
      text = document.createTextNode(msg);
      para.appendChild(text);
      consoleDiv.appendChild(para);
    }
  });
}();

function toRGB(H, S, V) {
  S /= 100;
  V /= 100;
  var C = V * S;
  H /= 60;
  var X = C * (1 - Math.abs((H % 2) - 1));
  var R = 0;
  var G = 0;
  var B = 0;
  if (0 <= H && H < 1) {
    R = C;
    G = X;
    B = 0;
  } else if (1 <= H && H < 2) {
    R = X;
    G = C;
    B = 0;
  } else if (2 <= H && H < 3) {
    R = 0;
    G = C;
    B = X;
  } else if (3 <= H && H < 4) {
    R = 0;
    G = X;
    B = C;
  } else if (4 <= H && H < 5) {
    R = X;
    G = 0;
    B = C;
  } else if (5 <= H && H < 6) {
    R = C;
    G = 0;
    B = X;
  } else {
    R = 0;
    G = 0;
    B = 0;
  }

  var m = V - C;
  R = Math.round(255 * (R + m)).toString(16);
  R.length < 2 ? R = "0" + R : R = "" + R;
  G = Math.round(255 * (G + m)).toString(16);
  G.length < 2 ? G = "0" + G : G = "" + G;
  B = Math.round(255 * (B + m)).toString(16);
  B.length < 2 ? B = "0" + B : B = "" + B;

  var RGB = "#" + R + G + B;
  return RGB;
}

function pause(milliseconds) {
  var dt = new Date();
  while ((new Date()) - dt <= milliseconds) { /* Do nothing */ }
}

function fadeIn() {
  var colorbox = document.querySelector("#colorbox");
  for (var i = 0; i <= 100; i++) {
    colorbox.style.backgroundColor = toRGB(150, 80, i);
    c.log(toRGB(150, 80, i));
    pause(10);
  }
}

Any thoughts?


Your problem is with understanding the flow of events in a browser (and JS in general). (Standard) JavaScript works as a single-threaded asynchronous process. As such, for anything to happen "in between" your code, you need to somehow return execution to the calling context. That's true when nested inside a call stack within JavaScript code as well as when you want to "see" the effect of your code on the browser window.

Your problem is that pause isn't pausing anything. It busy-waits. You need to return control to the browser.

You could achieve your goal like this:

function fadeIn() {
  var colorbox = document.querySelector("#colorbox");

  var i = 0;
  var interval = setInterval(function() {
    if(i > 100) {
      clearInterval(interval);
      return;
    }
    colorbox.style.backgroundColor = toRGB(150, 80, i);
    c.log(toRGB(150, 80, i));
    i++
  }, 10);
}

pause is not needed in this solution.