Review the differences between the two methods to learn a little bit more about how functional/declarative programming abstracts away the pain of iterative programming.
Approach with D3 idioms:
fiddle: http://jsfiddle.net/blakedietz/E66eT/1/
update: D3 Way
<!DOCTYPE html>
<html>
<head>
<title></title>
<style>
body {
background: #192887;
}
.graticule {
fill: none;
stroke: #fff;
stroke-width: .5px;
}
.land {
fill: #007421;
}
.dot {
fill: #c7141a;
}
.ring {
fill: none;
stroke: #c7141a;
}
</style>
<script src="http://d3js.org/d3.v3.min.js" charset="utf-8"></script>
</head>
<body>
<script>
var width = 960,
height = 500;
var projection = d3.geo.mercator()
.center([113, -3])
.scale(1275)
.translate([width / 2, height / 2])
.clipExtent([[0, 0], [width, height]])
.precision(.1);
var path = d3.geo.path()
.projection(projection);
var graticule = d3.geo.graticule()
.step([5, 5]);
var svg = d3.select("body").append("svg")
.attr("width", width)
.attr("height", height);
svg.append("path")
.datum(graticule)
.attr("class", "graticule")
.attr("d", path);
var data = [{x:-8,y:100},{x:-10,y:110},{x: -12,y:120}];
svg.selectAll("circle")
.data(data)
.enter()
.append("circle")
.attr("class","dot")
.attr("transform",translateCircle)
.attr("r",8);
function translateCircle(datum, index)
{
return "translate(" + projection([datum.y, datum.x]) + ")";
};
setInterval(function(){
svg
.selectAll("ring")
.data(data)
.enter()
.append("circle")
.attr("class", "ring")
.attr("transform", translateCircle)
.attr("r", 6)
.style("stroke-width", 3)
.style("stroke", "red")
.transition()
.ease("linear")
.duration(6000)
.style("stroke-opacity", 1e-6)
.style("stroke-width", 1)
.style("stroke", "brown")
.attr("r", 160)
.remove();
}, 750)
d3.select(self.frameElement).style("height", height + "px");
</script>
</body>
</html>
So I didn't create a fully d3 idiomatic approach for this solution, but it will work. If you can get this to work implicitly within a svg.selectAll("circle"/"unique selection"...), etc, that would be even more awesome. I'll work on that in the mean time. Until then there's this more explicitly iterative approach.
With Mike's example you're only appending a single element to the D.O.M. in the setInterval
call. In order to expedite the binding process, I've created a projection method which operates on a set of coordinates: the translateCircle will operate on a datum within a collection of coordinates allowing access to the internal attributes of each collection element.
Within each setInterval
call the forEach
method iterates over the collection of coordinates and then calls the same internals within the setInterval
method that was called by Mike originally.
Not So D3
<style>
body {
background: #192887;
}
.graticule {
fill: none;
stroke: #fff;
stroke-width: .5px;
}
.land {
fill: #007421;
}
.dot {
fill: #c7141a;
}
.ring {
fill: none;
stroke: #c7141a;
}
</style>
<script src="http://d3js.org/d3.v3.min.js" charset="utf-8"></script>
</head>
<body>
<script>
var width = 960,
height = 500;
var projection = d3.geo.mercator()
.center([113, -3])
.scale(1275)
.translate([width / 2, height / 2])
.clipExtent([[0, 0], [width, height]])
.precision(.1);
var path = d3.geo.path()
.projection(projection);
var graticule = d3.geo.graticule()
.step([5, 5]);
var svg = d3.select("body").append("svg")
.attr("width", width)
.attr("height", height);
svg.append("path")
.datum(graticule)
.attr("class", "graticule")
.attr("d", path);
var data = [{x:-8,y:100},{x:-10,y:110},{x: -12,y:120}];
svg.selectAll("circle")
.data(data)
.enter()
.append("circle")
.attr("class","dot")
.attr("transform",translateCircle)
.attr("r",8);
function translateCircle(datum, index)
{
return "translate(" + projection([datum.y, datum.x]) + ")";
};
setInterval(function(){
data.forEach(function(datum)
{
svg
.append("circle")
.attr("class", "ring")
.attr("transform", translateCircle(datum))
.attr("r", 6)
.style("stroke-width", 3)
.style("stroke", "red")
.transition()
.ease("linear")
.duration(6000)
.style("stroke-opacity", 1e-6)
.style("stroke-width", 1)
.style("stroke", "brown")
.attr("r", 160)
.remove();
})
}, 750)
d3.select(self.frameElement).style("height", height + "px");
</script>
</body>
</html>