GUI - Implemented link labels showing data on links when traffic is flowing..
Change-Id: I3fe602d20c5756620d2c4eb793dac2a0c8d1379c
Showing
4 changed files
with
153 additions
and
17 deletions
| ... | @@ -12,9 +12,9 @@ | ... | @@ -12,9 +12,9 @@ |
| 12 | "of:0000ffffffff0007/1-0E:2A:69:30:13:89/-1/0" | 12 | "of:0000ffffffff0007/1-0E:2A:69:30:13:89/-1/0" |
| 13 | ], | 13 | ], |
| 14 | "labels": [ | 14 | "labels": [ |
| 15 | - "Load{rate=98, latest=38080}", | 15 | + "Load{rate=20, latest=20000}", |
| 16 | - "Load{rate=98, latest=38080}", | 16 | + "Load{rate=10, latest=20000}", |
| 17 | - "Load{rate=98, latest=38080}" | 17 | + "" |
| 18 | ] | 18 | ] |
| 19 | } | 19 | } |
| 20 | ] | 20 | ] | ... | ... |
| ... | @@ -12,9 +12,9 @@ | ... | @@ -12,9 +12,9 @@ |
| 12 | "of:0000ffffffff0007/1-0E:2A:69:30:13:89/-1/0" | 12 | "of:0000ffffffff0007/1-0E:2A:69:30:13:89/-1/0" |
| 13 | ], | 13 | ], |
| 14 | "labels": [ | 14 | "labels": [ |
| 15 | - "Load{rate=98, latest=38080}", | 15 | + "", |
| 16 | - "Load{rate=98, latest=38080}", | 16 | + "Load{rate=98, latest=38456}", |
| 17 | - "Load{rate=98, latest=38080}" | 17 | + "Load{rate=98, latest=38789}" |
| 18 | ] | 18 | ] |
| 19 | } | 19 | } |
| 20 | ] | 20 | ] | ... | ... |
| ... | @@ -154,6 +154,17 @@ svg .node.host circle { | ... | @@ -154,6 +154,17 @@ svg .node.host circle { |
| 154 | stroke-dasharray: 8 8 | 154 | stroke-dasharray: 8 8 |
| 155 | } | 155 | } |
| 156 | 156 | ||
| 157 | +#topo svg .linkLabel rect { | ||
| 158 | + fill: #eef; | ||
| 159 | + stroke: blue; | ||
| 160 | + stroke-width: 0.3; | ||
| 161 | +} | ||
| 162 | +#topo svg .linkLabel text { | ||
| 163 | + text-anchor: middle; | ||
| 164 | + fill: #a13d11; | ||
| 165 | + stroke: none; | ||
| 166 | + font-size: 8pt; | ||
| 167 | +} | ||
| 157 | 168 | ||
| 158 | /* Fly-in details pane */ | 169 | /* Fly-in details pane */ |
| 159 | 170 | ... | ... |
| ... | @@ -186,8 +186,10 @@ | ... | @@ -186,8 +186,10 @@ |
| 186 | topoG, | 186 | topoG, |
| 187 | nodeG, | 187 | nodeG, |
| 188 | linkG, | 188 | linkG, |
| 189 | + linkLabelG, | ||
| 189 | node, | 190 | node, |
| 190 | link, | 191 | link, |
| 192 | + linkLabel, | ||
| 191 | mask; | 193 | mask; |
| 192 | 194 | ||
| 193 | // the projection for the map background | 195 | // the projection for the map background |
| ... | @@ -710,17 +712,25 @@ | ... | @@ -710,17 +712,25 @@ |
| 710 | 712 | ||
| 711 | // Revert any links hilighted previously. | 713 | // Revert any links hilighted previously. |
| 712 | link.classed('primary secondary animated optical', false); | 714 | link.classed('primary secondary animated optical', false); |
| 715 | + // Remove all previous labels. | ||
| 716 | + removeLinkLabels(); | ||
| 713 | 717 | ||
| 714 | - // Now hilight all links in the paths payload. | 718 | + // Now hilight all links in the paths payload, and attach |
| 719 | + // labels to them, if they are defined. | ||
| 715 | paths.forEach(function (p) { | 720 | paths.forEach(function (p) { |
| 716 | - var cls = p.class; | 721 | + var n = p.links.length, |
| 717 | - p.links.forEach(function (id) { | 722 | + i, |
| 718 | - var lnk = findLinkById(id); | 723 | + ldata; |
| 719 | - if (lnk) { | 724 | + |
| 720 | - lnk.el.classed(cls, true); | 725 | + for (i=0; i<n; i++) { |
| 726 | + ldata = findLinkById(p.links[i]); | ||
| 727 | + if (ldata) { | ||
| 728 | + ldata.el.classed(p.class, true); | ||
| 729 | + ldata.label = p.labels[i]; | ||
| 721 | } | 730 | } |
| 722 | - }); | 731 | + } |
| 723 | }); | 732 | }); |
| 733 | + updateLinks(); | ||
| 724 | } | 734 | } |
| 725 | 735 | ||
| 726 | // ............................... | 736 | // ............................... |
| ... | @@ -891,6 +901,10 @@ | ... | @@ -891,6 +901,10 @@ |
| 891 | return 'translate(' + x + ',' + y + ')'; | 901 | return 'translate(' + x + ',' + y + ')'; |
| 892 | } | 902 | } |
| 893 | 903 | ||
| 904 | + function rotate(deg) { | ||
| 905 | + return 'rotate(' + deg + ')'; | ||
| 906 | + } | ||
| 907 | + | ||
| 894 | function missMsg(what, id) { | 908 | function missMsg(what, id) { |
| 895 | return '\n[' + what + '] "' + id + '" missing '; | 909 | return '\n[' + what + '] "' + id + '" missing '; |
| 896 | } | 910 | } |
| ... | @@ -973,6 +987,12 @@ | ... | @@ -973,6 +987,12 @@ |
| 973 | return lnk; | 987 | return lnk; |
| 974 | } | 988 | } |
| 975 | 989 | ||
| 990 | + function removeLinkLabels() { | ||
| 991 | + network.links.forEach(function (d) { | ||
| 992 | + d.label = ''; | ||
| 993 | + }); | ||
| 994 | + } | ||
| 995 | + | ||
| 976 | var widthRatio = 1.4, | 996 | var widthRatio = 1.4, |
| 977 | linkScale = d3.scale.linear() | 997 | linkScale = d3.scale.linear() |
| 978 | .domain([1, 12]) | 998 | .domain([1, 12]) |
| ... | @@ -1004,13 +1024,15 @@ | ... | @@ -1004,13 +1024,15 @@ |
| 1004 | // provide ref to element selection from backing data.... | 1024 | // provide ref to element selection from backing data.... |
| 1005 | d.el = link; | 1025 | d.el = link; |
| 1006 | restyleLinkElement(d); | 1026 | restyleLinkElement(d); |
| 1007 | - | ||
| 1008 | - // TODO: add src/dst port labels etc. | ||
| 1009 | }); | 1027 | }); |
| 1010 | 1028 | ||
| 1011 | // operate on both existing and new links, if necessary | 1029 | // operate on both existing and new links, if necessary |
| 1012 | //link .foo() .bar() ... | 1030 | //link .foo() .bar() ... |
| 1013 | 1031 | ||
| 1032 | + // apply or remove labels | ||
| 1033 | + var labelData = getLabelData(); | ||
| 1034 | + applyLinkLabels(labelData); | ||
| 1035 | + | ||
| 1014 | // operate on exiting links: | 1036 | // operate on exiting links: |
| 1015 | link.exit() | 1037 | link.exit() |
| 1016 | .attr('stroke-dasharray', '3, 3') | 1038 | .attr('stroke-dasharray', '3, 3') |
| ... | @@ -1024,6 +1046,95 @@ | ... | @@ -1024,6 +1046,95 @@ |
| 1024 | }) | 1046 | }) |
| 1025 | .style('opacity', 0.0) | 1047 | .style('opacity', 0.0) |
| 1026 | .remove(); | 1048 | .remove(); |
| 1049 | + | ||
| 1050 | + // NOTE: invoke a single tick to force the labels to position | ||
| 1051 | + // onto their links. | ||
| 1052 | + tick(); | ||
| 1053 | + } | ||
| 1054 | + | ||
| 1055 | + function getLabelData() { | ||
| 1056 | + // create the backing data for showing labels.. | ||
| 1057 | + var data = []; | ||
| 1058 | + link.each(function (d) { | ||
| 1059 | + if (d.label) { | ||
| 1060 | + data.push({ | ||
| 1061 | + id: 'lab-' + d.key, | ||
| 1062 | + key: d.key, | ||
| 1063 | + label: d.label, | ||
| 1064 | + ldata: d | ||
| 1065 | + }); | ||
| 1066 | + } | ||
| 1067 | + }); | ||
| 1068 | + return data; | ||
| 1069 | + } | ||
| 1070 | + | ||
| 1071 | + var linkLabelOffset = '0.3em'; | ||
| 1072 | + | ||
| 1073 | + function applyLinkLabels(data) { | ||
| 1074 | + var entering; | ||
| 1075 | + | ||
| 1076 | + linkLabel = linkLabelG.selectAll('.linkLabel') | ||
| 1077 | + .data(data, function (d) { return d.id; }); | ||
| 1078 | + | ||
| 1079 | + entering = linkLabel.enter().append('g') | ||
| 1080 | + .classed('linkLabel', true) | ||
| 1081 | + .attr('id', function (d) { return d.id; }); | ||
| 1082 | + | ||
| 1083 | + entering.each(function (d) { | ||
| 1084 | + var el = d3.select(this), | ||
| 1085 | + rect, | ||
| 1086 | + text, | ||
| 1087 | + parms = { | ||
| 1088 | + x1: d.ldata.x1, | ||
| 1089 | + y1: d.ldata.y1, | ||
| 1090 | + x2: d.ldata.x2, | ||
| 1091 | + y2: d.ldata.y2 | ||
| 1092 | + }; | ||
| 1093 | + | ||
| 1094 | + d.el = el; | ||
| 1095 | + rect = el.append('rect'); | ||
| 1096 | + text = el.append('text').text(d.label); | ||
| 1097 | + rect.attr(rectAroundText(el)); | ||
| 1098 | + text.attr('dy', linkLabelOffset); | ||
| 1099 | + | ||
| 1100 | + el.attr('transform', transformLabel(parms)); | ||
| 1101 | + }); | ||
| 1102 | + | ||
| 1103 | + // Remove any links that are no longer required. | ||
| 1104 | + linkLabel.exit().remove(); | ||
| 1105 | + } | ||
| 1106 | + | ||
| 1107 | + function rectAroundText(el) { | ||
| 1108 | + var text = el.select('text'), | ||
| 1109 | + box = text.node().getBBox(); | ||
| 1110 | + | ||
| 1111 | + // translate the bbox so that it is centered on [x,y] | ||
| 1112 | + box.x = -box.width / 2; | ||
| 1113 | + box.y = -box.height / 2; | ||
| 1114 | + | ||
| 1115 | + // add padding | ||
| 1116 | + box.x -= 1; | ||
| 1117 | + box.width += 2; | ||
| 1118 | + return box; | ||
| 1119 | + } | ||
| 1120 | + | ||
| 1121 | + function transformLabel(p) { | ||
| 1122 | + var dx = p.x2 - p.x1, | ||
| 1123 | + dy = p.y2 - p.y1, | ||
| 1124 | + xMid = dx/2 + p.x1, | ||
| 1125 | + yMid = dy/2 + p.y1; | ||
| 1126 | + //length = Math.sqrt(dx*dx + dy*dy), | ||
| 1127 | + //rads = Math.asin(dy/length), | ||
| 1128 | + //degs = rads / (Math.PI*2) * 360; | ||
| 1129 | + | ||
| 1130 | + return translate(xMid, yMid); | ||
| 1131 | + | ||
| 1132 | + // TODO: consider making label parallel to line | ||
| 1133 | + //return [ | ||
| 1134 | + // translate(xMid, yMid), | ||
| 1135 | + // rotate(degs), | ||
| 1136 | + // translate(0, 8) | ||
| 1137 | + //].join(''); | ||
| 1027 | } | 1138 | } |
| 1028 | 1139 | ||
| 1029 | function createDeviceNode(device) { | 1140 | function createDeviceNode(device) { |
| ... | @@ -1443,6 +1554,18 @@ | ... | @@ -1443,6 +1554,18 @@ |
| 1443 | x2: function (d) { return d.target.x; }, | 1554 | x2: function (d) { return d.target.x; }, |
| 1444 | y2: function (d) { return d.target.y; } | 1555 | y2: function (d) { return d.target.y; } |
| 1445 | }); | 1556 | }); |
| 1557 | + | ||
| 1558 | + linkLabel.each(function (d) { | ||
| 1559 | + var el = d3.select(this); | ||
| 1560 | + var lnk = findLinkById(d.key), | ||
| 1561 | + parms = { | ||
| 1562 | + x1: lnk.source.x, | ||
| 1563 | + y1: lnk.source.y, | ||
| 1564 | + x2: lnk.target.x, | ||
| 1565 | + y2: lnk.target.y | ||
| 1566 | + }; | ||
| 1567 | + el.attr('transform', transformLabel(parms)); | ||
| 1568 | + }); | ||
| 1446 | } | 1569 | } |
| 1447 | 1570 | ||
| 1448 | // ============================== | 1571 | // ============================== |
| ... | @@ -1839,12 +1962,14 @@ | ... | @@ -1839,12 +1962,14 @@ |
| 1839 | .attr('id', 'topo-G') | 1962 | .attr('id', 'topo-G') |
| 1840 | .attr('transform', fcfg.translate()); | 1963 | .attr('transform', fcfg.translate()); |
| 1841 | 1964 | ||
| 1842 | - // subgroups for links and nodes | 1965 | + // subgroups for links, link labels, and nodes |
| 1843 | linkG = topoG.append('g').attr('id', 'links'); | 1966 | linkG = topoG.append('g').attr('id', 'links'); |
| 1967 | + linkLabelG = topoG.append('g').attr('id', 'linkLabels'); | ||
| 1844 | nodeG = topoG.append('g').attr('id', 'nodes'); | 1968 | nodeG = topoG.append('g').attr('id', 'nodes'); |
| 1845 | 1969 | ||
| 1846 | - // selection of nodes and links | 1970 | + // selection of links, linkLabels, and nodes |
| 1847 | link = linkG.selectAll('.link'); | 1971 | link = linkG.selectAll('.link'); |
| 1972 | + linkLabel = linkLabelG.selectAll('.linkLabel'); | ||
| 1848 | node = nodeG.selectAll('.node'); | 1973 | node = nodeG.selectAll('.node'); |
| 1849 | 1974 | ||
| 1850 | function chrg(d) { | 1975 | function chrg(d) { | ... | ... |
-
Please register or login to post a comment