[英]How to draw circles around circular path with D3js
如何使用D3js在圓形路徑周圍繪制隨機大小的圓圈,這樣小圓圈將隨機分布並且不會相互重疊。
以下是它的外觀:
這就是我能得到的
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力布局顯示它但不使用鏈接?
我已經對你的小提琴進行了一些更新並應用了碰撞檢測,就像我在評論中提到的演示一樣。 希望這可以幫助。
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 dx }, cy: function(d) { return dy }, 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 dx; }) .attr("cy", function(d) { return dy; }); }); 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 dx }, cy: function(d) { return dy }, 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 dx; }) .attr("cy", function(d) { return dy; }); }); 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>
是的,你可以通過強制布局來實現這一點。 這個想法是保持所有鏈接都不顯示 ,中心節點顯示none none。 這樣的事情:
nodeEnter.append("circle")
.style("display", function (d) {
return d.children ? "none" : ""; //ceneter node has children thus display will be none
})
在這種情況下,它看起來就像您想要的可視化。
在這里工作代碼
希望這可以幫助!
我在生成隨機坐標時找到了檢測碰撞函數的解決方案,這里是jsfiddle鏈接和代碼:
(function () {
var angle, offset, data, x, y, r,
collision, circle1, circle2,
circles = [],
size = [8, 15],
width = 500,
color = d3.scale.category10(),
height = 600,
radius = 130,
dispersion = 10,
svgContainer = d3.select('body').append("svg")
.attr("width", width)
.attr("height", height);
function detectCollision(c2, c1) {
var dx = c1.cx - c2.cx;
var dy = c1.cy - c2.cy;
var rSum = c1.r + c2.r;
return ((Math.pow(dx, 2) + Math.pow(dy, 2)) < Math.pow(rSum, 2));
}
var sh = 2, elements = 55;
data = d3.range(elements).map(function (i) {
do {
// dispersion += i / 50;
angle = Math.random() * Math.PI * 2;
offset = Math.max(size[0], size[1]) + radius + dispersion + (elements/sh);
x = offset + Math.cos(angle) * radius + rand(- (dispersion + i / sh), dispersion + i / sh);
y = offset + Math.sin(angle) * radius + rand(- (dispersion + i / sh), dispersion + i / sh);
r = rand(size[0], size[1]);
circle2 = {cx : x, cy : y, r : r};
collision = false;
if (circles.length > 1) {
circles.forEach(function (d) {
circle1 = {cx : d.cx, cy : d.cy, r : d.r};
if (detectCollision(circle1, circle2)) {
collision = true;
}
});
}
} while (collision);
circles.push(circle2);
return circles[circles.length - 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;
}
})();
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.