Files
netdisco/Netdisco/share/views/ajax/device/netmap.tt
Oliver Gorwits ca6a08ef46 Change from ?tab=tabname param to .../tabname path
The reason for this is that DataTables keys local data on the page path, so
each tab should have its own path. We're already doing this for reports and
admin tasks, so it also makes sense to have consistency with search and device
tabs.

Squashed commit of the following:

commit 4ad33a23a81122496adfe561ad14f039e6255eff
Author: Oliver Gorwits <oliver@cpan.org>
Date:   Sat Oct 25 14:46:17 2014 +0100

    fix search preference selection

commit 363e094935d386961e8773f787af41c46b83129a
Author: Oliver Gorwits <oliver@cpan.org>
Date:   Sat Oct 25 14:36:45 2014 +0100

    fix css selector to match begins with /search

commit 43c972ee0d9401f74dcc3bd30052dba130b0d068
Author: Oliver Gorwits <oliver@cpan.org>
Date:   Sat Oct 25 14:18:24 2014 +0100

    fix history push

commit 84f83eb46874b0222c0484014389713e4f027c8a
Author: Oliver Gorwits <oliver@cpan.org>
Date:   Sat Oct 25 14:06:44 2014 +0100

    update sidebar form for tab-path, remove hidden tab name field

commit 344d4679a83f714c998cd475c041f8effab0c696
Author: Oliver Gorwits <oliver@cpan.org>
Date:   Sat Oct 25 14:05:49 2014 +0100

    update template links for tab path

commit 9cf370d7eb4413aac6fc19c2c13a9bf670600965
Author: Oliver Gorwits <oliver@cpan.org>
Date:   Sat Oct 25 14:04:57 2014 +0100

    move tab-specific JS from common into specific includes files

commit c2d8592a18e389535368d1e74fed29fe5a0eabd8
Author: Oliver Gorwits <oliver@cpan.org>
Date:   Sat Oct 25 14:02:46 2014 +0100

    fix mode

commit 52487cea47eaaea7f5c74536ad6d4bb2a8d6ba4c
Author: Oliver Gorwits <oliver@cpan.org>
Date:   Sat Oct 25 14:01:15 2014 +0100

    move from tab param to tabname template var

commit b5a2424631a0050d5de3bc658746a40cd822e869
Merge: 531782b d8102bf
Author: Oliver Gorwits <oliver@cpan.org>
Date:   Sat Oct 25 10:50:00 2014 +0100

    Merge branch 'master' into em-device-ports-json
2014-10-25 14:51:15 +01:00

188 lines
6.2 KiB
JavaScript

