block by sxywu 379ba3f8f2e196cac6d229b5c1e7fae1

DS Aug, Code 6

Full Screen

Built with blockbuilder.org

forked from sxywu‘s block: DS Aug, Code 1

forked from sxywu‘s block: DS Aug, Code 1

forked from sxywu‘s block: DS Aug, Code 3

forked from sxywu‘s block: DS Aug, Code 4

forked from sxywu‘s block: DS Aug, Code 5

index.html

<!DOCTYPE html>
<head>
  <meta charset="utf-8">
  <script src="https://d3js.org/d3.v4.min.js"></script>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.15.0/lodash.min.js"></script>
  <style>
    body {
    }
  </style>
</head>

<body>
  <canvas id='canvas'></canvas>
  <svg id='svg'></svg>
  <script>
		var canvas = document.getElementById('canvas');
    var ctx = canvas.getContext('2d');
    ctx.globalCompositeOperation = 'overlay';
    
    // properties
    var padding = 50;
    var width = canvas.width = 800;
    var height = canvas.height = 1200;
    var maxRadius = 45;
    var TWO_PI = 2 * Math.PI;
    var colors = {
      'China': [[255,0,0], [255,255,0]],
      'United States': [[187, 19, 62], [0, 44, 119]],
      'Great Britain': [[0, 39, 118], [198, 12, 48]],
      'Italy': [[0, 146, 70], [206, 43, 55]],
      'Australia': [[0, 0, 139], [255, 0, 0]],
      'Malaysia': [[1, 0, 102], [255, 204, 0]],
      'Canada': [ [255, 255, 255], [255, 0, 0]],
      'F': [250,176,189],
      'M': [187,209,222]
    };
    
    // scale
    var radiusScale = d3.scaleLinear().range([maxRadius / 3 * 2, maxRadius]);
    var yScale = d3.scaleLinear().range([0, 1]);
    var xWidth = 0;
    
    function processData(data) {
      xWidth = (width - 2 * padding) / data.length;
    	_.each(data, function(d) {
        // create an artifical first score
        d.breakdown.unshift(d.breakdown[0]);
        d.processed = _.map(d.breakdown, function(score) {
          return _.map(score[2], function(num) {return num * score[0]});
        });
        d.totalDifficulty = _.reduce(d.breakdown, function(sum, score) {
          return sum + score[0];
        }, 0) * d.total;
      });
      
      var difficulty = _.chain(data).map('breakdown').flatten().map(0).value();
      var maxRadius = _.max(difficulty);
      var scores = _.chain(data).map('processed').flattenDeep().value();
      var minY = _.min(scores);
      var maxY = _.max(scores);
      
//       var minX = _.minBy(data, 'totalDifficulty').totalDifficulty - padding;
//       var maxX = _.maxBy(data, 'totalDifficulty').totalDifficulty + padding;
      
      radiusScale.domain([1, maxRadius]);
      yScale.domain([minY, maxY]);
    }
    
    // generate the flow line, given one event for one team
    function generateFlowData(team, i) {
      var gradient = ctx.createRadialGradient(0, 0, 0, 0, 0, maxRadius);
      gradient.addColorStop(1, 'rgba(' + colors[team.country][0] + ',0.1)');
      gradient.addColorStop(0, 'rgba(' + colors[team.country][1] + ',0.1)');
      
      return {
        centerX: xWidth * i + padding,
        centerY: padding,
        stroke: gradient,
        fill: 'rgba(' + colors[team.gender] + ', 0.01)',
        radii: _.map(team.breakdown, function(scores) {
          return radiusScale(scores[0]);
        }),
        points: _.map(team.processed, function(scores) {
        	return generateCircleData(scores);
      	}),
        length: _.map(team.breakdown, function(scores) {
          return Math.floor(scores[1]) * 4;
        }),
        rotations: _.map(team.breakdown, function(scores) {
          return scores[1] / team.total;
        }),
        dataPoints: [],
        totalLength: Math.floor(team.total) * 4,
        elapsed: 0,
        data: team
      }
    }
    
    // generate the data for just one of the circles in the flow line
    // majority of this function is taken from
    // Dan Gries's tutorial //rectangleworld.com/blog/archives/462
    // in particular the function setLinePoints
    function generateCircleData(scores) {
      var circle = {
				first: {x: 0, y: 1}
      };
      var last = {x: 1, y: 1};
      var minY = maxY = 1;
      var point, nextPoint;
      var dx, newX, newY;
      
      // connect first point with the last
      circle.first.next = last;
      _.each(scores, function(score) {
        point = circle.first;
        while (point.next) {
          nextPoint = point.next;
          dx = nextPoint.x - point.x;
          newX = 0.5 * (point.x + nextPoint.x);
          newY = 0.5 * (point.y + nextPoint.y);
          // vary the y-pos by the score, but subtract it
          // by what is around the mid-point so that
          // some are positive and others are negative
          newY += dx * (yScale(score) * 2 - 1);
          
          var newPoint = {x: newX, y: newY};
          
          //min, max
          if (newY < minY) {
            minY = newY;
          }
          else if (newY > maxY) {
            maxY = newY;
          }
          
          // insert mid-point
          newPoint.next = nextPoint;
          point.next = newPoint;
          
          point = nextPoint;
        }
      })
      
//       normalize to values between 0 and 1
      if (maxY != minY) {
        var normalizeRate = 1/(maxY - minY);
        point = circle.first;
        while (point != null) {
          point.y = normalizeRate*(point.y - minY);
          point = point.next;
        }
      }
      
      return circle;
    }
    
    function tweenPoints(circle1, circle2) {
      // interpolate all the points of the circles
      var interpolators = _.map(circle1, function(point1, i) {
        return {
          x: d3.interpolate(point1.x, circle2[i].x),
          y: d3.interpolate(point1.y, circle2[i].y)
        };
      });
      return function(t) {
        return _.map(interpolators, function(interpolate) {
          return {x: interpolate.x(t), y: interpolate.y(t)};
        });
      };
    }
    
    // given set of points making up a squiggly line
    // turn it into a squiggly imperfect circle
    // also calculate the interpolators for them
    function calculateCircles(flow) {
      flow.circles = [];
      flow.interpolators = [];
      var prevCircle = null;
			_.each(flow.points, function(points, i) {
        // calculate circles
        var point = points.first;
        var rotation = flow.rotations[i];
        var radii = flow.radii[i];
        var circle = [];
        
        var theta = TWO_PI * (point.x + rotation);
        var radius = radii * point.y;
        var x = radius * Math.cos(theta);
        var y = radius * Math.sin(theta);
        circle.push({x: x, y: y});
        
        while (point.next) {
          point = point.next;
          
          // given its x and y, calculate its theta and radius
          var theta = TWO_PI * (point.x + rotation);
          var radius = radii * point.y;

          var x = radius * Math.cos(theta);
          var y = radius * Math.sin(theta);

          circle.push({x: x, y: y});
        }
        flow.circles.push(circle);
        
        // now calculate the interpolators
        if (prevCircle) {
          var interpolators = tweenPoints(prevCircle, circle);
          flow.interpolators.push(interpolators);
        }

        prevCircle = circle;
      });
    }
    
    function drawCircle(elapsed, flow) {
      if (flow.elapsed === flow.totalLength) {
        // if the last set of drawings wasthe totalLength
        // we're finished drawing this flow line
        return true;
      }
      var drawCount;
      elapsed = Math.min(parseInt(elapsed) / flow.totalLength, 1);
      elapsed = d3.easeQuad(elapsed);
      elapsed = parseInt(flow.totalLength * elapsed);
      _.times(elapsed - flow.elapsed, function(t) {
        t += flow.elapsed;
        drawCount = t;
        
        _.some(flow.interpolators, function(interpolator, i) {
          var length = flow.length[i + 1];
          
          if (t > length) {
            // if elapsed is more than length of section
            // subtract length and move to next interpolator
            t -= length;
            return false;
          }
          
          // else this is the interpolator to use
          ctx.strokeStyle = flow.stroke;
          ctx.beginPath();

          flow.centerY += 0.5;
          var xOffset = (_.last(flow.radii) / 3) * Math.sin(drawCount/flow.data.total * TWO_PI);
          ctx.setTransform(1, 0, 0, 1, flow.centerX + xOffset, flow.centerY);

          var points = interpolator(t / length);
          _.each(points, function(pos) {
            ctx.lineTo(pos.x, pos.y);
          });

          ctx.closePath();
          ctx.stroke();
//           ctx.fill();
          
          if (t === length) {
            var x1 = flow.centerX + xOffset;
            var maxX = _.maxBy(flow.circles[i + 1], 'x').x;
            flow.dataPoints.push({
              x1: x1,
              x2: x1 + maxX,
              y: flow.centerY,
              score: flow.data.breakdown[i + 1]
            });
          }
          
          return true;
        });
      });

      flow.elapsed = elapsed;
      return false;
    }
    
    // load the data
    d3.json('data.json', function(data) {
      processData(data);
      var flows = _.map(data, function(d, i) {
        var flow = generateFlowData(d, i);
        calculateCircles(flow);
        return flow;
      })
      var t = d3.timer(function(elapsed) {
        var allFinished = true;
        _.each(flows, function(flow) {
          allFinished &= drawCircle(elapsed, flow);
        });
        if (allFinished) t.stop();
      });
    });
      
  </script>
