Shows the distribution of browsers and browser versions of Greasemonkey users over the past six months. Data from addons.mozilla.org, and massaged to a usable format by Yahoo Pipes.
xxxxxxxxxx
<html>
<head>
<title>Greasemonkey users by browser version</title>
<script type="text/javascript" src="https://cdn.jsdelivr.net/npm/d3@1.29.5/d3.js"></script>
<script type="text/javascript" src="https://cdn.jsdelivr.net/npm/d3@1.29.5/d3.layout.js"></script>
<script type="text/javascript" src="https://cdn.jsdelivr.net/npm/d3@1.29.5/d3.time.js"></script>
<script type="text/javascript" src="load_amo_stats.js"></script>
<style type="text/css">
svg {
width: 960px;
height: 500px;
border: solid 1px #ccc;
font: 10px sans-serif;
shape-rendering: crispEdges;
}
body, html { margin: 0; }
.axis {
shape-rendering: crispEdges;
}
.x.axis .minor {
stroke-opacity: .5;
}
.x.axis path {
display: none;
}
.y.axis line, .y.axis path {
fill: none;
stroke: #000;
}
</style>
</head>
<body>
<script type="text/javascript">
var w = 960
, h = 500
, a = 748 // Greasemonkey
, d = 365 >> 1 // number of days; AMO seems to cap somewhere below a year
, p = [20, 80, 30, 20]
, x = d3.scale.ordinal().rangeRoundBands([0, w - p[1] - p[3]])
, y = d3.scale.linear().range([0, h - p[0] - p[2]])
, z = d3.scale.category20c()
, xs = d3.time.scale().range([0, w - p[1] - p[3]])
, xAxis = d3.svg.axis().scale(xs).tickSize(5)
, yAxis = d3.svg.axis().scale(y).ticks(4).orient("right")
, data, folded; // for ease of peeking at the input data from the js console
var svg = d3.select("body").append("svg:svg")
.attr("width", w)
.attr("height", h)
.append("svg:g")
.attr("transform", "translate(" + p[3] + "," + (h - p[2]) + ")");
get_amo_stats(got_amo_stats, a, d);
function got_amo_stats(stats) {
folded = fold_by(data = stats/*, /([^\/]+)\// */);
var apps = Object.keys(folded[0]).filter(function(n) { return /[A-Z]/.test(n); });
draw(folded, apps);
}
// stats: an object with some keys on a "Browser/maj[.min[.build[...]]]" format
// output: ditto but with [.build[...]] keys rolled into "Browser/major" keys
// regexp: if given, a regexp whose first match group defines how to fold keys
// (example: /^(.*\/(?:0|[1-9]\d*\.?\d*))/ folds into x/0, x/1.0, ...)
function fold_by(stats, regexp) {
function fold(obj) {
var data = {}, renamed, key, val;
for (key in obj) {
val = obj[key];
if ((renamed = rename(key)))
data[renamed] = (data[renamed] || 0) + val;
else
data[key] = val;
}
return data;
}
var want = regexp || /^(.*\/\d+)/ // /^(.*\/(?:0|[1-9]\d*\.?\d*))/
, rename = function(k) { var m = want.exec(k); return m && m[1]; };
return stats.map(fold);
}
function dwim_sort(a, b, order) {
function n(c) { return String.fromCharCode(c); }
order = order || d3.ascending;
return order(a.replace(/\d+/g, n), b.replace(/\d+/g, n));
}
function draw(data, keys) {
// Transpose the data into layers by browser name+version.
var values = d3.layout.stack()(keys.map(function(key) {
return data.map(function(d) {
return { x: d.date, y: d[key], n: key };
}).sort(function(a, b) { return dwim_sort(a.n, b.n); });
}));
// Compute the x-domain (by date) and y-domain (by top).
x.domain(values[0].map(function(d) { return d.x; }));
y.domain([0, d3.max(data, function(d) { return d.total; })]).nice();
// Add a group for each browser version
var key = svg.selectAll("g.key")
.data(values)
.enter().append("svg:g")
.attr("class", "key")
.style("fill", function(d, i) { return z(i); })
.style("stroke", function(d, i) { return d3.rgb(z(i)).darker(); });
// ...with a browser name tooltip.
key.append("svg:title").text(function(d) { return d[0].n; });
// Add a rect for each date.
var rect = key.selectAll("rect")
.data(Object)
.enter().append("svg:rect")
.attr("x", function(d) { return x(d.x); })
.attr("y", function(d) { return -y(d.y0) - y(d.y); })
.attr("height", function(d) { return y(d.y); })
.attr("width", x.rangeBand());
y.domain(y.domain().reverse()); // enumerate y axis in [high, low] order
xs.domain([data[0].date, data[data.length-1].date]);
svg.append("svg:g")
.attr("class", "y axis")
.attr("transform", "translate("+ (w - p[1] - p[3]) +","+ (p[0] + p[2] - h) +")")
.call(yAxis);
// Add the x-axis.
svg.append("svg:g")
.attr("class", "x axis")
.call(xAxis);
}
</script>
</body>
</html>
Modified http://mbostock.github.com/d3/d3.js?1.29.1 to a secure url
Modified http://mbostock.github.com/d3/d3.layout.js?1.29.1 to a secure url
Modified http://mbostock.github.com/d3/d3.time.js?1.29.1 to a secure url
https://mbostock.github.com/d3/d3.js?1.29.1
https://mbostock.github.com/d3/d3.layout.js?1.29.1
https://mbostock.github.com/d3/d3.time.js?1.29.1