80233ffd5e346fe291df87f77369ce3c37beb905
1 var graph
, canvas
, layouter
, renderer
, divwait
, nodes
, announcements
, nodesIndex
, palette
, localInfo
;
2 document
.addEventListener( "DOMContentLoaded", init
, false);
5 * Returns an index of nodes by name
7 function createNodeIndex(nodes
) {
11 index
[nodes
[inode
].name
] = nodes
[inode
];
17 * Updates to have announcements in nodes list
19 function processNodeAnnouncements(nodes
, announcements
) {
20 var iannouncement
, remoteNode
, announcement
;
21 nodesIndex
= createNodeIndex(nodes
);
23 for(iannouncement
in announcements
) {
24 announcement
= announcements
[iannouncement
];
25 if (announcement
.remoteName
== '---' ) continue;
26 if (!( announcement
.remoteName
in nodesIndex
)) {
28 name
: announcement
.remoteName
,
32 nodesIndex
[newNode
.name
] = newNode
;
35 remoteNode
= nodesIndex
[announcement
.remoteName
];
36 if (!( 'announcements' in remoteNode
)) remoteNode
.announcements
= [];
37 remoteNode
.announcements
.push(announcement
);
42 palette
= generatePalette(200);
45 canvas
= document
.getElementById('canvas');
46 layouter
= new Graph
.Layout
.Spring(graph
);
47 renderer
= new Graph
.Renderer
.Raphael(canvas
.id
, graph
, canvas
.offsetWidth
, canvas
.offsetHeight
);
49 divwait
= document
.getElementById("wait");
51 XHR
.get('/cgi-bin/luci/status/bmx6/topology', null, function(nodesRequest
, nodesData
) {
54 XHR
.get('/cgi-bin/bmx6-info?$myself&', null, function(myselfRequest
, myselfData
) {
56 localAnnouncements
= [
57 {remoteName
: myselfData
.myself
.hostname
, advNet
: myselfData
.myself
.net4
},
58 {remoteName
: myselfData
.myself
.hostname
, advNet
: myselfData
.myself
.net6
}
61 XHR
.get('/cgi-bin/bmx6-info?$tunnels=&', null, function(tunnelsRequest
, tunnelsData
) {
64 announcements
= tunnelsData
.tunnels
;
65 for(iAnnouncement
in localAnnouncements
) {
66 announcements
.push(localAnnouncements
[iAnnouncement
])
69 processNodeAnnouncements(nodes
, announcements
);
71 divwait
.parentNode
.removeChild(divwait
);
78 function hashCode(str
) {
80 if (str
.length
== 0) return hash
;
81 for (i
= 0; i
< str
.length
; i
++) {
82 char = str
.charCodeAt(i
);
83 hash
= ((hash
<<5)-hash
)+char;
84 hash
= hash
& hash
; // Convert to 32bit integer
89 function generatePalette(size
) {
91 Raphael
.getColor(); // just to remove the grey one
92 for(i
= 0; i
< size
; i
++) {
93 arr
.push(Raphael
.getColor())
99 function getFillFromHash(hash
) {
100 return palette
[Math
.abs(hash
% palette
.length
)];
103 function hashAnnouncementsNames(announcementsNames
) {
104 return hashCode(announcementsNames
.sort().join('-'));
107 function getNodeAnnouncements(networkNode
) {
108 return networkNode
.announcements
;
111 function nodeRenderer(raphael
, node
) {
112 var nodeFill
, renderedNode
, options
;
114 'fill': 'announcements' in node
.networkNode
? getFillFromHash(
115 hashAnnouncementsNames(
116 getNodeAnnouncements(node
.networkNode
).map(function(ann
) {return ann
.advNet
;})
123 renderedNode
= raphael
.set();
125 renderedNode
.push(raphael
.ellipse(node
.point
[0], node
.point
[1], 30, 20).attr({"fill": options
['fill'], "stroke-width": options
['stroke-width']}));
126 renderedNode
.push(raphael
.text(node
.point
[0], node
.point
[1] + 30, node
.networkNode
.name
).attr({}));
128 renderedNode
.items
.forEach(function(el
) {
129 var announcements
, tooltip
= raphael
.set();
130 tooltip
.push(raphael
.rect(-60, -60, 120, 60).attr({"fill": "#fec", "stroke-width": 1, r
: "9px"}));
132 announcements
= getNodeAnnouncements(node
.networkNode
);
135 announcements
= announcements
.map(function(ann
) {return ann
.advNet
});
136 tooltip
.push(raphael
.text(0, -40, 'announcements\n' + announcements
.join('\n')).attr({}));
145 function genericNodeRenderer(raphael
, node
) {
148 renderedNode
= raphael
.set();
150 renderedNode
.push(raphael
.ellipse(node
.point
[0], node
.point
[1], 30, 20).attr({"fill": '#bfbfbf', "stroke-width": 1}));
151 renderedNode
.push(raphael
.text(node
.point
[0], node
.point
[1] + 30, node
.networkNode
.name
).attr({}));
161 function interpolateColor(minColor
,maxColor
,maxDepth
,depth
){
163 function d2h(d
) {return d
.toString(16);}
164 function h2d(h
) {return parseInt(h
,16);}
169 if(depth
== maxDepth
){
175 for(var i
=1; i
<= 6; i
+=2){
176 var minVal
= new Number(h2d(minColor
.substr(i
,2)));
177 var maxVal
= new Number(h2d(maxColor
.substr(i
,2)));
178 var nVal
= minVal
+ (maxVal
-minVal
) * (depth
/maxDepth
);
179 var val
= d2h(Math
.floor(nVal
));
180 while(val
.length
< 2){
187 function draw(nodes
) {
188 var node
, neighbourNode
, seenKey
, rxRate
, txRate
, seen
, i
, j
, currentName
, linkQuality
;
192 for (i
= 0; i
< (nodes
.length
); i
++) {
194 graph
.addNode(node
.name
, {
200 for (i
= 0; i
< (nodes
.length
); i
++) {
203 if (! node
.name
) continue;
205 currentName
= node
.name
;
207 for (j
= 0; j
< (node
.links
.length
); j
++) {
208 neighbourNode
= node
.links
[j
];
210 graph
.addNode(neighbourNode
.name
, {render
: genericNodeRenderer
, networkNode
: neighbourNode
});
212 seenKey
= (node
.name
< neighbourNode
.name
) ? node
.name
+ '|' + neighbourNode
.name
: neighbourNode
.name
+ '|' + node
.name
;
214 rxRate
= neighbourNode
.rxRate
;
215 txRate
= neighbourNode
.txRate
;
217 if (!seen
[seenKey
] && rxRate
> 0 && txRate
> 0) {
218 linkQuality
= ( rxRate
+ txRate
) / 2;
220 graph
.addEdge(node
.name
, neighbourNode
.name
, {
221 'label': rxRate
+ '/' + txRate
,
223 'stroke': interpolateColor('FF0000','00FF00', 5, 5 * ( linkQuality
- 1 )/100),
224 'fill': interpolateColor('FF0000','00FF00', 5, 5 * ( linkQuality
- 1 )/100),
225 'label-style': { 'font-size': 8 }
228 seen
[seenKey
] = true;