javascript - 如何使用 D3js 围绕圆形路径绘制圆圈

标签 javascript d3.js svg

如何用D3js在圆形路径周围绘制大小随机的圆圈,使小圆圈随机分布且不相互重叠。

它应该是这样的:

enter image description here

这是我能得到的

enter image description here

    jQuery(document).ready(function () {
    var angle, offset, data,
        size         = [8, 15],
        width        = 500,
        color        = d3.scale.category10(),
        height       = 600,
        radius       = 200,
        dispersion   = 10,
        svgContainer = d3.select('body').append("svg")
                .attr("width", width)
                .attr("height", height);

    data = d3.range(100).map(function () {
        angle  = Math.random() * Math.PI * 2;
        offset = Math.max(size[0], size[1]) + radius + dispersion;
        return {
            cx : offset + Math.cos(angle) * radius + rand(-dispersion, dispersion),
            cy : offset + Math.sin(angle) * radius + rand(-dispersion, dispersion),
            r  : rand(size[0], size[1])
        };

    });

    svgContainer.selectAll("circle")
            .data(data)
            .enter().append("circle")
            .attr({
                r    : function (d) {return d.r},
                cx   : function (d) {return d.cx},
                cy   : function (d) {return d.cy},
                fill : function (d, i) {return color(i % 3)}
            });

    function rand(min, max) {
        return Math.floor(Math.random() * (max - min + 1)) + min;
    }
});

http://jsfiddle.net/yb8bgcrn/1/

更新问题

有没有办法在不使用链接的情况下使用 d3 强制布局显示它?

最佳答案

我已经对您的 fiddle 进行了一些更新,并应用了我在评论中提到的演示中的碰撞检测。希望这会有所帮助。

var angle, offset, data,
  size = [8, 15],
  width = 500,
  color = d3.scale.category10(),
  height = 600,
  radius = 200,
  dispersion = 10,    
  svgContainer = d3.select('body').append("svg")
  .attr("width", width)
  .attr("height", height);

var force = d3.layout.force()
  .gravity(0.05)
  .charge(function(d, i) {
    return i ? 0 : -2000;
  })
  .distance(500)
  .size([width, height]);

data = d3.range(100).map(function() {
  angle = Math.random() * Math.PI * 2;
  offset = Math.max(size[0], size[1]) + radius + dispersion;
  return {
    x: offset + Math.cos(angle) * radius + rand(-dispersion, dispersion),
    y: offset + Math.sin(angle) * radius + rand(-dispersion, dispersion),
    radius: rand(size[0], size[1])
  };

});

force
  .nodes(data)
  .start();

root = data[0],
color = d3.scale.category10();

root.radius = 0;
root.fixed = true;

root.px = 250; //Center x
root.py = 275; //Center y

var nodes = svgContainer.selectAll("circle")
  .data(data)
  .enter().append("circle")
  .attr({
    r: function(d) {
      return d.radius
    },
    cx: function(d) {
      return d.x
    },
    cy: function(d) {
      return d.y
    },
    fill: function(d, i) {
      return color(i % 3)
    }
  });

force.on("tick", function(e) {
  var q = d3.geom.quadtree(data),
    i = 0,
    n = data.length;

  while (++i < n) q.visit(collide(data[i]));

  svgContainer.selectAll("circle")
    .attr("cx", function(d) {
      return d.x;
    })
    .attr("cy", function(d) {
      return d.y;
    });
});

function rand(min, max) {
  return Math.floor(Math.random() * (max - min + 1)) + min;
}

