Вот демо
Когда новые данные попадают в мой сервис d3, он загружает новый набор данных, но старый не удаляется. Поэтому у меня есть дубликаты узлов внутри элемента родительского узла 'g'. Новичок в d3, однако я много читал о selection.join()
вместо enter().append()
. Я также читал о том, как добавлять node.exit().remove();
и node.merge(node);
в определенные моменты.
Как видно из dom, все новые свойства узла находятся в элементе <g class = "node">
, продублированы, не заменяя исходные данные. Поэтому я получаю перекрытие контента.
Вот как устроены мои узлы...
const zoomContainer = d3.select('svg g');
const node = zoomContainer.selectAll('g').data(nodes, function (d) {
return d.id;
});
//zoomContainer.selectAll('.node').data(node).exit().remove();
const nodeEnter = node
.join('g')
.attr('class', 'node')
.call(
d3
.drag()
.on('start', (d) => this.dragended(d3, d, simulation))
.on('drag', function dragged(d) {
d.fx = d3.event.x;
d.fy = d3.event.y;
})
.on('end', (d) => this.dragended(d3, d, simulation))
);
nodeEnter
.append('circle')
.style('fill', '#fff')
.style('cursor', 'pointer')
.style('fill-opacity', '1')
.style('stroke-opacity', '0.5')
.attr('id', (d, i) => d.id)
.attr('r', 28);
nodeEnter
.append('image')
.attr('xlink:href', 'https://github.com/favicon.ico')
.attr('x', -15)
.attr('y', -60)
.attr('width', 16)
.attr('class', 'image')
.style('cursor', 'pointer')
.attr('height', 16);
const nodeText = nodeEnter
.data(nodes)
.append('text')
.style('text-anchor', 'middle')
.style('cursor', 'pointer')
.attr('dy', -3)
.attr('y', -25)
.attr('class', 'nodeText')
.attr('id', 'nodeText');
nodeText
.selectAll('tspan')
.data((d, i) => d.label)
.join('tspan')
.attr('class', 'nodeTextTspan')
.text((d) => d)
.style('font-size', '12px')
.attr('x', -10)
.attr('dx', 10)
.attr('dy', 15);
Я, наверное, мог бы очистить график принудительно, но мне нравится и нужен способ, которым .join()
можно сравнить, что изменилось, и какие опции использовать enter().append().exit()
. Если кто-нибудь может понять, почему дубликаты не удаляются/не объединяются, я был бы признателен.
ОБНОВЛЯТЬ:
Если я использую enter().append('g')
вместо join('g')
, я получаю лучший результат. Я могу использовать zoomContainer.selectAll('.node').data(node).exit().remove();
заранее, и мои узлы обновляются, но только после двойного нажатия кнопки «Обновить». Если я использую join('g')
, они дублируются, и я не могу использовать zoomContainer.selectAll('.node').data(node).exit().remove();
Вот демо
У вас опечатка, должно быть .selectAll('.node')
для выбора класса.
Итак, да, я играл с .node и node. С .node я получаю дубликаты внутри g, и только node я получаю дубликаты снаружи
Я добавил изображение для демонстрации дублирования внутри <g>. Если я .selectAll('node') старые узлы <g> остаются вместе с новыми
Массивы _exit кажутся пустыми. Хотя они правильно представляют, сколько узлов существует.
Нацеливание на элемент <g>
, а не на класс, а затем использование exit().remove()
, похоже, помогло... Я добавлял атрибут класса на уровне .enter()
в .join()
, а затем выполнял выход на этом. Демо здесь
const node = zoomContainer
.selectAll('.node')
.data(this.nodes, function (d) {
return d.id;
});
zoomContainer.selectAll('g').data(node).exit().remove();
Я изменил код в демо... они больше не дублируются, но новые элементы вложены в элемент 'g'.