Published
Edited
Apr 22, 2021
Insert cell
Insert cell
Insert cell
Insert cell
{

// split data into two
let data1 = data.slice(0, data.length/2);
let data2 = data.slice(data.length/2);;

let layoutR = 250;
let nodeR = 10;
let offsetX = 10;
let offsetY = 100;
let height = 900;
let two = new Two({
type: Two.Types.canvas,
width: width,
height: height
});

let scale1 = d3.scaleLinear()
.domain([-3, data1.length+2])
.range([0, Math.PI]);

let scale2 = d3.scaleLinear()
.domain([-3, data2.length+2])
.range([0, -Math.PI]);

let nodes = [];
let links = [];
data1.forEach((entry, i) => {

let theta = scale1(i);
entry.x = layoutR * Math.sin(theta);
entry.y = -(layoutR * Math.cos(theta));
entry.r = nodeR;

entry.textX = (layoutR + 20) * Math.sin(theta);
entry.textY = -((layoutR + 20) * Math.cos(theta));
entry.theta = theta;

entry.x += offsetX;
entry.textX += offsetX;

entry.y += offsetY;
entry.textY += offsetY;

nodes.push(entry);

//extract links
links = links.concat(entry.connections.map( (connetion) => {
return {
source: entry,
target: data.find(d => d.name === connetion)
}
}));
});

data2.forEach((entry, i) => {

let theta = scale2(i);
entry.x = layoutR * Math.sin(theta);
entry.y = -(layoutR * Math.cos(theta));
entry.r = nodeR;

entry.textX = (layoutR + 20) * Math.sin(theta);
entry.textY = -((layoutR + 20) * Math.cos(theta));
entry.theta = theta;

entry.x -= offsetX;
entry.textX -= offsetX;

entry.y -= offsetY;
entry.textY -= offsetY;
nodes.push(entry);

//extract links
links = links.concat(entry.connections.map( (connetion) => {
return {
source: entry,
target: data.find(d => d.name === connetion)
}
}));
});

let group = two.makeGroup();
group.translation.set(width/2, height/2);

links.forEach( link => {
let magicNr = 3.5;

let x1 = link.source.x;
let y1 = link.source.y;

let x2 = link.source.x - link.source.x / magicNr;
let y2 = link.source.y - link.source.y / magicNr;
let x3 = link.target.x - link.target.x / magicNr;
let y3 = link.target.y - link.target.y / magicNr;

let x4 = link.target.x;
let y4 = link.target.y;

let points = [
new Two.Anchor(x1, y1, null, null, x2, y2, Two.Commands.move),
new Two.Anchor(x4, y4, x3, y3, null, null, Two.Commands.curve)
];
points.forEach(p => p.relative = false);
let path = new Two.Path(points);
path.automatic = false;
path.fill = 'none';
path.stroke = 'grey';
path.opacity = 0.3;
path.linewidth = 1;
group.add(path);
});

nodes.forEach( node => {
let circle = two.makeCircle(node.x, node.y, node.r);
circle.stroke = 'grey';

let text = two.makeText(node.name, node.x, node.y)
text.fill = 'grey';

if (node.x >= 0) {
text.alignment = 'start';
text.position.x += 20;
} else {
text.alignment = 'end';
text.position.x -= 20;
}

group.add(circle, text);
});

two.update();
return two.renderer.domElement;
}
Insert cell
function degreesToRadians(degrees) {
return degrees * (Math.PI / 180);
}
Insert cell
Insert cell
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