Skip to content

Instantly share code, notes, and snippets.

@mbostock
Last active October 10, 2019 18:06
Show Gist options
  • Save mbostock/3750941 to your computer and use it in GitHub Desktop.
Save mbostock/3750941 to your computer and use it in GitHub Desktop.
Progress Events
license: gpl-3.0
redirect: https://observablehq.com/@mbostock/fetch-progress

This example demonstrates how to display the progress of an asynchronous request. Rather than saying d3.json(url, callback), use d3.json(url) to first create the request object, then register a "progress" event listener with xhr.on before starting the request with xhr.get.

You can also use this pattern to listen to "load" and "success" events separately. For example:

var xhr = d3.json(url)
    .on("progress", function() { console.log("progress", d3.event.loaded); })
    .on("load", function(json) { console.log("success!", json); })
    .on("error", function(error) { console.log("failure!", error); })
    .get();

This pattern also lets you cancel in-progress requests using xhr.abort, register custom headers with xhr.header, and even change the HTTP method and request body using xhr.send.

<!DOCTYPE html>
<meta charset="utf-8">
<style>
.progress-meter .background {
fill: #ccc;
}
.progress-meter .foreground {
fill: #000;
}
.progress-meter text {
font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
font-size: 24px;
font-weight: bold;
}
</style>
<body>
<script src="//d3js.org/d3.v3.min.js"></script>
<script>
var width = 960,
height = 500,
twoPi = 2 * Math.PI,
progress = 0,
total = 1308573, // must be hard-coded if server doesn't report Content-Length
formatPercent = d3.format(".0%");
var arc = d3.svg.arc()
.startAngle(0)
.innerRadius(180)
.outerRadius(240);
var svg = d3.select("body").append("svg")
.attr("width", width)
.attr("height", height)
.append("g")
.attr("transform", "translate(" + width / 2 + "," + height / 2 + ")");
var meter = svg.append("g")
.attr("class", "progress-meter");
meter.append("path")
.attr("class", "background")
.attr("d", arc.endAngle(twoPi));
var foreground = meter.append("path")
.attr("class", "foreground");
var text = meter.append("text")
.attr("text-anchor", "middle")
.attr("dy", ".35em");
d3.json("https://api.github.com/repos/mbostock/d3/git/blobs/2e0e3b6305fa10c1a89d1dfd6478b1fe7bc19c1e?" + Math.random())
.on("progress", function() {
var i = d3.interpolate(progress, d3.event.loaded / total);
d3.transition().tween("progress", function() {
return function(t) {
progress = i(t);
foreground.attr("d", arc.endAngle(twoPi * progress));
text.text(formatPercent(progress));
};
});
})
.get(function(error, data) {
meter.transition().delay(250).attr("transform", "scale(0)");
});
</script>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment