GUI -- TopoView - Initial work for implementing link selection.
- a step in the direction for showing port numbers. Change-Id: I313782374c82b87b6d426e88519a5ab7c072a622
Showing
5 changed files
with
256 additions
and
5 deletions
... | @@ -5,6 +5,7 @@ | ... | @@ -5,6 +5,7 @@ |
5 | <script src="app/view/topo/topoFilter.js"></script> | 5 | <script src="app/view/topo/topoFilter.js"></script> |
6 | <script src="app/view/topo/topoForce.js"></script> | 6 | <script src="app/view/topo/topoForce.js"></script> |
7 | <script src="app/view/topo/topoInst.js"></script> | 7 | <script src="app/view/topo/topoInst.js"></script> |
8 | +<script src="app/view/topo/topoLink.js"></script> | ||
8 | <script src="app/view/topo/topoModel.js"></script> | 9 | <script src="app/view/topo/topoModel.js"></script> |
9 | <script src="app/view/topo/topoOblique.js"></script> | 10 | <script src="app/view/topo/topoOblique.js"></script> |
10 | <script src="app/view/topo/topoPanel.js"></script> | 11 | <script src="app/view/topo/topoPanel.js"></script> | ... | ... |
... | @@ -232,6 +232,7 @@ | ... | @@ -232,6 +232,7 @@ |
232 | showNoDevs: showNoDevs, | 232 | showNoDevs: showNoDevs, |
233 | projection: function () { return projection; }, | 233 | projection: function () { return projection; }, |
234 | zoomLayer: function () { return zoomLayer; }, | 234 | zoomLayer: function () { return zoomLayer; }, |
235 | + zoomer: function () { return zoomer; }, | ||
235 | opacifyMap: opacifyMap, | 236 | opacifyMap: opacifyMap, |
236 | sendEvent: _tes_.sendEvent | 237 | sendEvent: _tes_.sendEvent |
237 | }; | 238 | }; |
... | @@ -287,7 +288,7 @@ | ... | @@ -287,7 +288,7 @@ |
287 | ); | 288 | ); |
288 | 289 | ||
289 | forceG = zoomLayer.append('g').attr('id', 'topo-force'); | 290 | forceG = zoomLayer.append('g').attr('id', 'topo-force'); |
290 | - tfs.initForce(forceG, uplink, dim); | 291 | + tfs.initForce(svg, forceG, uplink, dim); |
291 | tis.initInst({ showMastership: tfs.showMastership }); | 292 | tis.initInst({ showMastership: tfs.showMastership }); |
292 | tps.initPanels({ sendEvent: tes.sendEvent }); | 293 | tps.initPanels({ sendEvent: tes.sendEvent }); |
293 | tes.openSock(); | 294 | tes.openSock(); | ... | ... |
... | @@ -23,7 +23,7 @@ | ... | @@ -23,7 +23,7 @@ |
23 | 'use strict'; | 23 | 'use strict'; |
24 | 24 | ||
25 | // injected refs | 25 | // injected refs |
26 | - var $log, fs, sus, is, ts, flash, tis, tms, td3, tss, tts, tos, fltr, | 26 | + var $log, fs, sus, is, ts, flash, tis, tms, td3, tss, tts, tos, fltr, tls, |
27 | icfg, uplink; | 27 | icfg, uplink; |
28 | 28 | ||
29 | // configuration | 29 | // configuration |
... | @@ -728,15 +728,25 @@ | ... | @@ -728,15 +728,25 @@ |
728 | }; | 728 | }; |
729 | } | 729 | } |
730 | 730 | ||
731 | + function mkLinkApi(svg, forceG, uplink) { | ||
732 | + return { | ||
733 | + svg: svg, | ||
734 | + forceG: forceG, | ||
735 | + zoomer: uplink.zoomer(), | ||
736 | + network: network, | ||
737 | + showHosts: function () { return showHosts; } | ||
738 | + }; | ||
739 | + } | ||
740 | + | ||
731 | angular.module('ovTopo') | 741 | angular.module('ovTopo') |
732 | .factory('TopoForceService', | 742 | .factory('TopoForceService', |
733 | ['$log', 'FnService', 'SvgUtilService', 'IconService', 'ThemeService', | 743 | ['$log', 'FnService', 'SvgUtilService', 'IconService', 'ThemeService', |
734 | 'FlashService', 'TopoInstService', 'TopoModelService', | 744 | 'FlashService', 'TopoInstService', 'TopoModelService', |
735 | 'TopoD3Service', 'TopoSelectService', 'TopoTrafficService', | 745 | 'TopoD3Service', 'TopoSelectService', 'TopoTrafficService', |
736 | - 'TopoObliqueService', 'TopoFilterService', | 746 | + 'TopoObliqueService', 'TopoFilterService', 'TopoLinkService', |
737 | 747 | ||
738 | function (_$log_, _fs_, _sus_, _is_, _ts_, _flash_, | 748 | function (_$log_, _fs_, _sus_, _is_, _ts_, _flash_, |
739 | - _tis_, _tms_, _td3_, _tss_, _tts_, _tos_, _fltr_) { | 749 | + _tis_, _tms_, _td3_, _tss_, _tts_, _tos_, _fltr_, _tls_) { |
740 | $log = _$log_; | 750 | $log = _$log_; |
741 | fs = _fs_; | 751 | fs = _fs_; |
742 | sus = _sus_; | 752 | sus = _sus_; |
... | @@ -750,6 +760,7 @@ | ... | @@ -750,6 +760,7 @@ |
750 | tts = _tts_; | 760 | tts = _tts_; |
751 | tos = _tos_; | 761 | tos = _tos_; |
752 | fltr = _fltr_; | 762 | fltr = _fltr_; |
763 | + tls = _tls_; | ||
753 | 764 | ||
754 | icfg = is.iconConfig(); | 765 | icfg = is.iconConfig(); |
755 | 766 | ||
... | @@ -762,7 +773,7 @@ | ... | @@ -762,7 +773,7 @@ |
762 | // uplink is the api from the main topo source file | 773 | // uplink is the api from the main topo source file |
763 | // dim is the initial dimensions of the SVG as [w,h] | 774 | // dim is the initial dimensions of the SVG as [w,h] |
764 | // opts are, well, optional :) | 775 | // opts are, well, optional :) |
765 | - function initForce(forceG, _uplink_, _dim_, opts) { | 776 | + function initForce(svg, forceG, _uplink_, _dim_, opts) { |
766 | uplink = _uplink_; | 777 | uplink = _uplink_; |
767 | dim = _dim_; | 778 | dim = _dim_; |
768 | 779 | ||
... | @@ -774,6 +785,7 @@ | ... | @@ -774,6 +785,7 @@ |
774 | tts.initTraffic(mkTrafficApi(uplink)); | 785 | tts.initTraffic(mkTrafficApi(uplink)); |
775 | tos.initOblique(mkObliqueApi(uplink, fltr)); | 786 | tos.initOblique(mkObliqueApi(uplink, fltr)); |
776 | fltr.initFilter(mkFilterApi(uplink), d3.select('#mast-right')); | 787 | fltr.initFilter(mkFilterApi(uplink), d3.select('#mast-right')); |
788 | + tls.initLink(mkLinkApi(svg, forceG, uplink)); | ||
777 | 789 | ||
778 | settings = angular.extend({}, defaultSettings, opts); | 790 | settings = angular.extend({}, defaultSettings, opts); |
779 | 791 | ||
... | @@ -808,6 +820,7 @@ | ... | @@ -808,6 +820,7 @@ |
808 | } | 820 | } |
809 | 821 | ||
810 | function destroyForce() { | 822 | function destroyForce() { |
823 | + tls.destroyLink(); | ||
811 | fltr.destroyFilter(); | 824 | fltr.destroyFilter(); |
812 | tos.destroyOblique(); | 825 | tos.destroyOblique(); |
813 | tts.destroyTraffic(); | 826 | tts.destroyTraffic(); | ... | ... |
1 | +/* | ||
2 | + * Copyright 2015 Open Networking Laboratory | ||
3 | + * | ||
4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | ||
5 | + * you may not use this file except in compliance with the License. | ||
6 | + * You may obtain a copy of the License at | ||
7 | + * | ||
8 | + * http://www.apache.org/licenses/LICENSE-2.0 | ||
9 | + * | ||
10 | + * Unless required by applicable law or agreed to in writing, software | ||
11 | + * distributed under the License is distributed on an "AS IS" BASIS, | ||
12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
13 | + * See the License for the specific language governing permissions and | ||
14 | + * limitations under the License. | ||
15 | + */ | ||
16 | + | ||
17 | +/* | ||
18 | + ONOS GUI -- Topology Link Module. | ||
19 | + Functions for highlighting/selecting links | ||
20 | + */ | ||
21 | + | ||
22 | +(function () { | ||
23 | + 'use strict'; | ||
24 | + | ||
25 | + // injected refs | ||
26 | + var $log, fs, sus, ts; | ||
27 | + | ||
28 | + var api, | ||
29 | + network, | ||
30 | + enhancedLink = null; // the link which the mouse is hovering over | ||
31 | + | ||
32 | + // SVG elements; | ||
33 | + var svg, mouseG; | ||
34 | + | ||
35 | + | ||
36 | + // ======== ALGORITHM TO FIND LINK CLOSEST TO MOUSE ======== | ||
37 | + | ||
38 | + function setupMouse(forceG, zoomer) { | ||
39 | + $log.debug('set up mouse handlers for mouse move'); | ||
40 | + mouseG = forceG.append('g').attr('id', 'topo-mouse'); | ||
41 | + //mouseG.append('circle') | ||
42 | + // .attr({ | ||
43 | + // r: 5, | ||
44 | + // opacity: 0 | ||
45 | + // }) | ||
46 | + // .style('fill', 'red'); | ||
47 | + | ||
48 | + svg.on('mouseenter', function () { | ||
49 | + //$log.log('M--ENTER'); | ||
50 | + //mouseG.selectAll('circle').attr('opacity', 1); | ||
51 | + }) | ||
52 | + .on('mouseleave', function () { | ||
53 | + //$log.log('M--LEAVE'); | ||
54 | + //mouseG.selectAll('circle').attr('opacity', 0); | ||
55 | + }) | ||
56 | + .on('mousemove', function () { | ||
57 | + var m = d3.mouse(this), | ||
58 | + sc = zoomer.scale(), | ||
59 | + tr = zoomer.translate(), | ||
60 | + mx = (m[0] - tr[0]) / sc, | ||
61 | + my = (m[1] - tr[1]) / sc; | ||
62 | + | ||
63 | + //$log.log('M--MOVE', m); | ||
64 | + | ||
65 | + //mouseG.selectAll('circle') | ||
66 | + // .attr({ | ||
67 | + // cx: mx, | ||
68 | + // cy: my | ||
69 | + // }); | ||
70 | + updatePerps({x: mx, y: my}, zoomer); | ||
71 | + }); | ||
72 | + } | ||
73 | + | ||
74 | + function updatePerps(mouse, zoomer) { | ||
75 | + var proximity = 30 / zoomer.scale(), | ||
76 | + perpData, perps, nearest, minDist; | ||
77 | + | ||
78 | + function sq(x) { return x * x; } | ||
79 | + | ||
80 | + function pdrop(line, mouse) { | ||
81 | + var x1 = line.x1, | ||
82 | + y1 = line.y1, | ||
83 | + x2 = line.x2, | ||
84 | + y2 = line.y2, | ||
85 | + x3 = mouse.x, | ||
86 | + y3 = mouse.y, | ||
87 | + k = ((y2-y1) * (x3-x1) - (x2-x1) * (y3-y1)) / | ||
88 | + (sq(y2-y1) + sq(x2-x1)), | ||
89 | + x4 = x3 - k * (y2-y1), | ||
90 | + y4 = y3 + k * (x2-x1); | ||
91 | + return {x:x4, y:y4}; | ||
92 | + } | ||
93 | + | ||
94 | + function mdist(p, m) { | ||
95 | + return Math.sqrt(sq(p.x - m.x) + sq(p.y - m.y)); | ||
96 | + } | ||
97 | + | ||
98 | + function lineSeg(d) { | ||
99 | + return { | ||
100 | + x1: d.source.x, | ||
101 | + y1: d.source.y, | ||
102 | + x2: d.target.x, | ||
103 | + y2: d.target.y | ||
104 | + }; | ||
105 | + } | ||
106 | + | ||
107 | + function lineHit(line, p, m) { | ||
108 | + if (p.x < line.x1 && p.x < line.x2) return false; | ||
109 | + if (p.x > line.x1 && p.x > line.x2) return false; | ||
110 | + if (p.y < line.y1 && p.y < line.y2) return false; | ||
111 | + if (p.y > line.y1 && p.y > line.y2) return false; | ||
112 | + // line bisects, but are we close enough? | ||
113 | + return mdist(p, m) <= proximity; | ||
114 | + } | ||
115 | + | ||
116 | + if (network.links.length) { | ||
117 | + perpData = []; | ||
118 | + nearest = null; | ||
119 | + minDist = proximity * 2; | ||
120 | + | ||
121 | + network.links.forEach(function (d) { | ||
122 | + if (!api.showHosts() && d.type() === 'hostLink') { | ||
123 | + return; // skip hidden host links | ||
124 | + } | ||
125 | + | ||
126 | + var line = lineSeg(d), | ||
127 | + point = pdrop(line, mouse), | ||
128 | + hit = lineHit(line, point, mouse), | ||
129 | + dist; | ||
130 | + | ||
131 | + if (hit) { | ||
132 | + dist = mdist(point, mouse); | ||
133 | + if (dist < minDist) { | ||
134 | + minDist = dist; | ||
135 | + nearest = d; | ||
136 | + } | ||
137 | + /* | ||
138 | + perpData.push({ | ||
139 | + key: d.key, | ||
140 | + x1: mouse.x, | ||
141 | + y1: mouse.y, | ||
142 | + x2: point.x, | ||
143 | + y2: point.y | ||
144 | + }); | ||
145 | + */ | ||
146 | + } | ||
147 | + }); | ||
148 | + | ||
149 | + /* | ||
150 | + perps = mouseG.selectAll('line') | ||
151 | + .data(perpData, function (d) { return d.key; }) | ||
152 | + .attr({ | ||
153 | + x1: function (d) { return d.x1; }, | ||
154 | + y1: function (d) { return d.y1; }, | ||
155 | + x2: function (d) { return d.x2; }, | ||
156 | + y2: function (d) { return d.y2; } | ||
157 | + }); | ||
158 | + | ||
159 | + perps.enter().append('line') | ||
160 | + .attr({ | ||
161 | + x1: function (d) { return d.x1; }, | ||
162 | + y1: function (d) { return d.y1; }, | ||
163 | + x2: function (d) { return d.x2; }, | ||
164 | + y2: function (d) { return d.y2; } | ||
165 | + }) | ||
166 | + .style('stroke-width', 2) | ||
167 | + .style('stroke', 'limegreen'); | ||
168 | + | ||
169 | + perps.exit().remove(); | ||
170 | + */ | ||
171 | + | ||
172 | + enhanceNearestLink(nearest); | ||
173 | + } | ||
174 | + } | ||
175 | + | ||
176 | + | ||
177 | + function enhanceNearestLink(ldata) { | ||
178 | + // if the new link is same as old link, do nothing | ||
179 | + if (enhancedLink && ldata && enhancedLink.key === ldata.key) return; | ||
180 | + | ||
181 | + // first, unenhance the currently enhanced link | ||
182 | + if (enhancedLink) { | ||
183 | + unenhance(enhancedLink); | ||
184 | + } | ||
185 | + enhancedLink = ldata; | ||
186 | + if (enhancedLink) { | ||
187 | + enhance(enhancedLink); | ||
188 | + } | ||
189 | + } | ||
190 | + | ||
191 | + function unenhance(d) { | ||
192 | + d.el.style('stroke', '#666'); | ||
193 | + $log.debug('UN-enhancing link: ', d.key); | ||
194 | + } | ||
195 | + | ||
196 | + function enhance(d) { | ||
197 | + d.el.style('stroke', 'gold'); | ||
198 | + $log.debug('enhancing link: ', d.key); | ||
199 | + } | ||
200 | + | ||
201 | + | ||
202 | + | ||
203 | + | ||
204 | + // ========================== | ||
205 | + // Module definition | ||
206 | + | ||
207 | + angular.module('ovTopo') | ||
208 | + .factory('TopoLinkService', | ||
209 | + ['$log', 'FnService', 'SvgUtilService', 'ThemeService', | ||
210 | + | ||
211 | + function (_$log_, _fs_, _sus_, _ts_) { | ||
212 | + $log = _$log_; | ||
213 | + fs = _fs_; | ||
214 | + sus = _sus_; | ||
215 | + ts = _ts_; | ||
216 | + | ||
217 | + function initLink(_api_) { | ||
218 | + api = _api_; | ||
219 | + svg = api.svg; | ||
220 | + network = api.network; | ||
221 | + setupMouse(api.forceG, api.zoomer); | ||
222 | + } | ||
223 | + | ||
224 | + function destroyLink() { | ||
225 | + svg.on('mouseenter', null) | ||
226 | + .on('mouseleave', null) | ||
227 | + .on('mousemove', null); | ||
228 | + } | ||
229 | + | ||
230 | + return { | ||
231 | + initLink: initLink, | ||
232 | + destroyLink: destroyLink | ||
233 | + }; | ||
234 | + }]); | ||
235 | +}()); |
... | @@ -91,6 +91,7 @@ | ... | @@ -91,6 +91,7 @@ |
91 | <script src="app/view/topo/topoFilter.js"></script> | 91 | <script src="app/view/topo/topoFilter.js"></script> |
92 | <script src="app/view/topo/topoForce.js"></script> | 92 | <script src="app/view/topo/topoForce.js"></script> |
93 | <script src="app/view/topo/topoInst.js"></script> | 93 | <script src="app/view/topo/topoInst.js"></script> |
94 | + <script src="app/view/topo/topoLink.js"></script> | ||
94 | <script src="app/view/topo/topoModel.js"></script> | 95 | <script src="app/view/topo/topoModel.js"></script> |
95 | <script src="app/view/topo/topoOblique.js"></script> | 96 | <script src="app/view/topo/topoOblique.js"></script> |
96 | <script src="app/view/topo/topoPanel.js"></script> | 97 | <script src="app/view/topo/topoPanel.js"></script> | ... | ... |
-
Please register or login to post a comment