复杂圆图

时间:2016-10-26 10:30:15

标签: javascript d3.js svg

我花了很多时间尝试在SVG / D3.js中复制附图。我最接近的是使用附加的代码。我已经探索过使用树函数,但只能创建一个圆圈。

附加代码的问题是,通过手动输入每个圆圈必须坐的像素坐标,很难让它看起来平滑和智能。

有关信息,数据集只会为这些圆圈着色,因此在形状方面它可以完全是静态的。代码只需要生成形状,然后我可以根据数据集驱动颜色。

我想要创建的图片:

enter image description here

这是我的代码:



<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="utf-8">
  <title>D3 Test</title>
  <style type="text/css">

  </style>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>
</head>

<body>
  <script type="text/javascript">
    //Width and height
    var w = 1000;
    var h = 1000;
    var dataset = [6, 2, 5, 4, 5, 5, 5, 5, 3, 4, 5, 6];
    var svg = d3.select("body")
      .append("svg")
      .attr("width", w)
      .attr("height", h);
    var circles = svg.selectAll("circle")
      .data(dataset)
      .enter()
      .append("circle");


    circles.attr("cx", function(d, i) {
      var Xaxis;
      if (i === 0) {
        Xaxis = "500";
      } else if (i === 1) {
        Xaxis = "400";
      } else if (i === 2) {
        Xaxis = "420";
      } else if (i === 3) {
        Xaxis = "452.5";
      } else if (i === 4) {
        Xaxis = "485";
      } else if (i === 5) {
        Xaxis = "515";
      } else if (i === 6) {
        Xaxis = "547.5";
      } else if (i === 7) {
        Xaxis = "580";
      } else if (i === 8) {
        Xaxis = "600";
      } else if (i === 9) {
        Xaxis = "600";
      } else if (i === 10) {
        Xaxis = "650";
      } else if (i === 11) {
        Xaxis = "700";
      } else if (i === 12) {
        Xaxis = "750";
      } else if (i === 13) {
        Xaxis = "750";
      } else if (i === 14) {
        Xaxis = "750";
      } else if (i === 15) {
        Xaxis = "750";
      } else if (i === 16) {
        Xaxis = "750";
      }
      return Xaxis;
    })
    circles.attr("cy", function(d, i) {
        var Yaxis;
        if (i === 0) {
          Yaxis = "500";
        } else if (i === 1) {
          Yaxis = "500";
        } else if (i === 2) {
          Yaxis = "535";
        } else if (i === 3) {
          Yaxis = "560";
        } else if (i === 4) {
          Yaxis = "585";
        } else if (i === 5) {
          Yaxis = "585";
        } else if (i === 6) {
          Yaxis = "560";
        } else if (i === 7) {
          Yaxis = "535";
        } else if (i === 8) {
          Yaxis = "500";
        } else if (i === 9) {
          Yaxis = "600";
        } else if (i === 10) {
          Yaxis = "550";
        } else if (i === 11) {
          Yaxis = "500";
        } else if (i === 12) {
          Yaxis = "450";
        } else if (i === 13) {
          Yaxis = "600";
        } else if (i === 14) {
          Yaxis = "550";
        } else if (i === 15) {
          Yaxis = "500";
        } else if (i === 16) {
          Yaxis = "450";
        }
        return Yaxis;
      })
      .attr("r", function(d, i) {
        var size;
        if (i === 0) {
          size = "30";
        } else if (i > 0) {
          size = "20";
        }
        return size;
      })
      .attr("fill", function(d, i) {
        var returnColor;
        if (d === 1) {
          returnColor = "green";
        } else if (d === 2) {
          returnColor = "lightgreen";
        } else if (d === 3) {
          returnColor = "gold";
        } else if (d === 4) {
          returnColor = "darkorange";
        } else if (d === 5) {
          returnColor = "red";
        } else if (d === 6) {
          returnColor = "lightgrey";
        }
        return returnColor;
      });
  </script>

</body>

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

2 个答案:

答案 0 :(得分:7)

您可以使用一些三角法来定位您的圆圈。这就是你需要的:

要将圆圈定位在x轴上:

  

x-center +(距离* sin(角度))

