forked from emeeks's block: d3-bboxCollide
I forked this to see how it might work with boxes assigned a size and initial position by d3-hierarchy
treemap. I definitely don't think I have this figured out yet.
d3-bboxCollide provides bounding box collision detection for d3.forceSimulation
. This is useful for label adjustment or rectangular nodes. Each node receives a bounding box array of a top right and bottom left corner of that node relative to its x position. In the case of this dataset, that size is based on the length of the word in the source dataset.
A function for calculating this array based off the data is passed into the d3.bboxCollide
function, which is later passed as a "collide" constraint in your force settings.
var collide = d3.bboxCollide(function (d,i) {
return [[-d.value * 10, -d.value * 5],[d.value * 10, d.value * 5]]
})
The code above creates a rectangle scaled to the size of the randomized data. The data determines the y position creating a sort of rectilinear beeswarm plot.
xxxxxxxxxx
<html>
<head>
<title>Bounding Box Collision with Treemap</title>
<meta charset="utf-8" />
<script src="https://d3js.org/d3.v4.min.js"></script>
<script src="collide.js"></script>
</head>
<style>
svg {
height: 500px;
width: 500px;
border: 1px solid lightgray;
}
</style>
<body>
<div id="viz">
<svg class="main">
</svg>
</div>
</body>
<footer>
<script>
// use d3-hierarchy test data for treemap
// https://github.com/d3/d3-hierarchy/blob/master/test/treemap/index-test.js
var simple = {
"children": [
{
"value": 6
},
{
"value": 6
},
{
"value": 4
},
{
"value": 3
},
{
"value": 2
},
{
"value": 2
},
{
"value": 1
}
]
};
var treemap = d3.treemap().size([400, 300]).round(true),
root = treemap(d3.hierarchy(simple).sum(function(d){return d.value}).sort(d3.descending)),
nodes = root.descendants();
nodes = nodes.map(function(d){d.children=null;d.data=null;return d;}).slice(1);
var networkCenter = d3.forceCenter().x(200).y(150);
var forceX = d3.forceX(function (d) {return d.x0})
.strength(0.1)
var forceY = d3.forceY(function (d) {return d.y0})
.strength(0.1)
var collide = d3.bboxCollide(function (d,i) {
return [[d.x0, d.y1],[d.x1, d.y0]];
})
.strength(1)
.iterations(2)
var color = d3.scaleOrdinal(d3.schemeCategory20b)
var force = d3.forceSimulation(nodes)
.velocityDecay(0.6)
.force("center", networkCenter)
.force("x", forceX)
.force("y", forceY)
.force("collide", collide)
.on("tick", updateNetwork);
var nodeEnter = d3.select("svg.main")
.append("g")
.selectAll("g.node")
.data(nodes)
.enter()
.append("g")
.attr("class", "node")
nodeEnter.append("rect")
.attr("class", "base")
.style("fill-opacity", 0.75)
.style("stroke-width", 1)
.style("stroke-opacity", 0.5)
.style("stroke", function (d, i) {return d3.color(color(i)).darker(2)})
.style("fill", function (d, i) {return d3.color(color(i)).brighter(2)})
.style("width", function (d) {return d.x1 - d.x0})
.style("height", function (d) {return d.y1 - d.y0})
.style("x", function (d) {return 0})
.style("y", function (d) {return 0})
function updateNetwork() {
debugger;
d3.select("svg.main").selectAll("g.node")
.attr("transform", function (d) {return "translate(" + d.x + "," + d.y + ")"})
}
</script>
</footer>
</html>
https://d3js.org/d3.v4.min.js