rveciana - 66000-points-animation

66000 points animation

Open raw page in new tab

A version of the previous block, but improved to speed the drawing and to make fast transitions.

Based on this block by Peter Beshai

<!DOCTYPE html>
<meta charset="utf-8">
<style>
</style>
<body>
<script src="https://d3js.org/d3.v4.min.js"></script>

<script>
    const width = 960,
    height = 670;
    const duration = 1500;
    const ease = d3.easeCubic;
    let timer;
    let currLayout = 0;

    var canvas = d3.select("body")
        .append("canvas")
        .attr('height', height)
        .attr('width', width);

    var context = canvas.node().getContext("2d");


     var points = [];

    var penes = [{'Nom':'Dotze anys i un dia de reclusió temporal', 'Nombre': 11348, 'Color': '#eded07'},
         {'Nom':'Sobreseïment','Nombre': 10479, 'Color': '#afa'},
         {'Nom':'Absolt','Nombre': 7204, 'Color': '#7f7'},
         {'Nom':'Llibertat','Nombre': 6105, 'Color': '#8f8'},
         {'Nom':'Sense declaració de responsabilitats','Nombre': 5469, 'Color': '#cfc'},
         {'Nom':'Mort','Nombre': 4404, 'Color': '#f00'},
         {'Nom':'Vint anys de reclusió temporal','Nombre': 3826, 'Color': '#d18400'},   
         {'Nom':'Reclusió perpètua','Nombre': 3740, 'Color': '#d15a00'},
         {'Nom':'Quinze anys de reclusió temporal','Nombre': 3560, 'Color': '#d1aa00'},
         {'Nom':'Arxiu','Nombre': 3360, 'Color': '#afa'},
         {'Nom':'Sis anys i un dia de presó major','Nombre': 2022, 'Color': '#d1c600'},
         {'Nom':'Trenta anys de reclusió major','Nombre': 665, 'Color': '#d16500'},
         {'Nom':'Pena de multa','Nombre': 648, 'Color': '#b8d100'},
         {'Nom':'Sis mesos i un dia de presó menor','Nombre': 548, 'Color': '#cad100'},
         {'Nom':'Dotze anys i un dia de reclusió menor','Nombre': 516, 'Color': '#eded07'},
         {'Nom':'Dotze anys de presó major','Nombre': 434, 'Color': '#eded07'},
         {'Nom':'Destinat a Batalló de Treballadors o a','Nombre': 298, 'Color': '#156f72'},
         {'Nom':'Un any de presó menor','Nombre': 298, 'Color': '#cad100'},
         {'Nom':'Desglossament en un altre procediment','Nombre': 258, 'Color': '#bbb'},
         {'Nom':'Absolt i un mes d\'arrest menor','Nombre': 199, 'Color': '#e5ed04'},
         {'Nom':'Tres anys i un dia de presó menor','Nombre': 178, 'Color': '#d1c600'},
         {'Nom':'Nou anys de presó major','Nombre': 178, 'Color': '#d1b800'},
         {'Nom':'Vuit anys de presó major','Nombre': 171, 'Color': '#d1b800'},
         {'Nom':'Vint anys de reclusió major','Nombre': 11, 'Color': '#d17600'},
         {'Nom':'Altres','Nombre': 11, 'Color': '#aaa'},
    ];
    var totalVictimes = 65990;
    var j = 0;
    penes.forEach(function(pena){
        for(var i = 0; i<pena['Nombre']; i++){
            points.push({'color': pena['Color'], 'x': width/2, 'y': height/2, 'order': j});
            j++;
        }
    });

    for(var i=j; i<totalVictimes; i++){
        points.push('Altres');
    }
 

function orderedLayout(points){
    let stackHeight = 220;
    points.forEach((point) => {
        point.x = 3*Math.floor(point.order/stackHeight);
        point.y = 3*(point.order%stackHeight);;
    });
    return points;
}


function randomLayout(points){
    let stackHeight = 220;
    shuffle(points)
    points.forEach((point, i) => {
        point.x = 3*Math.floor(i/stackHeight);
        point.y = 3*(i%stackHeight);;
    });
    return points;
}


const layouts = [randomLayout, orderedLayout];

function draw() {
  context.clearRect(0,0,canvas.attr("width"),canvas.attr("height"));

  for (let i = 0; i < points.length; ++i) {
    const point = points[i];
    context.fillStyle = point.color;
    context.fillRect(point.x, point.y, 2, 2);
  }
}

function animate(layout) {
  // store the source position
  points.forEach(point => {
    point.sx = point.x;
    point.sy = point.y;
  });

  // get destination x and y position on each point
  layout(points);

  // store the destination position
  points.forEach(point => {
    point.tx = point.x;
    point.ty = point.y;
  });

  timer = d3.timer((elapsed) => {
    // compute how far through the animation we are (0 to 1)
    const t = Math.min(1, ease(elapsed / duration));

    // update point positions (interpolate between source and target)
    points.forEach(point => {
      point.x = point.sx * (1 - t) + point.tx * t;
      point.y = point.sy * (1 - t) + point.ty * t;
    });

    // update what is drawn on screen
    draw();


    // if this animation is over
    if (t === 1) {
      timer.stop();
      
      currLayout = (currLayout + 1) % layouts.length;

      animate(layouts[currLayout]);

    }
  });

}

animate(layouts[currLayout]);

function shuffle(array) {
//https://stackoverflow.com/questions/2450954/how-to-randomize-shuffle-a-javascript-array
  var currentIndex = array.length, temporaryValue, randomIndex;

  // While there remain elements to shuffle...
  while (0 !== currentIndex) {

    // Pick a remaining element...
    randomIndex = Math.floor(Math.random() * currentIndex);
    currentIndex -= 1;

    // And swap it with the current element.
    temporaryValue = array[currentIndex];
    array[currentIndex] = array[randomIndex];
    array[randomIndex] = temporaryValue;
  }

  return array;
}
</script>
</body>