вам нужно заполнить весь прямоугольник защитными узлами правильного размера.
Если вы хотите, чтобы защитные круги не комментировали часть кода.
Есть 2 g
элементов, один из которых содержит защитные узлы, а другой - blue
.
Редактировать
Если вы сделаете X-силу немного сильнее, узлы получатближе к фактическим центрам.
.force('x', d3.forceX()
.x( (d, i) => (d.type === "circle") ? circleCenters[i % 3] : d.fx )
.strength(0.3))
const nodes = d3.range(100).map(d => ({radius: 5, type: "circle"}));
const walls = [{}, {}, {}, {}].map((_, index) => ({
fx: 200 * index,
fy: 100,
width: 100,
height: 10,
radius: 5,
type: "wall"
}));
const circleCenters = [100, 300, 500];
// construct "invisible" circles covering the rects
var invCircles = [];
walls.forEach(e => {
d3.range(e.fx+3, e.fx+e.width-3, 3).forEach(cx => {
invCircles.push({
fx: cx,
fy: e.fy + e.radius,
radius: e.radius,
type: e.type
});
});
});
d3.forceSimulation(nodes.concat(invCircles))
.force('charge', d3.forceManyBody().strength(10))
.force('x', d3.forceX().x( (d, i) => (d.type === "circle") ? circleCenters[i % 3] : d.fx ).strength(0.3))
.force('y', d3.forceY().y(100))
.force('collision', d3.forceCollide().radius(d => d.radius))
.on('tick', ticked);
var wallGeom = d3.select('svg').append('g').attr('class', 'wall');
var circlesGeom = d3.select('svg').append('g').attr('class', 'circles');
wallGeom.selectAll('rect')
.data(walls)
.enter()
.append('rect')
.attr('width', d => d.width )
.attr('height', d => d.height )
.attr('fill', 'red')
.attr('x', d => d.fx)
.attr('y', d => d.fy);
// wallGeom.selectAll('circle')
// .data(invCircles)
// .enter()
// .append('circle')
// .attr('fill', 'yellow')
// .attr('r', d => d.radius)
// .attr('cx', d => d.fx)
// .attr('cy', d => d.fy);
function ticked() {
const u = d3.select('svg')
.select('.circles')
.selectAll('circle')
.data(nodes);
u.enter()
.append('circle')
.attr('fill', 'blue')
.attr('r', d => d.radius)
.merge(u)
.attr('cx', d => d.x)
.attr('cy', d => d.y);
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/4.13.0/d3.js"></script>
<svg width="90vw" height="90vh"></svg>