我通过遵循此示例https://www.d3-graph-gallery.com/graph/bubble_tooltip.html(仅在提取csv时将回调替换为promise)来使用D3 v5创建气泡图。到目前为止,效果很好。
现在,我需要能够对气泡不会彼此重叠的可视化应用物理效果,我相信我需要的是forceCollide。我已经尝试了一段时间,但似乎无法正常工作。这是我用于创建气泡的代码:
// Before I set dimensions, read the data, create x and y axis
// add bubble scales and create tooltips
// ...
//Add dots
var nodes = svg
.append("g")
.selectAll("circle")
.data(data);
nodes
.enter()
.append("circle")
.attr("class", "bubbles")
.attr("cx", function(d) {
return x(d.gdpPercap);
})
.attr("cy", function(d) {
return y(d.lifeExp);
})
.attr("r", function(d) {
return z(d.pop);
})
.style("fill", function(d) {
return myColor(d.continent);
})
// -3- Trigger the functions
.on("mouseover", showTooltip)
.on("mousemove", moveTooltip)
.on("mouseleave", hideTooltip);
任何帮助将不胜感激!
答案 0 :(得分:0)
您曾经能够找到解决方案吗?来自jsfiddle.net/30e1dga6:
data = [{
company: "Walmart",
total: 48,
women: 13,
men: 34,
unknown: 1,
percentage: 28
}, {
company: "Chevron",
total: 17,
women: 2,
men: 15,
unknown: 0,
percentage: 12
}, {
company: "General Motors Company",
total: 28,
women: 5,
men: 22,
unknown: 1,
percentage: 5
}, {
company: "ConocoPhillips",
total: 17,
women: 4,
men: 13,
unknown: 0,
percentage: 2
}, {
company: "General Electric Company",
total: 23,
women: 7,
men: 15,
unknown: 1,
percentage: 8
}, {
company: "Citigroup Inc.",
total: 39,
women: 4,
men: 32,
unknown: 3,
percentage: 38
}, {
company: "Bank of America Corporation",
total: 25,
women: 7,
men: 18,
unknown: 0,
percentage: 30
}, {
company: "AT&T Inc.",
total: 18,
women: 2,
men: 16,
unknown: 0,
percentage: 14
}, {
company: "JPMorgan Chase & Co.",
total: 88,
women: 21,
men: 64,
unknown: 3,
percentage: 17
}, {
company: "AIG",
total: 28,
women: 1,
men: 27,
unknown: 0,
percentage: 20
}, {
company: "Hewlett-Packard",
total: 44,
women: 7,
men: 37,
unknown: 0,
percentage: 22
}]
$(document).ready(function() {
// var data= getPercentage();
var width = 1000 //max size of the bubbles
var height = 800
color = d3.scale.linear()
.domain([0, 40]) //map colors based on value
.range(['#47DFFF', 'green']);; //color category
var bubble = d3.layout.pack()
.sort(null)
.size([width, height])
.padding(.5);
var svg = d3.select("#data-container").append("svg")
.attr("width", width)
.attr("height", height)
.attr("class", "bubble");
// Define the div for the tooltip
var div = d3.select("#data-container").append("div")
.attr("class", "tooltip")
.style("opacity", 0);
//convert numerical values from strings to numbers
data = data.map(function(d) {
d.value = +d["percentage"];
return d;
});
//bubbles needs very specific format, convert data to this.
var nodes = bubble.nodes({
children: data
}).filter(function(d) {
return !d.children;
});
// Charge Function
function charge(d) {
return -Math.pow(d.radius / 2, 2.0) / 8;
}
//force layout
var force = d3.layout.force()
.gravity(.9)
.charge(charge)
.nodes(nodes)
.friction(0.9);
//setup the chart
var bubbles = svg.append("g")
.attr("transform", "translate(0,0)")
.selectAll(".bubble")
.data(nodes)
.enter();
//create the bubbles
bubbles.append("circle")
.classed('bubble', true)
.attr("r", function(d) {
return d.r;
})
.attr("cx", function(d) {
return d.x;
})
.attr("cy", function(d) {
return d.y;
})
.attr('stroke', 'black')
.attr('stroke-width', 0)
//mouseover hover box
.on('mouseover', function(d) {
div.transition()
.duration(100)
.style("opacity", 1)
div.html(d.company + "<br>" + d.percentage + "% Female<br>Men: " + d.men + "<br>Women: " + d.women)
.style("left", (d3.event.pageX) + "px")
.style("top", (d3.event.pageY - 28) + "px");
d3.select(this)
.transition()
.duration(100)
.attr('stroke-width', 2)
})
.on('mouseout', function(d) {
div.transition()
.duration(100)
.style("opacity", 0);
d3.select(this)
.transition()
.duration(1000)
.attr('stroke-width', 0)
})
.style("fill", function(d) {
return color(d.value)
})
.call(force.drag);
var texts = svg.selectAll("text")
var bubbles = svg.selectAll(".bubble")
// groupBubbles();
force.on("tick", function(e) {
bubbles.attr("transform", function(d) {
return 'translate(' + [d.x, d.y] + ')';
});
});
force.start();
var splitCenters = {
1: {
x: width / 3,
y: height / 2
},
2: {
x: width / 2,
y: height / 2
},
3: {
x: 2 * width / 3,
y: height / 2
}
};
var center = {
x: width / 2,
y: height / 2
}
function groupBubbles() {
force.on('tick', function(e) {
var q = d3.geom.quadtree(bubbles),
i = 0,
n = bubbles.length;
while (++i < n) {
q.visit(collide(bubbles[i]));
}
bubbles.each(moveToCenter(e.alpha))
// .transition()
.attr('cx', function(d) {
return d.x;
})
.attr('cy', function(d) {
return d.y;
})
})
force.start()
}
function moveToCenter(alpha) {
return function(d) {
d.x = d.x + (center.x - d.x)
d.y = d.y + (center.y - d.y)
};
}
function splitBubbles() {
force.on('tick', function(e) {
var q = d3.geom.quadtree(bubbles),
i = 0,
n = bubbles.length;
while (++i < n) {
q.visit(collide(bubbles[i]));
}
bubbles.each(moveToSplit(e.alpha))
.transition()
.attr('cx', function(d) {
return d.x;
})
.attr('cy', function(d) {
return d.y;
});
});
force.start()
}
function moveToSplit(alpha) {
return function(d) {
// console.log(d.percentage)
var target;
if (d.percentage <= 10) {
target = splitCenters[1]
} else if (d.percentage > 10 && d.percentage < 20) {
target = splitCenters[2]
} else {
target = splitCenters[3]
}
d.x = d.x + (target.x - d.x)
d.y = target.y
}
}
$("#splitBubbles").click(splitBubbles)
$("#groupBubbles").click(groupBubbles)
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.5.17/d3.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.1.4/jquery.min.js"></script>
<button id="splitBubbles">Split</button>
<button id="groupBubbles">Group</button>
<div id="data-container">