Fortune 500 Demo

As seen on Fathom, done in Canvas and JavaScript. Best viewed in Chrome or Firefox. Click to select points; navigate with arrow keys.
Rank
Revenue
Profit
1955
1960
1965
1970
1975
1980
1985
1990
1995
2000
2005
2010

About

I thought the Fathom Fortune 500 vis, done in Java, was excellent. This version was created to demonstrate that 80,000 data points could be visualized with JavaScript using modern browser features. This visualization uses JavaScript and Canvas.

Vitals

  • JavaScript & Canvas
  • 237KB of Data
  • Tested in Chrome, Firefox, Android Webkit and Firefox Mobile.
draw()
/**
 * Main draw routine.
 *
 * This routine draws about the lines representing the data, about 27500 
 * points at once and represents the main critical section.  Previous
 * drawn values are remembered and used, together with the increment
 * paramenter, to render frames of animation.
 *
 * Optimizations include precalculating the data, array access vs. 
 * refinement, and using a single path and stroke.
 */
function draw (type, increment) {

  var
    year    = C_MAP[YEAR],
    index   = C_MAP[type],
    pIndex  = C_MAP[PREVIOUS],
    names   = F500.names,
    values  = F500.values,
    length1 = values.length,
    dec     = 1 - increment,
    length2,
    data,
    nameWidth,
    i, j,
    x, y;

  context.clearRect(0, 0, width, height);
  context.beginPath();

  for (i = 0; i < length1; i++) {

    data      = values[i];
    length2   = data.length;
    nameWidth = names[i].length / 4;

    for (j = 0; j < length2; j++) {
      x = data[j][year];
      data[j][pIndex] = y =
        increment * data[j][index] + dec * (data[j][pIndex] || data[j][index]);
      context.moveTo(x - nameWidth, y);
      context.lineTo(x + nameWidth, y);
    }
  }

  context.closePath();
  context.stroke();

  if (selected !== null)
    drawCompany(type, selected, increment);
}
calculate()
/**
 * Precalculate revenue, price and inflation.
 *
 * Revenue and profit are stored as actual values (in millions).  This value
 * is displayed to the user in the company popup.  To draw the data, these
 * values need to be translated to their y coordinates in the log scale.
 *
 * This translation is precalculated for speed at draw time and calculated
 * client-side to keep the data size down.
 *
 * Run after first draw.
 */
function calculate() {

  var
    rBase     = height / Math.log(6e5),
    pBase     = height / ( 2 * Math.log(1e6) ),
    rIndex    = D_MAP[REVENUE],
    pIndex    = D_MAP[PROFIT],
    yIndex    = D_MAP[YEAR],
    values    = F500.values,
    inflation = F500.inflation,
    half      = height / 2,
    length1   = values.length,
    length2,
    data,
    datum,
    year,
    v,
    i, j;

  for (i = 0; i < length1; i++) {

    data = values[i];
    length2 = data.length;

    for (j = 0; j < length2; j++) {
      datum = data[j];
      year = datum[yIndex];
      datum.push(Math.round(height - Math.log(datum[rIndex] - 40) * rBase));
      datum.push(Math.round(height - Math.log(datum[rIndex] * inflation[year] - 40) * rBase));
      v = datum[pIndex];
      if (v < 0) {
        datum.push(Math.round(half + Math.log(-10 * v) * pBase));
        datum.push(Math.round(half + Math.log(-10 * v * inflation[year]) * pBase));
      } else {
        datum.push(Math.round(half - Math.log(10 * v) * pBase));
        datum.push(Math.round(half - Math.log(10 * v * inflation[year]) * pBase));
      }
    }
  }
}