Пример кода:
var rects = this.view
.selectAll('rect.node')
.data(this.nodes, function (d) { return d.id; });
rects.enter()
.append('rect')
.attr('class', 'node')
.on('click', function (d) {
self.selectNode(d);
})
.call(d3.drag().on('drag', function (d) {
d3.select(this)
.attr('cx', d.position[0] += self.x.invert(d3.event.dx))
.attr('cy', d.position[1] += self.y.invert(d3.event.dy));
self.update();
}).on('end', function (d) {
self.groups.forEach(group => {
var contain = group.containNode(d);
var cover = group.isCoverNode(d);
if (contain && !cover)
group.removeNode(d);
else if (!contain && cover)
group.addNode(d);
});
}))
.attr('rx', 8)
.attr('ry', 8);
rects.exit().remove();
this.view.selectAll('rect.node')
.attr('x', function (d) {
return self.x(d.position[0]);
})
.attr('y', function (d) {
return self.y(d.position[1]);
})
.attr('width', function (d) {
return self.x(d.width);
})
.attr('height', function (d) {
return self.y(d.height);
})
.attr('class', function (d) {
return self.active === d ? 'node active' : 'node';
});
var titles = this.view
.selectAll('text.title')
.data(this.nodes, function (d) { return d.id; });
titles.enter()
.append('text')
.classed('title', true);
titles.exit().remove();
this.view.selectAll('text.title')
.attr('x', function (d) {
return self.x(d.position[0] + d.margin);
})
.attr('y', function (d) {
return self.y(d.position[1] + d.margin + d.title.size);
})
.text(function (d) {
return d.title.text;
})
.attr('font-size', function (d) {
return self.x(d.title.size) + 'px';
});
По определенному событию вызываю некий update, который обновляет все данные (как в примере), но при увеличении их количества начинает подтормаживать.
Важно, чтобы меньше приходилось вручную обновлять данные по частям, но и не трогать каждый раз querySelectorAll (см. скриншот), чем и занимается D3.js.
Бывают и случаи с группами
var groups = this.view
.selectAll('g.gg')
.data(this.nodes, function (d) { return d.id; });
var newGroups = groups.enter()
.append('g')
.classed('gg', true)
groups.exit().remove();
groups = newGroups.merge(groups);
var outputs = groups.selectAll('circle.output')
.data(function (d) {
return d.outputs;
});
outputs.exit().remove();
var newOutputs = outputs.enter()
.append('circle');
outputs = newOutputs.merge(outputs);
outputs.attr('class', function (d) {
return 'socket output ' + d.socket.id;
});
outputs
.on('mousedown', function (d) {
self.pickedOutput = d;
})
.attr('cx', function (d) {
return self.x(d.positionX());
})
.attr('cy', function (d) {
return self.y(d.positionY());
})
.attr('r', function (d) {
return self.x(d.socket.radius);
})
.append('title').text(function (d) {
return d.socket.name+'\n'+d.socket.hint
});
Как можно оптимизировать?
UPD: набросал простой пример
https://codepen.io/Ni55aN/pen/RgjEBV