Simon Hunt

Fixed node geometry so that [x,y] is now at the center of the rectangle. (Added debug circles).

Added radio buttons in mast head.
...@@ -25,9 +25,11 @@ ...@@ -25,9 +25,11 @@
25 --> 25 -->
26 <html> 26 <html>
27 <head> 27 <head>
28 + <meta charset="utf-8">
28 <title>ONOS GUI</title> 29 <title>ONOS GUI</title>
29 30
30 - <script src="libs/d3.min.js"></script> 31 + <!--TODO: use the minified version of d3, once debugging is complete -->
32 + <script src="libs/d3.js"></script>
31 <script src="libs/jquery-2.1.1.min.js"></script> 33 <script src="libs/jquery-2.1.1.min.js"></script>
32 34
33 <link rel="stylesheet" href="base.css"> 35 <link rel="stylesheet" href="base.css">
...@@ -42,10 +44,10 @@ ...@@ -42,10 +44,10 @@
42 <div id="mast"> 44 <div id="mast">
43 <img id="logo" src="img/onos-logo.png" width="60" height="38"> 45 <img id="logo" src="img/onos-logo.png" width="60" height="38">
44 <span class="title">Open Network Operating System</span> 46 <span class="title">Open Network Operating System</span>
45 - <span class="right"> 47 + <span id="displayModes" class="right">
46 - <span class="radio">[All Layers]</span> 48 + <span id="showAll" class="radio active">All Layers</span>
47 - <span class="radio">[Packet Only]</span> 49 + <span id="showPkt" class="radio">Packet Only</span>
48 - <span class="radio">[Optical Only]</span> 50 + <span id="showOpt" class="radio">Optical Only</span>
49 </span> 51 </span>
50 </div> 52 </div>
51 <div id="view"></div> 53 <div id="view"></div>
......
...@@ -31,7 +31,8 @@ ...@@ -31,7 +31,8 @@
31 var config = { 31 var config = {
32 options: { 32 options: {
33 layering: true, 33 layering: true,
34 - collisionPrevention: true 34 + collisionPrevention: true,
35 + showNodeXY: true
35 }, 36 },
36 XjsonUrl: 'rs/topology/graph', 37 XjsonUrl: 'rs/topology/graph',
37 jsonUrl: 'network.json', 38 jsonUrl: 'network.json',
...@@ -91,7 +92,8 @@ ...@@ -91,7 +92,8 @@
91 view = {}, 92 view = {},
92 network = {}, 93 network = {},
93 selected = {}, 94 selected = {},
94 - highlighted = null; 95 + highlighted = null,
96 + viewMode = 'showAll';
95 97
96 98
97 function loadNetworkView() { 99 function loadNetworkView() {
...@@ -126,6 +128,21 @@ ...@@ -126,6 +128,21 @@
126 }); 128 });
127 129
128 $(window).on('resize', resize); 130 $(window).on('resize', resize);
131 +
132 + // set up radio button behavior
133 + d3.selectAll("#displayModes .radio").on('click', function() {
134 + var id = d3.select(this).attr("id");
135 + if (id !== viewMode) {
136 + radioButton('displayModes', id);
137 + viewMode = id;
138 + alert("action: " + id);
139 + }
140 + });
141 + }
142 +
143 + function radioButton(group, id) {
144 + d3.selectAll("#" + group + " .radio").classed("active", false);
145 + d3.select("#" + group + " #" + id).classed("active", true);
129 } 146 }
130 147
131 148
...@@ -263,8 +280,6 @@ ...@@ -263,8 +280,6 @@
263 // + " scale(" + d3.event.scale + ")"); 280 // + " scale(" + d3.event.scale + ")");
264 // } 281 // }
265 282
266 - // TODO: svg.append('defs') for markers?
267 -
268 // TODO: move glow/blur stuff to util script 283 // TODO: move glow/blur stuff to util script
269 var glow = network.svg.append('filter') 284 var glow = network.svg.append('filter')
270 .attr('x', '-50%') 285 .attr('x', '-50%')
...@@ -295,8 +310,7 @@ ...@@ -295,8 +310,7 @@
295 // }); 310 // });
296 311
297 312
298 - 313 + // add links to the display
299 -
300 network.link = network.svg.append('g').selectAll('.link') 314 network.link = network.svg.append('g').selectAll('.link')
301 .data(network.force.links(), function(d) {return d.id}) 315 .data(network.force.links(), function(d) {return d.id})
302 .enter().append('line') 316 .enter().append('line')
...@@ -350,6 +364,7 @@ ...@@ -350,6 +364,7 @@
350 }); 364 });
351 365
352 366
367 + // add nodes to the display
353 network.node = network.svg.selectAll('.node') 368 network.node = network.svg.selectAll('.node')
354 .data(network.force.nodes(), function(d) {return d.id}) 369 .data(network.force.nodes(), function(d) {return d.id})
355 .enter().append('g') 370 .enter().append('g')
...@@ -386,15 +401,19 @@ ...@@ -386,15 +401,19 @@
386 }); 401 });
387 402
388 network.nodeRect = network.node.append('rect') 403 network.nodeRect = network.node.append('rect')
389 - .attr('rx', 5) 404 + .attr({
390 - .attr('ry', 5); 405 + rx: 5,
406 + ry: 5,
407 + width: 100,
408 + height: 12
409 + });
391 // note that width/height are adjusted to fit the label text 410 // note that width/height are adjusted to fit the label text
392 411
393 network.node.each(function(d) { 412 network.node.each(function(d) {
394 var node = d3.select(this), 413 var node = d3.select(this),
395 - rect = node.select('rect'), 414 + icon = iconUrl(d);
396 - icon = iconUrl(d), 415 +
397 - text = node.append('text') 416 + node.append('text')
398 // TODO: add label cycle behavior 417 // TODO: add label cycle behavior
399 .text(d.id) 418 .text(d.id)
400 .attr('dy', '1.1em'); 419 .attr('dy', '1.1em');
...@@ -402,63 +421,85 @@ ...@@ -402,63 +421,85 @@
402 if (icon) { 421 if (icon) {
403 var cfg = config.icons; 422 var cfg = config.icons;
404 node.append('svg:image') 423 node.append('svg:image')
405 - .attr('width', cfg.w) 424 + .attr({
406 - .attr('height', cfg.h) 425 + width: cfg.w,
407 - .attr('xlink:href', icon); 426 + height: cfg.h,
427 + 'xlink:href': icon
428 + });
408 // note, icon relative positioning (x,y) is done after we have 429 // note, icon relative positioning (x,y) is done after we have
409 // adjusted the bounds of the rectangle... 430 // adjusted the bounds of the rectangle...
410 } 431 }
411 432
433 + // for debugging...
434 + if (config.options.showNodeXY) {
435 + node.append('circle')
436 + .attr({
437 + class: 'debug',
438 + cx: 0,
439 + cy: 0,
440 + r: '3px'
441 + });
442 + }
412 }); 443 });
413 444
445 +
446 + // returns the newly computed bounding box
447 + function adjustRectToFitText(n) {
448 + var text = n.select('text'),
449 + box = text.node().getBBox(),
450 + lab = config.labels;
451 +
452 + text.attr('text-anchor', 'middle')
453 + .attr('y', '-0.8em')
454 + .attr('x', lab.imgPad/2)
455 + ;
456 +
457 + // TODO: figure out how to access the data on selection
458 + console.log("\nadjust rect for " + n.data().id);
459 + console.log(box);
460 +
461 + // translate the bbox so that it is centered on [x,y]
462 + box.x = -box.width / 2;
463 + box.y = -box.height / 2;
464 +
465 + // add padding
466 + box.x -= (lab.padLR + lab.imgPad/2);
467 + box.width += lab.padLR * 2 + lab.imgPad;
468 + box.y -= lab.padTB;
469 + box.height += lab.padTB * 2;
470 +
471 + return box;
472 + }
473 +
474 + function boundsFromBox(box) {
475 + return {
476 + x1: box.x,
477 + y1: box.y,
478 + x2: box.x + box.width,
479 + y2: box.y + box.height
480 + };
481 + }
482 +
414 // this function is scheduled to happen soon after the given thread ends 483 // this function is scheduled to happen soon after the given thread ends
415 setTimeout(function() { 484 setTimeout(function() {
416 network.node.each(function(d) { 485 network.node.each(function(d) {
417 // for every node, recompute size, padding, etc. so text fits 486 // for every node, recompute size, padding, etc. so text fits
418 var node = d3.select(this), 487 var node = d3.select(this),
419 - text = node.selectAll('text'), 488 + text = node.select('text'),
420 - bounds = {}, 489 + box = adjustRectToFitText(node),
421 - first = true; 490 + lab = config.labels;
422 -
423 - // NOTE: probably unnecessary code if we only have one line.
424 - text.each(function() {
425 - var box = this.getBBox();
426 - if (first || box.x < bounds.x1) {
427 - bounds.x1 = box.x;
428 - }
429 - if (first || box.y < bounds.y1) {
430 - bounds.y1 = box.y;
431 - }
432 - if (first || box.x + box.width < bounds.x2) {
433 - bounds.x2 = box.x + box.width;
434 - }
435 - if (first || box.y + box.height < bounds.y2) {
436 - bounds.y2 = box.y + box.height;
437 - }
438 - first = false;
439 - }).attr('text-anchor', 'middle');
440 -
441 - var lab = config.labels,
442 - oldWidth = bounds.x2 - bounds.x1;
443 -
444 - bounds.x1 -= oldWidth / 2;
445 - bounds.x2 -= oldWidth / 2;
446 -
447 - bounds.x1 -= (lab.padLR + lab.imgPad);
448 - bounds.y1 -= lab.padTB;
449 - bounds.x2 += lab.padLR;
450 - bounds.y2 += lab.padTB;
451 491
492 + // now make the computed adjustment
452 node.select('rect') 493 node.select('rect')
453 - .attr('x', bounds.x1) 494 + .attr(box);
454 - .attr('y', bounds.y1)
455 - .attr('width', bounds.x2 - bounds.x1)
456 - .attr('height', bounds.y2 - bounds.y1);
457 495
458 node.select('image') 496 node.select('image')
459 - .attr('x', bounds.x1 + config.icons.xoff) 497 + .attr('x', box.x + config.icons.xoff)
460 - .attr('y', bounds.y1 + config.icons.yoff); 498 + .attr('y', box.y + config.icons.yoff);
499 +
500 + var bounds = boundsFromBox(box);
461 501
502 + // todo: clean up extent and edge work..
462 d.extent = { 503 d.extent = {
463 left: bounds.x1 - lab.marginLR, 504 left: bounds.x1 - lab.marginLR,
464 right: bounds.x2 + lab.marginLR, 505 right: bounds.x2 + lab.marginLR,
...@@ -473,7 +514,6 @@ ...@@ -473,7 +514,6 @@
473 bottom : new geo.LineSegment(bounds.x1, bounds.y2, bounds.x2, bounds.y2) 514 bottom : new geo.LineSegment(bounds.x1, bounds.y2, bounds.x2, bounds.y2)
474 }; 515 };
475 516
476 - // ====
477 }); 517 });
478 518
479 network.numTicks = 0; 519 network.numTicks = 0;
......
...@@ -48,6 +48,26 @@ span.right { ...@@ -48,6 +48,26 @@ span.right {
48 } 48 }
49 49
50 /* 50 /*
51 + * Radio Buttons
52 + */
53 +
54 +span.radio {
55 + margin: 4px 0;
56 + border: 1px dotted #222;
57 + padding: 1px 6px;
58 + color: #eee;
59 + cursor: pointer;
60 +}
61 +
62 +span.radio.active {
63 + background-color: #bbb;
64 + border: 1px solid #eee;
65 + padding: 1px 6px;
66 + color: #666;
67 + font-weight: bold;
68 +}
69 +
70 +/*
51 * === DEBUGGING ====== 71 * === DEBUGGING ======
52 */ 72 */
53 svg { 73 svg {
...@@ -71,12 +91,6 @@ svg .link { ...@@ -71,12 +91,6 @@ svg .link {
71 -moz-transition: opacity 250ms; 91 -moz-transition: opacity 250ms;
72 } 92 }
73 93
74 -marker#end {
75 - fill: #666;
76 - stroke: #666;
77 - stroke-width: 1.5px;
78 -}
79 -
80 svg .node rect { 94 svg .node rect {
81 stroke-width: 1.5px; 95 stroke-width: 1.5px;
82 96
...@@ -88,6 +102,7 @@ svg .node rect { ...@@ -88,6 +102,7 @@ svg .node rect {
88 svg .node.device.roadm rect { 102 svg .node.device.roadm rect {
89 fill: #229; 103 fill: #229;
90 } 104 }
105 +
91 svg .node.device.switch rect { 106 svg .node.device.switch rect {
92 fill: #55f; 107 fill: #55f;
93 } 108 }
...@@ -102,6 +117,18 @@ svg .node text { ...@@ -102,6 +117,18 @@ svg .node text {
102 pointer-events: none; 117 pointer-events: none;
103 } 118 }
104 119
120 +/* for debugging */
121 +svg .node circle.debug {
122 + fill: white;
123 + stroke: red;
124 +}
125 +svg .node rect.debug {
126 + fill: yellow;
127 + stroke: red;
128 + opacity: 0.35;
129 +}
130 +
131 +
105 svg .node.selected rect { 132 svg .node.selected rect {
106 filter: url(#blue-glow); 133 filter: url(#blue-glow);
107 } 134 }
...@@ -119,6 +146,16 @@ svg .node.inactive.selected image { ...@@ -119,6 +146,16 @@ svg .node.inactive.selected image {
119 opacity: .6; 146 opacity: .6;
120 } 147 }
121 148
149 +/*
150 + * === currently unused ===============================================
151 + */
152 +
153 +svg marker#end {
154 + fill: #666;
155 + stroke: #666;
156 + stroke-width: 1.5px;
157 +}
158 +
122 svg .legend { 159 svg .legend {
123 position: fixed; 160 position: fixed;
124 } 161 }
......