【问题标题】:Forced Directed graph multiple edges using d3 canvas使用 d3 画布强制有向图多条边
【发布时间】:2017-10-06 16:00:17
【问题描述】:

我创建了具有多条边的强制有向图,但在渲染后仅显示,另一个重叠。我想创建类似https://bl.ocks.org/mattkohl/146d301c0fc20d89d85880df537de7b0#index.html

我的代码: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>  

【问题讨论】:

    标签: javascript jquery html d3.js canvas


    【解决方案1】:

    你可以这样画曲线:

      //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

    【讨论】:

    • 我对 edge 上的箭头和标签文本提出了另一个问题。因为我对 d3 和 canvas 的想法很少。你能帮我实现吗?stackoverflow.com/questions/46593199/…
    • 您的解决方案是正确的,但只需要每个边缘线的箭头和标签
    • @Sumeet 在生成的行上放置箭头并不容易,它涉及到一些很好的数学......也许有人可以扩展我的答案给你更好的答案。
    • 您可以在我的另一篇文章中查看示例查看我的第一条评论stackoverflow.com/questions/46593199/…
    猜你喜欢
    • 2016-11-13
    • 2014-07-09
    • 1970-01-01
    • 1970-01-01
    • 2012-03-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-08-16
    相关资源
    最近更新 更多