ffmap-backend/html/force.js
2012-06-05 16:29:50 +02:00

335 lines
8.6 KiB
JavaScript
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

function zigzag_amplitude(d) {
return d.amplitude;
}
function zigzag_len(d) {
return d.len;
}
function zigzag_angularFrequency(d) {
return d.angularFrequency;
}
d3.svg.zigzag = function() {
var amplitude = zigzag_amplitude,
len = zigzag_len,
angularFrequency = zigzag_angularFrequency;
function zigzag() {
var A = amplitude.apply(this, arguments),
l = len.apply(this, arguments),
ω = angularFrequency.apply(this, arguments) + 1;
start = -l/2;
end = l/2;
step = l/ω;
var s = "M" + start + ",0"
for (var i = 1; i<ω; i++)
s += "L" + (start + i*step) + "," + ((i%2)?A:-A);
s += "L" + end + ",0"
return s;
}
zigzag.amplitude = function(v) {
if (!arguments.length) return amplitude;
amplitude = d3.functor(v);
return zigzag;
};
zigzag.len = function(v) {
if (!arguments.length) return len;
len = d3.functor(v);
return zigzag;
};
zigzag.angularFrequency = function(v) {
if (!arguments.length) return angularFrequency;
angularFrequency = d3.functor(v);
return zigzag;
};
return zigzag;
};
function getOffset( el ) {
var _x = 0;
var _y = 0;
while( el && !isNaN( el.offsetLeft ) && !isNaN( el.offsetTop ) ) {
_x += el.offsetLeft - el.scrollLeft;
_y += el.offsetTop - el.scrollTop;
el = el.offsetParent;
}
return { top: _y, left: _x };
}
var offset = getOffset(document.getElementById('chart'));
var w = window.innerWidth - offset.left,
h = window.innerHeight - offset.top,
fill = d3.scale.category20();
var cp = d3.select("#chart").append("div")
.attr("id", "controlpanel");
var btns = cp.append("div")
.attr("class", "btn-group")
.attr("data-toggle", "buttons-radio");
btns.append("button")
.attr("class", "btn active left")
.attr("value", "all")
.text("Alles")
.on("click", update_graph);
btns.append("button")
.attr("class", "btn right")
.attr("value", "mesh")
.text("nur Mesh")
.on("click", update_graph);
cp.append("label")
.text("Knoten hervorheben:");
cp.append("br");
cp.append("input")
.on("keyup", function(){show_node(this.value)})
.on("change", function(){show_node(this.value)});
function show_node(mac) {
d3.selectAll("#chart .node").classed("marked", false);
if (mac.length == 0)
return;
d3.selectAll("#chart .node").each( function(d) {
if (d.id == mac)
d3.select(this).classed("marked", true);
})
}
var hashstr = window.location.hash.substring(1);
function update_graph() {
var value = jQuery(this).val()
render_graph(value);
}
render_graph("all");
function render_graph(type) {
d3.select("#chart svg").remove();
var vis = d3.select("#chart").append("svg")
.attr("width", w)
.attr("height", h);
d3.json("nodes.json", function(json) {
var force = d3.layout.force()
.charge(-100)
.gravity(0.02)
.friction(0.75)
.theta(0.1)
.linkDistance(function (d) { return d.distance; })
.linkStrength(function (d) { return d.strength; })
.nodes(json.nodes)
.links(json.links)
.size([w, h])
.start();
  var linkedByIndex = {};
  json.links.forEach(function(d) {
      linkedByIndex[d.source.index + "," + d.target.index] = 1;
  });
  json.links.forEach(function(d) {
var node, other;
if (d.source.group == 2) {
node = d.target;
other = d.source;
}
if (d.target.group == 2) {
node = d.source;
other = d.target;
}
if (node) {
if (node.uplinks === undefined)
node.uplinks = new Array();
node.uplinks.push(other);
}
  });
var linkdata = json.links;
if (type == "mesh")
linkdata = json.links.filter( function (d) {
return d.source.group != 2 && d.target.group != 2 &&
d.source.group != 3 && d.target.group != 3;
});
var link = vis.selectAll("line.link")
.data(linkdata)
.enter().append("line")
.attr("class", "link")
.style("stroke-width", function(d) { return Math.min(1, d.strength * 2); });
var linklabel = vis.selectAll("g")
.data(linkdata.filter(function (d) {return d.quality != "TT" && d.quality != "1.000"}))
.enter()
.append("g")
.append("path")
.attr("d", d3.svg.zigzag().amplitude(function (d) {
return Math.pow((1 - 1/d.quality), 0.5) * 8;
}).len(30).angularFrequency(4)
/*
d3.svg.arc().outerRadius(5).innerRadius(0)
.startAngle( function (d) {
return Math.PI/d.quality - Math.PI/2;
})
.endAngle( function (d) {
return -Math.PI/d.quality - Math.PI/2;
})
*/
)
.attr("fill", "transparent")
.attr("stroke", "#C83771")
.attr("stroke-width", "1px")
    function isConnected(a, b) {
        return linkedByIndex[a.index + "," + b.index] || linkedByIndex[b.index + "," + a.index] || a.index == b.index;
    }
 function fade(opacity) {
        return function(d) {
            node.style("stroke-opacity", function(o) {
var connected = isConnected(d, o);
if (connected && opacity != 1)
d3.select(this).classed("highlight", true);
else
d3.select(this).classed("highlight", false);
                thisOpacity = connected ? 1 : opacity;
                this.setAttribute('fill-opacity', thisOpacity);
                return thisOpacity;
            });
            link.style("stroke-opacity", function(o) {
                return o.source === d || o.target === d ? 1 : opacity;
            });
            linklabel.style("opacity", function(o) {
                return o.source === d || o.target === d ? 1 : opacity;
            });
        };
    }
function show_node_info(d) {
if (!(typeof nodeinfo === 'undefined'))
nodeinfo.remove();
nodeinfo = d3.select("#chart").append("div")
.attr("id", "nodeinfo");
nodeinfo.append("h1")
.text(d.name);
nodeinfo.append("p")
.text("primary: " + d.id);
nodeinfo.append("p")
.text("macs: " + d.macs);
nodeinfo.append("p")
.text(d.gps);
}
var node = vis.selectAll("svg.node")
.data(json.nodes.filter(function (d) {
return type != "mesh" || (d.group != 2 && d.group != 3);
}))
.enter().append("g")
.attr("class", "node")
.on("mouseover", fade(.2))
.on("mouseout", fade(1))
.on("click", show_node_info)
.call(force.drag);
node.append("ellipse")
.attr("rx", function(d) { if (d.group == 3) return 4; else return Math.max(10, d.name.length * 5); })
.attr("ry", function(d) { if (d.group == 3) return 4; else return 10; })
.style("fill", function(d) { if (d.group == 3) return fill(d.group); else return ""; })
.style("stroke", function(d) { return fill(d.group); });
node.append("text")
.attr("text-anchor", "middle")
.attr("y", "4px")
.text(function(d) { if (d.group == 3) return ""; else return d.name; });
node.append("title")
.text(function(d) { return d.macs; });
if (type == "mesh") {
var uplink_info = node.filter(function (d) {
if (d.uplinks !== undefined)
return d.uplinks.length > 0;
else
return false;
})
.append("g");
uplink_info.append("path")
.attr("d","m -2.8850049,-13.182327 c 7.5369165,0.200772 12.1529864,-1.294922 12.3338513,-10.639456 l 2.2140476,1.018191 -3.3137621,-5.293097 -3.2945999,5.20893 2.4339957,-0.995747 c -0.4041883,5.76426 -1.1549641,10.561363 -10.3735326,10.701179 z")
.style("fill", "#333");
uplink_info.append("text")
.attr("text-anchor", "middle")
.attr("y", 3 - 20)
.text(function (d) {return d.uplinks.length});
}
force.on("tick", function() {
link.attr("x1", function(d) { return d.source.x; })
.attr("y1", function(d) { return d.source.y; })
.attr("x2", function(d) { return d.target.x; })
.attr("y2", function(d) { return d.target.y; });
linklabel
.attr("transform", function(d) {
π = Math.PI;
Δx = d.source.x - d.target.x;
Δy = d.source.y - d.target.y;
m = Δy/Δx;
α = Math.atan(m);
α += Δx<0?π:0;
sin = Math.sin(α);
cos = Math.cos(α);
x = (Math.min(d.source.x, d.target.x) + Math.abs(Δx) / 2)
y = (Math.min(d.source.y, d.target.y) + Math.abs(Δy) / 2)
return "matrix(" + [cos, sin, -sin, cos, x, y].join(",") + ")";
});
node.attr("transform", function(d) { return "translate(" + d.x + "," + d.y + ")"; });
});
if (hashstr.length != 0)
show_node(hashstr);
});
}