blob: e172e0daadb4b9b658a13a97fdea13c73da8d7ff [file] [log] [blame]
Steven Burrows9edc7e02016-08-29 11:52:07 +01001/*
2 * Copyright 2016-present 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 Select Module.
19 */
20
21(function () {
22 'use strict';
23
Steven Burrows5fa057e2017-03-15 17:07:56 +000024 var t2zs, t2ddp;
Steven Burrowsaf96a212016-12-28 12:57:02 +000025
Steven Burrows9edc7e02016-08-29 11:52:07 +010026 // internal state
Steven Burrows5fa057e2017-03-15 17:07:56 +000027 var instance,
28 consumeClick,
Steven Burrowsaf96a212016-12-28 12:57:02 +000029 zoomer,
30 previousNearestLink; // previous link to mouse position
31
Steven Burrowsaf96a212016-12-28 12:57:02 +000032 function mouseClickHandler() {
Steven Burrows5fa057e2017-03-15 17:07:56 +000033 if (d3.event.defaultPrevented) return;
Steven Burrowsaf96a212016-12-28 12:57:02 +000034
35 if (!d3.event.shiftKey) {
Steven Burrows5fa057e2017-03-15 17:07:56 +000036 this.clearSelection();
Steven Burrowsaf96a212016-12-28 12:57:02 +000037 }
38
Steven Burrows5fa057e2017-03-15 17:07:56 +000039 if (!this.clickConsumed()) {
Steven Burrowsaf96a212016-12-28 12:57:02 +000040 if (previousNearestLink) {
Steven Burrows5fa057e2017-03-15 17:07:56 +000041 this.selectObject(previousNearestLink, true);
Steven Burrowsaf96a212016-12-28 12:57:02 +000042 }
43 }
Steven Burrowsaf96a212016-12-28 12:57:02 +000044 }
45
46 // Select Links
Steven Burrows5fa057e2017-03-15 17:07:56 +000047 function mouseMoveHandler(ev) {
Steven Burrowsaf96a212016-12-28 12:57:02 +000048 var mp = getLogicalMousePosition(this),
49 link = computeNearestLink(mp);
50
Steven Burrowsaf96a212016-12-28 12:57:02 +000051 if (link) {
52 if (previousNearestLink && previousNearestLink !== link) {
53 previousNearestLink.unenhance();
54 }
55 link.enhance();
56 } else if (previousNearestLink) {
57 previousNearestLink.unenhance();
58 }
59
60 previousNearestLink = link;
61 }
62
63 function getLogicalMousePosition(container) {
64 var m = d3.mouse(container),
65 sc = zoomer.scale(),
66 tr = zoomer.translate(),
67 mx = (m[0] - tr[0]) / sc,
68 my = (m[1] - tr[1]) / sc;
69 return { x: mx, y: my };
70 }
71
72 function sq(x) {
73 return x * x;
74 }
75
76 function mdist(p, m) {
77 return Math.sqrt(sq(p.x - m.x) + sq(p.y - m.y));
78 }
79
80 function prox(dist) {
81 return dist / zoomer.scale();
82 }
83
84 function computeNearestLink(mouse) {
85 var proximity = prox(30),
86 nearest = null,
87 minDist;
88
89 function pdrop(line, mouse) {
90 var x1 = line.x1,
91 y1 = line.y1,
92 x2 = line.x2,
93 y2 = line.y2,
94 x3 = mouse.x,
95 y3 = mouse.y,
96 k = ((y2 - y1) * (x3 - x1) - (x2 - x1) * (y3 - y1)) /
97 (sq(y2 - y1) + sq(x2 - x1)),
98 x4 = x3 - k * (y2 - y1),
99 y4 = y3 + k * (x2 - x1);
100 return { x: x4, y: y4 };
101 }
102
103 function lineHit(line, p, m) {
104 if (p.x < line.x1 && p.x < line.x2) return false;
105 if (p.x > line.x1 && p.x > line.x2) return false;
106 if (p.y < line.y1 && p.y < line.y2) return false;
107 if (p.y > line.y1 && p.y > line.y2) return false;
108 // line intersects, but are we close enough?
109 return mdist(p, m) <= proximity;
110 }
111
Steven Burrowsb11a8b82017-03-10 16:00:31 +0000112 var links = [];
113
Steven Burrows5fa057e2017-03-15 17:07:56 +0000114 if (instance.region.model.get('links')) {
115 links = instance.region.regionLinks();
Steven Burrowsb11a8b82017-03-10 16:00:31 +0000116 }
Steven Burrowsaf96a212016-12-28 12:57:02 +0000117
118 if (links.length) {
119 minDist = proximity * 2;
120
121 links.forEach(function (d) {
122 var line = d.get('position'),
123 point,
124 hit,
125 dist;
126
127 // TODO: Reinstate when showHost() is implemented
128 // if (!api.showHosts() && d.type() === 'hostLink') {
129 // return; // skip hidden host links
130 // }
131
132 if (line) {
133 point = pdrop(line, mouse);
134 hit = lineHit(line, point, mouse);
135 if (hit) {
136 dist = mdist(point, mouse);
137 if (dist < minDist) {
138 minDist = dist;
139 nearest = d;
140 }
141 }
142 }
143 });
144 }
145
146 return nearest;
147 }
148
Steven Burrows5fa057e2017-03-15 17:07:56 +0000149 var SelectionService = function () {
150 instance = this;
151 this.selectedNodes = [];
152 };
153
154 SelectionService.prototype = {
155 init: function () {
156 zoomer = t2zs.getZoomer();
157
158 var svg = d3.select('#topo2');
159 svg.on('mousemove', mouseMoveHandler);
160 svg.on('click', mouseClickHandler.bind(this));
161 },
162 updateDetails: function () {
163
164 var nodeCount = this.selectedNodes.length;
165
166 if (nodeCount === 1) {
167 this.selectedNodes[0].showDetails();
168 } else if (nodeCount > 1) {
169 t2ddp.showMulti(this.selectedNodes);
170 } else {
171 t2ddp.hide();
172 }
173 },
174 selectObject: function (node, multiSelectEnabled) {
175
176 var event = d3.event;
177
178 if (multiSelectEnabled && !event.shiftKey || !multiSelectEnabled) {
179 this.clearSelection();
180 }
181
182 var nodeIndex = _.indexOf(this.selectedNodes, node);
183
184 if (nodeIndex < 0) {
185 this.selectedNodes.push(node);
186 node.select();
187 } else {
188 this.removeNode(node, nodeIndex);
189 }
190
191 this.updateDetails();
192 },
193 removeNode: function (node, index) {
194 this.selectedNodes.splice(index, 1);
195 node.deselect();
196 },
197 clearSelection: function () {
198 _.each(this.selectedNodes, function (node) {
199 node.deselect();
200 });
201
202 this.selectedNodes = [];
203 this.updateDetails();
204 },
205 clickConsumed: function (x) {
206 var cc = consumeClick;
207 consumeClick = Boolean(x);
208 return cc;
209 }
210 };
211
Steven Burrows9edc7e02016-08-29 11:52:07 +0100212 angular.module('ovTopo2')
Steven Burrowsdfa52b02016-09-02 13:50:43 +0100213 .factory('Topo2SelectService', [
Steven Burrows5fa057e2017-03-15 17:07:56 +0000214 'Topo2ZoomService', 'Topo2DeviceDetailsPanel',
215 function (_t2zs_, _t2ddp_) {
Steven Burrowsbd402842017-03-08 21:30:38 +0000216 t2zs = _t2zs_;
Steven Burrows5fa057e2017-03-15 17:07:56 +0000217 t2ddp = _t2ddp_;
218 return instance || new SelectionService();
Steven Burrows9edc7e02016-08-29 11:52:07 +0100219 }
220 ]);
221
222})();