<script>
var winHeight = window.innerHeight;
var winWidth = window.innerWidth;
// links in the initial tree drawing use this generator
var treeLink = d3.svg.diagonal.radial()
.projection(function(d) { return [d.y, d.x / 180 * Math.PI]; });
// actual device neighbor links use this generator
var neighLink = d3.svg.diagonal.radial();
// store x,y for all circles on the map
var loc = {};
// store actual links between all nodes
var neighbors_data = {};
// main SVG background, with support for pan/zoom
var svg = d3.select("#netmap_pane").append("svg")
.attr("width", winWidth - 50)
.attr("height", winHeight - 100)
.attr("pointer-events", "all")
.append('g')
.call(d3.behavior.zoom().on("zoom", redraw))
.append("g")
.attr("transform", "translate(" + winHeight / 2 + "," + winHeight / 2 + ")");
// this is the image background
// XXX there must be a way to discover the radial tree's size?
svg.append('rect')
.attr("x", (0 - (winHeight * 2)))
.attr('width', "400%")
.attr("y", (0 - (winHeight * 2)))
.attr('height', "400%")
.attr('fill', 'white');
// handle pan and zoom
function redraw() {
svg.attr("transform",
"translate(" + d3.event.translate + ")"
+ "scale(" + d3.event.scale + ")"
+ "translate(" + (winHeight / 2) + "," + (winHeight / 2) + ")");
}
// save the x,y of an element into the loc dictionary
function recordLocation(d,i) {
var rect = this.getBoundingClientRect();
loc[d.name] = {
'x': (rect.left + ((rect.right - rect.left) / 2))
,'y': (rect.top + ((rect.bottom - rect.top) / 2))
};
}
// convert a device name to a valid CSS class name
function to_class(name) { return 'nd_' + name.replace(/\./g, "_") }
// handler for clicking on a circle - redirect to that device's netmap
function circleClick(d) {
window.location = '[% uri_for('/device/netmap') %]'
+ '?q=' + d.fullname
+ '&depth=[% params.depth | uri %]'
+ '&vlan=[% params.vlan | uri %]';
}
// handler for mouseover on a circle - show that device's real neighbors
function circleOver(d) {
$('.link').hide();
$('path.' + to_class(d.name)).show();
$(this).css('cursor', 'pointer');
$.each(neighbors_data[d.name], function(idx, target) {
if (! (target in loc)) { return true }
$('circle.' + to_class(target)).css('fill', '#e96cfa');
});
}
// handler for mouseout on a circle - hide real neighbours and show treeLinks
function circleOut(d) {
$.each(neighbors_data[d.name], function(idx, target) {
if (! (target in loc)) { return true }
$('circle.' + to_class(target)).css('fill', '#fff');
});
$(this).css('cursor', 'auto');
$('path.' + to_class(d.name)).hide();
$('.link').show();
}
// load all device connections into neighbors_data dictionary
$.getJSON('[% uri_for('/ajax/data/device/alldevicelinks') %]', function(data) {
neighbors_data = data;
// draw the tree
d3.json("[% uri_for('/ajax/data/device/netmap') %]?"
+ '&q=[% params.q | uri %]'
+ '&depth=[% params.depth | uri %]'
+ '&vlan=[% params.vlan | uri %]', function(error, root) {
var tree = d3.layout.tree()
// magic number "8" for scaling (network depth). seems to make things look right for me.
.size([360, (winHeight / 8 * (root['scale'] || 0))])
.separation(function(a, b) { return (a.parent == b.parent ? 1 : 2) / a.depth; });
var nodes = tree.nodes(root),
links = tree.links(nodes);
var link = svg.selectAll(".link")
.data(links)
.enter().append("path")
.attr("class", "link")
.attr("d", treeLink);
var node = svg.selectAll(".node")
.data(nodes)
.enter().append("g")
.attr("class", "node")
.attr("transform", function(d) { return "rotate(" + (d.x - 90) + ")translate(" + d.y + ")"; });
// begin to draw...
d3.select("#nd_waiting").remove();
node.append("circle")
.attr("r", 4.5)
// circle has class name of its device, so we can show/hide it
.attr("class", function(d) { return to_class(d.name) })
// store the x,y of every circle we've just drawn
.each(recordLocation)
// handlers for mouse interaction with the circles
.on("click", circleClick)
.on("mouseover", circleOver)
.on("mouseout", circleOut);
node.append("text")
.attr("dy", ".31em")
.attr("text-anchor", function(d) { return d.x < 180 ? "start" : "end"; })
.attr("transform", function(d) { return d.x < 180 ? "translate(8)" : "rotate(180)translate(-8)"; })
.text(function(d) { return d.name; });
// reorient text on the root node
svg.select(".node")
.attr("transform", function(d) {
return d.x < 180 ? "rotate(0)translate(0)" : "rotate(180)translate(0)"; });
// key (name) of the root node in our locations store
var rootname = svg.select(".node").data()[0].name;
// reformatted neighbors_data for the real neighbor links
var neighbors = [];
// need to build neighbors array only after we have built loc dictionary,
// after drawing the circles and storing their x,y
$.each(neighbors_data, function(key, val) {
if (! (key in loc)) { return true }
$.each(val, function(idx, name) {
if (! (name in loc)) { return true }
neighbors.push({
'source': {
'name': key
,'x': loc[key]['x']
,'y': loc[key]['y']
}
,'target': {
'name': name
,'x': loc[name]['x']
,'y': loc[name]['y']
}
});
});
});
// insert Netdisco neighbor links below circles but above tree links
svg.selectAll(".neighbor")
.data(neighbors)
.enter().insert("path", ".node")
// add class name of source device, so we can show/hide the link
// (also "neighbor" class)
.attr("class", function(d) { return ("neighbor " + to_class( d.source.name )) })
.attr("d", neighLink)
.attr("transform", "translate(-" + loc[rootname]['x'] + ",-" + loc[rootname]['y'] + ")");
});
}); // jquery getJSON for all connections
// vim: ft=javascript
</script>
<div id="nd_waiting" class="span2 alert"><i class="icon-spinner icon-spin"></i> Waiting for results...</div>