Gráficos forzados de bordes múltiples utilizando canvas d3

He creado un gráfico dirigido forzado que tiene múltiples aristas, pero después de rasgarlo solo muestra, el otro se superpone entre sí. Quiero crear algo como https://bl.ocks.org/mattkohl/146d301c0fc20d89d85880df537de7b0#index.html

Mi Código: JSBIN

   Sample Graph Rendring Using Canvas      var graph = {}//randomgraph.WattsStrogatz.beta(15, 4, 0.06); graph.nodes = [{"label":"x"} , {"label":"y"}]; graph.edges = [{source:0,target:1},{source:0,target:1}, {source:1,target:0}] var canvas = null var width = window.innerWidth, height = window.innerHeight; canvas = d3.select("body").append("canvas").attr("width",width).attr("height",height); var context = canvas.node().getContext("2d"); force = d3.forceSimulation() .force("link", d3.forceLink().id(function(d) { return d.index; })).force("charge", d3.forceManyBody()) .force("center", d3.forceCenter(width / 2, height / 2)); force.nodes(graph.nodes); force.force("link").links(graph.edges).distance(200); var detachedContainer = document.createElement("custom"); dataContainer = d3.select(detachedContainer); link = dataContainer.selectAll(".link").data(graph.edges) .enter().append("line").attr("class", "link") .style("stroke-width", 2) node = dataContainer.selectAll(".node").data(graph.nodes) .enter().append("g"); var circles = node.append("circle") .classed("circle-class", true) .attr("class", function (d){ return "node node_" + d.index;}) .attr("r", 5) .attr("fill", 'red') .attr("strokeStyle", 'black'); d3.timer(function(){ context.clearRect(0, 0, width, height); // draw links link.each(function(d) { context.strokeStyle = "#ccc"; /***** Elliptical arcs *****/ context.stroke(new Path2D(linkArc(d))); /***** Elliptical arcs *****/ }); context.lineWidth = 2; node.each(function(d) { context.beginPath(); context.moveTo(dx, dy); var r = d3.select(this).select("circle").node().getAttribute('r'); dx = Math.max(30, Math.min(width - 30, dx)); dy = Math.max(30, Math.min(height - 30, dy)); context.closePath(); context.arc(dx, dy, r, 0, 2 * Math.PI); context.fillStyle = d3.select(this).select("circle").node().getAttribute('fill'); context.strokeStyle = d3.select(this).select("circle").node().getAttribute('strokeStyle'); context.stroke(); context.fill(); context.beginPath(); context.arc(dx + 15, dy-20, 5, 0, 2 * Math.PI); context.fillStyle = "orange"; context.strokeStyle = "orange"; var data = d3.select(this).data(); context.stroke(); context.fill(); context.font = "10px Arial"; context.fillStyle = "black"; context.strokeStyle = "black"; context.fillText(parseInt(data[0].index),dx + 10, dy-15); }); }); circles.transition().duration(5000).attr('r', 20).attr('fill', 'orange'); canvas.node().addEventListener('click',function( event ){ console.log(event) // Its COMING ANY TIME INSIDE ON CLICK OF CANVAS }); /***** Elliptical arcs *****/ function linkArc(d) { var dx = d.target.x - d.source.x, dy = d.target.y - d.source.y, dr = Math.sqrt(dx * dx + dy * dy); return "M" + d.source.x + "," + d.source.y + "A" + dr + "," + dr + " 0 0,1 " + d.target.x + "," + d.target.y; } /***** Elliptical arcs *****/    

Puedes hacer la curva así:

  //make a curve object var curves = {}; function getCurveFactor(d){ var factor = 0.3;//you may change this as per your choice. //make a key var key = d.source.index + "---"+ d.target.index; //see if the key is present in the object if (curves[key]){ //if key is present you need a bigger curve //so that it does not overlap curves[key] = curves[key] + factor; } else { //no key present keep the curve simple curves[key] = 1; } return curves[key]; } 

Esta función hace que el arco:

  function arcPath(d) { var x1 = d.target.x, y1 = d.target.y, x2 = d.source.x, y2 = d.source.y, dx = x2 - x1, dy = y2 - y1, dr = Math.sqrt(dx * dx + dy * dy), drx = dr, dry = dr; //store the curve factor inside the data. if(!d.curve){ d.curve = getCurveFactor(d); } return "M" + x1 + "," + y1 + "A" + (drx/d.curve) + ", " + (dry) + " " + 0 + ", " + 0 + ", " + 0 + " " + x2 + "," + y2; } 

código de trabajo aquí