ONOS-2328 GUI -- Enhanced Topology View to show multiple links individually betw…
…een devices (1 - 4). 5 or more is a thick line. Change-Id: Ie096086454fd8d1d5d40f09396681f9cba8597a1
Showing
5 changed files
with
105 additions
and
52 deletions
| ... | @@ -367,17 +367,10 @@ | ... | @@ -367,17 +367,10 @@ |
| 367 | .classed('linkLabel', true) | 367 | .classed('linkLabel', true) |
| 368 | .attr('id', function (d) { return d.id; }); | 368 | .attr('id', function (d) { return d.id; }); |
| 369 | 369 | ||
| 370 | - // FIXME: x and y position calculated here, use link.position obj | ||
| 371 | entering.each(function (d) { | 370 | entering.each(function (d) { |
| 372 | var el = d3.select(this), | 371 | var el = d3.select(this), |
| 373 | rect, | 372 | rect, |
| 374 | - text, | 373 | + text; |
| 375 | - parms = { | ||
| 376 | - x1: d.ldata.source.x, | ||
| 377 | - y1: d.ldata.source.y, | ||
| 378 | - x2: d.ldata.target.x, | ||
| 379 | - y2: d.ldata.target.y | ||
| 380 | - }; | ||
| 381 | 374 | ||
| 382 | if (d.ldata.type() === 'hostLink') { | 375 | if (d.ldata.type() === 'hostLink') { |
| 383 | el.classed('hostLinkLabel', true); | 376 | el.classed('hostLinkLabel', true); |
| ... | @@ -390,7 +383,7 @@ | ... | @@ -390,7 +383,7 @@ |
| 390 | rect.attr(rectAroundText(el)); | 383 | rect.attr(rectAroundText(el)); |
| 391 | text.attr('dy', linkLabelOffset); | 384 | text.attr('dy', linkLabelOffset); |
| 392 | 385 | ||
| 393 | - el.attr('transform', transformLabel(parms)); | 386 | + el.attr('transform', transformLabel(d.ldata.position)); |
| 394 | }); | 387 | }); |
| 395 | 388 | ||
| 396 | // Remove any labels that are no longer required. | 389 | // Remove any labels that are no longer required. |
| ... | @@ -411,7 +404,6 @@ | ... | @@ -411,7 +404,6 @@ |
| 411 | return box; | 404 | return box; |
| 412 | } | 405 | } |
| 413 | 406 | ||
| 414 | - // FIXME: x and y position calculated here | ||
| 415 | function transformLabel(p) { | 407 | function transformLabel(p) { |
| 416 | var dx = p.x2 - p.x1, | 408 | var dx = p.x2 - p.x1, |
| 417 | dy = p.y2 - p.y1, | 409 | dy = p.y2 - p.y1, | ... | ... |
| ... | @@ -575,6 +575,82 @@ | ... | @@ -575,6 +575,82 @@ |
| 575 | 575 | ||
| 576 | // ========================== | 576 | // ========================== |
| 577 | 577 | ||
| 578 | + function getDefaultPos(link) { | ||
| 579 | + return { | ||
| 580 | + x1: link.source.x, | ||
| 581 | + y1: link.source.y, | ||
| 582 | + x2: link.target.x, | ||
| 583 | + y2: link.target.y | ||
| 584 | + }; | ||
| 585 | + } | ||
| 586 | + | ||
| 587 | + // returns amount of adjustment along the normal for given link | ||
| 588 | + function amt(numLinks, linkIdx) { | ||
| 589 | + var gap = 6; | ||
| 590 | + return (linkIdx - ((numLinks - 1) / 2)) * gap; | ||
| 591 | + } | ||
| 592 | + | ||
| 593 | + function calcMovement(d, amt, flipped) { | ||
| 594 | + var pos = getDefaultPos(d), | ||
| 595 | + mult = flipped ? -amt : amt, | ||
| 596 | + dx = pos.x2 - pos.x1, | ||
| 597 | + dy = pos.y2 - pos.y1, | ||
| 598 | + length = Math.sqrt((dx * dx) + (dy * dy)); | ||
| 599 | + | ||
| 600 | + return { | ||
| 601 | + x1: pos.x1 + (mult * dy / length), | ||
| 602 | + y1: pos.y1 + (mult * -dx / length), | ||
| 603 | + x2: pos.x2 + (mult * dy / length), | ||
| 604 | + y2: pos.y2 + (mult * -dx / length) | ||
| 605 | + }; | ||
| 606 | + } | ||
| 607 | + | ||
| 608 | + function calcPosition() { | ||
| 609 | + var lines = this, | ||
| 610 | + linkSrcId; | ||
| 611 | + lines.each(function (d) { | ||
| 612 | + if (d.type() === 'hostLink') { | ||
| 613 | + d.position = getDefaultPos(d); | ||
| 614 | + } | ||
| 615 | + }); | ||
| 616 | + | ||
| 617 | + function normalizeLinkSrc(link) { | ||
| 618 | + // ensure source device is consistent across set of links | ||
| 619 | + // temporary measure until link modeling is refactored | ||
| 620 | + if (!linkSrcId) { | ||
| 621 | + linkSrcId = link.source.id; | ||
| 622 | + return false; | ||
| 623 | + } | ||
| 624 | + | ||
| 625 | + return link.source.id !== linkSrcId; | ||
| 626 | + } | ||
| 627 | + | ||
| 628 | + angular.forEach(network.linksByDevice, function (linkArr) { | ||
| 629 | + var numLinks = linkArr.length, | ||
| 630 | + link; | ||
| 631 | + | ||
| 632 | + if (numLinks === 1) { | ||
| 633 | + link = linkArr[0]; | ||
| 634 | + link.position = getDefaultPos(link); | ||
| 635 | + } else if (numLinks >= 5) { | ||
| 636 | + // this code is inefficient, in the future the way links | ||
| 637 | + // are modeled will be changed | ||
| 638 | + angular.forEach(linkArr, function (link) { | ||
| 639 | + link.position = getDefaultPos(link); | ||
| 640 | + link.position.multiLink = true; | ||
| 641 | + }); | ||
| 642 | + } else { | ||
| 643 | + // calculate position of links | ||
| 644 | + linkSrcId = null; | ||
| 645 | + angular.forEach(linkArr, function (link, index) { | ||
| 646 | + var offsetAmt = amt(numLinks, index), | ||
| 647 | + needToFlip = normalizeLinkSrc(link); | ||
| 648 | + link.position = calcMovement(link, offsetAmt, needToFlip); | ||
| 649 | + }); | ||
| 650 | + } | ||
| 651 | + }); | ||
| 652 | + } | ||
| 653 | + | ||
| 578 | function updateLinks() { | 654 | function updateLinks() { |
| 579 | if (fLinksTimer) { | 655 | if (fLinksTimer) { |
| 580 | $timeout.cancel(fLinksTimer); | 656 | $timeout.cancel(fLinksTimer); |
| ... | @@ -602,14 +678,14 @@ | ... | @@ -602,14 +678,14 @@ |
| 602 | }); | 678 | }); |
| 603 | 679 | ||
| 604 | // operate on entering links: | 680 | // operate on entering links: |
| 605 | - // FIXME: x and y position calculated here - calculate position and add it to the link | ||
| 606 | var entering = link.enter() | 681 | var entering = link.enter() |
| 607 | .append('line') | 682 | .append('line') |
| 683 | + .call(calcPosition) | ||
| 608 | .attr({ | 684 | .attr({ |
| 609 | - x1: function (d) { return d.source.x; }, | 685 | + x1: function (d) { return d.position.x1; }, |
| 610 | - y1: function (d) { return d.source.y; }, | 686 | + y1: function (d) { return d.position.y1; }, |
| 611 | - x2: function (d) { return d.target.x; }, | 687 | + x2: function (d) { return d.position.x2; }, |
| 612 | - y2: function (d) { return d.target.y; }, | 688 | + y2: function (d) { return d.position.y2; }, |
| 613 | stroke: linkConfig[th].inColor, | 689 | stroke: linkConfig[th].inColor, |
| 614 | 'stroke-width': linkConfig.inWidth | 690 | 'stroke-width': linkConfig.inWidth |
| 615 | }); | 691 | }); |
| ... | @@ -664,24 +740,17 @@ | ... | @@ -664,24 +740,17 @@ |
| 664 | nodeAttr: { | 740 | nodeAttr: { |
| 665 | transform: function (d) { return sus.translate(d.x, d.y); } | 741 | transform: function (d) { return sus.translate(d.x, d.y); } |
| 666 | }, | 742 | }, |
| 667 | - // FIXME: x and y position calculated here, will be deleted | ||
| 668 | linkAttr: { | 743 | linkAttr: { |
| 669 | - x1: function (d) { return d.source.x; }, | 744 | + x1: function (d) { return d.position.x1; }, |
| 670 | - y1: function (d) { return d.source.y; }, | 745 | + y1: function (d) { return d.position.y1; }, |
| 671 | - x2: function (d) { return d.target.x; }, | 746 | + x2: function (d) { return d.position.x2; }, |
| 672 | - y2: function (d) { return d.target.y; } | 747 | + y2: function (d) { return d.position.y2; } |
| 673 | }, | 748 | }, |
| 674 | linkLabelAttr: { | 749 | linkLabelAttr: { |
| 675 | transform: function (d) { | 750 | transform: function (d) { |
| 676 | var lnk = tms.findLinkById(d.key); | 751 | var lnk = tms.findLinkById(d.key); |
| 677 | if (lnk) { | 752 | if (lnk) { |
| 678 | - // FIXME: x and y position calculated here, use link.position object | 753 | + return td3.transformLabel(lnk.position); |
| 679 | - return td3.transformLabel({ | ||
| 680 | - x1: lnk.source.x, | ||
| 681 | - y1: lnk.source.y, | ||
| 682 | - x2: lnk.target.x, | ||
| 683 | - y2: lnk.target.y | ||
| 684 | - }); | ||
| 685 | } | 754 | } |
| 686 | } | 755 | } |
| 687 | } | 756 | } |
| ... | @@ -693,8 +762,8 @@ | ... | @@ -693,8 +762,8 @@ |
| 693 | node.attr(tickStuff.nodeAttr); | 762 | node.attr(tickStuff.nodeAttr); |
| 694 | } | 763 | } |
| 695 | if (link) { | 764 | if (link) { |
| 696 | - // FIXME: instead of tickStuff here, use link.position object | 765 | + link.call(calcPosition) |
| 697 | - link.attr(tickStuff.linkAttr); | 766 | + .attr(tickStuff.linkAttr); |
| 698 | } | 767 | } |
| 699 | if (linkLabel) { | 768 | if (linkLabel) { |
| 700 | linkLabel.attr(tickStuff.linkLabelAttr); | 769 | linkLabel.attr(tickStuff.linkLabelAttr); |
| ... | @@ -827,7 +896,8 @@ | ... | @@ -827,7 +896,8 @@ |
| 827 | return old; | 896 | return old; |
| 828 | }, | 897 | }, |
| 829 | opacifyMap: uplink.opacifyMap, | 898 | opacifyMap: uplink.opacifyMap, |
| 830 | - inLayer: fltr.inLayer | 899 | + inLayer: fltr.inLayer, |
| 900 | + calcLinkPos: calcPosition | ||
| 831 | }; | 901 | }; |
| 832 | } | 902 | } |
| 833 | 903 | ... | ... |
| ... | @@ -104,16 +104,6 @@ | ... | @@ -104,16 +104,6 @@ |
| 104 | return {x:x4, y:y4}; | 104 | return {x:x4, y:y4}; |
| 105 | } | 105 | } |
| 106 | 106 | ||
| 107 | - // FIXME: x and y position calculated here, use link.position | ||
| 108 | - function lineSeg(d) { | ||
| 109 | - return { | ||
| 110 | - x1: d.source.x, | ||
| 111 | - y1: d.source.y, | ||
| 112 | - x2: d.target.x, | ||
| 113 | - y2: d.target.y | ||
| 114 | - }; | ||
| 115 | - } | ||
| 116 | - | ||
| 117 | function lineHit(line, p, m) { | 107 | function lineHit(line, p, m) { |
| 118 | if (p.x < line.x1 && p.x < line.x2) return false; | 108 | if (p.x < line.x1 && p.x < line.x2) return false; |
| 119 | if (p.x > line.x1 && p.x > line.x2) return false; | 109 | if (p.x > line.x1 && p.x > line.x2) return false; |
| ... | @@ -131,7 +121,7 @@ | ... | @@ -131,7 +121,7 @@ |
| 131 | return; // skip hidden host links | 121 | return; // skip hidden host links |
| 132 | } | 122 | } |
| 133 | 123 | ||
| 134 | - var line = lineSeg(d), | 124 | + var line = d.position, |
| 135 | point = pdrop(line, mouse), | 125 | point = pdrop(line, mouse), |
| 136 | hit = lineHit(line, point, mouse), | 126 | hit = lineHit(line, point, mouse), |
| 137 | dist; | 127 | dist; |
| ... | @@ -201,24 +191,23 @@ | ... | @@ -201,24 +191,23 @@ |
| 201 | td3.applyPortLabels(data, api.portLabelG()); | 191 | td3.applyPortLabels(data, api.portLabelG()); |
| 202 | } | 192 | } |
| 203 | 193 | ||
| 204 | - // FIXME: x and y position calculated here somewhere | ||
| 205 | function locatePortLabel(link, src) { | 194 | function locatePortLabel(link, src) { |
| 206 | - var near = src ? 'source' : 'target', | 195 | + var offset = 32, |
| 207 | - far = src ? 'target' : 'source', | 196 | + pos = link.position, |
| 208 | - ln = link[near], | 197 | + nearX = src ? pos.x1 : pos.x2, |
| 209 | - lf = link[far], | 198 | + nearY = src ? pos.y1 : pos.y2, |
| 210 | - offset = 32; | 199 | + farX = src ? pos.x2 : pos.x1, |
| 200 | + farY = src ? pos.y2 : pos.y1; | ||
| 211 | 201 | ||
| 212 | function dist(x, y) { return Math.sqrt(x*x + y*y); } | 202 | function dist(x, y) { return Math.sqrt(x*x + y*y); } |
| 213 | 203 | ||
| 214 | - var dx = lf.x - ln.x, | 204 | + var dx = farX - nearX, |
| 215 | - dy = lf.y - ln.y, | 205 | + dy = farY - nearY, |
| 216 | k = offset / dist(dx, dy); | 206 | k = offset / dist(dx, dy); |
| 217 | 207 | ||
| 218 | - return {x: k * dx + ln.x, y: k * dy + ln.y}; | 208 | + return {x: k * dx + nearX, y: k * dy + nearY}; |
| 219 | } | 209 | } |
| 220 | 210 | ||
| 221 | - | ||
| 222 | function selectLink(ldata) { | 211 | function selectLink(ldata) { |
| 223 | // if the new link is same as old link, do nothing | 212 | // if the new link is same as old link, do nothing |
| 224 | if (selectedLink && ldata && selectedLink.key === ldata.key) return; | 213 | if (selectedLink && ldata && selectedLink.key === ldata.key) return; | ... | ... |
| ... | @@ -209,7 +209,7 @@ | ... | @@ -209,7 +209,7 @@ |
| 209 | t = lnk.fromTarget, | 209 | t = lnk.fromTarget, |
| 210 | ws = (s && s.linkWidth) || 0, | 210 | ws = (s && s.linkWidth) || 0, |
| 211 | wt = (t && t.linkWidth) || 0; | 211 | wt = (t && t.linkWidth) || 0; |
| 212 | - return Math.max(ws, wt); | 212 | + return lnk.position.multiLink ? 5 : Math.max(ws, wt); |
| 213 | } | 213 | } |
| 214 | }); | 214 | }); |
| 215 | return lnk; | 215 | return lnk; | ... | ... |
| ... | @@ -39,6 +39,7 @@ | ... | @@ -39,6 +39,7 @@ |
| 39 | nodeLock(b) // test-and-set nodeLock state | 39 | nodeLock(b) // test-and-set nodeLock state |
| 40 | opacifyMap(b) // show or hide map layer | 40 | opacifyMap(b) // show or hide map layer |
| 41 | inLayer(d, layer) // return true if d in layer {'pkt'|'opt'} | 41 | inLayer(d, layer) // return true if d in layer {'pkt'|'opt'} |
| 42 | + calcLinkPos() // recomputes link pos based on node data | ||
| 42 | */ | 43 | */ |
| 43 | 44 | ||
| 44 | // configuration | 45 | // configuration |
| ... | @@ -155,6 +156,7 @@ | ... | @@ -155,6 +156,7 @@ |
| 155 | .attr(api.tickStuff.nodeAttr); | 156 | .attr(api.tickStuff.nodeAttr); |
| 156 | api.link().transition() | 157 | api.link().transition() |
| 157 | .duration(time) | 158 | .duration(time) |
| 159 | + .call(api.calcLinkPos) | ||
| 158 | .attr(api.tickStuff.linkAttr); | 160 | .attr(api.tickStuff.linkAttr); |
| 159 | api.linkLabel().transition() | 161 | api.linkLabel().transition() |
| 160 | .duration(time) | 162 | .duration(time) | ... | ... |
-
Please register or login to post a comment