并将其定位在y轴上:

  

y-center +(距离* cos(角度))

其中distance是圆与中心的距离,angle是以弧度表示的角度。要计算它,请使用:

rad = deg * Math.PI/180;

在下面的代码片段中,我使用组绘制圆圈图层,并使用每个组中圆圈的索引计算角度。我使用d3.range()设置圆圈数,并设置相同阵列中设置距中心距离的图层数量。检查一下:

&#13;
&#13;
var width = height = 500;
var svg = d3.select("body")
  .append("svg")
  .attr("width", width)
  .attr("height", height);

var color = d3.scaleOrdinal(d3.schemeCategory10)
  .domain(d3.range(16));

var data1 = d3.range(16);
var dataRadius = [70, 110, 150, 190, 230];

svg.append("circle").attr("cx", width / 2)
  .attr("cy", height / 2)
  .attr("r", 20)
  .attr("fill", "yellow");

var groups = svg.selectAll(".groups")
  .data(dataRadius)
  .enter()
  .append("g");

var circles = groups.selectAll(".circles")
  .data(data1)
  .enter()
  .append("circle");

circles.attr("cx", function(d, i) {
    var radius = this.parentNode.__data__;
    return width / 2 + (radius * Math.sin(i * (360 / (data1.length) * Math.PI / 180)))
  })
  .attr("cy", function(d, i) {
    var radius = this.parentNode.__data__;
    return height / 2 + (radius * Math.cos(i * (360 / (data1.length) * Math.PI / 180)))
  })
  .attr("r", function() {
    return this.parentNode.__data__ == 230 ? 24 : 14
  })
  .attr("fill", function(d, i) {
    return i == 13 || i == 14 ? color(i - 2) : "#ccc"
  });
&#13;
<script src="https://d3js.org/d3.v4.min.js"></script>
&#13;
&#13;
&#13;

答案 1 :(得分:2)

前奏

虽然这已经有一年了,但我想加上我自己的两分钱,提供一种与Gerardo proposed完全不同的方法。我时不时地提倡使用transform属性提供的强大的SVG转换。无论如何,这主要是因为没有注意到的原因而被忽视。一个这样的例子是我的answer"SVG marker - can I set length and angle?"。大多数开发人员似乎更喜欢自己做三角测量,尽管我认为我的解决方案不那么繁琐,并且结果代码更加干净和优雅,而且更直观易用。

为了充分了解正在发生的事情,我鼓励任何不熟悉该主题的人阅读并重新阅读SVG coordinate systems and transformations Sara Soueidan上由enter image description here组成的优秀三部曲系列。

我将要呈现的方法将所有三角函数卸载到浏览器,从而允许逐字SVG代码。如果你自己计算了圆圈的位置,你将会得到这样的坐标:

<circle cx="314.67156727579004" cy="276.78784026555627"></circle>

可以使用以下行生成相同的圆圈:

<g transform="rotate(30)">
  <circle transform="translate(70)"></circle>
</g>

请注意,某些不相关的属性(rfill)已从两个片段中删除,只关注定位。后者更清楚开发人员想要实现的目标:

  1. 将坐标系旋转30度。
  2. 沿旋转的x轴方向将坐标系转换70个像素。
  3. 在新的原点绘制圆圈。
  4. 甚至不需要cxcy属性,因为这些属性默认为0,允许我们从原点开始,然后通过将其包装在内来偏移整个图形另一组将它翻译成适合的。生成的SVG结构如下:

    https://angular.io/api/router/Resolve

    请查看以下代码片段以了解正常工作:

    const svg = d3.select("svg>g");
    
    const g = svg.selectAll(null)
      .data(d3.range(30, 361, 30))
      .enter().append("g")
        .attr("transform", d => `rotate(${d})`);
        
    g.selectAll(null)
      .data(d3.range(40, 171, 30))
      .enter().append("circle")
        .attr("transform", d => `translate(${d})`)
        .attr("r", (d, i) => i === 4 ? 15 : 10)
        .attr("fill", "#ccc");
      
    <script src="https://d3js.org/d3.v4.js"></script>
    <svg width="600" height="600">
      <g transform="translate(200,200)">
      </g>
    </svg>