在三角形内强制图表 d3.js

2024-04-24

我正在研究 d3.js 力图,我有一个问题。是否可以在具有某些坐标的三角形内制作力图?

这是我的代码:

var width = 500;
var height = 500;
//margin
var marginLeft = 10;
var marginTop = 10;
var marginRight = 10;
var marginBottom = 10;
var margin = { left: marginLeft , top: marginTop, right: marginRight, bottom: marginBottom};

//size of canvas
var innerWidth = width - margin.left - margin.right;
var innerHeight = height - margin.top - margin.bottom;

var radius = 10;

var svg = d3.select(".forcechart").append("svg")
    .attr("width", width) 
    .attr("height", height)
    .style("background", "#eee");

var tr = svg.append("polygon")       // attach a polygon
    .style("stroke", "black")  // colour the line
    .style("fill", "none")     // remove any fill colour
    .attr("points", "250,0, 12,173,  250,250");  // x,y points 

var group = svg.append("g")
    .attr("transform",  "translate(" + margin.left + "," + margin.top + ")");

var graph = {
    "nodes": [  { "x": 0, "y": 0 },
                { "x": 100,  "y":  100 },
                { "x": 500, "y": 500 },
                     { "x": 300, "y": 0 },
                   { "x": 300, "y": 0 },
                  { "x": 100,  "y":  100 },
                { "x": 500, "y": 500 },
                     { "x": 300, "y": 0 },
                   { "x": 300, "y": 0 },
                  { "x": 100,  "y":  100 },
                { "x": 500, "y": 500 },
                     { "x": 300, "y": 0 },
                   { "x": 300, "y": 0 },
                  { "x": 100,  "y":  100 },
                { "x": 500, "y": 500 },
                     { "x": 300, "y": 0 },
                   { "x": 300, "y": 0 },
                  { "x": 100,  "y":  100 },
                { "x": 500, "y": 500 },
                     { "x": 300, "y": 0 },
                   { "x": 300, "y": 0 },
            ],
    "links": []
    };


var nodes = graph.nodes,
    links = graph.links;

var force = d3.layout.force()
    .size([innerWidth, innerHeight])
    .nodes(nodes)
    .links(links);

force.linkDistance(100);
force.charge(-200);

var link = group.selectAll('.link')
    .data(links)
    .enter().append('line')
    .attr('class', 'link');

var node = group.selectAll('.node')
    .data(nodes)
    .enter().append('circle')
    .attr('class', 'node');

force.on('tick', function() {
    node.attr('r', radius)
        .attr('cx', function(d) { return d.x; })
        .attr('cy', function(d) { return d.y; });

    link.attr('x1', function(d) { return d.source.x; })
        .attr('y1', function(d) { return d.source.y; })
        .attr('x2', function(d) { return d.target.x; })
        .attr('y2', function(d) { return d.target.y; });

});


force.start();

完整代码在这里:http://codepen.io/Balzzac/pen/vGWXdQ http://codepen.io/Balzzac/pen/vGWXdQ。现在它是“group”内的力图,我需要使其位于三角形“tr”内,这样没有一个节点位于三角形的边界之外。

感谢帮助!

PS 抱歉我的英语=)


这个问题实际上有两个部分。首先,您需要将力布局收敛到与默认焦点不同的焦点上宽度/2,高度/2 https://github.com/mbostock/d3/wiki/Force-Layout#size。这个新焦点应该是三角形的质心。幸运的是d3 has 辅助方法 https://github.com/mbostock/d3/wiki/Polygon-Geom#centroid计算多边形的这个值。其次,现在我们正在三角形的质心上收敛,我们如何将节点限制在该三角形内。我下面使用的方法计算从质心到节点绘制的线与三角形边的线之间的交点(交点计算从此question https://stackoverflow.com/questions/563198/how-do-you-detect-where-two-line-segments-intersect)。所有 3 条边上都没有交点意味着圆在三角形中,而任何边上的交点意味着我们需要将圆带到该边上。

