D3.js v4 + - Как определить конкретное местоположение в раскладе силы - PullRequest
0 голосов
/ 19 октября 2018

Другие онлайн-уроки / ответы о D3.js v3.x или конкретных позициях по перетаскиваемым элементам.

Я посмотрел документацию и не до конца понимаю, как это сделать:

Я пытаюсь предотвратить наложение красных прямоугольников на круги без изменения положения прямоугольников.

Я указал fx и fy, но все еще безуспешно.

const nodes = d3.range(100).map(d => ({radius: 5, type: "circle"}));

const walls = [{}, {}, {}, {}].map((_, index) => ({
    fx: 200 * index,
    fy: 100,
    type: "wall"
}));

const circleCenters = [100, 300, 500];

d3.forceSimulation(nodes.concat(walls))
    .force('charge', d3.forceManyBody().strength(10))
    .force('x', d3.forceX().x(function (d, i) {
        if (d.type === "circle")
            return circleCenters[i % 3];
        else
            return d.fx;
    }))
    .force('y', d3.forceY().y(100))
    .force('collision', d3.forceCollide().radius(d => d.radius))
    .on('tick', ticked);

function ticked() {
    d3.select('svg')
        .selectAll('rect')
        .data(walls)
        .enter()
        .append('rect')
        .attr('width', 100)
        .attr('height', 10)
        .attr('fill', 'red')
        .attr('x', d => d.x)
        .attr('y', d => d.y);

    const u = d3.select('svg')
        .selectAll('circle')
        .data(nodes);

    u.enter()
        .append('circle')
        .merge(u)
        .attr('fill', 'blue')
        .attr('r', d => d.radius)
        .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>

1 Ответ

0 голосов
/ 20 октября 2018

вам нужно заполнить весь прямоугольник защитными узлами правильного размера.

Если вы хотите, чтобы защитные круги не комментировали часть кода.

Есть 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>
...