Published
Edited
Apr 29, 2021
1 fork
1 star
Insert cell
Insert cell
Insert cell
{
let height = 800;

let two = new Two({
type: Two.Types.canvas,
width: width,
height: height
});

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

//
let members = teams.reduce((acc, cur) => {
return acc.concat(cur.members);
},[]);

let connections = makeRandomConnections(members);

let teamConnections = makeConnectionsBetweenTeams(connections);

let xScale = d3.scaleBand()
.domain(members.map( m => m.id))
.range([0, 2 * Math.PI])
.paddingInner(0.5)
.paddingOuter(0.25)
let yScale = d3.scaleLinear()
.domain([0, 1])
.range([175, 180]);

teams.forEach( team => {

let first = team.members[0];
let last = team.members[team.members.length-1];
let sa = xScale(first.id) - (Math.PI/2)
let ea = (xScale(last.id) + xScale.bandwidth()) - (Math.PI/2);
let arc = two.makeArcSegment(0, 0, yScale(1), yScale(1) + 10, sa, ea);
arc.fill = team.color;
group.add(arc);
})

//connections between teams
connections.forEach(connection => {
if(connection.source.team === connection.target.team) { return null }
let magicNr = 3.5;
let theta1 = xScale(connection.source.id) +(xScale.bandwidth()/2);
let theta2 = xScale(connection.target.id) +(xScale.bandwidth()/2);
let r = yScale(0);
let sx = r * Math.sin(theta1);
let sy = -(r * Math.cos(theta1));

let tx = r * Math.sin(theta2);
let ty = -(r * Math.cos(theta2));

let x1 = sx - sx / magicNr;
let y1 = sy - sy / magicNr;

let x2 = tx - tx / magicNr;
let y2 = ty - ty / magicNr;

let points = [
new Two.Anchor(sx, sy, null, null, x1, y1, Two.Commands.move),
new Two.Anchor(tx, ty, x2, y2, 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);
});

//connections within teams
connections.forEach(connection => {
if(connection.source.team !== connection.target.team) { return null }
let magicNr = -6;
let theta1 = xScale(connection.source.id) +(xScale.bandwidth()/2);
let theta2 = xScale(connection.target.id) +(xScale.bandwidth()/2);
let r = yScale(1) + 15;
let sx = r * Math.sin(theta1);
let sy = -(r * Math.cos(theta1));

let tx = r * Math.sin(theta2);
let ty = -(r * Math.cos(theta2));

let x1 = sx - sx / magicNr;
let y1 = sy - sy / magicNr;

let x2 = tx - tx / magicNr;
let y2 = ty - ty / magicNr;

let points = [
new Two.Anchor(sx, sy, null, null, x1, y1, Two.Commands.move),
new Two.Anchor(tx, ty, x2, y2, 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);
});

members.forEach( (member,i) => {
let theta = xScale(member.id) +(xScale.bandwidth()/2);
let r1 = ((yScale(1) - yScale(0)) / 2) + yScale(0);
let r2 = yScale(1) + 50;

let sa = xScale(member.id) - (Math.PI/2)
let ea = (xScale(member.id) + xScale.bandwidth()) - (Math.PI/2);
let arc1 = two.makeArcSegment(0, 0, yScale(0), yScale(1), sa, ea);
let arc2 = two.makeArcSegment(0, 0, yScale(1)+10, yScale(1)+15, sa, ea);
let x1 = r1 * Math.sin(theta);
let y1 = -(r1 * Math.cos(theta));
let x2 = r2 * Math.sin(theta);
let y2 = -(r2 * Math.cos(theta));
let text = two.makeText(member.name,x2, y2);
text.size = 9;
if (x2 >= 0) {
text.alignment = 'start';
text.rotation = theta - degreesToRadians(90);
} else {
text.alignment = 'end';
text.rotation = theta - degreesToRadians(-90);
}
group.add(arc1, arc2, text);
});

//
two.update();

return two.renderer.domElement;
}
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Chance = require('chance');
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