UPDATE-- 稍微概括一下代码并将其转换为阻止这里 http://bl.ocks.org/larsenmtl/39a028da44db9e8daf14578cb354b5cb处理 N 边多边形。

让我们看一下代码:

<!DOCTYPE html>
<html>

<head>
  <script data-require="[email protected] /cdn-cgi/l/email-protection" data-semver="3.5.3" src="//cdnjs.cloudflare.com/ajax/libs/d3/3.5.3/d3.js"></script>
</head>

<body>
  <script>
    var width = 500,
        height = 500,
        radius = 10;

    var svg = d3.select("body").append("svg")
      .attr("width", width)
      .attr("height", height)
      .style("background", "#eee");

    // our polygon
    var trianglePoints = [
      [250, 0],
      [12, 173],
      [250, 250]
    ];

    var tr = svg.append("polygon") // attach a polygon
      .style("stroke", "black") // colour the line
      .style("fill", "none") // remove any fill colour
      .attr("points", trianglePoints.join(" ")); // x,y points 

    var group = svg.append("g");

    var nodes = d3.range(20).map(function(d){ return {} }),
      links = [],
      cent = d3.geom.polygon(trianglePoints).centroid();

    var force = d3.layout.force()
      .size([width, height])
      .nodes(nodes)
      .links(links);

    force.linkDistance(100);
    force.charge(-200);

    var link = group.selectAll('.link')
      .data(links)
      .enter().append('line')
      .attr('class', 'link');

    var node = group.selectAll('.node')
      .data(nodes)
      .enter().append('circle')
      .attr('class', 'node')
      .call(force.drag); //<-- make them draggable to test

    force.on('tick', function(e) {

      node.attr('r', radius)
        .attr('transform', function(d) {

          // change focus to the center of the triangle
          var x = (d.x - (width / 2 - cent[0])),
            y = (d.y - (height / 2 - cent[1]));

          // test intersections on all 3 edges
          var i = 
            getLineIntersection(trianglePoints[0][0], trianglePoints[0][1],
              trianglePoints[1][0], trianglePoints[1][1], cent[0], cent[1], x, y) ||
            getLineIntersection(trianglePoints[1][0], trianglePoints[1][1],
              trianglePoints[2][0], trianglePoints[2][1], cent[0], cent[1], x, y) ||
            getLineIntersection(trianglePoints[0][0], trianglePoints[0][1],
                trianglePoints[2][0], trianglePoints[2][1], cent[0], cent[1], x, y) ||
            false;
          
          // set it to intersection
          if (i){
            x = i.x;
            y = i.y;
          }

          return "translate(" + x + "," + y + ")";

        });

      link.attr('x1', function(d) {
          return d.source.x;
        })
        .attr('y1', function(d) {
          return d.source.y;
        })
        .attr('x2', function(d) {
          return d.target.x;
        })
        .attr('y2', function(d) {
          return d.target.y;
        });

    });

    // from https://stackoverflow.com/questions/563198/how-do-you-detect-where-two-line-segments-intersect
    function getLineIntersection(p0_x, p0_y, p1_x, p1_y, p2_x, p2_y, p3_x, p3_y) {
      var s1_x, s1_y, s2_x, s2_y;
      s1_x = p1_x - p0_x;
      s1_y = p1_y - p0_y;
      s2_x = p3_x - p2_x;
      s2_y = p3_y - p2_y;
      var s, t;
      s = (-s1_y * (p0_x - p2_x) + s1_x * (p0_y - p2_y)) / (-s2_x * s1_y + s1_x * s2_y);
      t = (s2_x * (p0_y - p2_y) - s2_y * (p0_x - p2_x)) / (-s2_x * s1_y + s1_x * s2_y);

      if (s >= 0 && s <= 1 && t >= 0 && t <= 1) {
        var intX = p0_x + (t * s1_x);
        var intY = p0_y + (t * s1_y);
        return {
          x: intX,
          y: intY
        };
      }
      return false;
    }

    force.start();
  </script>
</body>

</html>
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

在三角形内强制图表 d3.js 的相关文章

随机推荐