diff --git a/html/force-big.css b/html/force-big.css index c3647a5..ffb518e 100644 --- a/html/force-big.css +++ b/html/force-big.css @@ -6,15 +6,13 @@ stroke-width: 2.5px; } -.node text { - font-size: 11px; +.node text, .label text { + font-size: 10px; fill: #000; - font-weight: bold; } .link line { stroke: #ddd; - stroke-opacity: 1; stroke-width: 5px; } @@ -61,3 +59,7 @@ fill: #ddd; font-size: 0.8em; } + +.label rect { + fill: rgba(255, 255, 255, 1.0); +} diff --git a/html/force-light.css b/html/force-light.css index 104ce07..c12fcae 100644 --- a/html/force-light.css +++ b/html/force-light.css @@ -7,14 +7,13 @@ stroke-width: 2.5px; } -.node text { +.node text, .label text { font-size: 10px; fill: #333; } .link line { stroke: #777; - stroke-opacity: 1; stroke-width: 2.5px; } @@ -68,3 +67,11 @@ fill: #777; font-size: 0.8em; } + +.label rect { + fill: rgba(255, 255, 255, 0.8); +} + +.label.highlight rect { + fill: rgba(255, 255, 100, 0.9); +} diff --git a/html/force.css b/html/force.css index c14ade4..af8d7d1 100644 --- a/html/force.css +++ b/html/force.css @@ -12,6 +12,11 @@ stroke-width: 5px; } +.faded { + stroke-opacity: 0.2; + fill-opacity: 0.2; +} + .node.highlight ellipse { fill: #FFF0B3; } diff --git a/html/force.js b/html/force.js index b140315..45741a3 100644 --- a/html/force.js +++ b/html/force.js @@ -41,7 +41,7 @@ function resize() { d3.select("#chart") .attr("width", w).attr("height", h) - + if (vis) vis.attr("width", w).attr("height", h) @@ -53,7 +53,7 @@ function next_style() { var s; if (style !== undefined) s = d3.select("head link[title=" + style + "] + link") - + if (s == null || s[0][0] == null) s = d3.select("head link[title]") @@ -142,7 +142,7 @@ function show_node(mac) { d3.selectAll("#chart .node") .each( function(d) { - if (d.id == mac) + if (d.id == mac) d3.select(this) .classed("marked", true) }) @@ -156,32 +156,32 @@ function isConnected(a, b) { a.index == b.index } -function fade(opacity) { +function highlight(b) { return function(d) { if (dragging) return vis.selectAll("g.node") -   .style("stroke-opacity", function(o) { - var connected = isConnected(d, o) + .classed("faded", function(o) { + return !(isConnected(d, o)) && b + }) + .classed("highlight", function(o) { + return isConnected(d, o) && b + }) - if (connected && opacity != 1) - d3.select(this) - .classed("highlight", true) - else - d3.select(this) - .classed("highlight", false) + vis.selectAll("g.label") + .classed("faded", function(o) { + return !isConnected(d, o) && b + }) + .classed("highlight", function(o) { + return o == d && b + }) -         thisOpacity = connected?1:opacity -    this.setAttribute('fill-opacity', thisOpacity) -         return thisOpacity -  }) - - vis.selectAll(".link *") -   .style("stroke-opacity", function(o) { -  return o.source === d || o.target === d ? 1 : opacity + vis.selectAll(".link") +   .classed("faded", function(o) { +  return !(o.source === d || o.target === d) && b  })   } -} +} function show_node_info(d) { d3.selectAll("#nodeinfo").remove() @@ -238,6 +238,8 @@ vis.append("g").attr("class", "links") vis.append("g").attr("class", "nodes") +vis.append("g").attr("class", "labels") + var linkedByIndex var force = d3.layout.force() @@ -261,11 +263,11 @@ var force = d3.layout.force() switch (d.type) { case "vpn": return 0.01 case "client": return 1 - default: return 0.5 + default: return 1 } }) -force.on("tick", function() { +force.on("tick", function(e) { var size = force.size() var nodes = force.nodes() var nl = nodes.length @@ -287,7 +289,11 @@ force.on("tick", function() { .attr("x2", function(d) { return d.target.x }) .attr("y2", function(d) { return d.target.y }) - vis.selectAll(".node").attr("transform", function(d) { + vis.selectAll(".node").attr("transform", function(d) { + return "translate(" + d.x + "," + d.y + ")"; + }) + + vis.selectAll(".label").attr("transform", function(d) { return "translate(" + d.x + "," + d.y + ")"; }) }) @@ -405,11 +411,11 @@ function update() { return false if (!visible.clients && (d.source.flags.client || d.target.flags.client)) - return false + return false // hides links to clients if (!visible.vpn && (d.source.flags.vpn || d.target.flags.vpn)) - return false + return false return true }) @@ -478,7 +484,10 @@ function update() { return false return true - }) + }) + .sort(function(a, b) { + return (a.flags.client?1:0) < (b.flags.client?1:0) + }) var node = vis.select("g.nodes") .selectAll("g.node") @@ -493,8 +502,8 @@ function update() { return d.id }) .attr("class", "node") - .on("mouseover", fade(.2)) - .on("mouseout", fade(1)) + .on("mouseover", highlight(true)) + .on("mouseout", highlight(false)) .on("click", show_node_info) .call(node_drag) @@ -512,8 +521,7 @@ function update() { .attr("rx", function(d) { var r if (d.flags.client) r = 4 - else if (visible.labels) r = Math.max(10, d.name.length * 5) - else r = 10 + else r = 8 d.rx = r @@ -522,37 +530,55 @@ function update() { .attr("ry", function(d) { var r if (d.flags.client) r = 4 - else if (visible.labels) r = 10 - else r = 10 + else r = 8 d.ry = r return r }) - nodeEnter.filter(function(d) { - return !d.flags.client - }) - .append("text") - .attr("class", "name") - .attr("text-anchor", "middle") - .attr("y", "4px") + var label = vis.select("g.labels") + .selectAll("g.label") + .data(nodes.filter(function(d) { + return !d.flags.client && visible.labels + }), function(d) { + return d.id + } + ) - node.selectAll("text.name") + var labelEnter = label.enter() + .append("g") + .attr("id", function (d) { + return d.id + }) + .attr("class", "label") + + labelEnter.append("rect") + .attr("y", "10px") + .attr("x", function(d) { return - d.name.length * 7/2 }) + .attr("width", function(d) { return d.name.length * 7 }) + .attr("height", "15px") + + labelEnter.append("text") + .attr("class", "name") + .attr("text-anchor", "middle") + .attr("y", "21px") + .attr("x", "0px") + + label.selectAll("text.name") .text(function(d) { - if (visible.labels) - return d.name - - return "" + return d.name }) + label.exit().remove() + nodeEnter.append("title") node.selectAll("title") .text(function(d) { return d.name?d.name:" " }) node.selectAll(".uplinks").remove() - + if (!visible.vpn) { var uplink_info = node.filter(function (d) { return d.vpns > 0