Старые узлы в диаграмме d3 не удаляются при обновлении.

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

Скриншот

Вот функция обновления. Я пробовал различные учебники, перестраивал код, дважды проверял правильность обновляемых данных (т. Е. this.dataNodes мутирует, но полная замена объекта тоже не работает) и т. д. Честно говоря, не знаю, что Я должен искать больше.

 // ADDING LINKS
        this.link = this.linkGroup.selectAll("path")
            .data(this.dataLinks, (link) => {
              return link.target.id + link.source.id
            });

        this.link.exit().remove();

        const linkEnter = this.link.enter()
            .append("path")
            .attr("stroke-width", 2)
            .style("stroke", "#ccc")
            .style('marker-start', (d) => d.sync ? 'url(#start-arrow)' : '')
            .style('marker-end', (d) => 'url(#end-arrow)');


        this.link = linkEnter.merge(this.link);

        // ADDING NODES
        this.node = this.nodeGroup.selectAll(".nodes")
            .data(this.dataNodes, function (node) { return node.id });

        this.node.exit().remove();

        const nodeEnter = this.node.enter()
            .append("g")
            .call(this.dragAndDrop);

        // Main circle
        nodeEnter.append("circle")
            .attr("r", 10)
            .attr("fill", "grey")
        // ADDING CHARACTER NAMES
        nodeEnter.append("text")
            .attr("x", 12)
            .attr("dy", ".35em")
            .text(function (d) {return d.title;});

        this.node = nodeEnter.merge(this.node);

this.simulation.nodes(this.dataNodes).on("tick", this.tickActions );
this.simulation.force('link').links(this.dataLinks);
this.simulation.alphaTarget(1).restart();

РЕДАКТИРОВАТЬ: этот код вызывается при первом создании графа силы. this.updateSimulation — это функция, указанная выше, и она отображается без проблем. При повторном вызове все ранее созданные узлы остаются в графе.

this.svg = d3.select('#relationship-chart')
            .append('svg')
            .attr('width', this.width)
            .attr('height', this.height);


        // GROUPS
        this.linkGroup = this.svg.append("g").attr("class", "links");
        this.nodeGroup = this.svg.append("g").attr("class", "nodes");


        // MAIN SIMULATION
        this.link_force =  d3.forceLink()
            .id(function(d) { return d.id; })
            .distance(100);

        this.simulation = d3.forceSimulation()
            .force("link", this.link_force)
            .force("charge", d3.forceManyBody().strength(-200))
            .force('center', d3.forceCenter(this.width / 2, this.height / 2))
            //.force('collide', d3.forceCollide(25))
            .force("x", d3.forceX())
            .force("y", d3.forceY())
            .alphaTarget(1);

          // MISC DEFINTIONS
        this.dragAndDrop = d3.drag()
            .on("start", this.dragstarted)
            .on("drag", this.dragged)
            .on("end", this.dragended);

        // ADDING ARROWS
        this.svg.append('svg:defs').append('svg:marker')
            .attr('id', 'end-arrow')
            .attr('viewBox', '0 -5 10 10')
            .attr('refX', 7)
            .attr('markerWidth', 4)
            .attr('markerHeight', 4)
            .attr('orient', 'auto')
          .append('svg:path')
            .attr('d', 'M0,-5L10,0L0,5')
            .attr('fill', '#ccc');

        this.svg.append('svg:defs').append('svg:marker')
            .attr('id', 'start-arrow')
            .attr('viewBox', '0 -5 10 10')
            .attr('refX', 1)
            .attr('markerWidth', 4)
            .attr('markerHeight', 4)
            .attr('orient', 'auto')
            .append('svg:path')
            .attr('d', 'M10,-5L0,0L10,5')
            .attr('fill', '#ccc');


this.updateSimulation();

person Creis    schedule 02.07.2018    source источник
comment
Привет! Вы выбираете узлы с помощью класса .node, но я не вижу, чтобы вы присваивали этот класс созданным узлам при выборе ввода, поэтому вы можете каждый раз выбирать пустой набор элементов.   -  person Tom Shanley    schedule 02.07.2018
comment
Обновлен мой пост, чтобы включить больше информации. Когда я создаю nodeGroup, я добавляю узлы класса.   -  person Creis    schedule 02.07.2018
comment
на основе этого дополнительного кода вы создаете один элемент группы (g) с узлами класса (this.nodeGroup = this.svg.append(g).attr(class, nodes);), но позже вы пытаетесь выбрать все узлы в этой группе, использующие один и тот же класс: nodeGroup.selectAll(.nodes). Однако у вас нет элементов в этой группе с узлами класса, только родительская группа имеет этот класс.   -  person Tom Shanley    schedule 02.07.2018
comment
Похоже, проблема все-таки в этом. Большое спасибо!   -  person Creis    schedule 02.07.2018


Ответы (1)


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

До:

this.node = this.nodeGroup.selectAll(".nodes")
    .data(this.dataNodes, function (node) { return node.id });

this.node.exit().remove();

const nodeEnter = this.node.enter()
    .append("g")
    .call(this.dragAndDrop);

После:

this.node = this.nodeGroup.selectAll(".onenode")
    .data(this.dataNodes, (node) => { return node.id });

this.node.exit().remove();

const nodeEnter = this.node.enter()
    .append("g")
    .attr("class", "onenode")
    .call(this.dragAndDrop);
person Creis    schedule 02.07.2018