block by sxywu 0013618f4dedd57fd41baf1892b364d6

DS July: Code 5

Full Screen

Built with blockbuilder.org

forked from sxywu‘s block: DS July: Code 1

forked from sxywu‘s block: DS July: Code 2

forked from sxywu‘s block: DS July: Code 3

forked from sxywu‘s block: DS July: Code 4

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.13.1/lodash.js'></script>
  
  <style>
    svg {
      width: 900px;
      height: 10000px;
    }
    
    /* blend options taken from visual cinnamon tutorial: //www.visualcinnamon.com/2016/05/beautiful-color-blending-svg-d3.html */
    /*Set isolate on the group element*/
    .flower { isolation: isolate; }  
    /*Set blend mode on SVG element: e.g. screen, multiply*/
    .flower circle { mix-blend-mode: multiply; }
  </style>
</head>

<body>
  <svg>
  </svg>
  <script>
    var padding = 20;
    var svg = d3.select('svg')
    	.append('g')
    	.attr('transform', 'translate(' + [padding, padding] + ')');
    var flowerSize = 150;
		var petalPaths = [[
    	'M0,0',
      "C50,50 50,100 0,100",
      "C-50,100 -50,50 0,0"
    ],
    [
			'M-35,0',
      'C-25,25 25,25 35,0',
      'C50,25 25,75 0,100',
      'C-25,75 -50,25 -35,0'
    ],
    [
      'M0,0',
      'C50,40 50,70 20,100',
      'L0,85',
      'L-20,100',
      'C-50,70 -50,40 0,0'
    ],
    [
      'M0,0',
      'C50,25 50,75 0,100',
      'C-50,75 -50,25 0,0'
    ]];
    
    var numPetalScale = d3.scaleQuantize()
    	.range(_.range(5, 15));
    var flowerSizeScale = d3.scaleLinear()
    	.range([.05, .5]);
    var petalScale = d3.scaleOrdinal()
    	.range(_.range(4));
    var petalColors = d3.scaleOrdinal()
    	.range(['#FFC8F0', '#CBF2BD', '#AFE9FF', '#AFE9FF', '#FFF2B4']);
//     	.range(['#FF7453', '#F45492', '#3DCF45', '#0D9EE4', '#FFED4F']);
    
    // blur effect taken from visualcinnamon:
    // //www.visualcinnamon.com/2016/05/real-life-motion-effects-d3-visualization.html
    var defs = svg.append("defs");
    defs.append("filter")
      .attr("id", "motionFilter") 	//Give it a unique ID
      .attr("width", "300%")		//Increase the width of the filter region to remove blur "boundary"
      .attr("x", "-100%") 			//Make sure the center of the "width" lies in the middle of the element
      .append("feGaussianBlur")	//Append a filter technique
      .attr("in", "SourceGraphic")	//Perform the blur on the applied element
      .attr("stdDeviation", "8 8");	//Do a blur of 8 standard deviations in the horizontal and vertical direction

    
    d3.json('movies.json', function(movies) {
      movies = _.chain(movies)
      	.map(function(movie) {
        	movie.year = parseInt(movie.Year);
          movie.genres = movie.Genre.split(', ');
          movie.rating = parseFloat(movie.imdbRating);
          movie.votes = parseInt(movie.imdbVotes.replace(',', ''));

          return movie;
        }).sortBy(function(movie) {
        	return -movie.year
        }).value();
      
      // number of petals depending on number of rating votes
      var minVotes = d3.min(movies, function(d) {return d.votes});
      var maxVotes = d3.max(movies, function(d) {return d.votes});
      numPetalScale.domain([minVotes, maxVotes]);
      // overall flower size from rating
      var minRating = d3.min(movies, function(d) {return d.rating});
      var maxRating = d3.max(movies, function(d) {return d.rating});
      flowerSizeScale.domain([minRating, maxRating]);
      // get the top 4 genres by count
      var topGenres = _.chain(movies)
      	.map('genres').flatten()
      	.countBy().toPairs()
      	.sortBy(1).map(0)
      	.takeRight(4)
      	.value();
      topGenres.push('Other');
      petalColors.domain(topGenres);
      
      // draw flower for each movie
      var flowers = svg.selectAll('g.flower')
        .data(_.values(movies)).enter().append('g')
        .classed('flower', true)
        .attr('transform', function(d, i) {
          var scale = flowerSizeScale(d.rating);
          var x = (i % 6) * flowerSize;
          var y = Math.floor(i / 6) * flowerSize;
          return 'translate(' + x + ',' + y +
            ')scale(' + scale + ')';
        });
      
      // create the data for each flower's colors
      flowers.selectAll('circle')
      	.data(function(d) {
        	// if there's only one genre, center the circle
        	var cy = d.genres.length === 1 ? 0 : -flowerSize / 5;
        	return _.map(d.genres, function(genre, i) {
            genre = _.includes(topGenres, genre) ? genre : 'Other';
            return {
              cy: cy,
              scale: flowerSizeScale(d.rating),
              angle: (360/d.genres.length) * i,
              fill: petalColors(genre)
            }
          });
        }).enter().append('circle')
      	.attr('cy', function(d) {return d.cy})
        .attr('r', flowerSize / 2)
      	.attr('fill', function(d) {return d.fill})
      	.attr('transform', function(d) {
          var x = flowerSize / 2 / d.scale;
          var y = flowerSize / 2 / d.scale;
          return 'translate(' + [x, y] +
            ')rotate(' + d.angle + ')';
        }).style("filter", "url(#motionFilter)");
      
      flowers.selectAll('path')
        .data(function(d) {
        	var numPetals = numPetalScale(d.votes);
        	var path = petalPaths[petalScale(d.Rated)];
          return _.times(numPetals, function(i) {
            return {
              scale: flowerSizeScale(d.rating),
              angle: (360/numPetals) * i,
              path: path
            }
          });
        }).enter().append('path')
        .attr('stroke', '#444')
        .attr('stroke-width', function(d) {
        	return 2 / d.scale;
        }).attr('fill', 'none')
        .attr('d', function(d) {return d.path})
        .attr('transform', function(d) {
          var cx = flowerSize / 2 / d.scale;
          var cy = flowerSize / 2 / d.scale;
          return 'translate(' + [cx, cy] +
            ')rotate(' + [d.angle] + ')';
        });
    });
    
  </script>
</body>