首页 > 解决方案 > 如何在 d3.js 中定位特定区域的圆圈

问题描述

我在 d3 中创建了一个图形,它读取一个数组并在鼠标光标经过一个圆圈时显示数据。

我的图形有 3 个实体:

  1. 位于页面中心的主圆圈。
  2. 进入主圈的彩色饼图。
  3. 对应于代码中定义的数组的每条记录的小圆圈。

在此处输入图像描述

我希望能够找到主圆边缘的小圆圈,如下图所示。

在此处输入图像描述

知道怎么做吗?我将不胜感激任何建议或帮助。

我留下了我创建的图形的完整代码。非常感谢

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="utf-8">
    <title>D3 Test</title>
    <script src="//d3js.org/d3.v3.min.js"></script>
    <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css" integrity="sha384-Gn5384xqQ1aoWXA+058RXPxPg6fy4IWvTNh0E263XmFcJlSAwiGgFAW/dAiS6JXm" crossorigin="anonymous">
    <script src="https://code.jquery.com/jquery-3.2.1.slim.min.js" integrity="sha384-KJ3o2DKtIkvYIK3UENzmM7KCkRr/rE9/Qpg6aAZGJwFDMVNA/GpGFF93hXpG5KkN" crossorigin="anonymous"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.12.9/umd/popper.min.js" integrity="sha384-ApNbgh9B+Y1QKtv3Rn7W3mgPxhU9K/ScQsAP7hUibX39j7fakFPskvXusvfa0b4Q" crossorigin="anonymous"></script>
    <script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/js/bootstrap.min.js" integrity="sha384-JZR6Spejh4U02d8jOt6vLEHfe/JQGiRRSQQxSfFWpi1MquVdAyjUar5+76PVCmYl" crossorigin="anonymous"></script>
    <style>
        .underline {
            text-decoration: underline;
        }
    </style>
