Reputation: 573
I'd like your assistance in building a kind of 'gauge', an 'arc' based circle that would populate a value from 0 to 100 dynamically (8 gauges).
I was able to get this working (based on Arc Clock gist https://gist.github.com/mbostock/1098617), but now I'm trying to force a transition on every update and on the start.
I'm trying to implement the following flow: 1. arch loaded - goes from 0 to 100 -> from 100 to initial value 2. arch updated - goes from previous value to 0 -> from 0 to new value
Can't seem to find the right way to implement this...
The values are currently being inserted at random (10 increments)
var w = 1500,
h = 300,
x = d3.scale.ordinal().domain(d3.range(8)).rangePoints([0, w], 2);
var fields = [
{ name: "A", value: 100, previous: 0, size: 100 },
{ name: "B", value: 100, previous: 0, size: 100 },
{ name: "C", value: 100, previous: 0, size: 100 },
{ name: "D", value: 100, previous: 0, size: 100 },
{ name: "E", value: 100, previous: 0, size: 100 },
{ name: "F", value: 100, previous: 0, size: 100 },
{ name: "G", value: 100, previous: 0, size: 100 },
{ name: "H", value: 100, previous: 0, size: 100 }
];
var arc = d3.svg.arc()
.innerRadius(40)
.outerRadius(60)
.startAngle(0)
.endAngle(function (d) { return (d.value / d.size) * 2 * Math.PI; });
var svg = d3.select("body").append("svg:svg")
.attr("width", w)
.attr("height", h)
.append("svg:g")
.attr("transform", "translate(0," + (h / 2) + ")");
var path = svg.selectAll("path")
.data(fields.filter(function (d) { return d.value; }), function (d) { return d.name; })
.enter().append("svg:path")
.attr("transform", function (d, i) { return "translate(" + x(i) + ",0)"; })
.transition()
.ease("liniar")
.duration(750)
.attrTween("d", arcTween);
setTimeout(function () { services() }, 750);
setInterval(function () { services(); }, 5000);
function services() {
for (var i = 0; i < fields.length; i++) {
fields[i].previous = fields[i].value;
fields[i].value = Math.floor((Math.random() * 100) + 1);
}
path = svg.selectAll("path").data(fields.filter(function (d) { return d.value; }), function (d) { return d.name; });
path.transition()
.ease("linear")
.duration(1600)
.attrTween("d", arcTweenReversed);
}
function arcTween(b) {
var i = d3.interpolate({ value: b.previous }, b);
return function (t) {
return arc(i(t));
};
}
Here is JSFiddle to see it live: http://jsfiddle.net/p5xWZ/2/ Thanks in advance!
Upvotes: 2
Views: 2389
Reputation: 16659
Something like the following chain transition could complete the arc and then go back to the next value:
path.transition()
.ease("linear")
.duration(function(d, i) { return 1600 * ((d.size-d.value)/d.size); })
.delay(function(d, i) { return i * 10; })
.attrTween("d", completeArc)
.transition()
.ease("linear")
.duration(function(d, i) { return 1600 * (d.value/d.size); })
.attrTween("d", resetArc)
.style("fill", function (d) { if (d.value < 100) { return "green"; } else { return "red" } });
Where completing the arc goes to 100, and resetting the arc goes from 0 to the next value:
function completeArc(b) {
// clone the data for the purposes of interpolation
var newb = $.extend({}, b);
// Set to 100
newb.value = newb.size;
var i = d3.interpolate({value: newb.previous}, newb);
return function(t) {
return arc(i(t));
};
}
function resetArc(b) {
var i = d3.interpolate({value: 0}, b);
return function(t) {
return arc(i(t));
};
}
Fiddle here also with fill color added.
Upvotes: 2