Added keydown handler.
Some refactoring. Cleaned up debug configuration. Links now clipped to edges of node rectangles. Updated ONOS icon (just a placeholder for now)
Showing
3 changed files
with
108 additions
and
35 deletions
| ... | @@ -26,13 +26,19 @@ | ... | @@ -26,13 +26,19 @@ |
| 26 | (function (onos) { | 26 | (function (onos) { |
| 27 | 'use strict'; | 27 | 'use strict'; |
| 28 | 28 | ||
| 29 | + // reference to the framework api | ||
| 29 | var api = onos.api; | 30 | var api = onos.api; |
| 30 | 31 | ||
| 32 | + // configuration data | ||
| 31 | var config = { | 33 | var config = { |
| 34 | + debugOn: false, | ||
| 35 | + debug: { | ||
| 36 | + showNodeXY: true, | ||
| 37 | + showKeyHandler: false | ||
| 38 | + }, | ||
| 32 | options: { | 39 | options: { |
| 33 | layering: true, | 40 | layering: true, |
| 34 | - collisionPrevention: true, | 41 | + collisionPrevention: true |
| 35 | - showNodeXY: true | ||
| 36 | }, | 42 | }, |
| 37 | XjsonUrl: 'rs/topology/graph', | 43 | XjsonUrl: 'rs/topology/graph', |
| 38 | jsonUrl: 'network.json', | 44 | jsonUrl: 'network.json', |
| ... | @@ -88,20 +94,28 @@ | ... | @@ -88,20 +94,28 @@ |
| 88 | }, | 94 | }, |
| 89 | hostLinkWidth: 1.0, | 95 | hostLinkWidth: 1.0, |
| 90 | mouseOutTimerDelayMs: 120 | 96 | mouseOutTimerDelayMs: 120 |
| 91 | - }, | 97 | + }; |
| 92 | - view = {}, | 98 | + |
| 99 | + // state variables | ||
| 100 | + var view = {}, | ||
| 93 | network = {}, | 101 | network = {}, |
| 94 | selected = {}, | 102 | selected = {}, |
| 95 | highlighted = null, | 103 | highlighted = null, |
| 96 | viewMode = 'showAll'; | 104 | viewMode = 'showAll'; |
| 97 | 105 | ||
| 98 | 106 | ||
| 107 | + function debug(what) { | ||
| 108 | + return config.debugOn && config.debug[what]; | ||
| 109 | + } | ||
| 110 | + | ||
| 111 | + // load the topology view of the network | ||
| 99 | function loadNetworkView() { | 112 | function loadNetworkView() { |
| 100 | // Hey, here I am, calling something on the ONOS api: | 113 | // Hey, here I am, calling something on the ONOS api: |
| 101 | api.printTime(); | 114 | api.printTime(); |
| 102 | 115 | ||
| 103 | resize(); | 116 | resize(); |
| 104 | 117 | ||
| 118 | + // go get our network data from the server... | ||
| 105 | d3.json(config.jsonUrl, function (err, data) { | 119 | d3.json(config.jsonUrl, function (err, data) { |
| 106 | if (err) { | 120 | if (err) { |
| 107 | alert('Oops! Error reading JSON...\n\n' + | 121 | alert('Oops! Error reading JSON...\n\n' + |
| ... | @@ -109,14 +123,23 @@ | ... | @@ -109,14 +123,23 @@ |
| 109 | 'Error: ' + err.message); | 123 | 'Error: ' + err.message); |
| 110 | return; | 124 | return; |
| 111 | } | 125 | } |
| 112 | - console.log("here is the JSON data..."); | 126 | +// console.log("here is the JSON data..."); |
| 113 | - console.log(data); | 127 | +// console.log(data); |
| 114 | 128 | ||
| 115 | network.data = data; | 129 | network.data = data; |
| 116 | drawNetwork(); | 130 | drawNetwork(); |
| 117 | }); | 131 | }); |
| 118 | 132 | ||
| 119 | - $(document).on('click', '.select-object', function() { | 133 | + // while we wait for the data, set up the handlers... |
| 134 | + setUpClickHandler(); | ||
| 135 | + setUpRadioButtonHandler(); | ||
| 136 | + setUpKeyHandler(); | ||
| 137 | + $(window).on('resize', resize); | ||
| 138 | + } | ||
| 139 | + | ||
| 140 | + function setUpClickHandler() { | ||
| 141 | + // click handler for "selectable" objects | ||
| 142 | + $(document).on('click', '.select-object', function () { | ||
| 120 | // when any object of class "select-object" is clicked... | 143 | // when any object of class "select-object" is clicked... |
| 121 | // TODO: get a reference to the object via lookup... | 144 | // TODO: get a reference to the object via lookup... |
| 122 | var obj = network.lookup[$(this).data('id')]; | 145 | var obj = network.lookup[$(this).data('id')]; |
| ... | @@ -126,16 +149,34 @@ | ... | @@ -126,16 +149,34 @@ |
| 126 | // stop propagation of event (I think) ... | 149 | // stop propagation of event (I think) ... |
| 127 | return false; | 150 | return false; |
| 128 | }); | 151 | }); |
| 152 | + } | ||
| 129 | 153 | ||
| 130 | - $(window).on('resize', resize); | 154 | + function setUpRadioButtonHandler() { |
| 131 | - | 155 | + d3.selectAll('#displayModes .radio').on('click', function () { |
| 132 | - // set up radio button behavior | 156 | + var id = d3.select(this).attr('id'); |
| 133 | - d3.selectAll("#displayModes .radio").on('click', function() { | ||
| 134 | - var id = d3.select(this).attr("id"); | ||
| 135 | if (id !== viewMode) { | 157 | if (id !== viewMode) { |
| 136 | radioButton('displayModes', id); | 158 | radioButton('displayModes', id); |
| 137 | viewMode = id; | 159 | viewMode = id; |
| 138 | - alert("action: " + id); | 160 | + alert('action: ' + id); |
| 161 | + } | ||
| 162 | + }); | ||
| 163 | + } | ||
| 164 | + | ||
| 165 | + function setUpKeyHandler() { | ||
| 166 | + d3.select('body') | ||
| 167 | + .on('keydown', function () { | ||
| 168 | + processKeyEvent(); | ||
| 169 | + if (debug('showKeyHandler')) { | ||
| 170 | + network.svg.append('text') | ||
| 171 | + .attr('x', 5) | ||
| 172 | + .attr('y', 15) | ||
| 173 | + .style('font-size', '20pt') | ||
| 174 | + .text('keyCode: ' + d3.event.keyCode + | ||
| 175 | + ' applied to : ' + contextLabel()) | ||
| 176 | + .transition().duration(2000) | ||
| 177 | + .style('font-size', '2pt') | ||
| 178 | + .style('fill-opacity', 0.01) | ||
| 179 | + .remove(); | ||
| 139 | } | 180 | } |
| 140 | }); | 181 | }); |
| 141 | } | 182 | } |
| ... | @@ -145,6 +186,30 @@ | ... | @@ -145,6 +186,30 @@ |
| 145 | d3.select("#" + group + " #" + id).classed("active", true); | 186 | d3.select("#" + group + " #" + id).classed("active", true); |
| 146 | } | 187 | } |
| 147 | 188 | ||
| 189 | + function contextLabel() { | ||
| 190 | + return highlighted === null ? "(nothing)" : highlighted.id; | ||
| 191 | + } | ||
| 192 | + | ||
| 193 | + function processKeyEvent() { | ||
| 194 | + var code = d3.event.keyCode; | ||
| 195 | + switch (code) { | ||
| 196 | + case 76: // L | ||
| 197 | + cycleLabels(); | ||
| 198 | + break; | ||
| 199 | + case 80: // P | ||
| 200 | + togglePorts(); | ||
| 201 | + } | ||
| 202 | + | ||
| 203 | + } | ||
| 204 | + | ||
| 205 | + function cycleLabels() { | ||
| 206 | + alert('Cycle Labels - context = ' + contextLabel()); | ||
| 207 | + } | ||
| 208 | + | ||
| 209 | + function togglePorts() { | ||
| 210 | + alert('Toggle Ports - context = ' + contextLabel()); | ||
| 211 | + } | ||
| 212 | + | ||
| 148 | 213 | ||
| 149 | // ======================================================== | 214 | // ======================================================== |
| 150 | 215 | ||
| ... | @@ -430,8 +495,9 @@ | ... | @@ -430,8 +495,9 @@ |
| 430 | // adjusted the bounds of the rectangle... | 495 | // adjusted the bounds of the rectangle... |
| 431 | } | 496 | } |
| 432 | 497 | ||
| 433 | - // for debugging... | 498 | + // debug function to show the modelled x,y coordinates of nodes... |
| 434 | - if (config.options.showNodeXY) { | 499 | + if (debug('showNodeXY')) { |
| 500 | + node.select('rect').attr('fill-opacity', 0.5); | ||
| 435 | node.append('circle') | 501 | node.append('circle') |
| 436 | .attr({ | 502 | .attr({ |
| 437 | class: 'debug', | 503 | class: 'debug', |
| ... | @@ -599,34 +665,41 @@ | ... | @@ -599,34 +665,41 @@ |
| 599 | preventCollisions(); | 665 | preventCollisions(); |
| 600 | } | 666 | } |
| 601 | 667 | ||
| 602 | - // TODO: use intersection technique for source end of link also | 668 | + // clip visualization of links at bounds of nodes... |
| 603 | - network.link | 669 | + network.link.each(function(d) { |
| 604 | - .attr('x1', function(d) { | 670 | + var xs = d.source.x, |
| 605 | - return d.source.x; | 671 | + ys = d.source.y, |
| 606 | - }) | 672 | + xt = d.target.x, |
| 607 | - .attr('y1', function(d) { | 673 | + yt = d.target.y, |
| 608 | - return d.source.y; | 674 | + line = new geo.LineSegment(xs, ys, xt, yt), |
| 609 | - }) | 675 | + e, ix; |
| 610 | - .each(function(d) { | ||
| 611 | - var x = d.target.x, | ||
| 612 | - y = d.target.y, | ||
| 613 | - line = new geo.LineSegment(d.source.x, d.source.y, x, y); | ||
| 614 | 676 | ||
| 615 | - for (var e in d.target.edge) { | 677 | + for (e in d.source.edge) { |
| 616 | - var ix = line.intersect(d.target.edge[e].offset(x,y)); | 678 | + ix = line.intersect(d.source.edge[e].offset(xs, ys)); |
| 617 | if (ix.in1 && ix.in2) { | 679 | if (ix.in1 && ix.in2) { |
| 618 | - x = ix.x; | 680 | + xs = ix.x; |
| 619 | - y = ix.y; | 681 | + ys = ix.y; |
| 620 | break; | 682 | break; |
| 621 | } | 683 | } |
| 622 | } | 684 | } |
| 623 | 685 | ||
| 624 | - d3.select(this) | 686 | + for (e in d.target.edge) { |
| 625 | - .attr('x2', x) | 687 | + ix = line.intersect(d.target.edge[e].offset(xt, yt)); |
| 626 | - .attr('y2', y); | 688 | + if (ix.in1 && ix.in2) { |
| 689 | + xt = ix.x; | ||
| 690 | + yt = ix.y; | ||
| 691 | + break; | ||
| 692 | + } | ||
| 693 | + } | ||
| 627 | 694 | ||
| 695 | + d3.select(this) | ||
| 696 | + .attr('x1', xs) | ||
| 697 | + .attr('y1', ys) | ||
| 698 | + .attr('x2', xt) | ||
| 699 | + .attr('y2', yt); | ||
| 628 | }); | 700 | }); |
| 629 | 701 | ||
| 702 | + // position each node by translating the node (group) by x,y | ||
| 630 | network.node | 703 | network.node |
| 631 | .attr('transform', function(d) { | 704 | .attr('transform', function(d) { |
| 632 | return translate(d.x, d.y); | 705 | return translate(d.x, d.y); | ... | ... |
| ... | @@ -82,7 +82,7 @@ svg { | ... | @@ -82,7 +82,7 @@ svg { |
| 82 | svg .link { | 82 | svg .link { |
| 83 | fill: none; | 83 | fill: none; |
| 84 | stroke: #666; | 84 | stroke: #666; |
| 85 | - stroke-width: 1.5px; | 85 | + stroke-width: 2.0px; |
| 86 | opacity: .7; | 86 | opacity: .7; |
| 87 | /*marker-end: url(#end);*/ | 87 | /*marker-end: url(#end);*/ |
| 88 | 88 | ... | ... |
-
Please register or login to post a comment