</body>

data.json

[
  {
    "event": "Women's synchronized 3m springboard",
    "country": "Italy",
    "athletes": ["T. Cagnotto", "F. Dallapé"],
    "total": 313.83,
    "gender": "F",
    "breakdown": [
      [3, 71.1, [7.5, 7.5, 8, 8, 8, 8], [8, 7.5, 8, 8.5, 8]],
      [3.1, 66.03, [8, 7.5, 7.5, 6.5, 7, 7], [7, 7, 7, 7, 7.5]],
      [3, 74.7, [8, 8, 8, 7.5, 8, 8], [8.5, 8.5, 8.5, 8.5, 8.5]]
    ]
  },
  {
    "event": "Women's synchronized 3m springboard",
    "country": "China",
    "athletes": ["M.X. Wu", "T.M. Shi"],
    "total": 345.60,
    "gender": "F",
    "breakdown": [
      [3, 76.5, [8.5, 8.5, 8, 8.5, 7.5, 8], [9, 8.5, 9, 8.5, 8.5]],
      [3, 80.1, [9, 9, 9, 8.5, 9, 8.5], [8.5, 9, 9, 9, 9]],
      [3, 81, [9.5, 8.5, 9, 8.5, 9, 9], [9, 9, 9, 9, 9]]
    ]
  },
  {
    "event": "Women's synchronized 3m springboard",
    "country": "Australia",
    "athletes": ["M. Keeney", "A. Smith"],
    "total": 299.19,
    "gender": "F",
    "breakdown": [
      [3, 70.2, [8.5, 8, 8, 7, 7, 7], [8, 8.5, 8, 8, 8]],
      [3.1, 67.89, [7.5, 8, 7.5, 6.5, 6.5, 5.5], [7.5, 7.5, 7.5, 8, 7.5]],
      [3, 71.1, [7.5, 8, 7.5, 7.5, 7.5, 7.5], [8, 7.5, 8, 8.5, 8.5]]
    ]
  },
  {
    "event": "Women's synchronized 10m platform",
    "country": "Malaysia",
    "athletes": ["P. Rinong", "J.H. Cheong"],
    "total": 344.34,
    "gender": "W",
    "breakdown": [
      [3, 76.5, [6.5, 8, 8, 9, 8.5, 8.5], [8.5, 8, 8.5, 9, 9]],
      [3.2, 79.68, [8, 7.5, 8.5, 8, 8.5, 7.5], [8.5, 8.5, 8.5, 9, 8.5]],
      [3.2, 82.56, [8.5, 8.5, 8.5, 8.5, 8, 8.5], [8.5, 8.5, 9, 8.5, 9]]
    ]
  },
  {
    "event": "Women's synchronized 10m platform",
    "country": "China",
    "athletes": ["R. L. Chen", "H. X. Liu"],
    "total": 354,
    "gender": "W",
    "breakdown": [
      [3, 79.2, [8.5, 8.5, 9, 8.5, 8.5, 8.5], [9, 8.5, 9, 9, 9]],
      [3.2, 75.84, [8, 7.5, 7.5, 7, 8, 7.5], [9, 8, 8, 8.5, 8]],
      [3.2, 87.36, [9.5, 8.5, 8.5, 8.5, 8.5, 8.5], [9.5, 9.5, 9.5, 9.5, 9]]
    ]
  },
  {
    "event": "Women's synchronized 10m platform",
    "country": "Canada",
    "athletes": ["M. Benfeito", "R. Filion"],
    "total": 336.18,
    "gender": "W",
    "breakdown": [
      [3, 74.7, [8, 8, 8, 8, 8, 8], [9, 8.5, 8.5, 8.5, 8.5]],
      [3.3, 75.24, [7.5, 7, 7, 7, 7, 7.5], [8, 7.5, 8, 8, 8]],
      [3.2, 80.64, [8.5, 8, 8, 8.5, 8.5, 8], [8.5, 8.5, 8.5, 8.5, 9]]
    ]
  },
  {
    "event": "Men's synchronized 10m platform",
    "country": "United States",
    "athletes": ["S. Johnson", "D. Boudia"],
    "total": 457.11,
    "gender": "M",
    "breakdown": [
      [3.2, 83.52, [8.5, 8.5, 8.5, 8.5, 9, 8.5], 8.5, 8.5, 9, 9, 9],
      [3.4, 85.68, [7.5, 7, 7.5, 9, 9.5, 9], [8, 8.5, 8.5, 8.5, 8.5]],
      [3.7, 85.47, [7, 7, 7.5, 8, 7.5, 7.5], [8.5, 8, 8, 8, 7.5]],
      [3.6, 95.04, [8, 9, 8.5, 8.5, 8.5, 8.5], [9, 9, 9, 9, 9]]
    ]
  },
  {
    "event": "Men's synchronized 10m platform",
    "country": "China",
    "athletes": ["A. Chen", "Y. Lin"],
    "total": 496.98,
    "gender": "M",
    "breakdown": [
      [3.4, 92.82, [8.5, 8.5, 9, 9.5, 10, 9], [9.5, 9, 9, 9, 9.5]],
      [3.6, 85.32, [7, 7, 6.5, 8, 8.5, 8.5], [8, 8, 8, 8, 8.5]],
      [3.7, 106.56, [9.5, 9.5, 9, 9.5, 10, 9.5], [9.5, 9.5, 9.5, 10, 10]],
      [3.6, 98.28, [9, 9, 9, 9, 9, 9], [8.5, 9.5, 9, 9, 9.5]]
    ]
  },
  {
    "event": "Men's synchronized 10m platform",
    "country": "Great Britain",
    "athletes": ["T. Daley", "D. Goodfellow"],
    "total": 444.45,
    "gender": "M",
    "breakdown": [
      [3.2, 79.68, [9, 8.5, 8.5, 7.5, 7.5, 8], [9, 8, 8.5, 8.5, 8.5]],
      [3.4, 81.6, [8.5, 9, 8.5, 7.5, 7.5, 7.5], [8, 8.5, 8, 7.5, 8]],
      [3.7, 92.13, [8, 8, 8, 8, 8.5, 8], [9, 8.5, 8, 8.5, 8.5]],
      [3.6, 89.64, [8.5, 8.5, 8.5, 8, 7.5, 7.5], [8.5, 8.5, 8, 8.5, 8.5]]
    ]
  },
  {
    "event": "Men's synchronized 3m springboard",
    "country": "United States",
    "athletes": ["M. Hixon", "S. Dorman"],
    "total": 450.21,
    "gender": "M",
    "breakdown": [
      [3.4, 85.68, [8, 8, 8, 9, 8.5, 8.5], [8.5, 8.5, 8.5, 8.5, 8.5]],
      [3.5, 87.15, [8.5, 8, 8, 7, 8, 8.5], [8.5, 8.5, 8.5, 8.5, 8]],
      [3.4, 78.54, [7, 7.5, 7.5, 7.5, 8, 6], [7.5, 8.5, 7.5, 8, 8]],
      [3.8, 98.04, [8.5, 8, 8, 8.5, 8.5, 9], [9, 9, 8.5, 8.5, 9]]
    ]
  },
  {
    "event": "Men's synchronized 3m springboard",
    "country": "Great Britain",
    "athletes": ["J. Laugher", "C. Mears"],
    "total": 454.32,
    "gender": "M",
    "breakdown": [
      [3.4, 84.66, [7.5, 8, 7.5, 8.5, 8.5, 8.5], [8.5, 8, 8.5, 9, 8.5]],
      [3.4, 85.68, [8, 8, 8.5, 8, 8.5, 9], [8.5, 8.5, 8.5, 9, 8]],
      [3.9, 86.58, [7, 8, 7.5, 7.5, 8, 8.5], [7.5, 7, 7, 7.5, 7]],
      [3.8, 91.2, [7.5, 7.5, 7.5, 8.5, 8.5, 8.5], [8, 8, 8, 8.5, 8]]
    ]
  },
  {
    "event": "Men's synchronized 3m springboard",
    "country": "China",
    "athletes": ["K. Qin", "Y. Cao"],
    "total": 443.7,
    "gender": "M",
    "breakdown": [
      [3.4, 79.56, [8.5, 8, 8, 8, 7.5, 7.5], [8, 7.5, 8, 8, 7.5]],
      [3.4, 82.62, [9, 8.5, 8.5, 8, 6.5, 7], [8.5, 8, 8.5, 8.5, 8]],
      [3.5, 90.3, [9, 8.5, 8.5, 9.5, 9, 9], [8.5, 8.5, 8.5, 9, 8.5]],
      [3.8, 83.22, [7, 7.5, 7, 7, 7, 7.5], [7.5, 8, 7.5, 7, 7.5]]
    ]
  }
]