Skip to content

Instantly share code, notes, and snippets.

@kishorevarma
Last active October 18, 2016 15:00
Show Gist options
  • Save kishorevarma/a23267770c0ddcc1ba035525b2eda3ce to your computer and use it in GitHub Desktop.
Save kishorevarma/a23267770c0ddcc1ba035525b2eda3ce to your computer and use it in GitHub Desktop.
D3 Multiple Parents Tree like graph
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width">
<title>JS Bin</title>
<style>
.node {
fill: #ccc;
stroke: #666;
stroke-width: 2px;
width: 180px;
height: 80px;
}
.link {
stroke: blue;
stroke-width: 3px;
}
</style>
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.6/d3.min.js"></script>
</head>
<body>
<script>
const canvasWidth = 800;
const canvasHeight = 550;
const nodeWidth = 180;
const nodeHeight = 80;
const nodeTopMargin = 30;
const nodeLeftMargin = 100;
const columns = [
// column1 nodes
[{
id: "node1",
className: "active"
}, {
id: "node2"
}, {
id: "node3"
},{
id: "node4"
}],
// column2 nodes
[{
id: "node8"
}],
// column3 nodes
[{
id: "node9"
}, {
id: "node10"
}]
];
// Draw Main Canvas
const canvas = d3.select("body")
.append("svg")
.attr("width", canvasWidth)
.attr("height", canvasHeight);
// Get Column's First Node Vertical Position (y coordinate)
const getVerticalPosition = (nodes, nodeHeight, nodeTopMargin, canvasHeight) => {
const nodesCount = nodes.length;
return (canvasHeight - (nodesCount * nodeHeight + (nodesCount -1) * nodeTopMargin))/2;
};
// Get First Column Horizontally Position (x coordinate)
const getHorizantalPosition = (columns, nodeWidth, nodeLeftMargin, canvasWidth) => {
const columnsCount = columns.length;
return (canvasWidth - (columnsCount * nodeWidth + (columnsCount -1) * nodeLeftMargin))/2
};
// Get All Nodes positions (coordinates)
const getColumnNodes = (columns, options) => {
const {
nodeHeight,
nodeWidth,
nodeTopMargin,
nodeLeftMargin,
canvasHeight,
canvasWidth
} = options;
// First column horizantal position (x corordinate)
const columnHorizantalPosition = getHorizantalPosition(columns, nodeWidth, nodeLeftMargin, canvasWidth);
const allNodes = columns.map((column, index) => {
// First node vertical position of a column(y cordinate)
const verticalPosition = getVerticalPosition(column, nodeHeight, nodeTopMargin, canvasHeight);
const horizantalPosition = columnHorizantalPosition + index * (nodeLeftMargin + nodeWidth);
return column.map((node, nodeIndex) => {
return {
x: horizantalPosition,
y: verticalPosition + nodeIndex * (nodeTopMargin + nodeHeight),
data: node
}
})
})
return allNodes;
};
const columnNodes = getColumnNodes(columns, {
nodeHeight, nodeWidth, nodeTopMargin, nodeLeftMargin, canvasHeight, canvasWidth });
// Toatal Nodes
const nodes = columnNodes.reduce((prev, current) => prev.concat(current), []);
const getLinks = (columns) => {
return [].concat(
columns[0].map(({x, y, data}) => ({
source: {x, y},
target: columns[1][0],
data
})),
columns[2].map(({x, y, data}) => ({
source: columns[1][0],
target: {x, y},
data
}))
);
};
// Total Links( Edges)
const links = getLinks(columnNodes);
const diagonal = d3.svg.diagonal()
.projection(d => {
return [d.y , d.x]
});
canvas.selectAll(".node")
.data(nodes)
.enter()
.append("rect")
.attr("x", d => d.x)
.attr("y", d => d.y)
.attr("class", "node");
canvas.selectAll(".link")
.data(links)
.enter()
.append("path")
.attr("fill", "none")
.attr("stroke-width", 1)
.attr("stroke", (d) => {
return d.data && d.data.className == 'active' ? "red": "#666";
})
.attr("d", (data => {
const target = Object.assign({}, data.target);
const source = Object.assign({}, data.source);
// source
const sx = source.x + nodeWidth;
const sy = source.y + nodeHeight/2;
// target
const tx = target.x;
const ty = target.y + nodeHeight/2;
const data1 = {
source: {x: sy, y: sx},
target: {x: ty, y: tx}
}
return diagonal(data1);
}));
</script>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment