I have a JSON dataset that consists of an array of frames, with each frame containing an array of 10 nodes. Each node is represented as a dictionary with the node id and x,y coordinates. My objective is to devise a d3 animation that smoothly transitions between the positions of nodes in consecutive frames.
To achieve this, I initiated setInterval(...) to facilitate the transitions to the next set of node positions. Nevertheless, instead of smoothly updating the existing nodes through the transition process, a batch of new nodes are being added. I speculate whether I might be erring in implementing the key function, or if there's another flaw at play?
Below is an excerpt illustrating what the JSON data appears like:
[[{"y": "0.898287995669", "x": "0.824201870934", "v": "0"}, {"y": "0.738482578278", "x": "0.645352934631", "v": "1"}, {"y": "0.12255740116", "x": "0.113578656145", "v": "2"}, {"y": "0.603047665154", "x": "0.609252770235", "v": "3"}, {"y": "0.497780597993", "x": "0.490370637301", "v": "4"}, {"y": "0.450309984776", "x": "0.428403273731", "v": "5"}, {"y": "0.512235180495", "x": "0.552584811488", "v": "6"}, {"y": "0.808721117001", "x": "0.829379563316", "v": "7"}, {"y": "0.771161177414", "x": "0.378854605349...
And here's my current code snippet:
var width = 960,
height = 500;
var padding = 10;
// Inverted due to SVG's inverted y axis
var yscale = d3.scale.linear().domain([1,0]).range([padding, height - padding]);
var xscale = d3.scale.linear().domain([0,1]).range([padding, width - padding]);
var color = d3.scale.category20();
var svg = d3.select("body").append("svg")
.attr("width", width)
.attr("height", height);
d3.json("out.json", function(error, json) {
if (error) return console.warn(error);
var graphFrames = json;
startDrawing(graphFrames);
});
function drawFrame(graphFrame) {
// DATA JOIN
// Join new data with old elements, if any.
var nodes = svg.selectAll("node")
.data(graphFrame, function(d){ return d.v; });
// UPDATE
// Update old elements as needed.
nodes.transition()
.duration(750)
.attr("cx", function(d) { return xscale(d.x); })
.attr("cy", function(d) { return yscale(d.y); });
// ENTER
// Create new elements as needed.
nodes.enter().append("circle")
.attr("class", "node")
.attr("r", 5)
.attr("cx", function(d) { return xscale(d.x); })
.attr("cy", function(d) { return yscale(d.y); })
.style("fill", function(d, i){ return color(d.v % 20); });
// EXIT
// Remove old elements as needed.
//nodes.exit().remove();
}
var nextFrameIdx = 1;
function startDrawing(graphFrames){
// Initial display.
drawFrame(graphFrames[0]);
// Draw the next set of node coordinates at regular intervals
setInterval(function() {
drawFrame(graphFrames[nextFrameIdx]);
nextFrameIdx = (nextFrameIdx + 1) % graphFrames.length;
}, 1500);
}