Skip to content

Instantly share code, notes, and snippets.

@mmazanec22
Last active September 22, 2017 23:24
Show Gist options
  • Save mmazanec22/321d578efac8a1372eb1a04f2067b56a to your computer and use it in GitHub Desktop.
Save mmazanec22/321d578efac8a1372eb1a04f2067b56a to your computer and use it in GitHub Desktop.
Updating Bar Graph
<!DOCTYPE html>
<html>
<head>
<script src="https://d3js.org/d3.v3.min.js"></script>
<script type="text/javascript" src='./updateHistogram.js'></script>
<link rel="stylesheet" type="text/css" href="./styles.css">
</head>
<body>
<div class='parent-div'></div>
</body>
</html>
html, body {
height: 100%;
width: 100%;
overflow: hidden;
}
.parent-div {
height: 100%;
width: 100%;
}
.bar {
fill-opacity: 0.2;
stroke: white;
fill: dodgerblue;
}
.axis .domain {
stroke: none;
fill: none;
}
.axis text {
fill: dodgerblue;
font-size: 0.6rem;
letter-spacing: 0.05rem;
fill-opacity: 0.8;
}
.axis line {
stroke: dodgerblue;
}
document.addEventListener("DOMContentLoaded", function() {
const parentDiv = d3.select('.parent-div');
const example = new Histogram(parentDiv);
setInterval(function() {
example.update()
}, 2000)
});
class Histogram {
constructor(parentDiv) {
this.parentDiv = parentDiv;
this.width = 900
this.height = 500
this.verticalMargins = 40
this.horizontalMargins = 20
this.originalTimeDomain = [new Date(1980, 1), new Date(2017, 1)]
this.graphWidth = this.width - this.horizontalMargins * 2
this.graphHeight = this.height - this.verticalMargins * 2
this.histX = d3.scale.linear()
.domain(this.originalTimeDomain)
.range([0, this.graphWidth]);
this.histLayout = d3.layout.histogram()
.bins(this.histX.ticks(this.graphWidth / 10))
this.draw()
}
draw() {
const svg = this.parentDiv.append('svg')
.attr('position', 'absolute')
.attr('preserveAspectRatio', 'xMinYMin meet')
.attr('width', this.width)
.attr('height', this.height)
let dataToUse = this.makeData();
const xData = this.histLayout(dataToUse);
const yMax = d3.max(xData, d => d.length);
const y = d3.scale.linear()
.domain([0, yMax])
.range([this.graphHeight, 0]);
const xAxis = d3.svg.axis()
.scale(this.histX)
.orient('top')
.tickFormat(d => new Date(d).getYear());
const barGroup = svg.append('g')
.attr('class', 'bar-group')
const bars = barGroup.selectAll('.bar')
.data(xData);
bars.exit()
.transition()
.duration(750)
.attr('height', 0);
const barWidth = this.graphWidth / xData.length
bars.enter().append('rect')
.attr('class', 'bar')
.attr('y', 0.1)
.attr('height', 0)
.attr('width', barWidth)
.attr('transform', d => `translate(${this.histX(d.x) + this.horizontalMargins}, ${this.verticalMargins})`)
bars.transition()
.duration(750)
.attr('height', d => this.graphHeight - y(d.length));
const xAxisElements = svg.append('g')
.attr('class', 'x axis')
.attr('transform', `translate(${this.horizontalMargins} ${this.verticalMargins})`)
.call(xAxis);
xAxisElements.selectAll('path, line')
.style('shape-rendering', 'crispEdges');
}
update() {
const self = this;
let dataToUse = self.makeData();
const newXData = self.histLayout(dataToUse);
// Max height should be large enough to see the buckets where there is only one;
// but small enough that it looks like bars have changed when they have
const yMax = Math.max(d3.max(newXData, d => d.length), 16 / 2);
const y = d3.scale.linear()
.domain([0, yMax])
.range([self.graphHeight, 0]);
const bars = d3.selectAll('.bar')
.data(newXData);
bars.exit().attr('height', 0);
bars.transition()
.duration(750)
.attr('height', d => self.graphHeight - y(d.length));
}
makeData(length = 500) {
return new Array(500).fill({}).map(function() {
const year = Math.random() * (2017 - 1980) + 1980;
const month = Math.random() * (12 - 1) + 1;
const day = Math.random() * (30 - 1) + 1;
const hours = Math.random() * 23;
const minutes = Math.random() * 59 + 1;
return new Date(year, month, day, hours, minutes);
}).sort((a, b) => a - b)
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment