blob: 1b8da1f57916dfa316ab15d9729d33898a6bd982 [file] [log] [blame]
Simon Huntfb8ea1f2015-02-24 21:38:09 -08001/*
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,
Simon Hunt1a5301e2015-02-25 15:31:25 -080029 td3,
Simon Huntfb8ea1f2015-02-24 21:38:09 -080030 network,
31 enhancedLink = null; // the link which the mouse is hovering over
32
33 // SVG elements;
34 var svg, mouseG;
35
36
37 // ======== ALGORITHM TO FIND LINK CLOSEST TO MOUSE ========
38
39 function setupMouse(forceG, zoomer) {
40 $log.debug('set up mouse handlers for mouse move');
41 mouseG = forceG.append('g').attr('id', 'topo-mouse');
42 //mouseG.append('circle')
43 // .attr({
44 // r: 5,
45 // opacity: 0
46 // })
47 // .style('fill', 'red');
48
49 svg.on('mouseenter', function () {
50 //$log.log('M--ENTER');
51 //mouseG.selectAll('circle').attr('opacity', 1);
52 })
53 .on('mouseleave', function () {
54 //$log.log('M--LEAVE');
55 //mouseG.selectAll('circle').attr('opacity', 0);
56 })
57 .on('mousemove', function () {
58 var m = d3.mouse(this),
59 sc = zoomer.scale(),
60 tr = zoomer.translate(),
61 mx = (m[0] - tr[0]) / sc,
62 my = (m[1] - tr[1]) / sc;
63
64 //$log.log('M--MOVE', m);
65
66 //mouseG.selectAll('circle')
67 // .attr({
68 // cx: mx,
69 // cy: my
70 // });
71 updatePerps({x: mx, y: my}, zoomer);
72 });
73 }
74
75 function updatePerps(mouse, zoomer) {
76 var proximity = 30 / zoomer.scale(),
77 perpData, perps, nearest, minDist;
78
79 function sq(x) { return x * x; }
80
81 function pdrop(line, mouse) {
82 var x1 = line.x1,
83 y1 = line.y1,
84 x2 = line.x2,
85 y2 = line.y2,
86 x3 = mouse.x,
87 y3 = mouse.y,
88 k = ((y2-y1) * (x3-x1) - (x2-x1) * (y3-y1)) /
89 (sq(y2-y1) + sq(x2-x1)),
90 x4 = x3 - k * (y2-y1),
91 y4 = y3 + k * (x2-x1);
92 return {x:x4, y:y4};
93 }
94
95 function mdist(p, m) {
96 return Math.sqrt(sq(p.x - m.x) + sq(p.y - m.y));
97 }
98
99 function lineSeg(d) {
100 return {
101 x1: d.source.x,
102 y1: d.source.y,
103 x2: d.target.x,
104 y2: d.target.y
105 };
106 }
107
108 function lineHit(line, p, m) {
109 if (p.x < line.x1 && p.x < line.x2) return false;
110 if (p.x > line.x1 && p.x > line.x2) return false;
111 if (p.y < line.y1 && p.y < line.y2) return false;
112 if (p.y > line.y1 && p.y > line.y2) return false;
Simon Hunt5f361082015-02-25 11:36:38 -0800113 // line intersects, but are we close enough?
Simon Huntfb8ea1f2015-02-24 21:38:09 -0800114 return mdist(p, m) <= proximity;
115 }
116
117 if (network.links.length) {
118 perpData = [];
119 nearest = null;
120 minDist = proximity * 2;
121
122 network.links.forEach(function (d) {
123 if (!api.showHosts() && d.type() === 'hostLink') {
124 return; // skip hidden host links
125 }
126
127 var line = lineSeg(d),
128 point = pdrop(line, mouse),
129 hit = lineHit(line, point, mouse),
130 dist;
131
132 if (hit) {
133 dist = mdist(point, mouse);
134 if (dist < minDist) {
135 minDist = dist;
136 nearest = d;
137 }
138 /*
139 perpData.push({
140 key: d.key,
141 x1: mouse.x,
142 y1: mouse.y,
143 x2: point.x,
144 y2: point.y
145 });
146 */
147 }
148 });
149
150 /*
151 perps = mouseG.selectAll('line')
152 .data(perpData, function (d) { return d.key; })
153 .attr({
154 x1: function (d) { return d.x1; },
155 y1: function (d) { return d.y1; },
156 x2: function (d) { return d.x2; },
157 y2: function (d) { return d.y2; }
158 });
159
160 perps.enter().append('line')
161 .attr({
162 x1: function (d) { return d.x1; },
163 y1: function (d) { return d.y1; },
164 x2: function (d) { return d.x2; },
165 y2: function (d) { return d.y2; }
166 })
167 .style('stroke-width', 2)
168 .style('stroke', 'limegreen');
169
170 perps.exit().remove();
171 */
172
173 enhanceNearestLink(nearest);
174 }
175 }
176
177
178 function enhanceNearestLink(ldata) {
179 // if the new link is same as old link, do nothing
180 if (enhancedLink && ldata && enhancedLink.key === ldata.key) return;
181
182 // first, unenhance the currently enhanced link
183 if (enhancedLink) {
184 unenhance(enhancedLink);
185 }
186 enhancedLink = ldata;
187 if (enhancedLink) {
188 enhance(enhancedLink);
189 }
190 }
191
192 function unenhance(d) {
Simon Huntd5264122015-02-25 10:17:43 -0800193 d.el.classed('enhanced', false);
Simon Hunt1a5301e2015-02-25 15:31:25 -0800194 api.portLabelG().selectAll('.portLabel').remove();
Simon Huntfb8ea1f2015-02-24 21:38:09 -0800195 }
196
197 function enhance(d) {
Simon Huntd5264122015-02-25 10:17:43 -0800198 d.el.classed('enhanced', true);
Simon Hunt5f361082015-02-25 11:36:38 -0800199 $log.debug('[' + (d.srcPort || 'H') + '] ---> [' + d.tgtPort + ']', d.key);
Simon Hunt1a5301e2015-02-25 15:31:25 -0800200
Simon Hunt8ae474b2015-02-25 15:39:14 -0800201 // Define port label data objects.
202 // NOTE: src port is absent in the case of host-links.
203
204 var data = [{
205 id: 'topo-port-tgt',
206 num: d.tgtPort,
207 baseX: d.target.x,
208 baseY: d.target.y
209 }];
210
211 if (d.srcPort) {
212 data.push({
Simon Hunt1a5301e2015-02-25 15:31:25 -0800213 id: 'topo-port-src',
214 num: d.srcPort,
215 baseX: d.source.x,
216 baseY: d.source.y
Simon Hunt8ae474b2015-02-25 15:39:14 -0800217 });
218 }
Simon Hunt1a5301e2015-02-25 15:31:25 -0800219
220 td3.applyPortLabels(data, api.portLabelG());
Simon Huntfb8ea1f2015-02-24 21:38:09 -0800221 }
222
223
Simon Huntfb8ea1f2015-02-24 21:38:09 -0800224 // ==========================
225 // Module definition
226
227 angular.module('ovTopo')
228 .factory('TopoLinkService',
229 ['$log', 'FnService', 'SvgUtilService', 'ThemeService',
230
231 function (_$log_, _fs_, _sus_, _ts_) {
232 $log = _$log_;
233 fs = _fs_;
234 sus = _sus_;
235 ts = _ts_;
236
Simon Hunt1a5301e2015-02-25 15:31:25 -0800237 function initLink(_api_, _td3_) {
Simon Huntfb8ea1f2015-02-24 21:38:09 -0800238 api = _api_;
Simon Hunt1a5301e2015-02-25 15:31:25 -0800239 td3 = _td3_;
Simon Huntfb8ea1f2015-02-24 21:38:09 -0800240 svg = api.svg;
241 network = api.network;
242 setupMouse(api.forceG, api.zoomer);
243 }
244
245 function destroyLink() {
246 svg.on('mouseenter', null)
247 .on('mouseleave', null)
248 .on('mousemove', null);
249 }
250
251 return {
252 initLink: initLink,
253 destroyLink: destroyLink
254 };
255 }]);
256}());