Как расположить узел в центре по размеру радиуса? - PullRequest
1 голос
/ 07 октября 2019

Я хочу центрировать узлы в диаграмме направленной силы по размеру круга: мы хотим, чтобы самый большой круг был центрирован, а следующий самый большой круг вокруг него.

Вот JSFiddle: https://jsfiddle.net/5zrxgteh/1/

А вот функции симуляции и отметки:

 var simulation = d3.forceSimulation()
            .force("center", d3.forceCenter().x(width / 2).y(height / 2))
            .force("charge", d3.forceManyBody().strength(5))
            .force("collide", d3.forceCollide().strength(1).radius(function (d) {
                return rScale(d.value * 1.2);
            }).iterations(3));

 simulation
            .nodes(data)
            .on("tick", function (d) {
                elemEnter.selectAll(".pulse")
                    .attr("cx", function (d) {
                        return d.x = Math.max(50, Math.min(width - 50, d.x));
                    })
                    .attr("cy", function (d) {
                        return d.y = Math.max(50, Math.min(height - 50, d.y));
                    });

                elemEnter.selectAll(".circle")
                    .attr("cx", function (d) {
                        return d.x = Math.max(50, Math.min(width - 50, d.x));
                    })
                    .attr("cy", function (d) {
                        return d.y = Math.max(50, Math.min(height - 50, d.y));
                    });

                elemEnter.selectAll("text")
                    .attr("x", function (d) {
                        return d.x = Math.max(50, Math.min(width - 50, d.x));
                    })
                    .attr("y", function (d) {
                        return d.y = Math.max(50, Math.min(height - 50, d.y));
                    });
            });

1 Ответ

1 голос
/ 07 октября 2019

Если вы перестанете думать, что то, что вы хотите, сложно, как математически, так и визуально, потому что, если самые большие круги находятся рядом с центром, а расстояние до центра пропорционально диаметру круга, то у вас будет многопустые пробелы рядом с центром, и симуляция с этим не справится.

Однако, только для попытки, это возможное решение: рвите d3.forceCenter и используйте forceX и forceY вместо, регулируя их сильные стороны в соответствии с размером круга.

Чтобы это работало, мы сначала устанавливаем масштаб:

var strengthScale = d3.scalePow()
    .exponent(2)
    .range([0, 1])
    .domain([0, d3.max(data, function(d) {
        return d.value;
    })]);

Затем мы меняем симуляцию:

var simulation = d3.forceSimulation()
    .force("x", d3.forceX(width / 2).strength(function(d) {
      return strengthScale(d.value);
    }))
    .force("y", d3.forceY(height / 2).strength(function(d) {
      return strengthScale(d.value);
    }))
    .force("charge", d3.forceManyBody().strength(5))
    .force("collide", d3.forceCollide().strength(1).radius(function(d) {
      return rScale(d.value * 1.2);
    }).iterations(30));

Вот результирующий JSFiddle: https://jsfiddle.net/mea9nygb/2/

...