JSFiddle - React, Tailwind, and code Playground
JavaScript
var N = 4;
var vOffset = 50;
var hOffset = 100;
var rootXoffset = 30;
var rootYoffset = 50 * N;
var width = rootXoffset + hOffset * N;
var height = rootYoffset + vOffset * N + 30;
var rectWidth = 60;
var rectHeight = 30;
var svg = d3.select("body")
.append("svg")
.attr("width", width)
.attr("height", height);
var i,j;
var textbox;
var startX;
var startY;
var targetX;
var targetY;
// first draw lines
for(i=0; i<N; i++) {
for(j=0; j<i+1; j++) {
if (j==0){
startX = rootXoffset + hOffset * i + rectWidth/2;
startY = rootYoffset - vOffset * i + rectHeight/2;
svg.append("line")
.attr("x1", startX)
.attr("y1", startY)
.attr("x2", startX + hOffset * (N-i-1))
.attr("y2", startY + vOffset * (N-i-1))
.attr("stroke-width", 1)
.attr("stroke", "black");
}
if (j==i){
startX = rootXoffset + hOffset * i + rectWidth/2;
startY = rootYoffset + vOffset * i + rectHeight/2;
svg.append("line")
.attr("x1", startX)
.attr("y1", startY)
.attr("x2", startX + hOffset * (N-i-1))
.attr("y2", startY - vOffset * (N-i-1))
.attr("stroke-width", 1)
.attr("stroke", "black");
};
}
}
// ...than arrows and link labels...
for(i=0; i<N-1; i++) {
for(j=0; j<i+1; j++) {
targetX = rootXoffset + hOffset * i + hOffset;
targetY = rootYoffset - vOffset * i + (2*vOffset) * j - vOffset + rectHeight;
svg.append("line")
.attr("x1", targetX)
.attr("y1", targetY)
.attr("x2", targetX - 9)
.attr("y2", targetY + 3)
.attr("stroke-width", 2)
.attr("stroke", "black");
svg.append("line")
.attr("x1", targetX)
.attr("y1", targetY)
.attr("x2", targetX - 8)
...