Simon Hunt

GUI -- Re-worked ONOS Instance panel (WIP)

- added sample events, including updated addInstance event.
- cleaned up glyphs; added badges.
- fixed defect in floating panel .width(...) function.

Change-Id: I00d7ca38a1b291c4735b6dd5e39f0266549b545f
......@@ -50,79 +50,78 @@
.append('path').attr('d', birdData);
}
var bullhornData = "M0,13c0,3.733,2.561,6.148,6.019,6.809 " +
"C6.013,19.873,6,19.935,6,20v8 c0,1.105,0.895,2,2,2h3 " +
"c1.105,0,2-0.896,2-2v-8h3V6H8C3.582,6,0,8.582,0,13z " +
"M18,20h3V6h-3V20z M30,0l-7,4.667v16.667L30,26 c1.105,0,2-0.895,2-2" +
"V2 C32,0.896,31.105,0,30,0z";
function defBullhorn(defs) {
defs.append('symbol')
.attr({
id: 'bullhorn',
viewBox: '-4 -5 40 40'
})
.append('path').attr('d', bullhornData);
}
var glyphData = {
unknown: "M-20 -15 a5 5 0 0 1 5 -5 h30 a5 5 0 0 1 5 5 v30 " +
"a5 5 0 0 1 -5 5 h-30 a5 5 0 0 1 -5 -5 z ",
router: "M-45 0 A45 45 0 0 1 45 0 A45 45 0 0 1 -45 0 M -35 -5 " +
"l 12 0, 0 -8, 18 13, -18 13, 0 -8, -12 0 z M 35 -5 " +
"l -12 0, 0 -8, -18 13, 18 13, 0 -8, 12 0 z M -5 -8 " +
"l 0 -12, -8 0, 13 -18, 13 18, -8 0, 0 12 z M -5 8 " +
"l 0 12, -8 0, 13 18, 13 -18, -8 0, 0 -12 z ",
bgpSpeaker: "M-45 -15 a45 35 0 0 1 90 0 Q45 22 0 45 Q-45 22 -45 -15 z " +
"M -5 -26 l 12 0, 0 -8, 18 13, -18 13, 0 -8, -12 0 z M 5 2" +
" l -12 0, 0 -8, -18 13, 18 13, 0 -8, 12 0 z ",
"a5 5 0 0 1 -5 5 h-30 a5 5 0 0 1 -5 -5 z",
switch: "M-45 -35 a10 10 0 0 1 10 -10 h70 a 10 10 0 0 1 10 10 v70 a 10 10 0 0 1 -10 10 h -70 a 10 10 0 0 1 -10 -10 z M 5 -29 l 12 0, 0 -8, 18 13, -18 13, 0 -8, -12 0 z M 5 5 l 12 0, 0 -8, 18 13, -18 13, 0 -8, -12 0 z M -5 -15 l -12 0, 0 -8, -18 13, 18 13, 0 -8, 12 0 z M -5 19 l -12 0, 0 -8, -18 13, 18 13, 0 -8, 12 0 z",
node: "M-40 45 a5 5 0 0 1 -5 -5 v-65 a5 5 0 0 1 5 -5 h80 " +
"a5 5 0 0 1 5 5 v65 a5 5 0 0 1 -5 5 z M-41 -32.5 l11 -11 " +
"a10 3 0 0 1 10 -2 h40 a10 3 0 0 1 10 2 l11 11 z M-39 -20 " +
"a5 5 0 0 1 10 0 a5 5 0 0 1 -10 0 z",
switch: "M-45 -35 a10 10 0 0 1 10 -10 h70 a 10 10 0 0 1 10 10 " +
"v70 a 10 10 0 0 1 -10 10 h -70 a 10 10 0 0 1 -10 -10 z " +
"M 5 -29 l 12 0, 0 -8, 18 13, -18 13, 0 -8, -12 0 z M 5 5 " +
"l 12 0, 0 -8, 18 13, -18 13, 0 -8, -12 0 z M -5 -15 " +
"l -12 0, 0 -8, -18 13, 18 13, 0 -8, 12 0 z M -5 19 " +
"l -12 0, 0 -8, -18 13, 18 13, 0 -8, 12 0 z",
Xswitch: "M-45 -35 a10 10 0 0 1 10 -10 h70 a 10 10 0 0 1 10 10 v70 " +
"a 10 10 0 0 1 -10 10 h -70 a 10 10 0 0 1 -10 -10 z M 5 -29 " +
"l 12 0, 0 -8, 18 13, -18 13, 0 -8, -12 0 z M 5 5 " +
"l 12 0, 0 -8, 18 13, -18 13, 0 -8, -12 0 z M -5 -15 " +
"l -12 0, 0 -8, -18 13, 18 13, 0 -8, 12 0 z M -5 19 " +
"l -12 0, 0 -8, -18 13, 18 13, 0 -8, 12 0 z " ,
roadm: "M-45 -20 l25 -25 h40 l25 25 v40 l-25 25 h-40 l-25 -25 z " +
"M 3 -29 l 12 0, 0 -8, 18 13, -18 13, 0 -8, -12 0 z M 3 5 " +
"l 12 0, 0 -8, 18 13, -18 13, 0 -8, -12 0 z M -3 -15 " +
"l -12 0, 0 -8, -18 13, 18 13, 0 -8, 12 0 z M -3 19 " +
"l -12 0, 0 -8, -18 13, 18 13, 0 -8, 12 0 z ",
node: "M-40 45 a5 5 0 0 1 -5 -5 v-65 a5 5 0 0 1 5 -5 h80 " +
"a5 5 0 0 1 5 5 v65 a5 5 0 0 1 -5 5 z M-41 -32.5 l11 -11 " +
"a10 3 0 0 1 10 -2 h40 a10 3 0 0 1 10 2 l11 11 z M-39 -20 " +
"a5 5 0 0 1 10 0 a5 5 0 0 1 -10 0 z ",
"M 3 -29 l 12 0, 0 -8, 18 13, -18 13, 0 -8, -12 0 z M 3 5 " +
"l 12 0, 0 -8, 18 13, -18 13, 0 -8, -12 0 z M -3 -15 " +
"l -12 0, 0 -8, -18 13, 18 13, 0 -8, 12 0 z M -3 19 " +
"l -12 0, 0 -8, -18 13, 18 13, 0 -8, 12 0 z",
endstation: "M-45 -40 a5 5 0 0 1 5 -5 h65 a5 5 0 0 1 5 5 v80 " +
"a5 5 0 0 1 -5 5 h-65 a5 5 0 0 1 -5 -5 z M32.5 -41 l11 11 " +
"a3 10 0 0 1 2 10 v40 a3 10 0 0 1 -2 10 l-11 11 z M-38 -36 " +
"a2 2 0 0 1 2 -2 h56 a2 2 0 0 1 2 2 v26 a2 2 0 0 1 -2 2 h-56 " +
"a2 2 0 0 1 -2 -2 z M-35 -35 h54 v10 h-54 z M-35 -22 h54 v10 " +
"h-54 z M-13 15 a5 5 0 0 1 10 0 a5 5 0 0 1 -10 0 z "
"a5 5 0 0 1 -5 5 h-65 a5 5 0 0 1 -5 -5 z M32.5 -41 l11 11 " +
"a3 10 0 0 1 2 10 v40 a3 10 0 0 1 -2 10 l-11 11 z M-38 -36 " +
"a2 2 0 0 1 2 -2 h56 a2 2 0 0 1 2 2 v26 a2 2 0 0 1 -2 2 h-56 " +
"a2 2 0 0 1 -2 -2 z M-35 -35 h54 v10 h-54 z M-35 -22 h54 v10 " +
"h-54 z M-13 15 a5 5 0 0 1 10 0 a5 5 0 0 1 -10 0 z",
router: "M-45 0 A45 45 0 0 1 45 0 A45 45 0 0 1 -45 0 M -35 -5 " +
"l 12 0, 0 -8, 18 13, -18 13, 0 -8, -12 0 z M 35 -5 " +
"l -12 0, 0 -8, -18 13, 18 13, 0 -8, 12 0 z M -5 -8 " +
"l 0 -12, -8 0, 13 -18, 13 18, -8 0, 0 12 z M -5 8 " +
"l 0 12, -8 0, 13 18, 13 -18, -8 0, 0 -12 z",
bgpSpeaker: "M-45 -15 a45 35 0 0 1 90 0 Q45 22 0 45 Q-45 22 -45 -15 z " +
"M -5 -26 l 12 0, 0 -8, 18 13, -18 13, 0 -8, -12 0 z M 5 2" +
" l -12 0, 0 -8, -18 13, 18 13, 0 -8, 12 0 z"
};
var glyphParams = {
viewBox: '-55 -55 110 110'
};
function defGlyphs(defs) {
d3.map(glyphData).keys().forEach(function (key) {
defs.append('symbol')
.attr({
id: key,
viewBox: glyphParams.viewBox
})
.append('path').attr('d', glyphData[key]);
var badgeData = {
uiAttached: "M-3-2.5 a.5 .5 0 0 1 .5-.5 h5 a.5 .5 0 0 1 .5 .5 v3 " +
"a.5 .5 0 0 1-.5 .5 h-5 a.5 .5 0 0 1-.5-.5 z M-2.5-2.2 " +
"a.3 .3 0 0 1 .3-.3 h4.4 a.3 .3 0 0 1 .3 .3 v2.4 a.3 .3 0 0 1-.3 .3 " +
"h-4.4 a.3 .3 0 0 1-.3-.3 z M-3 1.55 h6 l1 1.45 h-8 z"
};
var badgeParams = {
viewBox: '-5 -5 10 10'
};
function defStuff(defs, params, data) {
d3.map(data).keys().forEach(function (key) {
defs.append('symbol')
.attr({
id: key,
viewBox: params.viewBox
})
.append('path').attr('d', data[key]);
});
}
// === register the functions as a library
onos.ui.addLib('glyphs', {
defBird: defBird,
defBullhorn: defBullhorn,
defGlyphs: defGlyphs
defGlyphs: function (defs) { defStuff(defs, glyphParams, glyphData); },
defBadges: function (defs) { defStuff(defs, badgeParams, badgeData); }
});
}(ONOS));
......
{
"event": "addDevice",
"payload": {
"id": "of:000000000000000a",
"type": "switch",
"online": true,
"master": "local",
"labels": [
"",
"NWOR",
"of:000000000000000a"
],
"props": {
"latitude": "29.951475",
"name": "NWOR",
"longitude": "-90.078434"
},
"location": {
"type": "latlng",
"lat": 29.951475,
"lng": -90.078434
}
}
}
{
"event": "addHost",
"payload": {
"id": "00:00:00:00:00:01/-1",
"type": "endstation",
"ingress": "00:00:00:00:00:01/-1/0-of:0000000000000001/1",
"egress": "of:0000000000000001/1-00:00:00:00:00:01/-1/0",
"cp": {
"device": "of:0000000000000001",
"port": 1
},
"labels": [
"10.0.0.1",
"00:00:00:00:00:01"
],
"props": {
"name": "CMBR",
"latitude": "44.37373",
"longitude": "-71.109734"
},
"location": {
"type": "latlng",
"lat": 44.37373,
"lng": -71.109734
}
}
}
{
"event": "addInstance",
"payload": {
"id": "onos-1",
"online": "true"
"id": "local",
"ip": "127.0.0.1",
"online": true,
"uiAttached": true,
"switches": 25,
"labels": [
"local",
"127.0.0.1"
]
}
}
......
{
"event": "showSummary",
"sid": 1,
"payload": {
"id": "ONOS Summary",
"type": "node",
"propOrder": [
"Devices",
"Links",
"Hosts",
"Topology SCCs",
"Paths",
"-",
"Intents",
"Flows",
"Version"
],
"props": {
"Devices": "25",
"Links": "112",
"Hosts": "25",
"Topology SCCs": "1",
"Paths": "1,272",
"-": "",
"Intents": "0",
"Flows": "0",
"Version": "1.0.0*"
}
}
}
{
"event": "cancelSummary",
"sid": 2,
"payload": {}
}
{
"event": "requestSummary",
"sid": 1,
"payload": {}
}
......@@ -2,10 +2,13 @@
"event": "addInstance",
"payload": {
"id": "192.168.56.101",
"ip": "192.168.56.101",
"online": true,
"uiAttached": true,
"switches": 4,
"labels": [
"192.168.56.101",
"127.0.0.1"
"192.168.56.101"
]
}
}
......
......@@ -2,11 +2,13 @@
"event": "addInstance",
"payload": {
"id": "onos-2",
"uiAttached": true,
"online": false,
"ip": "192.168.0.2",
"online": true,
"uiAttached": false,
"switches": 3,
"labels": [
"onos-2",
"127.0.0.1"
"192.168.0.2"
]
}
}
......
......@@ -2,10 +2,13 @@
"event": "addInstance",
"payload": {
"id": "onos-leader",
"ip": "192.168.0.5",
"online": false,
"uiAttached": false,
"switches": 0,
"labels": [
"onos-leader",
"127.0.0.1"
"192.168.0.5"
]
}
}
......
......@@ -2,10 +2,13 @@
"event": "addInstance",
"payload": {
"id": "onos-master",
"ip": "192.168.0.7",
"online": false,
"uiAttached": false,
"switches": 300,
"labels": [
"onos-master",
"127.0.0.1"
"192.168.0.7"
]
}
}
......
......@@ -2,10 +2,13 @@
"event": "addInstance",
"payload": {
"id": "onos-slave",
"ip": "192.168.0.11",
"online": false,
"uiAttached": false,
"switches": 17,
"labels": [
"onos-slave",
"127.0.0.1"
"192.168.0.11"
]
}
}
......
......@@ -821,7 +821,7 @@
if (w === undefined) {
return widthVal();
}
el.style('width', w);
el.style('width', w + 'px');
}
};
fpanels[id] = fp;
......
......@@ -32,7 +32,6 @@
/* TODO: move glyphs into framework */
#topo-oibox svg .glyphIcon,
#topo svg .glyphIcon {
fill: black;
stroke: none;
......@@ -43,6 +42,7 @@
stroke: none;
}
/* NODES */
#topo svg .node {
......@@ -313,10 +313,59 @@ svg .node.host circle {
/* ONOS instance stuff */
#topo-oibox {
height: 100px;
}
#topo-oibox div.onosInst {
display: inline-block;
width: 120px;
height: 100px;
}
#topo-oibox svg rect {
fill: #ccc;
stroke: #aaa;
stroke-width: 3.5;
}
#topo-oibox .online svg rect {
opacity: 1;
fill: #9cf;
stroke: #357;
}
#topo-oibox svg .glyphIcon {
fill: #888;
fill-rule: evenodd;
}
#topo-oibox .online svg .glyphIcon {
fill: #000;
}
#topo-oibox svg .badgeIcon {
fill: #aaa;
fill-rule: evenodd;
}
#topo-oibox .online svg .badgeIcon {
fill: #fff;
}
#topo-oibox .onosInst.mastership {
opacity: 0.3;
}
#topo-oibox .onosInst.mastership.affinity {
opacity: 1.0;
}
#topo-oibox .onosInst.mastership.affinity svg rect {
filter: url(#blue-glow);
}
/* ------------------------------------------------------ */
/* ------------------------------------------------------ */
/* ------------------------------------------------------ */
#topo-oibox .onosInst {
#topo-oibox .onosInst_OLD {
position: relative;
width: 88%;
left: 4%;
......@@ -333,31 +382,24 @@ svg .node.host circle {
border: 4px solid #aaa;
}
#topo-oibox .onosInst.online {
/* theme-related */
color: #113;
background-color: #9cf;
border: 4px solid #357;
}
#topo-oibox .onosInst .onosTitle {
#topo-oibox .onosInst_OLD .onosTitle {
text-align: center;
font-size: 10pt;
margin-top: 6px;
color: #888;
}
#topo-oibox .onosInst.online .onosTitle {
#topo-oibox .onosInst_OLD.online .onosTitle {
color: black;
}
#topo-oibox .onosInst svg .glyphIcon {
#topo-oibox .onosInst_OLD svg .glyphIcon {
opacity: 0.5;
fill: black;
stroke: none;
fill-rule: evenodd;
}
#topo-oibox .onosInst.online svg .glyphIcon {
#topo-oibox .onosInst_OLD.online svg .glyphIcon {
opacity: 1;
fill: black;
stroke: none;
......@@ -365,12 +407,12 @@ svg .node.host circle {
}
#topo-oibox .onosInst.online img {
#topo-oibox .onosInst_OLD.online img {
opacity: 1.0;
padding: 3px;
}
#topo-oibox .onosInst img.ui {
#topo-oibox .onosInst_OLD img.ui {
opacity: 1;
position: absolute;
top: 3px;
......@@ -379,14 +421,6 @@ svg .node.host circle {
height: 20px;
}
#topo-oibox .onosInst.mastership {
opacity: 0.3;
}
#topo-oibox .onosInst.mastership.affinity {
opacity: 1.0;
box-shadow: 0 2px 8px #33e;
}
#topo svg .suppressed {
opacity: 0.2;
......
......@@ -946,64 +946,120 @@
return s.replace(/px$/,'');
}
function appendGlyph(svg, ox, oy, dim, iid) {
svg.append('use').attr({
class: 'glyphIcon',
function appendUse(svg, ox, oy, dim, iid, cls) {
var use = svg.append('use').attr({
transform: translate(ox,oy),
'xlink:href': iid,
width: dim,
height: dim
});
if (cls) {
use.classed(cls, true);
}
return use;
}
function appendGlyph(svg, ox, oy, dim, iid, cls) {
appendUse(svg, ox, oy, dim, iid, cls).classed('glyphIcon', true);
}
function appendBadge(svg, ox, oy, dim, iid, cls) {
appendUse(svg, ox, oy, dim, iid,cls ).classed('badgeIcon', true);
}
function attachUiBadge(svg) {
appendBadge(svg, 12, 50, 30, '#uiAttached', 'uiBadge');
}
// ==============================
// onos instance panel functions
var instW = 120;
function viewBox(w, h) {
return '0 0 ' + w + ' ' + h;
}
function updateInstances() {
var onoses = oiBox.el.selectAll('.onosInst')
.data(onosOrder, function (d) { return d.id; });
.data(onosOrder, function (d) { return d.id; }),
boxW = instW * onosOrder.length;
// operate on existing onoses if necessary
onoses.classed('online', function (d) { return d.online; });
// adjust the width of the panel based on number of instances...
oiBox.width(boxW);
// operate on existing onos instances if necessary
onoses.each(function (d) {
var el = d3.select(this),
svg = el.select('svg');
// update online state
el.classed('online', d.online);
// update ui-attached state
svg.select('use.uiBadge').remove();
if (d.uiAttached) {
attachUiBadge(svg);
}
// TODO: update title and property values
});
// operate on new onos instances
var entering = onoses.enter()
.append('div')
.attr('class', 'onosInst')
.classed('online', function (d) { return d.online; })
.on('click', clickInst);
entering.each(function (d, i) {
entering.each(function (d) {
var el = d3.select(this),
img;
var css = window.getComputedStyle(this),
css = window.getComputedStyle(this),
w = stripPx(css.width),
h = stripPx(css.height) / 2;
h = stripPx(css.height);
var svg = el.append('svg').attr({
width: w,
height: h
height: h,
viewBox: viewBox(w, h)
});
var dim = 30;
appendGlyph(svg, 2, 2, 30, '#node');
svg.append('use')
svg.append('rect')
.attr({
class: 'birdBadge',
transform: translate(8,10),
'xlink:href': '#bird',
width: 18,
height: 18,
fill: '#fff'
x: 8,
y: 8,
width: 104,
height: 84,
rx: 12
});
$('<div>').attr('class', 'onosTitle').text(d.id).appendTo(el);
appendGlyph(svg, 9, 9, 36, '#node');
appendBadge(svg, 17, 19, 21, '#bird');
if (d.uiAttached) {
attachUiBadge(svg);
}
//svg.append('use')
// .attr({
// class: 'birdBadge',
// transform: translate(8,10),
// 'xlink:href': '#bird',
// width: 18,
// height: 18,
// fill: '#fff'
// });
//
//$('<div>').attr('class', 'onosTitle').text(d.id).appendTo(el);
// is the UI attached to this instance?
// TODO: need uiAttached boolean in instance data
// TODO: use SVG glyph, not png..
//if (d.uiAttached) {
if (i === 0) {
$('<img src="img/ui.png">').attr('class','ui').appendTo(el);
}
//if (i === 0) {
// $('<img src="img/ui.png">').attr('class','ui').appendTo(el);
//}
});
// operate on existing + new onoses here
......@@ -2194,8 +2250,8 @@
function loadGlyphs(svg) {
var defs = svg.append('defs');
gly.defBird(defs);
gly.defBullhorn(defs);
gly.defGlyphs(defs);
gly.defBadges(defs);
}
// ==============================
......@@ -2468,5 +2524,6 @@
summaryPane = onos.ui.addFloatingPanel('topo-summary');
detailPane = onos.ui.addFloatingPanel('topo-detail');
oiBox = onos.ui.addFloatingPanel('topo-oibox', 'TL');
oiBox.width(20);
}(ONOS));
......