dynamic update for links/switches
diff --git a/web/ons-demo/css/skin.default.css b/web/ons-demo/css/skin.default.css
index 6ff36ab..5063039 100644
--- a/web/ons-demo/css/skin.default.css
+++ b/web/ons-demo/css/skin.default.css
@@ -121,6 +121,13 @@
pointer-events: auto;
}
+.colorInactive {
+ opacity: 1;
+ fill: #444;
+ background-color: #444;
+ color: #222;
+}
+
.color0 {
opacity: .2;
pointer-events: none;
diff --git a/web/ons-demo/data/configuration.json b/web/ons-demo/data/configuration.json
index ab304eb..b36fced 100644
--- a/web/ons-demo/data/configuration.json
+++ b/web/ons-demo/data/configuration.json
@@ -5,14 +5,7 @@
"00:00:20:4e:7f:51:8a:35",
"00:00:00:00:00:00:ba:12",
"00:00:00:00:ba:5e:ba:13",
- "00:00:00:16:97:08:9a:46",
-
- "00:00:0e:46:7a:3a:69:45",
- "00:00:16:00:9d:ff:8f:4f",
- "00:00:5e:80:3f:db:d7:4d",
- "00:00:82:4f:75:82:a3:4b",
- "00:00:36:7d:90:c9:4f:49",
- "00:00:4e:27:27:d7:48:45"
+ "00:00:00:16:97:08:9a:46"
],
"aggregation": [
"00:00:00:00:00:00:01:01",
@@ -23,5 +16,26 @@
"00:00:00:00:00:00:06:01",
"00:00:00:00:00:00:07:01",
"00:00:00:00:00:00:08:01"
- ]
+ ],
+ "association": {
+ "00:00:00:08:a2:08:f9:01": [
+ "00:00:00:00:00:00:03:01"
+ ],
+ "00:00:00:00:ba:5e:ba:11": [
+ "00:00:00:00:00:00:02:01"
+ ],
+ "00:00:20:4e:7f:51:8a:35": [
+ "00:00:00:00:00:00:07:01"
+ ],
+ "00:00:00:00:00:00:ba:12": [
+ "00:00:00:00:00:00:04:01",
+ "00:00:00:00:00:00:05:01"
+ ],
+ "00:00:00:00:ba:5e:ba:13": [
+ "00:00:00:00:00:00:06:01"
+ ],
+ "00:00:00:16:97:08:9a:46": [
+ "00:00:00:00:00:00:08:01"
+ ]
+ }
}
\ No newline at end of file
diff --git a/web/ons-demo/js/app.js b/web/ons-demo/js/app.js
index 0a16fc2..432710f 100644
--- a/web/ons-demo/js/app.js
+++ b/web/ons-demo/js/app.js
@@ -36,9 +36,7 @@
return angle * (Math.PI / 180);
}
-function updateTopology(svg, model) {
-
- // DRAW THE NODES
+function createRingsFromModel(model) {
var rings = [{
radius: 3,
width: 6,
@@ -80,8 +78,6 @@
} else {
aggRange.max = angle;
}
-
-
});
// arrange aggregation switches to "fan out" to edge switches
@@ -96,39 +92,35 @@
// find the association between core switches and aggregation switches
var aggregationSwitchMap = {};
model.aggregationSwitches.forEach(function (s, i) {
- aggregationSwitchMap[s.dpid] = i + 1;
+ aggregationSwitchMap[s.dpid] = i;
});
- var coreSwitchMap = {};
- model.coreSwitches.forEach(function (s, i) {
- coreSwitchMap[s.dpid] = i + 1;
- });
-
- var coreLinks = {};
- model.links.forEach(function (l) {
- if (aggregationSwitchMap[l['src-switch']] && coreSwitchMap[l['dst-switch']]) {
- coreLinks[l['dst-switch']] = aggregationSwitchMap[l['src-switch']] - 1;
- }
- if (aggregationSwitchMap[l['dst-switch']] && coreSwitchMap[l['src-switch']]) {
- coreLinks[l['src-switch']] = aggregationSwitchMap[l['dst-switch']] - 1;
- }
- });
-
-
-
// put core switches next to linked aggregation switches
k = 360 / rings[2].switches.length;
rings[2].switches.forEach(function (s, i) {
// rings[2].angles[i] = k * i;
- rings[2].angles[i] = rings[1].angles[coreLinks[s.dpid]];
+ var associatedAggregationSwitches = model.configuration.association[s.dpid];
+ // TODO: go between if there are multiple
+ var index = aggregationSwitchMap[associatedAggregationSwitches[0]];
+
+ rings[2].angles[i] = rings[1].angles[index];
});
+ return rings;
+}
+
+function updateTopology(svg, model) {
+
+ // DRAW THE SWITCHES
+ var rings = svg.selectAll('.ring').data(createRingsFromModel(model));
+
function ringEnter(data, i) {
if (!data.switches.length) {
return;
}
-
+ // create the nodes
+ // TODO: do this in two layers so that the text can always be on top
var nodes = d3.select(this).selectAll("g")
.data(d3.range(data.switches.length).map(function() {
return data;
@@ -142,10 +134,8 @@
return "rotate(" + data.angles[i]+ ")translate(" + data.radius * 150 + ")rotate(" + (-data.angles[i]) + ")";
});
+ // add the cirles representing the switches
nodes.append("svg:circle")
- .attr('class', function (_, i) {
- return data.className + ' ' + controllerColorMap[data.switches[i].controller];
- })
.attr("transform", function(_, i) {
var m = document.querySelector('#viewbox').getTransformToElement().inverse();
if (data.scale) {
@@ -156,10 +146,8 @@
.attr("x", -data.width / 2)
.attr("y", -data.width / 2)
.attr("r", data.width)
- // .attr("fill", function (_, i) {
- // return controllerColorMap[data.switches[i].controller]
- // })
+ // add the text nodes which show on mouse over
nodes.append("svg:text")
.text(function (d, i) {return d.switches[i].dpid})
.attr("x", 0)
@@ -172,6 +160,7 @@
return "matrix( " + m.a + " " + m.b + " " + m.c + " " + m.d + " " + m.e + " " + m.f + " )";
})
+ // setup the mouseover behaviors
function showLabel(data, index) {
d3.select(document.getElementById(data.switches[index].dpid)).classed('nolabel', false);
}
@@ -184,27 +173,44 @@
nodes.on('mouseout', hideLabel);
}
- var ring = svg.selectAll("g")
- .data(rings)
- .enter().append("svg:g")
+ // append switches
+ rings.enter().append("svg:g")
.attr("class", "ring")
.each(ringEnter);
+ 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];
+ } else {
+ return data.className + ' ' + 'colorInactive';
+ }
+ })
+ }
+
+ // update switches
+ rings.each(ringUpdate);
+
+ // switches should not change during operation of the ui so no
+ // rings.exit()
+
+
// 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", rings[0].width*3);
- }
+ // function zoom(data, index) {
+ // var g = d3.select(document.getElementById(data.switches[index].dpid)).select('circle');
+ // g.transition().duration(100).attr("r", rings[0].width*3);
+ // }
- svg.selectAll('.edge').on('mouseover', zoom);
- svg.selectAll('.edge').on('mousedown', zoom);
+ // 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", rings[0].width);
- }
- svg.selectAll('.edge').on('mouseout', unzoom);
+ // function unzoom(data, index) {
+ // var g = d3.select(document.getElementById(data.switches[index].dpid)).select('circle');
+ // g.transition().duration(100).attr("r", rings[0].width);
+ // }
+ // svg.selectAll('.edge').on('mouseout', unzoom);
// DRAW THE LINKS
@@ -217,20 +223,30 @@
})
.interpolate("basis");
- d3.select('svg').selectAll('path').data(model.links).enter().append("svg:path").attr("d", function (d) {
+ // key on link dpids since these will come/go during demo
+ var links = d3.select('svg').selectAll('path').data(model.links, function (d) {
+ return d['src-switch']+'->'+d['dst-switch'];
+ });
+
+ // add new links
+ links.enter().append("svg:path").attr("d", function (d) {
+
var src = d3.select(document.getElementById(d['src-switch']));
var dst = d3.select(document.getElementById(d['dst-switch']));
var srcPt = document.querySelector('svg').createSVGPoint();
srcPt.x = src.attr('x');
- srcPt.y = src.attr('y') + 10;
+ srcPt.y = src.attr('y') + 10; // tmp: make up and down links distinguishable
var dstPt = document.querySelector('svg').createSVGPoint();
dstPt.x = dst.attr('x');
- dstPt.y = dst.attr('y') - 10;
+ dstPt.y = dst.attr('y') - 10; // tmp: make up and down links distinguishable
return line([srcPt.matrixTransform(src[0][0].getCTM()), dstPt.matrixTransform(dst[0][0].getCTM())]);
});
+
+ // remove old links
+ links.exit().remove();
}
function updateControllers(model) {
@@ -288,7 +304,7 @@
updateModel(function (newModel) {
console.log('Update time: ' + (Date.now() - d)/1000 + 's');
- if (!oldModel && JSON.stringify(oldModel) != JSON.stringify(newModel)) {
+ if (true || !oldModel && JSON.stringify(oldModel) != JSON.stringify(newModel)) {
updateControllers(newModel);
updateTopology(svg, newModel);
} else {
@@ -312,6 +328,7 @@
setTimeout(function () {
// workaround for another Chrome v25 bug
// viewbox transform stuff doesn't work in combination with browser zoom
+ // also works in Chrome v27
d3.select('#svg-container').style('zoom', window.document.body.clientWidth/window.document.width);
sync(svg);
}, 100);
diff --git a/web/ons-demo/js/model.js b/web/ons-demo/js/model.js
index 1f90362..94bbdfe 100644
--- a/web/ons-demo/js/model.js
+++ b/web/ons-demo/js/model.js
@@ -8,7 +8,8 @@
flows: [],
controllers: results.controllers,
activeControllers: results.activeControllers,
- links: results.links
+ links: results.links,
+ configuration: results.configuration
}
// sort the switches
@@ -35,7 +36,10 @@
});
results.switches.forEach(function (s) {
- s.controller = results.mapping[s.dpid][0].controllerId;
+ var mapping = results.mapping[s.dpid]
+ if (mapping) {
+ s.controller = mapping[0].controllerId;
+ }
if (coreSwitchDPIDs[s.dpid]) {
model.coreSwitches.push(s);