D3 v5 силовая направленная графическая интерполяция - PullRequest
0 голосов
/ 20 марта 2019

У меня есть силовой ориентированный граф, у которого есть узлы (круги) в разных кластерах и движение круга из одного места в другое.Это то, что я копирую https://flowingdata.com/2016/08/23/make-a-moving-bubbles-chart-to-show-clustering-and-distributions/ Что я хочу сделать, это контролировать движение пузырьков при их перемещении из одного кластера в другой

Мой первоначальный подход состоял в том, чтобы поместить переход в тиковый методОднако в соответствии с полученным предложением и после того, как я еще больше подумал, я чувствую, что не стоит помещать переход в тик, как он называется несколько раз.Однако движение пузырьков контролируется внутри функции тика, которая, в свою очередь, вызывает функцию гравитации.Мой вопрос - возможно ли в этом сценарии управлять движением пузырьков?

Не могли бы вы сообщить мне, подходит ли выбранный мной подход именно здесь?Если да, что я делаю не так в текущем коде?Если нет, подскажите, пожалуйста, в каком направлении мне нужно двигаться?

Обновление:

Я удалил код из функции тиков согласно комментариям и включил его в функцию таймерачто я использую для анимации и код выглядит следующим образом

var force = d3.forceSimulation(nodes)
    .force('charge', d3.forceManyBody().strength(-300))
    .force('collision', d3.forceCollide().radius(function (d) {
        return 1.1 * d.radius;
    }))
.on('tick', tick);

force.alpha(0.01);
force.alphaDecay = 0.1;
force.alphaTarget(.001);

force.force('x', d3.forceX().x(function (d) {
   return foci[d.state].x;
}));

force.force('y', d3.forceY().y(function (d) {
   return foci[d.state].y;
}));

function tick(e) {
 circle

    .each(gravity(.051 * .8))
    .style("fill", function (d) {
        return d.color;
    })

    .attr("cx", function (d) {
        return d.x;
    })
    .attr("cy", function (d) {
        return d.y;
    })


 }

setTimeout(timer, 10);

function timer() {

    var freezeTimer = 1000;


    d3.range(nodes.length).map(function (i) {
        var currentNode = nodes[i];

        // some business logic to update node object

        console.log(d3.select("#circle_" +currentNode.id));
        d3.select("#circle_" +currentNode.id)
        .transition()
        .attrTween("pathTween", function(d) {
            // console.log(this);
            if(d.previousState == 0 && d.state == 4) {

                var lineData1 = [
                    { x: 840, y: 600 },
                    { x: 800, y: 220 },
                    { x: 120, y: 120 },
                    ];

                    var path = svg.append("path")
                    .attr("d", line(lineData1))
                    .attr("stroke", "red")
                    .attr("fill", "none")
                    .attr("stroke-width", 1)
                    .attr("stroke-linecap", "round")
                    .attr("opacity", "0.5");


                var length = path.node().getTotalLength(); // Get the length of the path
                // console.log("Length: " + length);
                var r = d3.interpolate(0, length); //Set up interpolation from 0 to the path length
                return function(t){
                    var point = path.node().getPointAtLength(r(t)); // Get the next point along the path
                    // console.log(point);
                    circle // Select the circle
                        .attr("x", point.x) // Set the cx
                        .attr("y", point.y)
                        .attr("r", 4) // Set the cy
                }
            } 
        });


    });
...