chart = {
const vis = d3.select(DOM.svg(width, height));
var
dr = 4,
off = 15,
expand = {},
data, net, force, hullg, hull, linkg, link, nodeg, node;
setTimeout(() => {
data = miserables;
let flowNodes = [];
let flowLinks = [];
console.log('flowLogsResponse', flowLogsResponse);
let flowResponse = flowLogsResponse;
flowResponse = flowResponse.slice(0, 5000);
flowResponse = flowResponse.filter(x => !x.key.source_name.includes('elastic-') && !x.key.dest_name.includes('elastic-'));
for (let i = 0; i < flowResponse.length; i++) {
const flow = flowResponse[i];
const sourceFullName = flow.key.source_name + '.' + flow.key.source_namespace;
flowNodes.push({
name: sourceFullName,
group: flow.key.source_namespace
});
const destFullName = flow.key.dest_name + '.' + flow.key.dest_namespace;
flowNodes.push({
name: destFullName,
group: flow.key.dest_namespace
});
}
flowNodes = _(flowNodes).uniqBy(x => x.name).sortBy(x => x.name).value();
for (let i = 0; i < flowResponse.length; i++) {
const flow = flowResponse[i];
const sourceFullName = flow.key.source_name + '.' + flow.key.source_namespace;
const sourceIndex = flowNodes.findIndex(x => x.name === sourceFullName);
const destFullName = flow.key.dest_name + '.' + flow.key.dest_namespace;
const destIndex = flowNodes.findIndex(x => x.name === destFullName);
flowLinks.push({
source: sourceIndex,
target: destIndex,
value: 1000,
});
}
flowLinks = _(flowLinks).value();
data = {
links: flowLinks,
nodes: flowNodes,
};
for (var i=0; i<data.links.length; ++i) {
var o = data.links[i];
o.source = data.nodes[o.source];
o.target = data.nodes[o.target];
}
hullg = vis.append("g");
linkg = vis.append("g");
nodeg = vis.append("g");
init();
vis.attr("opacity", 1e-6)
.transition()
.duration(1000)
.attr("opacity", 1);
}, 0);
var curve = d3.svg.line()
.interpolate("cardinal-closed")
.tension(.85);
var fill = d3.scale.category20();
function noop() { return false; }
function nodeid(n) {
return n.size ? "_g_"+n.group : n.name;
}
function linkid(l) {
var u = nodeid(l.source),
v = nodeid(l.target);
return u<v ? u+"|"+v : v+"|"+u;
}
function getGroup(n) { return n.group; }
function network(data, prev, index, expand) {
expand = expand || {};
var gm = {},
nm = {},
lm = {},
gn = {},
gc = {},
nodes = [],
links = [];
if (prev) {
prev.nodes.forEach(function(n) {
var i = index(n), o;
if (n.size > 0) {
gn[i] = n;
n.size = 0;
} else {
o = gc[i] || (gc[i] = {x:0,y:0,count:0});
o.x += n.x;
o.y += n.y;
o.count += 1;
}
});
}
for (var k=0; k<data.nodes.length; ++k) {
var n = data.nodes[k],
i = index(n),
l = gm[i] || (gm[i]=gn[i]) || (gm[i]={group:i, size:0, nodes:[]});
if (expand[i]) {
nm[n.name] = nodes.length;
nodes.push(n);
if (gn[i]) {
n.x = gn[i].x + Math.random();
n.y = gn[i].y + Math.random();
}
} else {
if (l.size == 0) {
nm[i] = nodes.length;
nodes.push(l);
if (gc[i]) {
l.x = gc[i].x / gc[i].count;
l.y = gc[i].y / gc[i].count;
}
}
l.nodes.push(n);
}
l.size += 1;
n.group_data = l;
}
for (i in gm) { gm[i].link_count = 0; }
for (k=0; k<data.links.length; ++k) {
var e = data.links[k],
u = index(e.source),
v = index(e.target);
if (u != v) {
gm[u].link_count++;
gm[v].link_count++;
}
u = expand[u] ? nm[e.source.name] : nm[u];
v = expand[v] ? nm[e.target.name] : nm[v];
var i = (u<v ? u+"|"+v : v+"|"+u),
l = lm[i] || (lm[i] = {source:u, target:v, size:0});
l.size += 1;
}
for (i in lm) { links.push(lm[i]); }
return {nodes: nodes, links: links};
}
function convexHulls(nodes, index, offset) {
var hulls = {};
for (var k=0; k<nodes.length; ++k) {
var n = nodes[k];
if (n.size) continue;
var i = index(n),
l = hulls[i] || (hulls[i] = []);
l.push([n.x-offset, n.y-offset]);
l.push([n.x-offset, n.y+offset]);
l.push([n.x+offset, n.y-offset]);
l.push([n.x+offset, n.y+offset]);
}
var hullset = [];
for (i in hulls) {
hullset.push({group: i, path: d3.geom.hull(hulls[i])});
}
return hullset;
}
function drawCluster(d) {
return curve(d.path);
}
function init() {
if (force) force.stop();
net = network(data, net, getGroup, expand);
force = d3.layout.force()
.nodes(net.nodes)
.links(net.links)
.size([width, height])
.linkDistance(function(l, i) {
var n1 = l.source, n2 = l.target;
return 30 +
Math.min(20 * Math.min((n1.size || (n1.group != n2.group ? n1.group_data.size : 0)),
(n2.size || (n1.group != n2.group ? n2.group_data.size : 0))),
-30 +
30 * Math.min((n1.link_count || (n1.group != n2.group ? n1.group_data.link_count : 0)),
(n2.link_count || (n1.group != n2.group ? n2.group_data.link_count : 0))),
100);
})
.linkStrength(function(l, i) {
return 1;
})
.gravity(0.05)
.charge(-600)
.friction(0.5)
.start();
hullg.selectAll("path.hull").remove();
hull = hullg.selectAll("path.hull")
.data(convexHulls(net.nodes, getGroup, off))
.enter().append("path")
.attr("class", "hull")
.attr("d", drawCluster)
.style("fill", function(d) { return fill(d.group); })
.on("click", function(d) {
console.log("hull click", d, arguments, this, expand[d.group]);
expand[d.group] = false; init();
});
link = linkg.selectAll("line.link").data(net.links, linkid);
link.exit().remove();
link.enter().append("line")
.attr("class", "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; })
.style("stroke-width", function(d) { return d.size || 1; });
node = nodeg.selectAll("circle.node").data(net.nodes, nodeid);
node.exit().remove();
node.enter().append("circle")
.attr("class", function(d) { return "node" + (d.size?"":" leaf"); })
.attr("r", function(d) { return d.size ? d.size + dr : dr+1; })
.attr("cx", function(d) { return d.x; })
.attr("cy", function(d) { return d.y; })
.style("fill", function(d) { return fill(d.group); })
.on("click", function(d) {
console.log("node click", d, arguments, this, expand[d.group]);
expand[d.group] = !expand[d.group];
init();
});
node.call(force.drag);
force.on("tick", function() {
if (!hull.empty()) {
hull.data(convexHulls(net.nodes, getGroup, off))
.attr("d", drawCluster);
}
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; });
node.attr("cx", function(d) { return d.x; })
.attr("cy", function(d) { return d.y; });
});
}
return vis.node();
}