block by renecnielsen 53c9c161e391434b3ba0e1bc84ff56c8

openvis tweets #1

Full Screen

Open in new tab to scroll.

Built with blockbuilder.org

forked from sxywu‘s block: openvis tweets #1

index.html

<!DOCTYPE html>
<head>
  <meta charset="utf-8">
  <script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.5/d3.min.js"></script>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/d3-legend/1.10.0/d3-legend.js"></script>
  <script src='https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.11.2/lodash.js'></script>
  <link href='https://fonts.googleapis.com/css?family=Lora' rel='stylesheet' type='text/css'>
  <style>
    body {
      font-family: 'Lora', serif;
      margin:0;
    }
    #vis {
      width:600px;
      height: 2400px;
    }
    #body {
      height: 100%;
      position: fixed;
      top: 0;
      left: 650px;
      right: 0px;
      overflow: scroll;
    }
    #legend {
      width: 100%;
      height: 75px;
    }
    .tweet {
      padding: 10px;
    }
    text {
      font-size: .8em;
    }
  </style>
</head>

<body>
  <svg id='vis'></svg>
  <div id='body'>
    <div>
      Tweets with #openvisconf or @openvisconf.  Click on the pies to view tweets.
    </div>
  	<svg id='legend' />
    <div id='title'></div>
    <div id='content'></div>
  </div>
  
  <script>
    d3.json('https://raw.githubusercontent.com/sxywu/fishy/master/clean-results_min.json', function(tweets) {
      var radius = 40;
      var width = radius * 2 + 40;
      var take = 100;
      var perRow = 5;
      var color = d3.scale.ordinal()
      	.domain(['original', 'RT'])
      	.range(['#0088CC', '#F89406']);
      var dateFormat = d3.time.format('%x %I:%M%p');
      
      // group the tweets by user, then sort and take top 100
      var usersSorted = _.chain(tweets.results)
        .groupBy(function(t) {
          t.date = new Date(t.postedTime);
          return t.actor.preferredUsername
        }).sortBy(function(t) {return -t.length})
      	.take(take)
      	.map(function(t) {
          return {
            tweets: t,
            username: t[0].actor.preferredUsername,
            length: t.length
          };
        }).value();
      
      // calculate the radius for each user
      var minRadius = d3.min(usersSorted, function(d) {return d.length});
      var maxRadius = d3.max(usersSorted, function(d) {return d.length});
      var radiusScale = d3.scale.log()
      	.domain([minRadius, maxRadius])
      	.range([radius / 4, radius]);
      _.each(usersSorted, function(user) {
        user.type = _.chain(user.tweets)
        	.groupBy(function(tweet) {
            return tweet.body.match(/^RT/) || 'original'
          }).map(function(tweets, type) {
            return {
              type: type,
              tweets: tweets,
              radius: radiusScale(user.length)
            };
          }).sortBy(function(type) {
          	return type.type === 'original' ? -1 : 1;
          }).value();
      });
      
      // 
      var legend = d3.legend.color()
        .shape("circle")
        .shapePadding(10)
        .scale(color);
      d3.select('#legend')
      	.append('g')
      	.attr('transform', "translate(20,20)")
          .call(legend);
      var content = d3.select('#content');
      var title = d3.select('#title');
      
      // draw pies for each user
      var pie = d3.layout.pie()
				.value(function(type) {return type.tweets.length})
      	.sort(null);
      var arc = d3.svg.arc()
      	.innerRadius(function(type) {return type.data.radius * 0.5})
        .outerRadius(function(type) {return type.data.radius * 0.8});

   		var svg = d3.select('svg');
      var circle = svg.selectAll('g')
        .data(usersSorted)
      	.enter().append('g')
      		.attr('transform', function(d, i) {
            return 'translate(' + ((i % perRow) * width + width / 2) +
              ',' + (Math.floor(i / perRow) * width + width / 2) + ')'
          });
      
			var pie = circle.selectAll('path')
      	.data(function(d) {return pie(d.type)})
        .enter().append('path')
      		.attr("fill", function(type) {return color(type.data.type)})
          .attr("d", arc)
      		.style('cursor', 'pointer')
      		.on('click', function(type) {
            // opacity for selected pie
            pie.attr('fill-opacity', 0.45);
            d3.select(this)
            	.attr('fill-opacity', 1);
            
            // put in the title
            var user = type.data.tweets[0].actor.displayName;
            var tweetLength = type.data.tweets.length;
            var tweetType = type.data.type;
            title.text(user + ' (' + tweetLength + ' ' + tweetType + ')');
            
            console.log(type.data)
            // add the tweets
            var data = content.selectAll('.tweet')
            	.data(type.data.tweets);
            data.enter().append('div')
            	.classed('tweet', true);
            data.exit().remove();
            
            // with the way data inheritance works
            // it's just easier to first remove all children
            // and then re-append them .____.
            data.selectAll('div').remove();
            
           	data.append('div')
              .text(function(d) {return dateFormat(d.date)});
            data.append('div')
              .style('cursor', 'pointer')
              .on('click', function(d) {
              	window.open(d.link, '_new');
              }).text(function(d) {console.log(d); return d.body});
          });
      
      circle.append('text')
      	.attr('y', radius)
      	.attr('text-anchor', 'middle')
      	.attr('dy', '.35em')
      	.style('cursor', 'pointer')
      	.text(function(d) {
        	return d.username + ' (' + d.tweets.length + ')';
      	}).on('click', function(d) {
          window.open('//twitter.com/' + d.username, '_new');
        });
      
    });
  </script>
</body>