如何将d3.arc嵌套在另一个内部?

时间:2016-12-10 15:34:43

标签: d3.js geometry

我试图将使用d3.arc生成的弧完美地嵌套在另一个弧内。

我可以通过绘制"我自己":

来做到这一点



<!DOCTYPE html>
<html>

<head>
  <script data-require="d3@4.0.0" data-semver="4.0.0" src="https://d3js.org/d3.v4.min.js"></script>
</head>

<body>
  <script>
    function arc_position(x, y, radius, angle) {
      return {
        x: x + (radius * Math.cos(angle)),
        y: y + (radius * Math.sin(angle))
      };
    }

    function describe_arc(x, y, radius, startAngle, endAngle) {

      var s = arc_position(x, y, radius, endAngle);
      var e = arc_position(x, y, radius, startAngle);

      var sweep = e - s <= 180 ? '0' : '1';

      var d = [
        'M', s.x, s.y,
        'A', radius, radius, 0, sweep, 0, e.x, e.y
      ].join(' ');

      return d;
    }

    var svg = d3.select("body")
      .append("svg")
      .attr("width", 500)
      .attr("height", 500)
      .append("g");
      
    var s = arc_position(250, 250, 200, Math.PI/2);
    var e = arc_position(250, 250, 200, (Math.PI * 3)/2);
      
    svg.append("path")
      .style("fill", "none")
      .style("stroke", "orange")
      .style("stroke-width", "20px")
      .attr("d", describe_arc(250,250,180,(Math.PI * 3)/2, Math.PI/2));
      
    svg.append("path")
      .style("fill", "none")
      .style("stroke", "orange")
      .style("stroke-width", "20px")
      .attr("d", "M" + (s.x + 30) + "," + s.y + "L" + (e.x + 30) + "," + e.y);

    svg.append("path")
      .style("fill", "none")
      .style("stroke", "steelblue")
      .style("stroke-width", "20px")
      .attr("d", describe_arc(250,250,200,(Math.PI * 3)/2, Math.PI/2));
    
    svg.append("path")
      .style("fill", "none")
      .style("stroke", "steelblue")
      .style("stroke-width", "20px")
      .attr("d", "M" + (s.x + 10) + "," + s.y + "L" + (e.x + 10) + "," + e.y);
    
  </script>
</body>

</html>
&#13;
&#13;
&#13;

但我无法找出使用d3.arc的方法:

&#13;
&#13;
<!DOCTYPE html>
<html>

  <head>
    <script data-require="d3@4.0.0" data-semver="4.0.0" src="https://d3js.org/d3.v4.min.js"></script>
  </head>

  <body>
    <script>
      
      var svg = d3.select("body")
        .append("svg")
        .attr("width", 500)
        .attr("height", 500)
        .append("g")
        .attr("transform","translate(250,250)");
        
      var arc = d3.arc()
        .innerRadius(0)
        .outerRadius(200)
        .startAngle(0)
        .endAngle(Math.PI);

      svg.append("path")
        .style("fill", "none")
        .style("stroke", "steelblue")
        .style("stroke-width", "20px")
        .attr("d", arc());
        
      arc.outerRadius(200 - 40);
      
      svg.append("path")
        .style("fill", "none")
        .style("stroke", "orange")
        .style("stroke-width", "20px")
        .attr("d", arc())
        .attr("transform", "translate(20,0)")
      
    </script>
  </body>

</html>
&#13;
&#13;
&#13;

有什么想法吗?

3 个答案:

答案 0 :(得分:5)

我认为只使用d3.arc有一种很好的方法可以做到这一点,因为这是用于绘制圆圈的部分而你是在尝试绘制部分椭圆。

您可以使用笔划宽度和内弧半径offsetAngle = sin(stroke width / inner radius)生成角度偏移。弧startAngleoffsetAngleendAngleMath.PI - offsetAngle

不幸的是,这将生成包含圆的中心点的路径。你可以通过从生成的路径(L0,0)中删除innerArc().replace("L0,0","")来合并一些有效的东西,这样就会给你提供你想要的东西,尽管是一种丑陋的方式。

因为它是一个相当简单的路径,所以最好使用自己的路径生成器代替它。

&#13;
&#13;
<!DOCTYPE html>
<html>

  <head>
    <script data-require="d3@4.0.0" data-semver="4.0.0" src="https://d3js.org/d3.v4.min.js"></script>
  </head>

  <body>
    <script>
      
      var svg = d3.select("body")
        .append("svg")
        .attr("width", 500)
        .attr("height", 500)
        .append("g")
        .attr("transform","translate(250,250)");
        
      var outerRadius = 200;
      var stroke = 20;
      var innerRadius = outerRadius - stroke;
      var innerAngle = Math.sin(stroke/innerRadius);

      var outerArc = d3.arc()
        .innerRadius(0)
        .outerRadius(outerRadius)
        .startAngle(0)
        .endAngle(Math.PI);

      var innerArc = d3.arc()
        .innerRadius(0)
        .outerRadius(innerRadius)
        .startAngle(innerAngle)
        .endAngle(Math.PI - innerAngle);

      svg.append("path")
        .style("fill", "none")
        .style("stroke", "steelblue")
        .style("stroke-width", stroke)
        .attr("d", outerArc());
      
      svg.append("path")
        .style("fill", "none")
        .style("stroke", "orange")
        .style("stroke-width", stroke)
        .attr("d", innerArc().replace("L0,0",""));
      
    </script>
  </body>

</html>
&#13;
&#13;
&#13;

答案 1 :(得分:3)

(这不是一个答案,只是一个评论,我选择伪装成答案,因为我需要S.O.片段)

我相信Paul S是正确的,他应该得到绿色标记的大奖:你在内(橙色)路径上想要画的是< strong>不圆弧,而是椭圆。并且,正如文档所说,

  

电弧发生器产生圆形或环形扇区

,这不适用于创建椭圆扇区。

您可以在以下演示中轻松看到:使用for循环,我们绘制外半径减小的弧。完美填充每个弧的内部空间的唯一方法是,如果下一个较小的拱门具有先前的相同的中心,则更大的一个:

&#13;
&#13;
<!DOCTYPE html>
<html>

  <head>
    <script data-require="d3@4.0.0" data-semver="4.0.0" src="https://d3js.org/d3.v4.min.js"></script>
  </head>

  <body>
    <script>
      
      var svg = d3.select("body")
        .append("svg")
        .attr("width", 500)
        .attr("height", 500)
        .append("g")
        .attr("transform","translate(250,250)");
        
      var arc = d3.arc()
        .innerRadius(0)
        .outerRadius(200)
        .startAngle(0)
        .endAngle(Math.PI);
      
      var color = d3.scaleOrdinal(d3.schemeCategory10);
      
      for(var i = 0; i<11; i++){

      svg.append("path")
        .style("stroke", color(i))
        .style("fill", "none")
        .style("stroke-width", "20px")
        .attr("d", arc());
        
      arc.outerRadius(200 - 20*i);
        
        };
      
    </script>
  </body>

</html>
&#13;
&#13;
&#13;

有一种更简单的方法可视化。让我们创建一个具有巨大笔划的圆弧:

&#13;
&#13;
<!DOCTYPE html>
<html>

  <head>
    <script data-require="d3@4.0.0" data-semver="4.0.0" src="https://d3js.org/d3.v4.min.js"></script>
  </head>

  <body>
    <script>
      
      var svg = d3.select("body")
        .append("svg")
        .attr("width", 500)
        .attr("height", 500)
        .append("g")
        .attr("transform","translate(250,250)");
        
      var arc = d3.arc()
        .innerRadius(0)
        .outerRadius(150)
        .startAngle(0)
        .endAngle(Math.PI);

      svg.append("path")
        .style("fill", "none")
        .style("stroke", "steelblue")
        .style("stroke-width", "100px")
        .attr("d", arc());
        
      
    </script>
  </body>

</html>
&#13;
&#13;
&#13;

看看蓝色圆弧:它是一个半圆形。现在看看里面的白色空间:它显然半圆形。蓝色的东西是半圆形,但它内部的空间不是。

因此,由于d3.arc()现在没有设置两个不同焦点的选项,因此选项会创建您自己的功能(如您所做)或黑客攻击路径(正如Paul S所做的那样)。

答案 2 :(得分:0)

您绘制第二个弧,其外半径为cout << "Value of node in main.cpp before rotation: " << tree1.root->left->right->left->key << endl; tree1.findParentRotate(5); cout << "Value of node in main.cpp after rotation: " << tree1.root->left->right->left->key << endl; ,中心偏移R - 2 * strokewidth

但较小的弧应该与较大的弧相同相同的中心和外半径strokewidth