function collide(node) {
  var r = node.radius + 16,
    nx1 = node.x - r,
    nx2 = node.x + r,
    ny1 = node.y - r,
    ny2 = node.y + r;
  return function(quad, x1, y1, x2, y2) {
    if (quad.point && (quad.point !== node)) {
      var x = node.x - quad.point.x,
        y = node.y - quad.point.y,
        l = Math.sqrt(x * x + y * y),
        r = node.radius + quad.point.radius;
      if (l < r) {
        l = (l - r) / l * .5;
        node.x -= x *= l;
        node.y -= y *= l;
        quad.point.x += x;
        quad.point.y += y;
      }
    }
    return x1 > nx2 || x2 < nx1 || y1 > ny2 || y2 < ny1;
  };
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>

编辑:

你的意思是这样的吗?

var angle, offset, data,
  size = [8, 15],
  width = 500,
  color = d3.scale.category10(),
  height = 600,
  radius = 200,
  dispersion = 10,    
  svgContainer = d3.select('body').append("svg")
  .attr("width", width)
  .attr("height", height).append("g");

var force = d3.layout.force()
  .gravity(0.05)
  .charge(function(d, i) {    
    return i ? -20 : -2000;
  })
  .distance(500)
  .size([width, height]);

data = d3.range(100).map(function() {
  angle = Math.random() * Math.PI * 2;
  offset = Math.max(size[0], size[1]) + radius + dispersion;
  return {
    x: offset + Math.cos(angle) * radius + rand(-dispersion, dispersion),
    y: offset + Math.sin(angle) * radius + rand(-dispersion, dispersion),
    radius: rand(size[0], size[1])
  };

});

force
  .nodes(data)
  .start();

root = data[0],
color = d3.scale.category10();

root.radius = 0;
root.fixed = true;

root.px = 250; //Center x
root.py = 275; //Center y

var nodes = svgContainer.selectAll("circle")
  .data(data)
  .enter().append("circle")
  .attr({
    r: function(d) {
      return d.radius
    },
    cx: function(d) {
      return d.x
    },
    cy: function(d) {
      return d.y
    },
    fill: function(d, i) {
      return color(i % 3)
    }
  });

var rotation = 0;
setInterval(function(){
  if(force.alpha()==0){
  if(!rotation)    
    rotation = Math.random() * 50;
  else
    rotation = rotation+1;
  svgContainer.attr("transform","rotate("+rotation+", "+(width/2)+","+(height/2)+")");
  }
  //force.theta(0.5);
},250);

force.on("tick", function(e) {
  var q = d3.geom.quadtree(data),
    i = 0,
    n = data.length;

  while (++i < n) q.visit(collide(data[i]));

  svgContainer.selectAll("circle")
    .attr("cx", function(d) {
      return d.x;
    })
    .attr("cy", function(d) {
      return d.y;
    });
});

function rand(min, max) {
  return Math.floor(Math.random() * (max - min + 1)) + min;
}

function collide(node) {
  var r = node.radius + 16,
    nx1 = node.x - r,
    nx2 = node.x + r,
    ny1 = node.y - r,
    ny2 = node.y + r;
  return function(quad, x1, y1, x2, y2) {
    if (quad.point && (quad.point !== node)) {
      var x = node.x - quad.point.x,
        y = node.y - quad.point.y,
        l = Math.sqrt(x * x + y * y),
        r = node.radius + quad.point.radius;
      if (l < r) {
        l = (l - r) / l * .5;
        node.x -= x *= l;
        node.y -= y *= l;
        quad.point.x += x;
        quad.point.y += y;
      }
    }
    return x1 > nx2 || x2 < nx1 || y1 > ny2 || y2 < ny1;
  };
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>

关于javascript - 如何使用 D3js 围绕圆形路径绘制圆圈,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33029742/

相关文章:

javascript - 如何使用 javascript 将值插入到与另一个字符串匹配的位置的字符串中?

javascript - Vue函数不更新数据变量

javascript - 为什么我的悬停功能无法正常工作?

css - 更改动画或过渡的 SVG Logo 的大小

android - iOS Swift 像 Android 一样将 SVG 图像添加到按钮

flash - 将 flash 中创建的矢量形状导出为 svg

javascript - 如何使用 JavaScriptExecutor 获取浏览器状态栏上显示的文本

javascript - D3 scale.invert() 没有返回 x 的日期

javascript - 即使将元素设置为自动,如何确定元素的 z-index

javascript - 如何在 d3v4 中的两点之间绘制箭头?