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,25 +149,67 @@ | ... | @@ -126,25 +149,67 @@ |
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); |
139 | } | 161 | } |
140 | }); | 162 | }); |
141 | } | 163 | } |
142 | 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(); | ||
180 | + } | ||
181 | + }); | ||
182 | + } | ||
183 | + | ||
143 | function radioButton(group, id) { | 184 | function radioButton(group, id) { |
144 | d3.selectAll("#" + group + " .radio").classed("active", false); | 185 | d3.selectAll("#" + group + " .radio").classed("active", false); |
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) { | 676 | + |
611 | - var x = d.target.x, | 677 | + for (e in d.source.edge) { |
612 | - y = d.target.y, | 678 | + ix = line.intersect(d.source.edge[e].offset(xs, ys)); |
613 | - line = new geo.LineSegment(d.source.x, d.source.y, x, y); | 679 | + if (ix.in1 && ix.in2) { |
680 | + xs = ix.x; | ||
681 | + ys = ix.y; | ||
682 | + break; | ||
683 | + } | ||
684 | + } | ||
614 | 685 | ||
615 | - for (var e in d.target.edge) { | 686 | + for (e in d.target.edge) { |
616 | - var ix = line.intersect(d.target.edge[e].offset(x,y)); | 687 | + ix = line.intersect(d.target.edge[e].offset(xt, yt)); |
617 | if (ix.in1 && ix.in2) { | 688 | if (ix.in1 && ix.in2) { |
618 | - x = ix.x; | 689 | + xt = ix.x; |
619 | - y = ix.y; | 690 | + yt = ix.y; |
620 | break; | 691 | break; |
621 | } | 692 | } |
622 | } | 693 | } |
623 | 694 | ||
624 | d3.select(this) | 695 | d3.select(this) |
625 | - .attr('x2', x) | 696 | + .attr('x1', xs) |
626 | - .attr('y2', y); | 697 | + .attr('y1', ys) |
627 | - | 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