restructure d3 model data so that nodes can be presented in a different order than the corresponding data index. This allows nodes to be brought to front when mouse over
diff --git a/web/ons-demo/js/app.js b/web/ons-demo/js/app.js
index 825b1a3..4930ddb 100644
--- a/web/ons-demo/js/app.js
+++ b/web/ons-demo/js/app.js
@@ -123,11 +123,31 @@
 		rings[2].angles[i] = rings[1].angles[index];
 	});
 
+	// TODO: construct this form initially rather than converting. it works better because
+	// it allows binding by dpid
+	var testRings = [];
+	rings.forEach(function (ring) {
+		var testRing = [];
+		ring.switches.forEach(function (s, i) {
+			var testSwitch = {
+				dpid: s.dpid,
+				state: s.state,
+				radius: ring.radius,
+				width: ring.width,
+				className: ring.className,
+				angle: ring.angles[i],
+				controller: s.controller
+			}
+			testRing.push(testSwitch);
+		});
 
 
+		testRings.push(testRing);
+	});
 
 
-	return rings;
+//	return rings;
+	return testRings;
 }
 
 function updateTopology(svg, model) {
@@ -136,44 +156,50 @@
 	var rings = svg.selectAll('.ring').data(createRingsFromModel(model));
 
 	function ringEnter(data, i) {
-		if (!data.switches.length) {
+		if (!data.length) {
 			return;
 		}
 
 		// create the nodes
 		var nodes = d3.select(this).selectAll("g")
-			.data(d3.range(data.switches.length).map(function() {
-				return data;
-			}))
+			.data(data, function (data) {
+				return data.dpid;
+			})
 			.enter().append("svg:g")
 			.classed('nolabel', true)
-			.attr("id", function (_, i) {
-				return data.switches[i].dpid;
+			.attr("id", function (data, i) {
+				return data.dpid;
 			})
-			.attr("transform", function(_, i) {
-				return "rotate(" + data.angles[i]+ ")translate(" + data.radius * 150 + ")rotate(" + (-data.angles[i]) + ")";
+			.attr("transform", function(data, i) {
+				return "rotate(" + data.angle+ ")translate(" + data.radius * 150 + ")rotate(" + (-data.angle) + ")";
 			});
 
 		// add the cirles representing the switches
 		nodes.append("svg:circle")
-			.attr("transform", function(_, i) {
+			.attr("transform", function(data, i) {
 				var m = document.querySelector('#viewbox').getTransformToElement().inverse();
 				if (data.scale) {
 					m = m.scale(data.scale);
 				}
 				return "matrix( " + m.a + " " + m.b + " " + m.c + " " + m.d + " " + m.e + " " + m.f + " )";
 			})
-			.attr("x", -data.width / 2)
-			.attr("y", -data.width / 2)
-			.attr("r", data.width)
+			.attr("x", function (data) {
+				return -data.width / 2;
+			})
+			.attr("y", function (data) {
+				return -data.width / 2;
+			})
+			.attr("r", function (data) {
+				return data.width;
+			})
 
 		// setup the mouseover behaviors
 		function showLabel(data, index) {
-			d3.select(document.getElementById(data.switches[index].dpid + '-label')).classed('nolabel', false);
+			d3.select(document.getElementById(data.dpid + '-label')).classed('nolabel', false);
 		}
 
 		function hideLabel(data, index) {
-			d3.select(document.getElementById(data.switches[index].dpid + '-label')).classed('nolabel', true);
+			d3.select(document.getElementById(data.dpid + '-label')).classed('nolabel', true);
 		}
 
 		nodes.on('mouseover', showLabel);
@@ -187,10 +213,13 @@
 
 
 	function ringUpdate(data, i) {
-		nodes = d3.select(this).selectAll("circle");
-		nodes.attr('class', function (_, i)  {
-				if (data.switches[i].state == 'ACTIVE') {
-					return data.className + ' ' + controllerColorMap[data.switches[i].controller];
+		nodes = d3.select(this).selectAll("g")
+			.data(data, function (data) {
+				return data.dpid;
+			})
+		nodes.select('circle').attr('class', function (data, i)  {
+				if (data.state == 'ACTIVE') {
+					return data.className + ' ' + controllerColorMap[data.controller];
 				} else {
 					return data.className + ' ' + 'colorInactive';
 				}
@@ -207,30 +236,30 @@
 	var labelRings = svg.selectAll('.labelRing').data(createRingsFromModel(model));
 
 	function labelRingEnter(data, i) {
-		if (!data.switches.length) {
+		if (!data.length) {
 			return;
 		}
 
 		// create the nodes
 		var nodes = d3.select(this).selectAll("g")
-			.data(d3.range(data.switches.length).map(function() {
-				return data;
-			}))
+			.data(data, function (data) {
+				return data.dpid;
+			})
 			.enter().append("svg:g")
 			.classed('nolabel', true)
-			.attr("id", function (_, i) {
-				return data.switches[i].dpid + '-label';
+			.attr("id", function (data, i) {
+				return data.dpid + '-label';
 			})
-			.attr("transform", function(_, i) {
-				return "rotate(" + data.angles[i]+ ")translate(" + data.radius * 150 + ")rotate(" + (-data.angles[i]) + ")";
+			.attr("transform", function(data, i) {
+				return "rotate(" + data.angle+ ")translate(" + data.radius * 150 + ")rotate(" + (-data.angle) + ")";
 			});
 
 		// add the text nodes which show on mouse over
 		nodes.append("svg:text")
-				.text(function (d, i) {return d.switches[i].dpid})
+				.text(function (data, i) {return data.dpid})
 				.attr("x", 0)
 				.attr("y", 0)
-				.attr("transform", function(_, i) {
+				.attr("transform", function(data, i) {
 					var m = document.querySelector('#viewbox').getTransformToElement().inverse();
 					if (data.scale) {
 						m = m.scale(data.scale);
@@ -250,18 +279,18 @@
 
 	// do mouseover zoom on edge nodes
 	function zoom(data, index) {
-		var g = d3.select(document.getElementById(data.switches[index].dpid)).select('circle');
-			g.transition().duration(100).attr("r", g.data()[0].width*3);
+		var g = d3.select(document.getElementById(data.dpid)).select('circle');
+			g.transition().duration(100).attr("r", data.width*3);
 			// TODO: this doesn't work because the data binding is by index
-//			d3.select(this.parentNode).moveToFront();
+			d3.select(this.parentNode).moveToFront();
 	}
 
 	svg.selectAll('.edge').on('mouseover', zoom);
 	svg.selectAll('.edge').on('mousedown', zoom);
 
 	function unzoom(data, index) {
-		var g = d3.select(document.getElementById(data.switches[index].dpid)).select('circle');
-			g.transition().duration(100).attr("r", g.data()[0].width);
+		var g = d3.select(document.getElementById(data.dpid)).select('circle');
+			g.transition().duration(100).attr("r", data.width);
 	}
 	svg.selectAll('.edge').on('mouseout', unzoom);
 
@@ -309,6 +338,7 @@
 
 	// remove old links
 	links.exit().remove();
+
 }
 
 function updateControllers(model) {