forked from katielong's block: Circular Force-Layout
xxxxxxxxxx
<html>
<head>
<meta charset="utf-8">
<script src="https://d3js.org/d3.v4.js"></script>
<script src="https://d3js.org/queue.v1.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.12.2/jquery.min.js"></script>
<link rel="stylesheet" href="style.css">
<link href="https://fonts.googleapis.com/css?family=PT+Serif" rel="stylesheet">
</head>
<body>
<div id="network">
<svg width="1500" height="600" viewBox="0 0 1500 600" preserveAspectRatio="xMidYMid meet"></svg>
</div>
<script>
var width = 1500,
height = 600;
var hl_r = 8,
reg_r = 5,
chart_x = 0,
chart_y = -100
var searched = null,
focus = false;
var node_type = ["type1", "type2", "type3", "type4", "type5", "type6", "type7"];
var color_node = d3.scaleOrdinal().domain(node_type)
.range(['rgb(72,169,197)', 'rgb(117,102,160)', 'rgb(120, 157, 74)',
'rgb(171,224,106)', 'rgb(232,119,34)', 'rgb(331, 170, 49)',
'rgb(137,141,141)'
]);
var clusters = {};
var node_r = d3.scaleLinear().range([3, 20]);
var svg = d3.select("svg");
function gravity(alpha) {
return function(d) {
d.y += (d.cy - d.y) * alpha;
d.x += (d.cx - d.x) * alpha;
};
}
var simulation = d3.forceSimulation()
.force("link", d3.forceLink().id(function(d) {
return d.id;
}).strength(3))
.force("charge", d3.forceManyBody())
.force("center", d3.forceCenter(width / 2, height / 2))
.force("collide", d3.forceCollide(function(d) {
return (d.radius * 2 + 10)
}).strength(0.2))
.force("gravity", gravity(0.8))
.alphaMin(0.0001);
queue()
.defer(d3.csv, "node.csv")
.defer(d3.csv, "link.csv")
.defer(d3.json, "position.json")
.await(drawNetwork);
function drawNetwork(err, node, link, pos) {
var data = {},
nodes = [],
links = [];
node.forEach(function(d) {
d.in_out = +d.in_out;
d.cluster = d.in_out;
d.tot_current = +d.tot_current;
d.from_other = +d.from_other;
d.tot_original = +d.tot_original;
d.within = +d.within;
d.out = +d.out;
nodes.push(d);
});
link.forEach(function(d) {
d.count = +d.count;
links.push(d);
});
data['nodes'] = nodes;
data['links'] = links;
node_r.domain(d3.extent(data.nodes, function(d) {
return d.tot_original;
}));
svg.append("defs")
.append("marker")
.attr("id", "out")
.attr("viewBox", "0, -5, 10, 10")
.attr("refX", 23)
.attr("refY", 0)
.attr("markerWidth", 7)
.attr("markerHeight", 15)
.attr("orient", "auto")
.append("path")
.attr("d", "M0,-5L10,0L0,5");
svg.append("defs")
.append("marker")
.attr("id", "in")
.attr("viewBox", "0, -5, 10, 10")
.attr("refX", 23)
.attr("refY", 0)
.attr("markerWidth", 7)
.attr("markerHeight", 15)
.attr("orient", "auto")
.append("path")
.attr("d", "M0,-5L10,0L0,5")
.attr("fill", "rgb(218, 41, 28)");
var link = svg.append("g")
.attr("class", "links")
.selectAll("line")
.data(data.links)
.enter()
.append("line")
.filter(function(d) {
return d.source !== d.target
});
var node = svg.append("g")
.selectAll("circle")
.data(data.nodes)
.enter().append("circle")
.each(function(d) {
d.highlight_mode = (d.in_out === 1) ? d.stay : d.tot_current;
d.normal_mode = (d.in_out === 1) ? d.tot_original : d.tot_current;
d.radius = node_r(d.normal_mode);
if (!clusters[d.cluster] || d.radius > clusters[d.cluster].radius) {
clusters[d.cluster] = d;
}
})
.attr("class", function(d) {
return "nodes" + " _" + d.in_out
})
.attr("r", function(d) {
return d.radius
})
.attr("fill", function(d) {
return color_node(d.type);
})
.style("stroke-opacity", 0.9)
.call(d3.drag()
.on("start", dragstarted)
.on("drag", dragged)
.on("end", dragended));
var legend = svg.append("g")
.attr("width", 170)
.attr("height", 140)
.attr("transform", "translate(" + (9 * width / 10 - 50) + "," + 480 + ")");
var legend_each = legend.selectAll("g")
.data(node_type)
.enter()
.append("g")
.attr("transform", function(d, i) {
return "translate(" + 0 + "," + ((i - 3) * 20) + ")"
});
node.append("title")
.text(function(d) {
return d.id
});
node.on("mouseover", function(d) { mouseevent(d, "mouseover"); })
.on("mouseout", function(d) { mouseevent(d, "mouseout"); });
link.attr("stroke", "rgb(208,211,212)")
.style("stroke-opacity", 0.3);
legend_each.append("circle")
.attr("class", "legend-circle")
.attr("r", hl_r)
.attr("fill", function(d, i) {
return color_node(d);
});
legend_each.append("text")
.attr("class", "legend-text")
.attr("x", hl_r * 2)
.attr("y", 5)
.text(function(d) {
return d;
});
simulation
.nodes(data.nodes)
.on("tick", ticked);
simulation.force("link")
.links(data.links);
function ticked() {
node.each(cluster(0.2))
.attr("cx", function(d) {
return (pos[d.id].x + chart_x);
})
.attr("cy", function(d) {
return (pos[d.id].y + chart_y)
})
.attr("id", function(d) {
return "_" + d.index;
})
.each(function(d) {
data.nodes.filter(function(e) {
return e.id === d.id
}).x = d.x;
data.nodes.filter(function(e) {
return e.id === d.id
}).y = d.y;
});
link.attr("x1", function(d) {
return (pos[d.source.id].x + chart_x);
})
.attr("y1", function(d) {
return (pos[d.source.id].y + chart_y);
})
.attr("x2", function(d) {
return (pos[d.target.id].x + chart_x);
})
.attr("y2", function(d) {
return (pos[d.target.id].y + chart_y);
})
.attr("class", function(d) {
return ("from" + d.source.index + " to" + d.target.index);
});
}
function cluster(alpha) {
return function(d) {
var cluster = clusters[d.cluster];
if (cluster === d) return;
var x = d.x - cluster.x,
y = d.y - cluster.y,
l = Math.sqrt(x * x + y * y),
r = d.radius + cluster.radius;
if (l !== r) {
l = (l - r) / l * alpha;
d.x -= x *= l;
d.y -= y *= l;
cluster.x += x;
cluster.y += y;
}
};
}
function dragstarted(d) {
if (!d3.event.active) simulation.alphaTarget(0.3).restart();
d.fx = d.x;
d.fy = d.y;
}
function dragged(d) {
d.fx = d3.event.x;
d.fy = d3.event.y;
}
function dragended(d) {
if (!d3.event.active) simulation.alphaTarget(0);
d.fx = null;
d.fy = null;
}
function mouseevent(d, event, mode) {
var line_out_color = (event === "mouseover") ? "black" : "rgb(208,211,212)",
line_in_color = (event === "mouseover") ? "rgb(218, 41, 28)" : "rgb(208,211,212)",
line_opacity = (event === "mouseover") ? 1 : 0.3,
dot_self_color = (event === "mouseover") ? "rgb(218, 41, 28)" : "#fff",
dot_other_color = (event === "mouseover") ? "black" : "#fff",
dot_selected_opacity = 1,
dot_other_opacity = (event === "mouseover") ? 0.1 : 1,
dot_self_stroke_width = (event === "mouseover") ? 2 : 1;
// clear out
d3.selectAll("circle.nodes").attr("r", function(e) {
return e.radius
}).style("stroke", "#fff").style("stroke-width", dot_self_stroke_width);
d3.selectAll("line").attr("marker-end", "none").style("stroke", "rgb(208,211,212)").style("stroke-opacity", 0.3);
d3.selectAll("text.background-text").style("fill", "rgb(208,211,212)").style("stroke", "rgb(208,211,212)")
// color lines
d3.selectAll("line.to" + d.index).each(function(e) {
e.type = "in";
})
.attr("marker-end", function(e) {
return (event === "mouseover") ? "url(#" + e.type + ")" : "none";
})
.style("stroke", line_in_color)
.transition()
.duration(500)
.style("stroke-opacity", line_opacity);
d3.selectAll("line.from" + d.index).each(function(e) {
e.type = "out"
})
.attr("marker-end", function(e) {
return (event === "mouseover") ? "url(#" + e.type + ")" : "none";
})
.style("stroke", line_out_color)
.transition()
.duration(500)
.style("stroke-opacity", line_opacity);
// highlight dots
d3.selectAll("circle.nodes").transition().style("opacity", dot_other_opacity);
// self
d3.selectAll("circle#_" + d.index)
.style("stroke", dot_self_color)
.transition()
.duration(800)
.attr("r", function(e) {
return (event === "mouseover") ? node_r(e.highlight_mode) : node_r(e.normal_mode)
})
.style("opacity", dot_selected_opacity)
.style("stroke-width", dot_self_stroke_width);
// to dots
d3.selectAll("line.from" + d.index).filter(function(e) {
return e.target.index !== e.source.index
}).each(function(e) {
if (event === "mouseover") {
d3.select("circle#_" + e.target.index)
.style("stroke", dot_other_color)
.attr("r", function(e1) {
return (event === "mouseover") ? node_r(e.count) : e1.radius
})
.each(function(e1) {
e1.select_radius = d3.select(this).attr("r");
})
.transition()
.duration(300)
.style("opacity", dot_selected_opacity);
} else {
d3.select("circle#_" + e.target.index)
.attr("r", function(e1) {
return e1.radius
})
.style("stroke", dot_other_color)
.style("opacity", dot_selected_opacity);
}
});
// from dots
d3.selectAll("line.to" + d.index).filter(function(e) {
return e.target.index !== e.source.index
}).each(function(e) {
d3.select("circle#_" + e.source.index)
.attr("r", function(e1) {
return (event === "mouseover") ? node_r(e.count) : e1.radius
})
.each(function(e1) {
e1.select_radius = d3.select(this).attr("r");
})
.style("stroke", dot_other_color)
.transition()
.duration(300)
.style("opacity", dot_selected_opacity);
});
}
}
</script>
</body>
</html>
Modified http://d3js.org/d3.v4.js to a secure url
Modified http://d3js.org/queue.v1.min.js to a secure url
https://d3js.org/d3.v4.js
https://d3js.org/queue.v1.min.js
https://ajax.googleapis.com/ajax/libs/jquery/1.12.2/jquery.min.js