blob: dcf1b2894c6470173a8b128ab28cbd599c9be48e [file] [log] [blame]
Steven Burrows57e24e92016-08-04 18:38:24 +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 Links Module.
19 Module that holds the links for a region
20 */
21
22(function () {
23 'use strict';
24
Steven Burrows6deb4ce2016-08-26 16:06:23 +010025 var $log;
Steven Burrows9edc7e02016-08-29 11:52:07 +010026 var Collection, Model, region, ts, sus;
27
28 var linkLabelOffset = '0.35em';
Steven Burrows57e24e92016-08-04 18:38:24 +010029
Steven Burrowsec1f45c2016-08-08 16:14:41 +010030 var widthRatio = 1.4,
31 linkScale = d3.scale.linear()
32 .domain([1, 12])
33 .range([widthRatio, 12 * widthRatio])
34 .clamp(true),
35 allLinkTypes = 'direct indirect optical tunnel UiDeviceLink',
36 allLinkSubTypes = 'inactive not-permitted';
37
38 // configuration
39 var linkConfig = {
40 light: {
41 baseColor: '#939598',
42 inColor: '#66f',
43 outColor: '#f00'
44 },
45 dark: {
46 // TODO : theme
47 baseColor: '#939598',
48 inColor: '#66f',
49 outColor: '#f00'
50 },
51 inWidth: 12,
52 outWidth: 10
53 };
54
55 var defaultLinkType = 'direct',
56 nearDist = 15;
57
58 function createLink() {
59
60 var linkPoints = this.linkEndPoints(this.get('epA'), this.get('epB'));
Steven Burrowsec1f45c2016-08-08 16:14:41 +010061
62 var attrs = angular.extend({}, linkPoints, {
63 key: this.get('id'),
64 class: 'link',
65 weight: 1,
66 srcPort: this.get('srcPort'),
67 tgtPort: this.get('dstPort'),
68 position: {
69 x1: 0,
70 y1: 0,
71 x2: 0,
72 y2: 0
73 }
74 // functions to aggregate dual link state
Steven Burrows9edc7e02016-08-29 11:52:07 +010075 // extra: link.extra
Steven Burrowsec1f45c2016-08-08 16:14:41 +010076 });
77
78 this.set(attrs);
79 }
80
Steven Burrows9edc7e02016-08-29 11:52:07 +010081 function rectAroundText(el) {
82 var text = el.select('text'),
83 box = text.node().getBBox();
84
85 // translate the bbox so that it is centered on [x,y]
86 box.x = -box.width / 2;
87 box.y = -box.height / 2;
88
89 // add padding
90 box.x -= 4;
91 box.width += 8;
92 return box;
93 }
94
Steven Burrowsec1f45c2016-08-08 16:14:41 +010095 function linkEndPoints(srcId, dstId) {
96
Steven Burrows6deb4ce2016-08-26 16:06:23 +010097 var sourceNode = this.region.findNodeById(srcId)
98 var targetNode = this.region.findNodeById(dstId)
Steven Burrowsec1f45c2016-08-08 16:14:41 +010099
Steven Burrows6deb4ce2016-08-26 16:06:23 +0100100 if (!sourceNode || !targetNode) {
101 $log.error('Node(s) not on map for link:' + srcId + ':' + dstId);
102 //logicError('Node(s) not on map for link:\n' + sMiss + dMiss);
103 return null;
104 }
Steven Burrowsec1f45c2016-08-08 16:14:41 +0100105
106 this.source = sourceNode.toJSON();
107 this.target = targetNode.toJSON();
108
109 return {
110 source: sourceNode,
111 target: targetNode
112 };
113 }
114
115 function createLinkCollection(data, _region) {
116
117 var LinkModel = Model.extend({
118 region: _region,
119 createLink: createLink,
120 linkEndPoints: linkEndPoints,
121 type: function () {
122 return this.get('type');
123 },
124 expected: function () {
Steven Burrows9edc7e02016-08-29 11:52:07 +0100125 // TODO: original code is: (s && s.expected) && (t && t.expected);
Steven Burrowsec1f45c2016-08-08 16:14:41 +0100126 return true;
127 },
128 online: function () {
Steven Burrows9edc7e02016-08-29 11:52:07 +0100129 // TODO: remove next line
Steven Burrowsec1f45c2016-08-08 16:14:41 +0100130 return true;
Steven Burrows9edc7e02016-08-29 11:52:07 +0100131
Steven Burrowsec1f45c2016-08-08 16:14:41 +0100132 return both && (s && s.online) && (t && t.online);
133 },
Steven Burrows9edc7e02016-08-29 11:52:07 +0100134 enhance: function () {
135 var data = [],
136 point;
137
138 angular.forEach(this.collection.models, function (link) {
139 link.unenhance();
140 });
141
142 this.el.classed('enhanced', true);
143 point = this.locatePortLabel();
144 angular.extend(point, {
145 id: 'topo-port-tgt',
146 num: this.get('portB')
147 });
148 data.push(point);
149
150 var entering = d3.select('#topo-portLabels').selectAll('.portLabel')
151 .data(data).enter().append('g')
152 .classed('portLabel', true)
153 .attr('id', function (d) { return d.id; });
154
155 entering.each(function (d) {
156 var el = d3.select(this),
157 rect = el.append('rect'),
158 text = el.append('text').text(d.num);
159
160 rect.attr(rectAroundText(el))
161 .attr('rx', 2)
162 .attr('ry', 2);
163
164 text.attr('dy', linkLabelOffset)
165 .attr('text-anchor', 'middle');
166
167 el.attr('transform', sus.translate(d.x, d.y));
168 });
169 },
170 unenhance: function () {
171 this.el.classed('enhanced', false);
172 d3.select('#topo-portLabels').selectAll('.portLabel').remove();
173 },
174 locatePortLabel: function (link, src) {
175 var offset = 32,
176 pos = this.get('position'),
177 nearX = src ? pos.x1 : pos.x2,
178 nearY = src ? pos.y1 : pos.y2,
179 farX = src ? pos.x2 : pos.x1,
180 farY = src ? pos.y2 : pos.y1;
181
182 function dist(x, y) { return Math.sqrt(x*x + y*y); }
183
184 var dx = farX - nearX,
185 dy = farY - nearY,
186 k = offset / dist(dx, dy);
187
188 return {x: k * dx + nearX, y: k * dy + nearY};
189 },
Steven Burrowsec1f45c2016-08-08 16:14:41 +0100190 restyleLinkElement: function (immediate) {
191 // this fn's job is to look at raw links and decide what svg classes
192 // need to be applied to the line element in the DOM
193 var th = ts.theme(),
194 el = this.el,
195 type = this.get('type'),
Steven Burrowsec1f45c2016-08-08 16:14:41 +0100196 online = this.online(),
197 modeCls = this.expected() ? 'inactive' : 'not-permitted',
Steven Burrows6deb4ce2016-08-26 16:06:23 +0100198 lw = 1.2,
Steven Burrowsec1f45c2016-08-08 16:14:41 +0100199 delay = immediate ? 0 : 1000;
200
Steven Burrowsec1f45c2016-08-08 16:14:41 +0100201 // NOTE: understand why el is sometimes undefined on addLink events...
202 // Investigated:
203 // el is undefined when it's a reverse link that is being added.
204 // updateLinks (which sets ldata.el) isn't called before this is called.
205 // Calling _updateLinks in addLinkUpdate fixes it, but there might be
206 // a more efficient way to fix it.
207 if (el && !el.empty()) {
208 el.classed('link', true);
209 el.classed(allLinkSubTypes, false);
210 el.classed(modeCls, !online);
211 el.classed(allLinkTypes, false);
212 if (type) {
213 el.classed(type, true);
214 }
215 el.transition()
216 .duration(delay)
217 .attr('stroke-width', linkScale(lw))
218 .attr('stroke', linkConfig[th].baseColor);
219 }
220 },
Steven Burrowsec1f45c2016-08-08 16:14:41 +0100221 onEnter: function (el) {
Steven Burrows9edc7e02016-08-29 11:52:07 +0100222 var _this = this,
223 link = d3.select(el);
224
Steven Burrowsec1f45c2016-08-08 16:14:41 +0100225 this.el = link;
226
227 this.restyleLinkElement();
228
229 if (this.get('type') === 'hostLink') {
230 sus.visible(link, api.showHosts());
231 }
232 }
233 });
Steven Burrows57e24e92016-08-04 18:38:24 +0100234
235 var LinkCollection = Collection.extend({
Steven Burrowsec1f45c2016-08-08 16:14:41 +0100236 model: LinkModel,
Steven Burrows57e24e92016-08-04 18:38:24 +0100237 });
238
239 return new LinkCollection(data);
240 }
241
242 angular.module('ovTopo2')
243 .factory('Topo2LinkService',
Steven Burrows9edc7e02016-08-29 11:52:07 +0100244 ['$log', 'Topo2Collection', 'Topo2Model', 'ThemeService', 'SvgUtilService',
Steven Burrows57e24e92016-08-04 18:38:24 +0100245
Steven Burrows9edc7e02016-08-29 11:52:07 +0100246 function (_$log_, _Collection_, _Model_, _ts_, _sus_) {
Steven Burrows57e24e92016-08-04 18:38:24 +0100247
Steven Burrows6deb4ce2016-08-26 16:06:23 +0100248 $log = _$log_;
Steven Burrowsec1f45c2016-08-08 16:14:41 +0100249 ts = _ts_;
Steven Burrows9edc7e02016-08-29 11:52:07 +0100250 sus = _sus_;
Steven Burrows57e24e92016-08-04 18:38:24 +0100251 Collection = _Collection_;
Steven Burrowsec1f45c2016-08-08 16:14:41 +0100252 Model = _Model_;
Steven Burrows57e24e92016-08-04 18:38:24 +0100253
254 return {
255 createLinkCollection: createLinkCollection
256 };
257 }
258 ]);
259
260})();