Another step forward with the UI.
- Added hosts to test data.
- Messed with colors and icons.
- Added more internal configuration values.
diff --git a/web/gui/src/main/webapp/network.js b/web/gui/src/main/webapp/network.js
index 80d11b7..ef190e7 100644
--- a/web/gui/src/main/webapp/network.js
+++ b/web/gui/src/main/webapp/network.js
@@ -10,17 +10,33 @@
var api = onos.api;
var config = {
- layering: false,
+ options: {
+ layering: false,
+ collisionPrevention: true
+ },
jsonUrl: 'network.json',
iconUrl: {
- pkt: 'pkt.png',
- opt: 'opt.png'
+ logo: 'img/onos-logo.tiff',
+ device: 'img/device.png',
+ host: 'img/host.png',
+ pkt: 'img/pkt.png',
+ opt: 'img/opt.png'
},
mastHeight: 32,
force: {
- linkDistance: 240,
- linkStrength: 0.8,
- charge: -400,
+ note: 'node.class or link.class is used to differentiate',
+ linkDistance: {
+ infra: 240,
+ host: 100
+ },
+ linkStrength: {
+ infra: 1.0,
+ host: 0.4
+ },
+ charge: {
+ device: -800,
+ host: -400
+ },
ticksWithoutCollisions: 50,
marginLR: 20,
marginTB: 20,
@@ -37,12 +53,21 @@
marginLR: 3,
marginTB: 2
},
+ icons: {
+ w: 32,
+ h: 32,
+ xoff: -12,
+ yoff: -10
+ },
constraints: {
ypos: {
- pkt: 0.3,
- opt: 0.7
+ host: 0.15,
+ switch: 0.3,
+ roadm: 0.7
}
- }
+ },
+ hostLinkWidth: 1.0,
+ mouseOutTimerDelayMs: 120
},
view = {},
network = {},
@@ -104,14 +129,23 @@
var nw = network.forceWidth,
nh = network.forceHeight;
- network.data.nodes.forEach(function(n) {
+ function yPosConstraintForNode(n) {
+ return config.constraints.ypos[n.type || 'host'];
+ }
+
+ // Note that both 'devices' and 'hosts' get mapped into the nodes array
+
+ // first, the devices...
+ network.data.devices.forEach(function(n) {
var ypc = yPosConstraintForNode(n),
ix = Math.random() * 0.6 * nw + 0.2 * nw,
iy = ypc * nh,
node = {
id: n.id,
+ labels: n.labels,
+ class: 'device',
+ icon: 'device',
type: n.type,
- status: n.status,
x: ix,
y: iy,
constraint: {
@@ -123,21 +157,61 @@
network.nodes.push(node);
});
- function yPosConstraintForNode(n) {
- return config.constraints.ypos[n.type] || 0.5;
- }
+ // then, the hosts...
+ network.data.hosts.forEach(function(n) {
+ var ypc = yPosConstraintForNode(n),
+ ix = Math.random() * 0.6 * nw + 0.2 * nw,
+ iy = ypc * nh,
+ node = {
+ id: n.id,
+ labels: n.labels,
+ class: 'host',
+ icon: 'host',
+ type: n.type,
+ x: ix,
+ y: iy,
+ constraint: {
+ weight: 0.7,
+ y: iy
+ }
+ };
+ network.lookup[n.id] = node;
+ network.nodes.push(node);
+ });
+ // now, process the explicit links...
network.data.links.forEach(function(n) {
var src = network.lookup[n.src],
dst = network.lookup[n.dst],
id = src.id + "~" + dst.id;
var link = {
+ class: 'infra',
id: id,
+ type: n.type,
+ width: n.linkWidth,
source: src,
target: dst,
- strength: config.force.linkStrength
+ strength: config.force.linkStrength.infra
+ };
+ network.links.push(link);
+ });
+
+ // finally, infer host links...
+ network.data.hosts.forEach(function(n) {
+ var src = network.lookup[n.id],
+ dst = network.lookup[n.cp.device],
+ id = src.id + "~" + dst.id;
+
+ var link = {
+ class: 'host',
+ id: id,
+ type: 'hostLink',
+ width: config.hostLinkWidth,
+ source: src,
+ target: dst,
+ strength: config.force.linkStrength.host
};
network.links.push(link);
});
@@ -145,13 +219,15 @@
function createLayout() {
+ var cfg = config.force;
+
network.force = d3.layout.force()
+ .size([network.forceWidth, network.forceHeight])
.nodes(network.nodes)
.links(network.links)
- .linkStrength(function(d) { return d.strength; })
- .size([network.forceWidth, network.forceHeight])
- .linkDistance(config.force.linkDistance)
- .charge(config.force.charge)
+ .linkStrength(function(d) { return cfg.linkStrength[d.class]; })
+ .linkDistance(function(d) { return cfg.linkDistance[d.class]; })
+ .charge(function(d) { return cfg.charge[d.class]; })
.on('tick', tick);
network.svg = d3.select('#view').append('svg')
@@ -205,9 +281,10 @@
network.link = network.svg.append('g').selectAll('.link')
.data(network.force.links(), function(d) {return d.id})
.enter().append('line')
- .attr('class', 'link');
+ .attr('class', function(d) {return 'link ' + d.class});
- // TODO: drag behavior
+
+ // == define node drag behavior...
network.draggedThreshold = d3.scale.linear()
.domain([0, 0.1])
.range([5, 20])
@@ -258,7 +335,11 @@
.data(network.force.nodes(), function(d) {return d.id})
.enter().append('g')
.attr('class', function(d) {
- return 'node ' + d.type;
+ var cls = 'node ' + d.class;
+ if (d.type) {
+ cls += ' ' + d.type;
+ }
+ return cls;
})
.attr('transform', function(d) {
return translate(d.x, d.y);
@@ -281,29 +362,32 @@
}
network.mouseoutTimeout = setTimeout(function() {
highlightObject(null);
- }, 160);
+ }, config.mouseOutTimerDelayMs);
}
});
network.nodeRect = network.node.append('rect')
.attr('rx', 5)
- .attr('ry', 5)
- .attr('width', 126)
- .attr('height', 40);
+ .attr('ry', 5);
+ // note that width/height are adjusted to fit the label text
network.node.each(function(d) {
var node = d3.select(this),
rect = node.select('rect'),
- img = node.append('svg:image')
- .attr('x', -16)
- .attr('y', -16)
- .attr('width', 32)
- .attr('height', 32)
- .attr('xlink:href', iconUrl(d)),
+ icon = iconUrl(d),
text = node.append('text')
.text(d.id)
- .attr('dy', '1.1em'),
- dummy;
+ .attr('dy', '1.1em');
+
+ if (icon) {
+ var cfg = config.icons;
+ node.append('svg:image')
+ .attr('width', cfg.w)
+ .attr('height', cfg.h)
+ .attr('xlink:href', icon);
+ // note, icon relative positioning (x,y) is done after we have
+ // adjusted the bounds of the rectangle...
+ }
});
@@ -352,7 +436,8 @@
.attr('height', bounds.y2 - bounds.y1);
node.select('image')
- .attr('x', bounds.x1);
+ .attr('x', bounds.x1 + config.icons.xoff)
+ .attr('y', bounds.y1 + config.icons.yoff);
d.extent = {
left: bounds.x1 - lab.marginLR,
@@ -384,7 +469,7 @@
}
function iconUrl(d) {
- return config.iconUrl[d.type];
+ return config.iconUrl[d.icon];
}
function translate(x, y) {
@@ -440,7 +525,7 @@
function tick(e) {
network.numTicks++;
- if (config.layering) {
+ if (config.options.layering) {
// adjust the y-coord of each node, based on y-pos constraints
network.nodes.forEach(function (n) {
var z = e.alpha * n.constraint.weight;
@@ -450,7 +535,7 @@
});
}
- if (network.preventCollisions) {
+ if (config.options.collisionPrevention && network.preventCollisions) {
preventCollisions();
}
diff --git a/web/gui/src/main/webapp/network.json b/web/gui/src/main/webapp/network.json
index b4f1b6e..c43e0ef 100644
--- a/web/gui/src/main/webapp/network.json
+++ b/web/gui/src/main/webapp/network.json
@@ -1,56 +1,163 @@
{
- "id": "network-v1",
"meta": {
- "__comment_1__": "This is sample data for developing the ONOS UI",
- "foo": "bar",
- "zoo": "goo"
+ "comments": [
+ "This is sample data for developing the ONOS UI (network view)",
+ " in a standalone mode (no server required).",
+ " Eventually, we will wire this up to live data",
+ " from the server, via a websocket.",
+ "",
+ "Note that this is just a first-draft of the data --",
+ " additional fields will be added when they are needed."
+ ],
+ "otherMetaData": "can go here..."
},
- "nodes": [
+ "devices": [
{
- "id": "sample1",
- "type": "opt",
- "status": "good"
+ "id": "of:0000000000000001",
+ "labels": ["00:00:00:00:00:00:00:01", "of/::01", "opt-1"],
+ "type": "roadm"
},
{
- "id": "00:00:00:00:00:00:00:02",
- "type": "opt",
- "status": "good"
+ "id": "of:0000000000000002",
+ "labels": ["00:00:00:00:00:00:00:02", "of/::02", "opt-2"],
+ "type": "roadm"
},
{
- "id": "00:00:00:00:00:00:00:03",
- "type": "opt",
- "status": "good"
+ "id": "of:0000000000000003",
+ "labels": ["00:00:00:00:00:00:00:03", "of/::03", "opt-3"],
+ "type": "roadm"
},
{
- "id": "00:00:00:00:00:00:00:04",
- "type": "opt",
- "status": "good"
+ "id": "of:0000000000000004",
+ "labels": ["00:00:00:00:00:00:00:04", "of/::04", "opt-4"],
+ "type": "roadm"
},
{
- "id": "00:00:00:00:00:00:00:11",
- "type": "pkt",
- "status": "good"
+ "id": "of:0000000000000011",
+ "labels": ["00:00:00:00:00:00:00:11", "of/::11", "pkt-11"],
+ "type": "switch"
},
{
- "id": "00:00:00:00:00:00:00:12",
- "type": "pkt",
- "status": "good"
+ "id": "of:0000000000000012",
+ "labels": ["00:00:00:00:00:00:00:12", "of/::12", "pkt-12"],
+ "type": "switch"
},
{
- "id": "00:00:00:00:00:00:00:13",
- "type": "pkt",
- "status": "good"
+ "id": "of:0000000000000013",
+ "labels": ["00:00:00:00:00:00:00:13", "of/::13", "pkt-13"],
+ "type": "switch"
}
],
+ "linkNotes": [
+ "even though we have 'directionality' (src/dst), each link is",
+ " considered to be bi-directional. Note that links between hosts",
+ " and edge switches are inferred from host information, and not",
+ " explicitly represented here."
+ ],
"links": [
- { "src": "sample1", "dst": "00:00:00:00:00:00:00:02" },
- { "src": "sample1", "dst": "00:00:00:00:00:00:00:03" },
- { "src": "sample1", "dst": "00:00:00:00:00:00:00:04" },
- { "src": "00:00:00:00:00:00:00:02", "dst": "00:00:00:00:00:00:00:03" },
- { "src": "00:00:00:00:00:00:00:02", "dst": "00:00:00:00:00:00:00:04" },
- { "src": "00:00:00:00:00:00:00:03", "dst": "00:00:00:00:00:00:00:04" },
- { "src": "00:00:00:00:00:00:00:13", "dst": "00:00:00:00:00:00:00:03" },
- { "src": "00:00:00:00:00:00:00:12", "dst": "00:00:00:00:00:00:00:02" },
- { "src": "00:00:00:00:00:00:00:11", "dst": "sample1" }
+ {
+ "src": "of:0000000000000001",
+ "dst": "of:0000000000000002",
+ "type": "optical",
+ "linkWidth": 1.5
+ },
+ {
+ "src": "of:0000000000000001",
+ "dst": "of:0000000000000003",
+ "type": "optical",
+ "linkWidth": 1.5
+ },
+ {
+ "src": "of:0000000000000001",
+ "dst": "of:0000000000000004",
+ "type": "optical",
+ "linkWidth": 1.5
+ },
+ {
+ "src": "of:0000000000000002",
+ "dst": "of:0000000000000003",
+ "type": "optical",
+ "linkWidth": 1.5
+ },
+ {
+ "src": "of:0000000000000002",
+ "dst": "of:0000000000000004",
+ "type": "optical",
+ "linkWidth": 1.5
+ },
+ {
+ "src": "of:0000000000000003",
+ "dst": "of:0000000000000004",
+ "type": "optical",
+ "linkWidth": 1.5
+ },
+ {
+ "src": "of:0000000000000013",
+ "dst": "of:0000000000000003",
+ "type": "direct",
+ "linkWidth": 1.0
+ },
+ {
+ "src": "of:0000000000000012",
+ "dst": "of:0000000000000002",
+ "type": "direct",
+ "linkWidth": 1.0
+ },
+ {
+ "src": "of:0000000000000011",
+ "dst": "of:0000000000000001",
+ "type": "direct",
+ "linkWidth": 1.0
+ }
+ ],
+ "hosts": [
+ {
+ "id": "00:60:d3:00:11:01/7",
+ "labels": ["00:60:d3:00:11:01/7", "Host-11-A"],
+ "cp" : {
+ "device": "of:0000000000000011",
+ "port": 6
+ }
+ },
+ {
+ "id": "00:60:d3:00:11:02/7",
+ "labels": ["00:60:d3:00:11:02/7", "Host-11-B"],
+ "cp" : {
+ "device": "of:0000000000000011",
+ "port": 8
+ }
+ },
+ {
+ "id": "00:60:d3:00:12:01/4",
+ "labels": ["00:60:d3:00:12:01/4", "Host-12-C"],
+ "cp" : {
+ "device": "of:0000000000000012",
+ "port": 12
+ }
+ },
+ {
+ "id": "00:60:d3:00:12:02/4",
+ "labels": ["00:60:d3:00:12:02/4", "Host-12-D"],
+ "cp" : {
+ "device": "of:0000000000000012",
+ "port": 13
+ }
+ },
+ {
+ "id": "00:60:d3:00:13:01/19",
+ "labels": ["00:60:d3:00:13:01/19", "Host-13-E"],
+ "cp" : {
+ "device": "of:0000000000000013",
+ "port": 7
+ }
+ },
+ {
+ "id": "00:60:d3:00:13:02/19",
+ "labels": ["00:60:d3:00:13:02/19", "Host-13-F"],
+ "cp" : {
+ "device": "of:0000000000000013",
+ "port": 8
+ }
+ }
]
}
diff --git a/web/gui/src/main/webapp/onos.css b/web/gui/src/main/webapp/onos.css
index 340ae79..b2df75c 100644
--- a/web/gui/src/main/webapp/onos.css
+++ b/web/gui/src/main/webapp/onos.css
@@ -38,7 +38,7 @@
* Network Graph elements ======================================
*/
-.link {
+svg .link {
fill: none;
stroke: #666;
stroke-width: 1.5px;
@@ -56,7 +56,7 @@
stroke-width: 1.5px;
}
-.node rect {
+svg .node rect {
stroke-width: 1.5px;
transition: opacity 250ms;
@@ -64,13 +64,15 @@
-moz-transition: opacity 250ms;
}
-/*differentiate between packet and optical nodes*/
-svg .node.pkt rect {
- fill: #77a;
+svg .node.device.roadm rect {
+ fill: #229;
+}
+svg .node.device.switch rect {
+ fill: #55f;
}
-svg .node.opt rect {
- fill: #7a7;
+svg .node.host rect {
+ fill: #787;
}
svg .node text {
@@ -121,15 +123,13 @@
#frame {
width: 100%;
height: 100%;
- background-color: #cdf;
+ background-color: #fff;
}
#mast {
height: 32px;
- background-color: #abe;
+ padding: 6px;
+ background-color: #ccc;
vertical-align: baseline;
}
-#main {
- background-color: #99c;
-}
diff --git a/web/gui/src/main/webapp/opt.png b/web/gui/src/main/webapp/opt.png
deleted file mode 100644
index 2f2c88e..0000000
--- a/web/gui/src/main/webapp/opt.png
+++ /dev/null
Binary files differ
diff --git a/web/gui/src/main/webapp/pkt.png b/web/gui/src/main/webapp/pkt.png
deleted file mode 100644
index 1b1d5a3..0000000
--- a/web/gui/src/main/webapp/pkt.png
+++ /dev/null
Binary files differ