我正在尝试在矩形div中绘制圆圈。我已经按照问题13339615的建议(我使用的答案也在fiddle中提供,这很有效。
然而,作为d3的全新,我无法弄清楚如何标记圆圈。我基本上想要重新创建的内容类似于此article中的可视化。
我尝试了以下对小提琴的修改:
var bubbles = bubbleGroup.selectAll("circle")
.data(data)
.enter()
.append("circle")
.append("text").attr("dy", ".3em")
.style("text-anchor", "middle").text("test");
但这打破了可视化。
关注问题13615381我也尝试过这样的事情:
var bubbles = bubbleGroup.selectAll("circle")
.data(data)
.enter()
.append("circle");
bubbleGroup.append("text")
.attr("dx", function(d){return -20})
.text(function(d){return "test"})
但文本不显示。我成像的代码应该是这些的一些变化,但我无法弄明白。
谢谢!
答案 0 :(得分:0)
通过将circle
和text
放在g
内并调整g
css-transform来修复。
var bubbles = bubbleGroup.selectAll("g")
.data(data)
.enter().append("g").attr("class","gBubble");
bubbles.append("circle")
.on("mouseover",function(){
$(this).attr("cursor","pointer")
})
.on("click",function(){alert("clicked")});
bubbles.append("text").text(function(d){return d.name;}).style("opacity","1");
答案 1 :(得分:0)
(function() {
//D3 program to fit circles of different sizes
//in a rectangle of fixed aspect ratio
//as tightly as reasonable.
//
//By Amelia Bellamy-Royds, in response to
//http://stackoverflow.com/questions/13339615/packing-different-sized-circles-into-rectangle-d3-js
//Based on Mike Bostock's
//"http://bl.ocks.org/mbostock/7882658" example:
//http://bl.ocks.org/mbostock/7882658
//parameters//
var N = 25; //number of nodes
var sortOrder = -1;
//>0 for ascending, <0 for descending, 0 for no sort
//create data array//
var data = [], i = N;
var randNorm = d3.random.normal(1,0.6);
while(i--) data.push({
"size": Math.max(randNorm(), 0.1) });
//circle area will be proportional to size
var dataMax = d3.max(data, function(d){return d.size;});
var totalSize = d3.sum(data, function(d){return d.size;});
//________________//
//Set up SVG and rectangle//
var svg = d3.select("svg");
var digits = /(\d*)/;
var margin = 50; //space in pixels from edges of SVG
var padding = 4; //space in pixels between circles
var svgStyles = window.getComputedStyle(svg.node());
var width = parseFloat(svgStyles["width"]) - 2*margin;
var height = parseFloat(svgStyles["height"]) - 2*margin;
var usableArea = Math.PI*
Math.pow( Math.min(width,height)/2 ,2)*0.667;
var scaleFactor = Math.sqrt(usableArea)/
Math.sqrt(totalSize)/Math.PI;
var rScale = d3.scale.sqrt()
//make radius proportional to square root of data r
.domain([0, dataMax]) //data range
.range([0, Math.sqrt(dataMax)*scaleFactor]);
//The rScale range will be adjusted as necessary
//during packing.
//The initial value is based on scaling such that the total
//area of the circles is 2/3 the area of the largest circle
//you can draw within the box.
/*
console.log("Dimensions: ", [height, width]);
console.log("area", width*height);
console.log("Usable area: ", usableArea);
console.log("TotalSize: ", totalSize);
console.log("Initial Scale: ", scaleFactor);
console.log("RScale: ",rScale.domain(), rScale.range());
console.log("r(1)", rScale(1) );
// */
var box = svg.append("rect")
.attr({ "height": height, "width":width,
"x":margin, "y":margin,
"class":"box"
});
var bubbleGroup = svg.append("g")
.attr("class", "bubbles")
.attr("transform",
"translate(" + [margin,margin] + ")");
//__Initialize layout objects__//
// Use the pack layout to initialize node positions:
d3.layout.pack()
.sort((
sortOrder?
( (sortOrder<0)?
function(a,b){return b.size - a.size;} : //descending
function(a,b){return a.size - b.size;} ) : //ascending
function(a,b){return 0;} //no sort
))
.size([width/scaleFactor, height/scaleFactor])
.value(function(d) { return d.size; })
.nodes({children:data});
//Use the force layout to optimize:
var force = d3.layout.force()
.nodes(data)
.size([width/scaleFactor, height/scaleFactor])
.gravity(.5)
.charge(0) //don't repel
.on("tick", updateBubbles);
//Create circles!//
var bubbles = bubbleGroup.selectAll("circle")
.data(data)
.enter()
.append("circle");
//Create text
var text = bubbleGroup.selectAll("text")
.data(data).enter().append("text")
.attr("dy", function(d){
return d.y;
})
.attr("dx", function(d){
return d.x;
}).style("text-anchor", "middle").text("test");
// Create a function for this tick round,
// with a new quadtree to detect collisions
// between a given data element and all
// others in the layout, or the walls of the box.
//keep track of max and min positions from the quadtree
var bubbleExtent;
function collide(alpha) {
var quadtree = d3.geom.quadtree(data);
var maxRadius = Math.sqrt(dataMax);
var scaledPadding = padding/scaleFactor;
var boxWidth = width/scaleFactor;
var boxHeight = height/scaleFactor;
//re-set max/min values to min=+infinity, max=-infinity:
bubbleExtent = [[Infinity, Infinity],[-Infinity, -Infinity]];
return function(d) {
//check if it is pushing out of box:
var r = Math.sqrt(d.size) + scaledPadding,
nx1 = d.x - r,
nx2 = d.x + r,
ny1 = d.y - r,
ny2 = d.y + r;
if (nx1 < 0) {
d.x = r;
}
if (nx2 > boxWidth) {
d.x = boxWidth - r;
}
if (ny1 < 0) {
d.y = r;
}
if (ny2 > boxHeight) {
d.y = boxHeight - r;
}
//check for collisions
r = r + maxRadius,
//radius to center of any possible conflicting nodes
nx1 = d.x - r,
nx2 = d.x + r,
ny1 = d.y - r,
ny2 = d.y + r;
quadtree.visit(function(quad, x1, y1, x2, y2) {
if (quad.point && (quad.point !== d)) {
var x = d.x - quad.point.x,
y = d.y - quad.point.y,
l = Math.sqrt(x * x + y * y),
r = Math.sqrt(d.size) + Math.sqrt(quad.point.size)
+ scaledPadding;
if (l < r) {
l = (l - r) / l * alpha;
d.x -= x *= l;
d.y -= y *= l;
quad.point.x += x;
quad.point.y += y;
}
}
return x1 > nx2 || x2 < nx1 || y1 > ny2 || y2 < ny1;
});
//update max and min
r = r-maxRadius; //return to radius for just this node
bubbleExtent[0][0] = Math.min(bubbleExtent[0][0],
d.x - r);
bubbleExtent[0][1] = Math.min(bubbleExtent[0][1],
d.y - r);
bubbleExtent[1][0] = Math.max(bubbleExtent[1][0],
d.x + r);
bubbleExtent[1][1] = Math.max(bubbleExtent[1][1],
d.y + r);
};
}
function updateBubbles() {
bubbles
.each( collide(0.5) ); //check for collisions
text.each(collide(0.5));//check for text collisions
//update the scale to squeeze in the box
//to match the current extent of the bubbles
var bubbleWidth = bubbleExtent[1][0] - bubbleExtent[0][0];
var bubbleHeight = bubbleExtent[1][1] - bubbleExtent[0][1];
scaleFactor = (height/bubbleHeight +
width/bubbleWidth)/2; //average
/*
console.log("Box dimensions:", [height, width]);
console.log("Bubble dimensions:", [bubbleHeight, bubbleWidth]);
console.log("ScaledBubble:", [scaleFactor*bubbleHeight,
scaleFactor*bubbleWidth]);
//*/
rScale
.range([0, Math.sqrt(dataMax)*scaleFactor]);
//shift the bubble cluster to the top left of the box
bubbles
.each( function(d){
d.x -= bubbleExtent[0][0];
d.y -= bubbleExtent[0][1];
});
//update positions and size according to current scale:
bubbles
.attr("r", function(d){return rScale(d.size);} )
.attr("cx", function(d){return scaleFactor*d.x;})
.attr("cy", function(d){return scaleFactor*d.y;});
text
.attr("dy", function(d){
return (scaleFactor*d.y)+4;
})
.attr("dx", function(d){
return scaleFactor*d.x*2;
});
}
force.start();
})();
&#13;
rect.box {
fill:none;
stroke:royalblue;
stroke-width:5;
shape-rendering: crispEdges;
}
g.bubbles circle {
fill:rgba(255,0,64,0.5);
stroke:rgb(255,0,64);
stroke-width:3;
}
g.bubbles text {
fill:royalblue;
font-family:sans-serif;
text-anchor:middle;
alignment-baseline:middle;
opacity:1;
pointer-events:all;
transition:1s;
}
g.bubbles text:hover {
opacity:1;
}
&#13;
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>
<svg height=500 width=500></svg>
&#13;
我已经在圆圈中添加了文字,也包含了碰撞行为。 最初文本是不可见的,因为在他们提到的CSS中如下所示
g.bubbles text {
fill:royalblue;
font-family:sans-serif;
text-anchor:middle;
alignment-baseline:middle;
opacity:0;//See this value, this makes text to invisible
pointer-events:all;
transition:1s;
}
g.bubbles text:hover {
opacity:1;
}
在我的片段中,我通过将其不透明度改为1来将其更改为可见。
并更新了fiddle