2017-10-06 95 views
2

我创建了具有多个边的强制有向图,但是在折叠后它只显示另一边,而另一个则相互重叠。我想创造这样https://bl.ocks.org/mattkohl/146d301c0fc20d89d85880df537de7b0#index.html使用d3画布强制定向图形多边形

我的代码:JSBIN

<!DOCTYPE html> 
<html> 
<head> 
     <title>Sample Graph Rendring Using Canvas</title> 
     <script src="https://rawgit.com/gka/randomgraph.js/master/randomgraph.js"></script> 
     <script src="https://d3js.org/d3.v4.min.js"></script> 
</head> 
<body> 
    <script> 
     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(d.x, d.y); 
       var r = d3.select(this).select("circle").node().getAttribute('r'); 

       d.x = Math.max(30, Math.min(width - 30, d.x)); 
       d.y = Math.max(30, Math.min(height - 30, d.y));   
       context.closePath(); 
       context.arc(d.x, d.y, 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(d.x + 15, d.y-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),d.x + 10, d.y-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 *****/ 
    </script> 
</body> 
</html> 

回答

2

您可以作出这样的曲线:

//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]; 
    } 

该功能使电弧:

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; 
      } 

工作代码here

+0

我对边缘上的箭头和标签文本提出了另一个问题。因为我对d3和画布有最小的想法。你能帮我实现吗?https://stackoverflow.com/questions/46593199/elliptical-arc-arrow-edge-d3-forced-layout – Sumeet

+0

你的解决方案是正确的,但只有箭头和每个边缘线的标签是必需的 – Sumeet

+2

@ Sumeet将箭头放在生成的线上并不容易,它涉及到一些很好的数学......可能有人可以扩展我的答案,给你更好的答案。 – Cyril