Skip to content

Instantly share code, notes, and snippets.

@willkg
Last active May 31, 2020 03:13
Show Gist options
  • Save willkg/c4d5a272f86ae4510750 to your computer and use it in GitHub Desktop.
Save willkg/c4d5a272f86ae4510750 to your computer and use it in GitHub Desktop.
Proof of concept for d3-izing Input data

This is a proof of concept for using Input data with d3 to generate your own dashboard.

Fork this gist and tweak your own dashboard. Keep in mind that Input requests are throttled. If you're tweaking things, you might want to switch to the stage server at input.allizom.org and then switch to the prod server when your code is more stable.

If you have an interesting dashboard, let me know!

Thanks to:

  • Mike for d3.nest tweaks in POC code
  • Ricky for doing a last-minute review of the code for the new API bits this required
  • Matt for organizing d3 training which gave me the idea

/will

willkg AT mozilla DOT com

<!DOCTYPE html>
<head>
<meta charset="utf-8" />
<style>
.last div {
background: #ffffcc;
border-radius: 5px;
border: 2px solid #ffff44;
color: black;
margin: 1em;
padding: 1em;
}
.chart rect {
fill: steelblue;
}
.chart text {
fill: black;
font: 10px sans-serif;
}
</style>
<body>
<p>
Last day of happy responses broken down by product:
</p>
<svg class="chart"></svg>
<p>
Most recent happy responses:
</p>
<div class="last"></div>
<script src="http://d3js.org/d3.v3.min.js"></script>
<script src="main.js"></script>
</body>
"use strict";
var inputUrl = "https://input.mozilla.org/api/v1/feedback/?happy=1&date_delta=1d&format=json";
var width = 420,
barHeight = 20;
var x = d3.scale.linear()
.range([0, width]);
var chart = d3.select(".chart")
.attr("width", width);
var last = d3.select(".last");
var barsSVG = chart.append('g')
.classed('bars', true);
var labelsSVG = chart.append('g')
.classed('labels', true);
var updateData = function() {
var url = inputUrl + '&foo=' + Date.now();
d3.json(url, function(error, data) {
var productData;
console.log(error);
console.log(data);
// Make an aggregator that splits data by product name, and then reduces
// the groups by counting the number of elements in it.
var aggregator = d3.nest()
.key(function(d) {
return d.product = d.product || 'Unknown';
})
.rollup(function(group) {
return {name: group[0].product, value: group.length};
});
// Apply the aggregator and retrieve values. Add Total. Sort
// by length.
productData = aggregator.map(data.results, d3.map).values();
productData.push({name: 'Total', value: data.count})
productData.sort(function(a, b) { return d3.descending(a.value, b.value); });
console.log('data', productData);
x = x.domain([0, d3.max(productData, function(d) { return d.value; })]);
// Data join
var bars = barsSVG.selectAll('rect').data(productData);
var labels = labelsSVG.selectAll('text').data(productData);
var recent = last.selectAll('div')
.data(data.results.slice(0, 10).reverse(), function(d) { return d.created + d.description; });
// Enter
bars.enter()
.append('rect');
labels.enter()
.append('text');
recent.enter()
.insert('div', ':first-child')
.style('opacity', 0)
.transition()
.duration(2000)
.text(function (d) { return d.created + ': ' + d.description; })
.style('opacity', 1);
// Update
bars.attr('x', 0)
.attr('y', function(d, i) { return i * barHeight; })
.attr("height", barHeight - 1)
.attr("width", 0)
.transition()
.attr("width", function(d) { return x(d.value); });
labels.attr("x", function(d) { return 5; })
.attr("y", function(d, i) { return (i + 0.6) * barHeight; })
.text(function(d) { return d.name + ': ' + d.value; })
.style('text-anchor', 'middle-left');
// Exit
bars.exit()
.transition()
.attr("width", 0)
.remove();
labels.exit().remove();
recent.exit().remove();
});
};
updateData();
// Pulls recent data every 2 minutes.
setInterval(updateData, 120000);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment