D3
OG
Old school D3 from simpler times
All examples
By author
By category
About
tomshanley
Full window
Github gist
Network flow with happy path
Built with
blockbuilder.org
<!DOCTYPE html> <head> <meta charset="utf-8"> <script src="https://d3js.org/d3.v4.min.js"></script> <style> body { margin:50;top:50;right:50;bottom:50;left:50; } </style> </head> <body> <script> let data = [ { "source": "node1", "target": "node2", "value": 20, "mainflow": true }, { "source": "node1", "target": "node3", "value": 8, "mainflow": false }, { "source": "node1", "target": "node4", "value": 5, "mainflow": false }, { "source": "node2", "target": "node1", "value": 9, "mainflow": false }, { "source": "node2", "target": "node3", "value": 18, "mainflow": true }, { "source": "node2", "target": "node4", "value": 5, "mainflow": false }, { "source": "node3", "target": "node1", "value": 5, "mainflow": false }, { "source": "node3", "target": "node2", "value": 3, "mainflow": false }, { "source": "node3", "target": "node4", "value": 15, "mainflow": true }, { "source": "node4", "target": "node1", "value": 5, "mainflow": false }, { "source": "node4", "target": "node2", "value": 8, "mainflow": false }, { "source": "node4", "target": "node3", "value": 5, "mainflow": false } ] let radians = 0.0174532925 let width = 1000 let height = 300 let centre = height/2 let nestedData = d3.nest() .key(function(d){ return d.source }) .entries(data) nestedData.forEach(function(d){ d.total = d.values.reduce(function(sum, v){ return sum + v.value }, 0) }) let series = nestedData.map(function(d){ return d.key }) let radius = d3.scaleSqrt() .domain([0, d3.max(nestedData, function(d){ return d.total })]) .range([0, 50]) let angle = d3.scalePoint() .domain(series) .range([0, 90]) let strokeWidth = d3.scaleLinear() .domain([0, d3.max(data, function(d){ return d.value })]) .range([0, 50]) let nodeCentreX = d3.scalePoint() .padding(0.5) .domain(series) .range([0,width]) let colour = d3.scaleOrdinal() .domain(series) .range(["rgb(53,97,143)", "rgb(42,210,127)", "rgb(108,33,142)", "rgb(100,212,253)"]) var svg = d3.select("body").append("svg") .attr("width", width) .attr("height", height) var g = svg.append("g") var nodes = g.selectAll("circle") .data(nestedData) .enter() .append("g") .attr("transform", function(d) { return "translate(" + nodeCentreX(d.key) + "," + centre + ")" }) var links = nodes.selectAll("line") .data(function(d){ return d.values }) .enter() .append("line") .style("stroke", function(d) { return colour(d.target) }) .style("stroke-width", function(d) { return strokeWidth(d.value) }) .attr("x2", function(d){ return x2(d.source, d.target, d.mainflow) }) .attr("y2", function(d){ return y2(d.source, d.target, d.mainflow) }) nodes.append("circle") .attr("cx", 0) .attr("cy", 0) .attr("r", function(d){ return radius(d.total) }) .style("fill", function(d) { return colour(d.key) }) .style("stroke", "white") .style("stroke-width", 5) nodes.append("text") .text(function(d){ return d.key }) .style("text-anchor", "middle") .style("fill", "white") function x2(source, target, main){ return linkLength(main) * Math.sin(getAngle(source, target) * radians) } function y2(source, target, main){ return linkLength(main) * Math.cos(getAngle(source, target) * radians) } function getAngle(source, target){ let offset1 = 120 + angle(source) let offset2 = angle(target) let totalOffset = offset1 - offset2 return totalOffset } function linkLength(isMainFlow) { return isMainFlow ? nodeCentreX.step() : nodeCentreX.step() * 0.6 } </script> </body>
https://d3js.org/d3.v4.min.js