</head>
<body style="background-color: rgb(233, 236, 239)">
<br><legend align="center">D3 Test</legend><hr>
  <div class="container">
      <div class="jumbotron">
    <script type="text/javascript">
    var w = 1200;
    var h = 550;
    var padding = 20;
    var radius = Math.min(w, h);


    var dataset = [
          [ 600, 150]
    ];

    var data = [
            [5, 20, "1.- Lorem Ipsum es simplemente el texto de relleno de las imprentas y archivos de texto."],
            [480, 90, "2.- Lorem Ipsum ha sido el texto de relleno estándar de las industrias desde el año 1500"],
            [750, 50, "3.- cuando un impresor (N. del T. persona que se dedica a la imprenta) desconocido usó una galería de textos"],
            [100, 33, "4.- Es un hecho establecido hace demasiado tiempo que un"],
            [330, 95, "5.- Parecerlo un español que se puede leer. Muchos paquetes de autoedición y editores de páginas web usan el Lorem Ipsum como su te"],
            [410, 12, "6- Ingresó como texto de relleno en documentos electrónicos, quedan"],
            [475, 44, "7.- Esencialmente igual al original. Fue popularizado en los 60s "],
            [25, 67, " 8.- Más recientemente con software de autoedición, como por ejemplo Al"],
            [85, 21, "9.- Normal de las letras, al contrario de usar textos como por ejemplo "],
            [220, 88, "10.- Muchas variaciones de los pasajes de Lorem Ipsum disponibles, pero la mayoría sufrió alteraciones en al"]
          ];
    var data_colors = [ 5, 10, 13, 19, 21, 25, 22, 18, 15, 13, 11, 12, 15, 20, 18, 17, 16, 18, 23, 25, 15, 20, 18, 17, 16, 18, 23, 25 ];

    var data_2 = [
        [122, 72]
    ];

      var xScale_data = d3.scale.linear()
                .domain([0, d3.max(data, function(d) { return d[0]; })])
                .range([padding, w - padding * 2]);

      var yScale_data = d3.scale.linear()
                .domain([0, d3.max(data, function(d) { return d[1]; })])
                .range([h - padding, padding * 4]);

      var rScale = d3.scale.linear()
                .domain([0, d3.max(dataset, function(d) { return d[1]; })])
                .range([2, 5]);

      var rScale_data = d3.scale.linear()
                .domain([0, d3.max(data, function(d) { return d[1]; })])
                .range([2, 5]);

      //Crear un elemento SVG
      var svg = d3.select("div.jumbotron")
        .append("svg")
            .attr("width", w)
            .attr("height", h)

      svg.selectAll("circle")
        .data(dataset)
        .enter()
        .append("circle")
            .attr("cx", w / 2)
            .attr("cy", h / 2)

            .attr("r", function(d) {
                return rScale(d[1]) * 25;
            })
            .attr("stroke", "rgb(255, 255, 255)")
            .attr("stroke-width", "8")
            .attr("fill", function(d) {
                return "rgb(233, 236, 239)";
            });

            svg.on("click", function() {
                document.getElementById("msg").setAttribute("style", "display:none;");
                document.getElementById("msg").innerHTML = '';
                d3.event.stopPropagation();
            });

      var dataCircle = d3.select("svg")
        .append("svg")
            .attr("width", w)
            .attr("height", h)

      dataCircle.selectAll("circle")
        .data(data)
        .enter()
        .append("circle")
            .attr("cx", function(d) {
                return xScale_data(d[0]);
            })
            .attr("cy", function(d) {
                return yScale_data(d[1]);
            })
            .attr("id", function(d){
                return "circle-" + d[1]
            })
            .on("mouseover", function(d) {
                document.getElementById("msg").removeAttribute("style");
                document.getElementById("circle-" + d[1]).setAttribute("stroke", "rgb(140, 233, 255)");
                document.getElementById("circle-" + d[1]).setAttribute("stroke-width", "5");
                document.getElementById("msg").innerHTML = d[2];
                d3.event.stopPropagation();
            })
            .on("mouseout", function(d) {
                document.getElementById("msg").setAttribute("style", "display:none;");
                document.getElementById("circle-" + d[1]).removeAttribute("stroke");
                document.getElementById("circle-" + d[1]).removeAttribute("stroke-width");
                document.getElementById("msg").innerHTML = '';
                d3.event.stopPropagation();
            })
            .on("click", function(d) {
                document.getElementById("msg").removeAttribute("style");
                document.getElementById("msg").innerHTML = d[2];
                d3.event.stopPropagation();
            })
            .attr("style", "cursor:pointer;")

            .attr("r", function(d) {
                return rScale_data(d[1]) * 8;
            })

            .attr("fill", function(d) {
                return "rgba(" + Math.floor((Math.random() * 255) + 0) + "," + Math.floor((Math.random() * 255) + 0) + "," + Math.floor((Math.random() * 255) + 0) + ", 0.30)";
            })

    var color = d3.scale.category20();

    var pie = d3.layout.pie()
        .value(function(d) { return 5; })
        .sort(null);

    var arc = d3.svg.arc()
        .innerRadius(radius - 508)
        .outerRadius(radius - 480);

    var svg = d3.select("svg")
        .append("svg")
            .attr("width", w )
            .attr("height", h )
            .append("g")
                .attr("transform", "translate(" + w / 2 + "," + h / 2 + ")");

    svg.datum(data_colors).selectAll("path")
        .data(pie)
        .enter()
        .append("path")
            .attr("cx", w / 2)
            .attr("cy", h / 2)
            .attr("r", 125)
            .attr("fill", function(d, i) { return color(i); })
            .attr("d", arc);

    </script>
      <div class="row">
        <div class="col-lg-12">
          <div id="msg" style="display:none;" class="underline alert alert-warning" align="center"></div>
        </div>
      </div>
    </div>
  </div>
</body>
</html>

标签: javascriptd3.jssvg

解决方案


如果您不需要太明确小圆圈在主圆圈周围的位置,您可以使用 d3.forceRadial ( https://github.com/d3/d3-force#forceRadial )。

如果您想更精确地了解小圆出现在主圆的圆周上的位置,您可以编写一个函数,根据所需的半径和角度指定 x 和 y 坐标(相对于圆心),例如

function xyCoordinates(angle, radius) {
            let radians = 0.0174532925
            let x = radius * Math.sin(a * radians)
            let y = radius * Math.cos(a * radians)
            return [x,y]        
}

推荐阅读