Skip to content

Instantly share code, notes, and snippets.

@sxywu
Last active April 30, 2016 14:42
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
Star You must be signed in to star a gist
Save sxywu/9ea31a49cc0af1fdeed189619f651f5b to your computer and use it in GitHub Desktop.
openvis tweets #3
<!DOCTYPE html>
<head>
<meta charset="utf-8">
<script src="https://fb.me/react-0.14.3.js"></script>
<script src="https://fb.me/react-dom-0.14.3.js"></script>
<script src="https://npmcdn.com/babel-core@5.8.34/browser.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.5/d3.min.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;
color: #49438C;
}
svg {
width: 100%;
height: 125px;
}
text {
font-size: .8em;
}
.axis path,
.axis line {
fill: none;
stroke: #000;
shape-rendering: crispEdges;
}
a {
color: #fe2b75;
}
</style>
</head>
<body>
<div id='main'></div>
<script type="text/babel">
var padding = {top: 25, left: 50};
var colors = {purple: '#49438C', pink: '#fe2b75'};
var startDate = new Date('2016-04-25T00:00:00-04:00');
var endDate = new Date('2016-04-27T00:00:00-04:00');
var dateFormat = d3.time.format('%x %I:%M%p');
var Histogram = React.createClass({
getInitialState() {
return {
width: window.innerWidth - padding.left * 2,
height: 75,
bars: [],
};
},
componentWillMount() {
this.timeScale = d3.time.scale()
.domain([startDate, endDate])
.range([0, this.state.width]);
this.heightScale = d3.scale.linear()
.range([5, this.state.height]);
this.axis = d3.svg.axis()
.orient('bottom')
.ticks(d3.time.hours, 6)
.scale(this.timeScale);
},
componentDidMount() {
this.axisG = d3.select(this.refs.axis);
},
componentWillReceiveProps(nextProps) {
var minHeight = d3.min(nextProps.tweetsByTime, time => time.tweets.length);
var maxHeight = d3.max(nextProps.tweetsByTime, time => time.tweets.length);
this.heightScale.domain([minHeight, maxHeight]);
var bars = [];
_.each(nextProps.tweetsByTime, (time) => {
bars.push({
data: time,
x: Math.floor(this.timeScale(time.date) * 100) / 100,
height: Math.floor(this.heightScale(time.tweets.length) * 100) / 100,
selected: time === nextProps.selectedTime,
});
});
this.setState({bars});
},
componentDidUpdate() {
this.axisG.call(this.axis);
},
onClick(bar) {
this.props.onClick(bar);
},
render() {
var barWidth = Math.floor(this.state.width / this.state.bars.length);
var bars = _.map(this.state.bars, (bar, i) => {
var x = bar.x - (barWidth / 2);
var y = this.state.height - bar.height;
var barStyle = {
fill: bar.selected ? colors['pink'] : colors['purple'],
fillOpacity: 0.5,
cursor: 'pointer',
}
return (<rect key={i} x={x} y={y} width={barWidth} height={bar.height}
style={barStyle} onClick={this.onClick.bind(this, bar.data)} />);
});
var axis = (<g className='axis' ref='axis'
transform={'translate(0,' + this.state.height + ')'} />);
return (
<svg>
<g transform={'translate(' + padding.left + ',' + padding.top + ')'}>
{bars}
{axis}
</g>
</svg>
);
}
});
var App = React.createClass({
getInitialState() {
return {
tweets: {},
tweetsByTime: [],
selectedTime: {},
};
},
componentWillMount() {
d3.json('tweets.json', tweets => {
tweets = _.chain(tweets)
.filter(tweet => {
tweet.date = new Date(tweet.postedTime);
return startDate <= tweet.date && tweet.date <= endDate;
}).sortBy(tweet => tweet.date)
.reduce((obj, tweet) => {
obj[tweet.link] = tweet;
return obj;
}, {})
.value();
// group by every 5min
var coeff = 1000 * 60 * 15;
var tweetsByTime = _.chain(tweets)
.groupBy(tweet => {
tweet.dateRounded = Math.floor(tweet.date.getTime() / coeff) * coeff;
return tweet.dateRounded;
}).map((tweets, time) => {
return {
date: new Date(parseInt(time)),
tweets: tweets,
}
}).value();
this.setState({tweets, tweetsByTime});
});
},
onClickBar(selectedTime) {
this.setState({selectedTime});
},
render() {
var tweetStyle = {
padding: '10px',
};
var tweets = _.map(this.state.selectedTime.tweets, (tweet, i) => {
return (
<div key={i} style={tweetStyle}>
<strong>{tweet.actor.displayName}</strong> (<a href={tweet.link} target='_new'>{dateFormat(tweet.date)}</a>)
<div dangerouslySetInnerHTML={{__html: tweet.body}} />
</div>
);
});
return (
<div>
<div style={{padding: padding.left}}>
Tweets with #openvisconf or @openvisconf. Click on bars to see tweets from that time block.
</div>
<Histogram {...this.state} onClick={this.onClickBar} />
<div style={tweetStyle}>
{tweets}
</div>
</div>
);
},
});
ReactDOM.render(
<App />,
document.getElementById('main')
);
</script>
</body>
This file has been truncated, but you can view the full file.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment