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]; | ||
730 | + } | ||
721 | } | 731 | } |
722 | }); | 732 | }); |
723 | - }); | 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