blob: ed1667fe27fdeab679e0909b4cf87555fb99395f [file] [log] [blame]
Steven Burrows9edc7e02016-08-29 11:52:07 +01001/*
Brian O'Connora09fe5b2017-08-03 21:12:30 -07002 * Copyright 2016-present Open Networking Foundation
Steven Burrows9edc7e02016-08-29 11:52:07 +01003 *
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,
Steven Burrows1c2a9682017-07-14 16:52:46 +010030 previousNearestLink; // previous link to mouse position
Steven Burrowsaf96a212016-12-28 12:57:02 +000031
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 = [];
Steven Burrows247ab152017-03-29 13:55:54 +0100152 this.selectionOrder = [];
Steven Burrows5fa057e2017-03-15 17:07:56 +0000153 };
154
155 SelectionService.prototype = {
156 init: function () {
157 zoomer = t2zs.getZoomer();
158
159 var svg = d3.select('#topo2');
160 svg.on('mousemove', mouseMoveHandler);
161 svg.on('click', mouseClickHandler.bind(this));
162 },
163 updateDetails: function () {
164
Steven Burrows1c2a9682017-07-14 16:52:46 +0100165 var nodeCount = this.selectedNodes.length;
Steven Burrows5fa057e2017-03-15 17:07:56 +0000166
167 if (nodeCount === 1) {
168 this.selectedNodes[0].showDetails();
Steven Burrows1c2a9682017-07-14 16:52:46 +0100169 } else if (nodeCount > 1) {
Steven Burrows5fa057e2017-03-15 17:07:56 +0000170 t2ddp.showMulti(this.selectedNodes);
171 } else {
172 t2ddp.hide();
173 }
174 },
175 selectObject: function (node, multiSelectEnabled) {
176
Steven Burrows247ab152017-03-29 13:55:54 +0100177 var event = d3.event,
178 nodeIndex = _.indexOf(this.selectionOrder, node.get('id'));
Steven Burrows5fa057e2017-03-15 17:07:56 +0000179
180 if (nodeIndex < 0) {
Steven Burrows247ab152017-03-29 13:55:54 +0100181
182 if (multiSelectEnabled && !event.shiftKey || !multiSelectEnabled) {
183 this.clearSelection();
184 }
185
Steven Burrows5fa057e2017-03-15 17:07:56 +0000186 this.selectedNodes.push(node);
Steven Burrows247ab152017-03-29 13:55:54 +0100187 this.selectionOrder.push(node.get('id'));
188
Steven Burrows5fa057e2017-03-15 17:07:56 +0000189 node.select();
190 } else {
191 this.removeNode(node, nodeIndex);
192 }
193
194 this.updateDetails();
195 },
196 removeNode: function (node, index) {
197 this.selectedNodes.splice(index, 1);
Steven Burrows247ab152017-03-29 13:55:54 +0100198 this.selectionOrder.splice(index, 1);
Steven Burrows5fa057e2017-03-15 17:07:56 +0000199 node.deselect();
200 },
201 clearSelection: function () {
202 _.each(this.selectedNodes, function (node) {
203 node.deselect();
204 });
205
206 this.selectedNodes = [];
Steven Burrows247ab152017-03-29 13:55:54 +0100207 this.selectionOrder = [];
Steven Burrows5fa057e2017-03-15 17:07:56 +0000208 this.updateDetails();
209 },
210 clickConsumed: function (x) {
211 var cc = consumeClick;
212 consumeClick = Boolean(x);
213 return cc;
Steven Burrows1c2a9682017-07-14 16:52:46 +0100214 },
Steven Burrows5fa057e2017-03-15 17:07:56 +0000215 };
216
Steven Burrows9edc7e02016-08-29 11:52:07 +0100217 angular.module('ovTopo2')
Steven Burrowsdfa52b02016-09-02 13:50:43 +0100218 .factory('Topo2SelectService', [
Steven Burrows5fa057e2017-03-15 17:07:56 +0000219 'Topo2ZoomService', 'Topo2DeviceDetailsPanel',
220 function (_t2zs_, _t2ddp_) {
Steven Burrowsbd402842017-03-08 21:30:38 +0000221 t2zs = _t2zs_;
Steven Burrows5fa057e2017-03-15 17:07:56 +0000222 t2ddp = _t2ddp_;
223 return instance || new SelectionService();
Steven Burrows1c2a9682017-07-14 16:52:46 +0100224 },
Steven Burrows9edc7e02016-08-29 11:52:07 +0100225 ]);
226
227})();