blob: 614608224ee629bfb546ef18b1d7067996256b67 [file] [log] [blame]
Simon Hunta4242de2015-02-24 17:11:55 -08001/*
Brian O'Connora09fe5b2017-08-03 21:12:30 -07002 * Copyright 2015-present Open Networking Foundation
Simon Hunta4242de2015-02-24 17:11:55 -08003 *
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 D3 Module.
19 Functions for manipulating the D3 visualizations of the Topology
20 */
21
22(function () {
23 'use strict';
24
25 // injected refs
Steven Burrows1c2a9682017-07-14 16:52:46 +010026 var sus, is, ts, ps, ttbs;
Simon Hunta4242de2015-02-24 17:11:55 -080027
28 // api to topoForce
Steven Burrowsf17f0ab2017-04-11 11:03:58 -070029 var zoomer, api;
Simon Hunta4242de2015-02-24 17:11:55 -080030 /*
31 node() // get ref to D3 selection of nodes
32 link() // get ref to D3 selection of links
33 linkLabel() // get ref to D3 selection of link labels
34 instVisible() // true if instances panel is visible
35 posNode() // position node
36 showHosts() // true if hosts are to be shown
37 restyleLinkElement() // update link styles based on backing data
38 updateLinkLabelModel() // update backing data for link labels
39 */
40
41 // configuration
Simon Hunta5487ad2016-06-16 13:10:41 -070042 var devIconDim = 36,
Simon Hunte9062fc2016-12-22 11:40:06 -080043 devColorDim = 32,
Simon Hunta5487ad2016-06-16 13:10:41 -070044 labelPad = 4,
45 hostRadius = 14,
46 badgeConfig = {
Simon Hunt5674db92015-10-22 16:12:48 -070047 radius: 12,
Simon Hunt004fc2c2015-10-23 11:55:58 -070048 yoff: 5,
Steven Burrows1c2a9682017-07-14 16:52:46 +010049 gdelta: 10,
Simon Hunta5487ad2016-06-16 13:10:41 -070050 },
51 halfDevIcon = devIconDim / 2,
52 devBadgeOff = { dx: -halfDevIcon, dy: -halfDevIcon },
53 hostBadgeOff = { dx: -hostRadius, dy: -hostRadius },
Steven Burrowsf17f0ab2017-04-11 11:03:58 -070054 portLabelDim = 30,
Simon Hunta5487ad2016-06-16 13:10:41 -070055 status = {
56 i: 'badgeInfo',
57 w: 'badgeWarn',
Steven Burrows1c2a9682017-07-14 16:52:46 +010058 e: 'badgeError',
Simon Huntf44d7262016-06-14 14:46:56 -070059 };
60
Simon Hunt1eee51d2016-02-26 19:12:13 -080061 // NOTE: this type of hack should go away once we have implemented
62 // the server-side UiModel code.
63 // {virtual -> cord} is for the E-CORD demo at ONS 2016
64 var remappedDeviceTypes = {
Simon Hunte9062fc2016-12-22 11:40:06 -080065 virtual: 'cord',
66
67 // for now, map to the new glyphs via this lookup.
68 // may have to find a better way to do this...
69 'switch': 'm_switch',
70 roadm: 'm_roadm',
71 otn: 'm_otn',
72 roadm_otn: 'm_roadm_otn',
73 fiber_switch: 'm_fiberSwitch',
74 microwave: 'm_microwave',
75 };
76
77 var remappedHostTypes = {
78 router: 'm_router',
79 endstation: 'm_endstation',
Steven Burrows1c2a9682017-07-14 16:52:46 +010080 bgpSpeaker: 'm_bgpSpeaker',
Simon Hunt1eee51d2016-02-26 19:12:13 -080081 };
82
83 function mapDeviceTypeToGlyph(type) {
84 return remappedDeviceTypes[type] || type || 'unknown';
85 }
86
Simon Hunte9062fc2016-12-22 11:40:06 -080087 function mapHostTypeToGlyph(type) {
88 return remappedHostTypes[type] || type || 'unknown';
89 }
90
Simon Hunt5674db92015-10-22 16:12:48 -070091 function badgeStatus(badge) {
92 return status[badge.status] || status.i;
93 }
94
Simon Hunta4242de2015-02-24 17:11:55 -080095 // internal state
96 var deviceLabelIndex = 0,
97 hostLabelIndex = 0;
98
Simon Hunta5487ad2016-06-16 13:10:41 -070099 // note: these are the device icon colors without affinity (no master)
Simon Hunta4242de2015-02-24 17:11:55 -0800100 var dColTheme = {
101 light: {
Simon Huntf44d7262016-06-14 14:46:56 -0700102 online: '#444444',
Steven Burrows1c2a9682017-07-14 16:52:46 +0100103 offline: '#cccccc',
Simon Hunta4242de2015-02-24 17:11:55 -0800104 },
105 dark: {
Simon Huntf44d7262016-06-14 14:46:56 -0700106 // TODO: theme
107 online: '#444444',
Steven Burrows1c2a9682017-07-14 16:52:46 +0100108 offline: '#cccccc',
109 },
Simon Hunta4242de2015-02-24 17:11:55 -0800110 };
111
Simon Huntf44d7262016-06-14 14:46:56 -0700112 function devGlyphColor(d) {
113 var o = d.online,
114 id = d.master,
115 otag = o ? 'online' : 'offline';
116 return o ? sus.cat7().getColor(id, 0, ts.theme())
117 : dColTheme[ts.theme()][otag];
Simon Hunta4242de2015-02-24 17:11:55 -0800118 }
119
120 function setDeviceColor(d) {
Simon Hunte9062fc2016-12-22 11:40:06 -0800121 // want to color the square rectangle (no longer the 'use' glyph)
Steven Burrows1c2a9682017-07-14 16:52:46 +0100122 d.el.selectAll('rect').filter(function (d, i) { return i === 1; })
Simon Huntf44d7262016-06-14 14:46:56 -0700123 .style('fill', devGlyphColor(d));
Simon Hunta4242de2015-02-24 17:11:55 -0800124 }
125
Simon Hunta4242de2015-02-24 17:11:55 -0800126 function incDevLabIndex() {
Steven Burrowsbbe3dda2016-09-26 14:41:59 -0700127 setDevLabIndex(deviceLabelIndex+1);
Steven Burrows1c2a9682017-07-14 16:52:46 +0100128 switch (deviceLabelIndex) {
Bri Prebilic Cole9cf1a8d2015-04-21 13:15:29 -0700129 case 0: return 'Hide device labels';
130 case 1: return 'Show friendly device labels';
131 case 2: return 'Show device ID labels';
132 }
Simon Hunta4242de2015-02-24 17:11:55 -0800133 }
134
Thomas Vachuska0af26912016-03-21 21:37:30 -0700135 function setDevLabIndex(mode) {
136 deviceLabelIndex = mode % 3;
137 var p = ps.getPrefs('topo_prefs', ttbs.defaultPrefs);
138 p.dlbls = deviceLabelIndex;
139 ps.setPrefs('topo_prefs', p);
140 }
141
Simon Hunt10618f62017-06-15 19:30:52 -0700142 function incHostLabIndex() {
143 setHostLabIndex(hostLabelIndex+1);
Steven Burrows1c2a9682017-07-14 16:52:46 +0100144 switch (hostLabelIndex) {
Simon Hunt10618f62017-06-15 19:30:52 -0700145 case 0: return 'Show friendly host labels';
146 case 1: return 'Show host IP Addresses';
147 case 2: return 'Show host MAC Addresses';
148 }
149 }
150
151 function setHostLabIndex(mode) {
152 hostLabelIndex = mode % 3;
153 var p = ps.getPrefs('topo_prefs', ttbs.defaultPrefs);
154 p.hlbls = hostLabelIndex;
155 ps.setPrefs('topo_prefs', p);
156 }
157
Simon Hunta4242de2015-02-24 17:11:55 -0800158 function hostLabel(d) {
159 var idx = (hostLabelIndex < d.labels.length) ? hostLabelIndex : 0;
160 return d.labels[idx];
161 }
Simon Huntf44d7262016-06-14 14:46:56 -0700162
Simon Hunta4242de2015-02-24 17:11:55 -0800163 function deviceLabel(d) {
164 var idx = (deviceLabelIndex < d.labels.length) ? deviceLabelIndex : 0;
165 return d.labels[idx];
166 }
Simon Huntf44d7262016-06-14 14:46:56 -0700167
Simon Hunta4242de2015-02-24 17:11:55 -0800168 function trimLabel(label) {
169 return (label && label.trim()) || '';
170 }
171
Simon Huntf44d7262016-06-14 14:46:56 -0700172 function computeLabelWidth(n) {
173 var text = n.select('text'),
174 box = text.node().getBBox();
175 return box.width + labelPad * 2;
176 }
177
178 function iconBox(dim, labelWidth) {
Simon Hunta4242de2015-02-24 17:11:55 -0800179 return {
Simon Huntf44d7262016-06-14 14:46:56 -0700180 x: -dim/2,
181 y: -dim/2,
182 width: dim + labelWidth,
Steven Burrows1c2a9682017-07-14 16:52:46 +0100183 height: dim,
184 };
Simon Hunta4242de2015-02-24 17:11:55 -0800185 }
186
Simon Hunt5674db92015-10-22 16:12:48 -0700187 function updateDeviceRendering(d) {
Simon Huntf44d7262016-06-14 14:46:56 -0700188 var node = d.el,
189 bdg = d.badge,
190 label = trimLabel(deviceLabel(d)),
191 labelWidth;
Simon Hunta4242de2015-02-24 17:11:55 -0800192
Simon Huntf44d7262016-06-14 14:46:56 -0700193 node.select('text').text(label);
194 labelWidth = label ? computeLabelWidth(node) : 0;
Simon Hunta4242de2015-02-24 17:11:55 -0800195
196 node.select('rect')
197 .transition()
Simon Huntf44d7262016-06-14 14:46:56 -0700198 .attr(iconBox(devIconDim, labelWidth));
Simon Hunta4242de2015-02-24 17:11:55 -0800199
Simon Hunt5674db92015-10-22 16:12:48 -0700200 if (bdg) {
Simon Hunta5487ad2016-06-16 13:10:41 -0700201 renderBadge(node, bdg, devBadgeOff);
Simon Hunte9343f32015-10-21 18:07:46 -0700202 }
203 }
204
Andrea Campanella52125412015-12-03 14:50:40 -0800205 function updateHostRendering(d) {
206 var node = d.el,
Simon Huntc2bfe332015-12-04 11:01:24 -0800207 bdg = d.badge;
Andrea Campanella52125412015-12-03 14:50:40 -0800208
209 updateHostLabel(d);
Andrea Campanella52125412015-12-03 14:50:40 -0800210
Andrea Campanella52125412015-12-03 14:50:40 -0800211 if (bdg) {
Simon Hunta5487ad2016-06-16 13:10:41 -0700212 renderBadge(node, bdg, hostBadgeOff);
Simon Huntc2bfe332015-12-04 11:01:24 -0800213 }
214 }
Andrea Campanella52125412015-12-03 14:50:40 -0800215
Simon Huntc2bfe332015-12-04 11:01:24 -0800216 function renderBadge(node, bdg, boff) {
217 var bsel,
218 bcr = badgeConfig.radius,
219 bcgd = badgeConfig.gdelta;
Andrea Campanella52125412015-12-03 14:50:40 -0800220
Simon Huntc2bfe332015-12-04 11:01:24 -0800221 node.select('g.badge').remove();
Andrea Campanella52125412015-12-03 14:50:40 -0800222
Simon Huntc2bfe332015-12-04 11:01:24 -0800223 bsel = node.append('g')
224 .classed('badge', true)
225 .classed(badgeStatus(bdg), true)
226 .attr('transform', sus.translate(boff.dx, boff.dy));
Andrea Campanella52125412015-12-03 14:50:40 -0800227
Simon Huntc2bfe332015-12-04 11:01:24 -0800228 bsel.append('circle')
229 .attr('r', bcr);
230
231 if (bdg.txt) {
232 bsel.append('text')
233 .attr('dy', badgeConfig.yoff)
234 .attr('text-anchor', 'middle')
235 .text(bdg.txt);
236 } else if (bdg.gid) {
237 bsel.append('use')
238 .attr({
239 width: bcgd * 2,
240 height: bcgd * 2,
241 transform: sus.translate(-bcgd, -bcgd),
Steven Burrows1c2a9682017-07-14 16:52:46 +0100242 'xlink:href': '#' + bdg.gid,
Simon Huntc2bfe332015-12-04 11:01:24 -0800243 });
Andrea Campanella52125412015-12-03 14:50:40 -0800244 }
245 }
246
Simon Hunta4242de2015-02-24 17:11:55 -0800247 function updateHostLabel(d) {
248 var label = trimLabel(hostLabel(d));
249 d.el.select('text').text(label);
250 }
251
252 function updateDeviceColors(d) {
253 if (d) {
254 setDeviceColor(d);
255 } else {
256 api.node().filter('.device').each(function (d) {
257 setDeviceColor(d);
258 });
259 }
260 }
261
262
263 // ==========================
264 // updateNodes - subfunctions
265
266 function deviceExisting(d) {
267 var node = d.el;
268 node.classed('online', d.online);
Simon Hunt5674db92015-10-22 16:12:48 -0700269 updateDeviceRendering(d);
Simon Hunta4242de2015-02-24 17:11:55 -0800270 api.posNode(d, true);
271 }
272
273 function hostExisting(d) {
Andrea Campanella52125412015-12-03 14:50:40 -0800274 updateHostRendering(d);
Simon Hunta4242de2015-02-24 17:11:55 -0800275 api.posNode(d, true);
276 }
277
278 function deviceEnter(d) {
279 var node = d3.select(this),
Simon Hunt1eee51d2016-02-26 19:12:13 -0800280 glyphId = mapDeviceTypeToGlyph(d.type),
Simon Hunta4242de2015-02-24 17:11:55 -0800281 label = trimLabel(deviceLabel(d)),
Steven Burrows1c2a9682017-07-14 16:52:46 +0100282 rect, crect, glyph, labelWidth;
Simon Hunta4242de2015-02-24 17:11:55 -0800283
284 d.el = node;
285
Simon Huntf44d7262016-06-14 14:46:56 -0700286 rect = node.append('rect');
Simon Hunte9062fc2016-12-22 11:40:06 -0800287 crect = node.append('rect');
Simon Hunta4242de2015-02-24 17:11:55 -0800288
Steven Burrows1c2a9682017-07-14 16:52:46 +0100289 node.append('text').text(label)
Simon Huntf44d7262016-06-14 14:46:56 -0700290 .attr('text-anchor', 'left')
291 .attr('y', '0.3em')
Simon Hunta5487ad2016-06-16 13:10:41 -0700292 .attr('x', halfDevIcon + labelPad);
Simon Hunta4242de2015-02-24 17:11:55 -0800293
Simon Huntf44d7262016-06-14 14:46:56 -0700294 glyph = is.addDeviceIcon(node, glyphId, devIconDim);
Simon Hunta4242de2015-02-24 17:11:55 -0800295
Simon Huntf44d7262016-06-14 14:46:56 -0700296 labelWidth = label ? computeLabelWidth(node) : 0;
297
298 rect.attr(iconBox(devIconDim, labelWidth));
Simon Hunte9062fc2016-12-22 11:40:06 -0800299 crect.attr(iconBox(devColorDim, 0));
Simon Huntf44d7262016-06-14 14:46:56 -0700300 glyph.attr(iconBox(devIconDim, 0));
301
Simon Hunta5487ad2016-06-16 13:10:41 -0700302 node.attr('transform', sus.translate(-halfDevIcon, -halfDevIcon));
Steven Burrowsf17f0ab2017-04-11 11:03:58 -0700303
304 d.el.selectAll('*')
305 .style('transform', 'scale(' + api.deviceScale() + ')');
Simon Hunta4242de2015-02-24 17:11:55 -0800306 }
307
308 function hostEnter(d) {
309 var node = d3.select(this),
Simon Hunte9062fc2016-12-22 11:40:06 -0800310 glyphId = mapHostTypeToGlyph(d.type),
Simon Hunta5487ad2016-06-16 13:10:41 -0700311 textDy = hostRadius + 10;
Simon Hunta4242de2015-02-24 17:11:55 -0800312
313 d.el = node;
314 sus.visible(node, api.showHosts());
315
Simon Hunte9062fc2016-12-22 11:40:06 -0800316 is.addHostIcon(node, hostRadius, glyphId);
Simon Hunta4242de2015-02-24 17:11:55 -0800317
318 node.append('text')
319 .text(hostLabel)
320 .attr('dy', textDy)
321 .attr('text-anchor', 'middle');
Steven Burrowsf17f0ab2017-04-11 11:03:58 -0700322
323 d.el.selectAll('g').style('transform', 'scale(' + api.deviceScale() + ')');
324 d.el.selectAll('text').style('transform', 'scale(' + api.deviceScale() + ')');
Simon Hunta4242de2015-02-24 17:11:55 -0800325 }
326
327 function hostExit(d) {
328 var node = d.el;
329 node.select('use')
330 .style('opacity', 0.5)
331 .transition()
332 .duration(800)
333 .style('opacity', 0);
334
335 node.select('text')
336 .style('opacity', 0.5)
337 .transition()
338 .duration(800)
339 .style('opacity', 0);
340
341 node.select('circle')
342 .style('stroke-fill', '#555')
343 .style('fill', '#888')
344 .style('opacity', 0.5)
345 .transition()
346 .duration(1500)
347 .attr('r', 0);
348 }
349
350 function deviceExit(d) {
351 var node = d.el;
352 node.select('use')
353 .style('opacity', 0.5)
354 .transition()
355 .duration(800)
356 .style('opacity', 0);
357
358 node.selectAll('rect')
359 .style('stroke-fill', '#555')
360 .style('fill', '#888')
361 .style('opacity', 0.5);
362 }
363
364
365 // ==========================
366 // updateLinks - subfunctions
367
Simon Hunta4242de2015-02-24 17:11:55 -0800368 function linkEntering(d) {
Steven Burrowsec1f45c2016-08-08 16:14:41 +0100369
Simon Hunta4242de2015-02-24 17:11:55 -0800370 var link = d3.select(this);
371 d.el = link;
Steven Burrowsf17f0ab2017-04-11 11:03:58 -0700372 d.el.style('stroke-width', api.linkWidthScale() + 'px');
Simon Hunta4242de2015-02-24 17:11:55 -0800373 api.restyleLinkElement(d);
374 if (d.type() === 'hostLink') {
375 sus.visible(link, api.showHosts());
376 }
377 }
378
379 var linkLabelOffset = '0.3em';
380
381 function applyLinkLabels() {
382 var entering;
383
384 api.updateLinkLabelModel();
385
386 // for elements already existing, we need to update the text
387 // and adjust the rectangle size to fit
388 api.linkLabel().each(function (d) {
389 var el = d3.select(this),
390 rect = el.select('rect'),
391 text = el.select('text');
392 text.text(d.label);
393 rect.attr(rectAroundText(el));
394 });
395
396 entering = api.linkLabel().enter().append('g')
397 .classed('linkLabel', true)
398 .attr('id', function (d) { return d.id; });
399
400 entering.each(function (d) {
401 var el = d3.select(this),
402 rect,
Bri Prebilic Cole038aedd2015-07-13 15:25:16 -0700403 text;
Simon Hunta4242de2015-02-24 17:11:55 -0800404
405 if (d.ldata.type() === 'hostLink') {
406 el.classed('hostLinkLabel', true);
407 sus.visible(el, api.showHosts());
408 }
409
410 d.el = el;
411 rect = el.append('rect');
412 text = el.append('text').text(d.label);
413 rect.attr(rectAroundText(el));
414 text.attr('dy', linkLabelOffset);
415
Carmelo Casconed01eda62016-08-02 10:19:15 -0700416 el.attr('transform', transformLabel(d.ldata.position, d.key));
Simon Hunta4242de2015-02-24 17:11:55 -0800417 });
418
419 // Remove any labels that are no longer required.
420 api.linkLabel().exit().remove();
421 }
422
423 function rectAroundText(el) {
424 var text = el.select('text'),
425 box = text.node().getBBox();
426
427 // translate the bbox so that it is centered on [x,y]
428 box.x = -box.width / 2;
429 box.y = -box.height / 2;
430
431 // add padding
432 box.x -= 1;
433 box.width += 2;
434 return box;
435 }
436
Carmelo Casconed01eda62016-08-02 10:19:15 -0700437 function generateLabelFunction() {
Simon Hunte093e782017-03-31 10:19:08 -0700438 var labels = [],
439 xGap = 15,
440 yGap = 17;
Carmelo Casconed01eda62016-08-02 10:19:15 -0700441
Simon Hunte093e782017-03-31 10:19:08 -0700442 return function (newId, newX, newY) {
Carmelo Casconed01eda62016-08-02 10:19:15 -0700443 var idx = -1;
444
Simon Hunte093e782017-03-31 10:19:08 -0700445 labels.forEach(function (lab, i) {
446 var minX, maxX, minY, maxY;
447
448 if (lab.id === newId) {
Carmelo Casconed01eda62016-08-02 10:19:15 -0700449 idx = i;
450 return;
451 }
Simon Hunte093e782017-03-31 10:19:08 -0700452 minX = lab.x - xGap;
453 maxX = lab.x + xGap;
454 minY = lab.y - yGap;
455 maxY = lab.y + yGap;
Carmelo Casconed01eda62016-08-02 10:19:15 -0700456
457 if (newX > minX && newX < maxX && newY > minY && newY < maxY) {
458 // labels are overlapped
459 newX = newX - xGap;
460 newY = newY - yGap;
461 }
462 });
463
464 if (idx === -1) {
Steven Burrows1c2a9682017-07-14 16:52:46 +0100465 labels.push({ id: newId, x: newX, y: newY });
Simon Hunte093e782017-03-31 10:19:08 -0700466 } else {
Steven Burrows1c2a9682017-07-14 16:52:46 +0100467 labels[idx] = { id: newId, x: newX, y: newY };
Carmelo Casconed01eda62016-08-02 10:19:15 -0700468 }
469
Steven Burrows1c2a9682017-07-14 16:52:46 +0100470 return { x: newX, y: newY };
471 };
Carmelo Casconed01eda62016-08-02 10:19:15 -0700472 }
473
Simon Hunte093e782017-03-31 10:19:08 -0700474 var getLabelPos = generateLabelFunction();
Carmelo Casconed01eda62016-08-02 10:19:15 -0700475
476 function transformLabel(p, id) {
Simon Hunta4242de2015-02-24 17:11:55 -0800477 var dx = p.x2 - p.x1,
478 dy = p.y2 - p.y1,
479 xMid = dx/2 + p.x1,
480 yMid = dy/2 + p.y1;
Carmelo Casconed01eda62016-08-02 10:19:15 -0700481
482 if (id) {
Simon Hunte093e782017-03-31 10:19:08 -0700483 var pos = getLabelPos(id, xMid, yMid);
Carmelo Casconed01eda62016-08-02 10:19:15 -0700484 return sus.translate(pos.x, pos.y);
485 }
486
Simon Hunta4242de2015-02-24 17:11:55 -0800487 return sus.translate(xMid, yMid);
488 }
489
Simon Hunt1a5301e2015-02-25 15:31:25 -0800490 function applyPortLabels(data, portLabelG) {
491 var entering = portLabelG.selectAll('.portLabel')
492 .data(data).enter().append('g')
493 .classed('portLabel', true)
494 .attr('id', function (d) { return d.id; });
495
Steven Burrowsf17f0ab2017-04-11 11:03:58 -0700496 var labelScale = portLabelDim / (portLabelDim * zoomer.scale());
497
Simon Hunt1a5301e2015-02-25 15:31:25 -0800498 entering.each(function (d) {
499 var el = d3.select(this),
500 rect = el.append('rect'),
501 text = el.append('text').text(d.num);
502
Steven Burrowsf17f0ab2017-04-11 11:03:58 -0700503 rect.attr(rectAroundText(el))
504 .style('transform', 'scale(' + labelScale + ')');
505 text.attr('dy', linkLabelOffset)
506 .style('transform', 'scale(' + labelScale + ')');
507
Simon Hunt969b3c92015-02-25 18:11:31 -0800508 el.attr('transform', sus.translate(d.x, d.y));
Simon Hunt1a5301e2015-02-25 15:31:25 -0800509 });
510 }
511
Bri Prebilic Cole80401762015-07-16 11:36:18 -0700512 function labelPoint(linkPos) {
513 var lengthUpLine = 1 / 3,
514 dx = linkPos.x2 - linkPos.x1,
515 dy = linkPos.y2 - linkPos.y1,
516 movedX = dx * lengthUpLine,
517 movedY = dy * lengthUpLine;
518
519 return {
520 x: movedX,
Steven Burrows1c2a9682017-07-14 16:52:46 +0100521 y: movedY,
Bri Prebilic Cole80401762015-07-16 11:36:18 -0700522 };
523 }
524
525 function calcGroupPos(linkPos) {
526 var moved = labelPoint(linkPos);
527 return sus.translate(linkPos.x1 + moved.x, linkPos.y1 + moved.y);
528 }
529
530 // calculates where on the link that the hash line for 5+ label appears
531 function hashAttrs(linkPos) {
532 var hashLength = 25,
533 halfLength = hashLength / 2,
534 dx = linkPos.x2 - linkPos.x1,
535 dy = linkPos.y2 - linkPos.y1,
536 length = Math.sqrt((dx * dx) + (dy * dy)),
537 moveAmtX = (dx / length) * halfLength,
538 moveAmtY = (dy / length) * halfLength,
539 mid = labelPoint(linkPos),
540 angle = Math.atan(dy / dx) + 45;
541
542 return {
543 x1: mid.x - moveAmtX,
544 y1: mid.y - moveAmtY,
545 x2: mid.x + moveAmtX,
546 y2: mid.y + moveAmtY,
547 stroke: api.linkConfig()[ts.theme()].baseColor,
Steven Burrows1c2a9682017-07-14 16:52:46 +0100548 transform: 'rotate(' + angle + ',' + mid.x + ',' + mid.y + ')',
Bri Prebilic Cole80401762015-07-16 11:36:18 -0700549 };
550 }
551
552 function textLabelPos(linkPos) {
553 var point = labelPoint(linkPos),
554 dist = 20;
555 return {
556 x: point.x + dist,
Steven Burrows1c2a9682017-07-14 16:52:46 +0100557 y: point.y + dist,
Bri Prebilic Cole80401762015-07-16 11:36:18 -0700558 };
559 }
560
561 function applyNumLinkLabels(data, lblsG) {
562 var labels = lblsG.selectAll('g.numLinkLabel')
563 .data(data, function (d) { return 'pair-' + d.id; }),
564 entering;
565
566 // update existing labels
567 labels.each(function (d) {
568 var el = d3.select(this);
569
570 el.attr({
Steven Burrows1c2a9682017-07-14 16:52:46 +0100571 transform: function (d) { return calcGroupPos(d.linkCoords); },
Bri Prebilic Cole80401762015-07-16 11:36:18 -0700572 });
573 el.select('line')
574 .attr(hashAttrs(d.linkCoords));
575 el.select('text')
576 .attr(textLabelPos(d.linkCoords))
577 .text(d.num);
578 });
579
580 // add new labels
581 entering = labels
582 .enter()
583 .append('g')
584 .attr({
585 transform: function (d) { return calcGroupPos(d.linkCoords); },
Steven Burrows1c2a9682017-07-14 16:52:46 +0100586 id: function (d) { return 'pair-' + d.id; },
Bri Prebilic Cole80401762015-07-16 11:36:18 -0700587 })
588 .classed('numLinkLabel', true);
589
590 entering.each(function (d) {
591 var el = d3.select(this);
592
593 el.append('line')
594 .classed('numLinkHash', true)
595 .attr(hashAttrs(d.linkCoords));
596 el.append('text')
597 .classed('numLinkText', true)
598 .attr(textLabelPos(d.linkCoords))
599 .text(d.num);
600 });
601
602 // remove old labels
603 labels.exit().remove();
604 }
605
Simon Hunta4242de2015-02-24 17:11:55 -0800606 // ==========================
607 // Module definition
608
609 angular.module('ovTopo')
610 .factory('TopoD3Service',
Steven Burrows1c2a9682017-07-14 16:52:46 +0100611 ['SvgUtilService', 'IconService', 'ThemeService',
Thomas Vachuska0af26912016-03-21 21:37:30 -0700612 'PrefsService', 'TopoToolbarService',
Simon Hunta4242de2015-02-24 17:11:55 -0800613
Steven Burrows1c2a9682017-07-14 16:52:46 +0100614 function (_sus_, _is_, _ts_, _ps_, _ttbs_) {
Simon Hunta4242de2015-02-24 17:11:55 -0800615 sus = _sus_;
616 is = _is_;
617 ts = _ts_;
Thomas Vachuska0af26912016-03-21 21:37:30 -0700618 ps = _ps_;
619 ttbs = _ttbs_;
Simon Hunta4242de2015-02-24 17:11:55 -0800620
Steven Burrowsf17f0ab2017-04-11 11:03:58 -0700621 function initD3(_api_, _zoomer_) {
Simon Hunta4242de2015-02-24 17:11:55 -0800622 api = _api_;
Steven Burrowsf17f0ab2017-04-11 11:03:58 -0700623 zoomer = _zoomer_;
Simon Hunta4242de2015-02-24 17:11:55 -0800624 }
625
626 function destroyD3() { }
627
628 return {
629 initD3: initD3,
630 destroyD3: destroyD3,
631
632 incDevLabIndex: incDevLabIndex,
Thomas Vachuska0af26912016-03-21 21:37:30 -0700633 setDevLabIndex: setDevLabIndex,
Simon Hunt10618f62017-06-15 19:30:52 -0700634 incHostLabIndex: incHostLabIndex,
635 setHostLabIndex: setHostLabIndex,
Simon Hunta4242de2015-02-24 17:11:55 -0800636 hostLabel: hostLabel,
637 deviceLabel: deviceLabel,
638 trimLabel: trimLabel,
639
Simon Hunt5674db92015-10-22 16:12:48 -0700640 updateDeviceLabel: updateDeviceRendering,
Simon Hunta4242de2015-02-24 17:11:55 -0800641 updateHostLabel: updateHostLabel,
642 updateDeviceColors: updateDeviceColors,
643
644 deviceExisting: deviceExisting,
645 hostExisting: hostExisting,
646 deviceEnter: deviceEnter,
647 hostEnter: hostEnter,
648 hostExit: hostExit,
649 deviceExit: deviceExit,
650
Simon Hunta4242de2015-02-24 17:11:55 -0800651 linkEntering: linkEntering,
652 applyLinkLabels: applyLinkLabels,
Simon Hunt1a5301e2015-02-25 15:31:25 -0800653 transformLabel: transformLabel,
Bri Prebilic Cole80401762015-07-16 11:36:18 -0700654 applyPortLabels: applyPortLabels,
Steven Burrows1c2a9682017-07-14 16:52:46 +0100655 applyNumLinkLabels: applyNumLinkLabels,
Simon Hunta4242de2015-02-24 17:11:55 -0800656 };
657 }]);
658}());