Create a gist now

Instantly share code, notes, and snippets.

@cmdoptesc /README.md forked from mbostock/.block
Last active Aug 29, 2015

What would you like to do?
D3 Arc Progress Gauge / Meter (for d3-js group)

D3: Async Arc Progress Gauge / Meter

View on bl.ocks.org/cmdoptesc/e9b3bfc6f43b4bd237e2

Forked from Bostock's original Progress Events example to answer Rex X's post on the d3-js group:

The progress meter is based on the number of files that have downloaded. In our case, numberOfFiles is set to 20.

We then generate 20 random durations between 0 - 3000ms to simulate download times, and call setTimeout using the durations. Each timer then calls update, which increments the number of files downloaded, increasing the progress arc with a tweening function.

If you open up the console (CMD + OPT + J / CTRL + SHIFT + J), you can see the async events firing.

Also, it should be noted that unlike Bostock's earlier arc tween example, we're not following the usual D3 conventions by binding data to any SVG elements and updating the data.

al lin, jul 2015

<!DOCTYPE html>
<meta charset="utf-8">
<head>
<title>D3 Async Arc Progress Gauge / Meter</title>
<style>
.progress-meter .background {
fill: #ddd;
}
.progress-meter .foreground {
fill: rgb(192, 192, 192);
}
.progress-meter text {
font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
font-size: 24px;
font-weight: bold;
}
</style>
</head>
<body>
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.5/d3.min.js"></script>
<script>
// be sure to check out the console logs to see the async events!
var width = 960,
height = 500,
twoPi = 2 * Math.PI,
progress = 0,
total = 0,
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));
// if you're going off Bostock's original ArcTween example
// (http://bl.ocks.org/mbostock/5100636), you would bind the arc angle
// to the SVG as a data attribute like this:
//
// meter.append("path")
// .datum({endAngle: twoPi})
// .attr("class", "background")
// .attr("d", arc);
var foreground = meter.append("path")
.attr("class", "foreground");
var text = meter.append("text")
.attr("text-anchor", "middle")
.attr("dy", ".35em");
// = = = = = Breaking off from Bostock's example = = = = =
// used to to create dummy data
var generateDurations = function(numberOfFiles) {
var i = 0, durations = [];
for(i=0; i<numberOfFiles; i++) {
durations.push(Math.floor(Math.random() * 3000));
}
return durations;
}
var count = 0;
var update = function(fileNumber) {
console.log("File "+ (fileNumber+1) + " downloaded.");
count++;
var interp = d3.interpolate(progress, count / total);
d3.transition().duration(400).tween("progressName", function() {
return function(t) {
progress = interp(t);
foreground.attr("d", arc.endAngle(twoPi * progress))
.style("fill", function() {
// not necessary -- just makes the arc darker as it progresses
var gray = Math.floor(12 - (12*progress)) * 16;
return "rgb("+ gray +","+ gray +","+ gray +")";
});
text.text(formatPercent(progress));
};
});
if(count >= total) {
meter.transition().delay(250).attr("transform", "scale(0)");
}
};
var initialize = function() {
var numberOfFiles = 20;
var fileDurations = generateDurations(numberOfFiles);
total = numberOfFiles;
var i = 0;
for(i=0; i<fileDurations.length; i++) {
console.log("Setting a "+ fileDurations[i] + "ms timeout for File "+ (i+1))
setTimeout(function(that) {
// using a closure to capture the value of i at this moment in the loop
return function() {
update(that);
};
}(i), fileDurations[i]);
}
}();
</script>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment