Skip to content

Instantly share code, notes, and snippets.

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

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); })

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">
.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;
<script src="//"></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()
var svg ="body").append("svg")
.attr("width", width)
.attr("height", height)
.attr("transform", "translate(" + width / 2 + "," + height / 2 + ")");
var meter = svg.append("g")
.attr("class", "progress-meter");
.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("" + 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));
.get(function(error, data) {
meter.transition().delay(250).attr("transform", "scale(0)");
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment