Merge pull request #301 from pgreyson/master
partial flow chooser, bug fixes and improvements
diff --git a/web/ons-demo/RELEASE_NOTES.txt b/web/ons-demo/RELEASE_NOTES.txt
index 95786fd..48834fb 100644
--- a/web/ons-demo/RELEASE_NOTES.txt
+++ b/web/ons-demo/RELEASE_NOTES.txt
@@ -1,3 +1,13 @@
+** March 28, 2013 **
+- basic flow chooser
+ - click in "eye" to show full list
+ - click on "eye" in full list to monitor that flow in the top slot (and show the flow in topology)
+ - other flows get pushed down one slot
+ - when a flow is pushed off the list, it is no longer displayed in topology
+- bug fix for link disappearing after being added
+- color improvements
+- draw vector while linking to make it clearer what's going to happen
+
** March 27, 2013 **
- click onos node "eye" icon to highlight switches associated with that controller
- double click onos node else where to activate/deactivate
diff --git a/web/ons-demo/assets/eye.svg b/web/ons-demo/assets/black-eye.svg
similarity index 100%
rename from web/ons-demo/assets/eye.svg
rename to web/ons-demo/assets/black-eye.svg
diff --git a/web/ons-demo/assets/white-eye.svg b/web/ons-demo/assets/white-eye.svg
new file mode 100644
index 0000000..8f3b180
--- /dev/null
+++ b/web/ons-demo/assets/white-eye.svg
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ version="1.1"
+ width="512"
+ height="512"
+ viewBox="0 0 512 512"
+ id="Layer_1"
+ xml:space="preserve"><metadata
+ id="metadata13"><rdf:RDF><cc:Work
+ rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" /><dc:title></dc:title></cc:Work></rdf:RDF></metadata><defs
+ id="defs11" />
+<g
+ id="g3"
+ style="fill:#ffffff;fill-opacity:1">
+ <path
+ d="m 506.637,242.501 c -5.362,-6.347 -11.263,-12.33 -17.171,-18.193 -31.897,-31.679 -68.549,-59.921 -108.648,-80.411 -25.618,-13.08 -53.038,-23.655 -81.451,-28.721 -14.453,-2.586 -28.617,-3.912 -43.474,-3.938 -14.447,0.025 -28.908,1.353 -43.361,3.938 -28.412,5.065 -55.775,15.641 -81.393,28.721 -40.102,20.489 -76.724,48.733 -108.622,80.411 -5.909,5.862 -11.794,11.847 -17.155,18.193 -7.147,8.484 -7.147,18.515 0,27 16.344,19.353 35.774,36.575 55.542,52.321 42.57,33.915 91.25,62.278 144.993,73.711 16.621,3.524 33.299,5.244 49.998,5.228 16.904,0.018 33.488,-1.702 50.107,-5.228 53.744,-11.433 102.534,-39.796 145.104,-73.711 19.768,-15.745 39.194,-32.969 55.538,-52.321 7.146,-8.483 7.139,-18.514 -0.007,-27 z M 255.892,354.552 c -54.334,-0.104 -98.348,-44.177 -98.348,-98.554 0,-54.351 44.014,-98.438 98.348,-98.543 54.809,0.104 98.347,44.192 98.347,98.543 0.001,54.376 -43.538,98.447 -98.347,98.554 z"
+ id="path5"
+ style="fill:#ffffff;fill-opacity:1" />
+ <path
+ d="m 255.86,217.881 c -21.06,0 -38.106,17.059 -38.106,38.115 0,21.068 17.047,38.123 38.106,38.123 21.058,0 38.124,-17.055 38.124,-38.123 0,-21.056 -17.067,-38.115 -38.124,-38.115 z"
+ id="path7"
+ style="fill:#ffffff;fill-opacity:1" />
+</g>
+</svg>
\ No newline at end of file
diff --git a/web/ons-demo/css/layout.default.css b/web/ons-demo/css/layout.default.css
index e46f165..018e728 100644
--- a/web/ons-demo/css/layout.default.css
+++ b/web/ons-demo/css/layout.default.css
@@ -44,25 +44,33 @@
-webkit-box-orient: vertical;
}
+#flowChooser {
+ position: absolute;
+ top: 0px;
+ left: 0px;
+ height: 100%;
+ display: -webkit-box;
+ overflow: scroll;
+}
+
.selectedFlow {
display: -webkit-box;
+ position: relative;
+}
+
+#showFlowChooser {
+ position: relative;
+ display: -webkit-box;
+ -webkit-box-pack: center;
+}
+
+.selectedFlow .srcDPID, .selectedFlow .dstDPID {
-webkit-user-select: auto;
}
#selectedFlowsHeader {
display: -webkit-box;
-}
-
-.flowIndex {
- width: 1.5em;
-}
-
-.flowId {
- width: 5em;
-}
-
-.srcDPID, .dstDPID {
- width: 20em;
+ height: 1.5em;
}
.iperf {
diff --git a/web/ons-demo/css/skin.default.css b/web/ons-demo/css/skin.default.css
index 579d940..aebf68b 100644
--- a/web/ons-demo/css/skin.default.css
+++ b/web/ons-demo/css/skin.default.css
@@ -6,6 +6,14 @@
margin: 0px;
}
+#topology.linking {
+ cursor: crosshair;
+}
+
+.nodrop {
+ cursor: not-allowed;
+}
+
.status {
padding: 1em;
}
@@ -87,23 +95,40 @@
background-color: black;
}
+#flowChooser .selectedFlow {
+ background-color: rgba(255, 255, 255, .75);
+ color: black;
+}
+
+#flowChooser .flowId {
+ padding-left: 2em;
+}
+
+
.selectedFlow.selected {
color: black;
background-color:#AAA;
}
-circle.highlight {
+.highlight circle {
stroke: rgba(255, 255, 255, .5);
stroke-width: 2px;
}
+#linkVector {
+ fill: none;
+ stroke-width: 1px;
+ stroke: rgba(255, 255, 255, .75);
+ pointer-events: none;
+}
+
path {
pointer-events: none;
}
path.flow {
fill: none;
- stroke-width: 3px;
+ stroke-width: 5px;
stroke: rgba(255, 255, 255, .35);
}
@@ -111,13 +136,26 @@
border-top: 1px solid #AAA;
}
-.flowIndex, .flowId, .srcDPID, .dstDPID, .iperf {
+#flowChooser {
+ pointer-events: none;
+ background-color: rgba(0, 0, 0, .25);
+}
+
+
+.flowId, .srcDPID, .dstDPID, .iperf {
display: -webkit-box;
-webkit-box-pack: center;
-webkit-box-align: center;
+ width: 3em;
}
-.flowIndex, .flowId, .srcDPID, .dstDPID {
+
+.srcDPID, .dstDPID {
+ width: 12em;
+}
+
+
+.flowId, .srcDPID, .dstDPID {
border-right: 1px solid #AAA;
}
@@ -132,13 +170,22 @@
position: relative;
}
-.controllerEye {
+.black-eye {
position: absolute;
top: 0px;
left: 0px;
height: 100%;
- width: 2em;
- background-image: url('../assets/eye.svg');
+ width: 2.25em;
+ background-image: url('../assets/black-eye.svg');
+ background-size: auto 100%;
+ background-repeat: no-repeat;
+ background-position: .25em center;
+}
+
+.white-eye {
+ height: 100%;
+ width: 2.25em;
+ background-image: url('../assets/white-eye.svg');
background-size: auto 100%;
background-repeat: no-repeat;
background-position: .25em center;
@@ -202,14 +249,14 @@
}
.color1 {
- opacity: .2;
+ opacity: .15;
pointer-events: none;
fill: #EC0033;
background-color: #EC0033;
}
.color2 {
- opacity: .2;
+ opacity: .15;
fill: #FFBA00;
background-color: #FFBA00;
}
diff --git a/web/ons-demo/index.html b/web/ons-demo/index.html
index e89f409..d157ecc 100644
--- a/web/ons-demo/index.html
+++ b/web/ons-demo/index.html
@@ -38,13 +38,13 @@
</div>
</div>
<div id='selectedFlowsHeader'>
- <div class='flowIndex'></div>
- <div class='flowId'>flow id</div>
+ <div id='showFlowChooser' class='flowId'><div class='white-eye'></div></div>
<div class='srcDPID'>src</div>
<div class='dstDPID'>dst</div>
<div class='iperf'>iperf</div>
</div>
<div id='selectedFlows'></div>
+<div id='flowChooser'></div>
<script src="js/app.js"></script>
</body>
diff --git a/web/ons-demo/js/app.js b/web/ons-demo/js/app.js
index daf767c..0fa5fa3 100644
--- a/web/ons-demo/js/app.js
+++ b/web/ons-demo/js/app.js
@@ -15,7 +15,7 @@
});
var model;
-var svg, selectedFlowsView;
+var svg;
var updateTopology;
var pendingLinks = {};
@@ -24,13 +24,10 @@
'color2',
'color3',
'color4',
- 'color5',
- 'color6',
'color7',
'color8',
'color9',
- 'color10',
- 'color11',
+// 'color11',
'color12'
];
colors.reverse();
@@ -49,7 +46,7 @@
window.addEventListener('resize', function () {
// this is too slow. instead detect first resize event and hide the paths that have explicit matrix applied
// either that or is it possible to position the paths so they get the automatic transform as well?
-// updateTopology(svg, model);
+// updateTopology();
});
var svg = d3.select('#svg-container').append('svg:svg');
@@ -68,26 +65,31 @@
attr('id', 'viewbox').append('svg:g').attr('transform', 'translate(500 500)');
}
-var selectedFlowsData = [
- {selected: false, flow: null},
- {selected: false, flow: null},
- {selected: false, flow: null}
-];
+var selectedFlows = [null, null, null];
function drawFlows() {
// DRAW THE FLOWS
- var flows = d3.select('svg').selectAll('.flow').data(selectedFlowsData, function (d) {
- return d.flow ? d.flow.flowId.value : null;
+ var flows = d3.select('svg').selectAll('.flow').data(selectedFlows, function (d) {
+ return d ? d.flowId.value : null;
});
- flows.enter().append("svg:path")
- .attr('class', 'flow')
- .attr('d', function (d) {
- if (!d.flow) {
+ flows.enter().append("svg:path").attr('class', 'flow')
+ .attr('stroke-dasharray', '4, 10')
+ .append('svg:animate')
+ .attr('attributeName', 'stroke-dashoffset')
+ .attr('attributeType', 'xml')
+ .attr('from', '500')
+ .attr('to', '-500')
+ .attr('dur', '20s')
+ .attr('repeatCount', 'indefinite');
+
+
+ flows.attr('d', function (d) {
+ if (!d) {
return;
}
var pts = [];
- d.flow.dataPath.flowEntries.forEach(function (flowEntry) {
+ d.dataPath.flowEntries.forEach(function (flowEntry) {
var s = d3.select(document.getElementById(flowEntry.dpid.value));
var pt = document.querySelector('svg').createSVGPoint();
pt.x = s.attr('x');
@@ -97,102 +99,111 @@
});
return line(pts);
})
- .attr('stroke-dasharray', '3, 10')
- .append('svg:animate')
- .attr('attributeName', 'stroke-dashoffset')
- .attr('attributeType', 'xml')
- .attr('from', '500')
- .attr('to', '-500')
- .attr('dur', '20s')
- .attr('repeatCount', 'indefinite');
-
- flows.style('visibility', function (d) {
- if (d) {
- return d.selected ? '' : 'hidden';
- }
- })
// "marching ants"
- // TODO: this will only be true if there's an iperf session running
- flows.select('animate').attr('from', function (d) {
- if (d.flow) {
- if (d.selected) {
- return '500';
- } else {
- return '-500';
- }
- }
- });
+ flows.select('animate').attr('from', 500);
+
+ flows.exit().remove();
}
-function updateFlowView() {
- selectedFlowsView.data(selectedFlowsData);
-
- selectedFlowsView.classed('selected', function (d) {
- if (d.flow) {
- return d.selected;
- }
- });
-
- selectedFlowsView.select('.flowId')
- .text(function (d) {
- if (d.flow) {
- return d.flow.flowId.value;
- }
- });
-
- selectedFlowsView.select('.srcDPID')
- .text(function (d) {
- if (d.flow) {
- return d.flow.dataPath.srcPort.dpid.value;
- }
- });
-
- selectedFlowsView.select('.dstDPID')
- .text(function (d) {
- if (d.flow) {
- return d.flow.dataPath.dstPort.dpid.value;
- }
- });
-}
-
-function createFlowView() {
- function rowEnter(d, i) {
+function showFlowChooser() {
+ function rowEnter(d) {
var row = d3.select(this);
- row.on('click', function () {
- selectedFlowsData[i].selected = !selectedFlowsData[i].selected;
- updateFlowView();
- drawFlows();
- });
-
row.append('div')
- .classed('flowIndex', true)
- .text(function () {
- return i+1;
+ .classed('black-eye', true).
+ on('click', function () {
+ selectedFlows.unshift(d);
+ selectedFlows = selectedFlows.slice(0, 3);
+
+ updateSelectedFlows();
+ updateTopology();
});
row.append('div')
- .classed('flowId', true);
+ .classed('flowId', true)
+ .text(function (d) {
+ return d.flowId.value;
+ });
row.append('div')
- .classed('srcDPID', true);
+ .classed('srcDPID', true)
+ .text(function (d) {
+ return d.dataPath.srcPort.dpid.value;
+ });
+
row.append('div')
- .classed('dstDPID', true);
+ .classed('dstDPID', true)
+ .text(function (d) {
+ return d.dataPath.dstPort.dpid.value;
+ });
- row.append('div')
- .classed('iperf', true);
}
- var flows = d3.select('#selectedFlows')
+ var flows = d3.select('#flowChooser')
+ .append('div')
+ .style('pointer-events', 'auto')
.selectAll('.selectedFlow')
- .data(selectedFlowsData)
+ .data(model.flows)
.enter()
.append('div')
.classed('selectedFlow', true)
.each(rowEnter);
+ setTimeout(function () {
+ d3.select(document.body).on('click', function () {
+ d3.select('#flowChooser').html('');
+ d3.select(document.body).on('click', null);
+ });
+ }, 0);
+}
+
+function updateSelectedFlows() {
+ function rowEnter(d) {
+ var row = d3.select(this);
+ row.append('div').classed('flowId', true);
+ row.append('div').classed('srcDPID', true);
+ row.append('div').classed('dstDPID', true);
+ row.append('div').classed('iperf', true);
+ }
+
+ function rowUpdate(d) {
+ var row = d3.select(this);
+ row.select('.flowId')
+ .text(function (d) {
+ if (d) {
+ return d.flowId.value;
+ }
+ });
+
+ row.select('.srcDPID')
+ .text(function (d) {
+ if (d) {
+ return d.dataPath.srcPort.dpid.value;
+ }
+ });
+
+ row.select('.dstDPID')
+ .text(function (d) {
+ if (d) {
+ return d.dataPath.dstPort.dpid.value;
+ }
+ });
+ }
+
+ var flows = d3.select('#selectedFlows')
+ .selectAll('.selectedFlow')
+ .data(selectedFlows);
+
+ flows.enter()
+ .append('div')
+ .classed('selectedFlow', true)
+ .each(rowEnter);
+
+ flows.each(rowUpdate);
+
+ flows.exit().remove();
return flows;
}
@@ -329,12 +340,8 @@
return linkMap;
}
-updateTopology = function(svg, model) {
-
- // DRAW THE SWITCHES
- var rings = svg.selectAll('.ring').data(createRingsFromModel(model));
-
-
+// removes links from the pending list that are now in the model
+function reconcilePendingLinks(model) {
var links = [];
model.links.forEach(function (link) {
links.push(link);
@@ -344,19 +351,32 @@
for (linkId in pendingLinks) {
links.push(pendingLinks[linkId]);
}
+ return links
+}
+updateTopology = function() {
+
+ // DRAW THE SWITCHES
+ var rings = svg.selectAll('.ring').data(createRingsFromModel(model));
+
+ var links = reconcilePendingLinks(model);
var linkMap = createLinkMap(links);
// var flowMap = createFlowMap(model);
function mouseOverSwitch(data) {
+
+ d3.event.preventDefault();
+
+ d3.select(document.getElementById(data.dpid + '-label')).classed('nolabel', false);
+
if (data.highlighted) {
return;
}
// only highlight valid link or flow destination by checking for class of existing highlighted circle
- var highlighted = svg.selectAll('circle.highlight')[0];
+ var highlighted = svg.selectAll('.highlight')[0];
if (highlighted.length == 1) {
- var s = d3.select(highlighted[0]);
+ var s = d3.select(highlighted[0]).select('circle');
// only allow links
// edge->edge (flow)
// aggregation->core
@@ -380,21 +400,20 @@
data.target = true;
}
-
- d3.select(document.getElementById(data.dpid + '-label')).classed('nolabel', false);
var node = d3.select(document.getElementById(data.dpid));
- node.select('circle').classed('highlight', true).transition().duration(100).attr("r", widths.core);
+ node.classed('highlight', true).select('circle').transition().duration(100).attr("r", widths.core);
data.highlighted = true;
node.moveToFront();
}
function mouseOutSwitch(data) {
+ d3.select(document.getElementById(data.dpid + '-label')).classed('nolabel', true);
+
if (data.mouseDown)
return;
- d3.select(document.getElementById(data.dpid + '-label')).classed('nolabel', true);
var node = d3.select(document.getElementById(data.dpid));
- node.select('circle').classed('highlight', false).transition().duration(100).attr("r", widths[data.className]);
+ node.classed('highlight', false).select('circle').transition().duration(100).attr("r", widths[data.className]);
data.highlighted = false;
data.target = false;
}
@@ -402,12 +421,42 @@
function mouseDownSwitch(data) {
mouseOverSwitch(data);
data.mouseDown = true;
+ d3.select('#topology').classed('linking', true);
+
+ d3.select('svg')
+ .append('svg:path')
+ .attr('id', 'linkVector')
+ .attr('d', function () {
+ var s = d3.select(document.getElementById(data.dpid));
+
+ var pt = document.querySelector('svg').createSVGPoint();
+ pt.x = s.attr('x');
+ pt.y = s.attr('y');
+ pt = pt.matrixTransform(s[0][0].getCTM());
+
+ return line([pt, pt]);
+ });
+
+
+ if (data.className === 'core') {
+ d3.selectAll('.edge').classed('nodrop', true);
+ }
+ if (data.className === 'edge') {
+ d3.selectAll('.core').classed('nodrop', true);
+ d3.selectAll('.aggregation').classed('nodrop', true);
+ }
+ if (data.className === 'aggregation') {
+ d3.selectAll('.edge').classed('nodrop', true);
+ d3.selectAll('.aggregation').classed('nodrop', true);
+ }
}
function mouseUpSwitch(data) {
if (data.mouseDown) {
data.mouseDown = false;
+ d3.select('#topology').classed('linking', false);
d3.event.stopPropagation();
+ d3.selectAll('.nodrop').classed('nodrop', false);
}
}
@@ -515,14 +564,60 @@
// always on top
var labelRings = svg.selectAll('.labelRing').data(createRingsFromModel(model));
+ d3.select(document.body).on('mousemove', function () {
+ if (!d3.select('#topology').classed('linking')) {
+ return;
+ }
+ var linkVector = document.getElementById('linkVector');
+ if (!linkVector) {
+ return;
+ }
+ linkVector = d3.select(linkVector);
+
+ var highlighted = svg.selectAll('.highlight')[0];
+ var s1 = null, s2 = null;
+ if (highlighted.length > 1) {
+ var s1 = d3.select(highlighted[0]);
+ var s2 = d3.select(highlighted[1]);
+
+ } else if (highlighted.length > 0) {
+ var s1 = d3.select(highlighted[0]);
+ }
+ var src = s1;
+ if (s2 && !s2.data()[0].target) {
+ src = s2;
+ }
+ if (src) {
+ linkVector.attr('d', function () {
+ var srcPt = document.querySelector('svg').createSVGPoint();
+ srcPt.x = src.attr('x');
+ srcPt.y = src.attr('y');
+ srcPt = srcPt.matrixTransform(src[0][0].getCTM());
+
+ var svg = document.getElementById('topology');
+ var mouse = d3.mouse(viewbox);
+ var dstPt = document.querySelector('svg').createSVGPoint();
+ dstPt.x = mouse[0];
+ dstPt.y = mouse[1];
+ dstPt = dstPt.matrixTransform(viewbox.getCTM());
+
+ return line([srcPt, dstPt]);
+ });
+ }
+ });
+
d3.select(document.body).on('mouseup', function () {
function clearHighlight() {
svg.selectAll('circle').each(function (data) {
data.mouseDown = false;
+ d3.select('#topology').classed('linking', false);
mouseOutSwitch(data);
- })
+ });
+ d3.select('#linkVector').remove();
};
+ d3.selectAll('.nodrop').classed('nodrop', false);
+
function removeLink(link) {
var path1 = document.getElementById(link['src-switch'] + '=>' + link['dst-switch']);
var path2 = document.getElementById(link['dst-switch'] + '=>' + link['src-switch']);
@@ -538,10 +633,10 @@
}
- var highlighted = svg.selectAll('circle.highlight')[0];
+ var highlighted = svg.selectAll('.highlight')[0];
if (highlighted.length == 2) {
- var s1Data = d3.select(highlighted[0]).data()[0];
- var s2Data = d3.select(highlighted[1]).data()[0];
+ var s1Data = highlighted[0].__data__;
+ var s2Data = highlighted[1].__data__;
var srcData, dstData;
if (s1Data.target) {
@@ -592,16 +687,16 @@
pending: true
};
pendingLinks[makeLinkKey(link2)] = link2;
- updateTopology(svg, model);
+ updateTopology();
linkUp(link1);
- // remove the pending link after 10s
+ // remove the pending links after 10s
setTimeout(function () {
delete pendingLinks[makeLinkKey(link1)];
delete pendingLinks[makeLinkKey(link2)];
- updateTopology(svg, model);
+ updateTopology();
}, 10000);
}
}
@@ -718,7 +813,7 @@
var dstPt = document.querySelector('svg').createSVGPoint();
dstPt.x = dst.attr('x');
- dstPt.y = dst.attr('y'); // tmp: make up and down links distinguishable
+ dstPt.y = dst.attr('y');
dstPt = dstPt.matrixTransform(dst[0][0].getCTM());
var midPt = document.querySelector('svg').createSVGPoint();
@@ -740,7 +835,7 @@
drawFlows();
}
-function updateControllers(model) {
+function updateControllers() {
var controllers = d3.select('#controllerList').selectAll('.controller').data(model.controllers);
controllers.enter().append('div')
.each(function (c) {
@@ -751,7 +846,7 @@
return d;
})
.append('div')
- .attr('class', 'controllerEye');
+ .attr('class', 'black-eye');
controllers.attr('class', function (d) {
var color = 'colorInactive';
@@ -781,7 +876,7 @@
}
});
- controllers.select('.controllerEye').on('click', function (c) {
+ controllers.select('.black-eye').on('click', function (c) {
var allSelected = true;
for (var key in controllerColorMap) {
if (!d3.select(document.body).classed(controllerColorMap[key] + '-selected')) {
@@ -806,30 +901,26 @@
}
-function sync(svg, selectedFlowsView) {
+function sync(svg) {
var d = Date.now();
updateModel(function (newModel) {
// console.log('Update time: ' + (Date.now() - d)/1000 + 's');
+ var modelChanged = false;
if (!model || JSON.stringify(model) != JSON.stringify(newModel)) {
- updateControllers(newModel);
-
- // fake flows right now
- var i;
- for (i = 0; i < newModel.flows.length && i < selectedFlowsData.length; i+=1) {
- var selected = selectedFlowsData[i] ? selectedFlowsData[i].selected : false;
- selectedFlowsData[i].flow = newModel.flows[i];
- selectedFlowsData[i].selected = selected;
- }
-
- updateFlowView(newModel);
- updateTopology(svg, newModel);
+ modelChanged = true;
+ model = newModel;
} else {
// console.log('no change');
}
- updateHeader(newModel);
- model = newModel;
+ if (modelChanged) {
+ updateControllers();
+ updateSelectedFlows();
+ updateTopology();
+ }
+
+ updateHeader(newModel);
// do it again in 1s
setTimeout(function () {
@@ -839,7 +930,13 @@
}
svg = createTopologyView();
-selectedFlowsView = createFlowView();
+updateSelectedFlows();
+
+d3.select('#showFlowChooser').on('click', function () {
+ showFlowChooser();
+});
+
+
// workaround for Chrome v25 bug
// if executed immediately, the view box transform logic doesn't work properly
// fixed in Chrome v27
@@ -848,5 +945,5 @@
// 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, selectedFlowsView);
+ sync(svg);
}, 100);
diff --git a/web/ons-demo/js/utils.js b/web/ons-demo/js/utils.js
index 17100b1..4f6d0c1 100644
--- a/web/ons-demo/js/utils.js
+++ b/web/ons-demo/js/utils.js
@@ -11,4 +11,14 @@
}
return parameters;
+}
+
+function findLink(model, dpid) {
+ var links = [];
+ model.links.forEach(function (link) {
+ if (link['src-switch'] == dpid || link['dst-switch'] == dpid) {
+ links.push(link);
+ }
+ });
+ return links;
}
\ No newline at end of file