Published
Edited
Jul 7, 2020
1 fork
9 stars
Insert cell
Insert cell
Insert cell
chart = {
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 sourceIndex = 2 * i;
const sourceFullName = flow.key.source_name + '.' + flow.key.source_namespace;
flowNodes.push({
id: sourceFullName,
group: flow.key.source_namespace
});

const destIndex = 2 * i + 1;
const destFullName = flow.key.dest_name + '.' + flow.key.dest_namespace;
flowNodes.push({
id: destFullName,
group: flow.key.dest_namespace
});

flowLinks.push({
source: sourceFullName,
target: destFullName,
value: 10
});
}
// const links = data.links.map(d => Object.create(d));
// const nodes = data.nodes.map(d => Object.create(d));

// const links = _(flowLinks).value();
// const nodes = _(flowNodes).uniqBy(x => x.id).sortBy(x => x.id).value();
const links = _(flowLinks).value();
const nodes = _(flowNodes).uniqBy(x => x.id).sortBy(x => x.id).value();
let groups = d3.nest().key(d => d.group).entries(nodes);
// groups = groups.filter(g => g.values.length >= 3);
function convexHulls(nodes) {
debugger;
const offset = 15;
var hulls = {};

// create point sets
for (var k=0; k<nodes.length; ++k) {
var n = nodes[k];
if (n.size) continue;
var i = n.group,
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]);
}

// create convex hulls
var hullset = [];
for (i in hulls) {
hullset.push({group: i, path: d3.polygonHull(hulls[i])});
}

return hullset;
}
var curve = d3.line().curve(d3.curveCardinalClosed.tension(0.85));
function drawCluster(d) {
return curve(d.path);
}
const clusterHullPath = function(d){
const hull = d3.polygonHull(d.values)
return "M" +
hull.map(v => [v.x, v.y]).join("L") + "Z"
}

const simulation = d3.forceSimulation(nodes)
.force("link", d3.forceLink(links)
.id(d => d.id)
.strength(d => d.source.group === d.target.group ? 1 : 0.05))
.force("charge", d3.forceManyBody().strength(-105))
.force("x", d3.forceX())
.force("y", d3.forceY());

const svg = d3.create("svg")
.attr("viewBox", [-width / 2, -height / 2, width, height]);
const hullg = svg.append("g");
const hulls = hullg
.selectAll("path.hull")
.data(convexHulls(nodes))
.enter().append("path")
.attr("class", "hull")
.attr("d", drawCluster)
.style("fill", color);

const link = svg.append("g")
.attr("stroke", "#999")
.attr("stroke-opacity", 0.6)
.selectAll("line")
.data(links)
.join("line")
.attr("stroke-width", d => Math.sqrt(d.value));

const node = svg.append("g")
.attr("stroke", "#fff")
.attr("stroke-width", 1.5)
.selectAll("circle")
.data(nodes)
.join("circle")
.attr("r", 5)
.attr("fill", color)
.call(drag(simulation));

node.append("title")
.text(d => d.id);

simulation.on("tick", () => {
link
.attr("x1", d => d.source.x)
.attr("y1", d => d.source.y)
.attr("x2", d => d.target.x)
.attr("y2", d => d.target.y);

node
.attr("cx", d => d.x)
.attr("cy", d => d.y);
hulls
.data(convexHulls(nodes))
.attr("d", drawCluster);
});

invalidation.then(() => simulation.stop());

return svg.node();
}
Insert cell
data = FileAttachment("miserables.json").json()
Insert cell
flowLogsResponse = FileAttachment("flow-logs-slow-response.json").json();
Insert cell
height = 1200
Insert cell
width = 1200
Insert cell
Insert cell
drag = simulation => {
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;
}
return d3.drag()
.on("start", dragstarted)
.on("drag", dragged)
.on("end", dragended);
}
Insert cell
d3 = require("d3@5")
Insert cell
_ = require('lodash@4.17.15')
Insert cell

Purpose-built for displays of data

Observable is your go-to platform for exploring data and creating expressive data visualizations. Use reactive JavaScript notebooks for prototyping and a collaborative canvas for visual data exploration and dashboard creation.
Learn more