Я работаю над визузализацией графика, используя D3 в режиме позвоночника. Я разрешаю пользователю изменять размер графика, плавно переходить с использованием преобразований webkit и перерисовывать при выпуске. Чтобы код был прост, я просто перерисовываю график в новом масштабе, вместо того, чтобы пересчитывать новые позиции и размеры элементов (это был мой оригинальный подход, но моя команда запросила маршрут перерисовки).
[Я разговаривал с Бостоком через твиттер. На самом деле это не самый предпочтительный способ делать вещи]
Вещь, которую я замечаю, заключается в том, что для каждого перерисовки я сбрасываю тонны узлов, которые не очищаются.
Это не связано с циклическими ссылками в обработчиках/закрытиях событий, поскольку я отключил все, кроме моих меток (они не привязаны к обработчикам), и происходит такое же поведение.
Я попытался агрессивно удалить элементы из графика, но узлы dom все еще течет.
Вот какой код. 'render' вызывается для нового набора меток. После завершения масштабирования "close" вызывается на старом графике, а новый создается с помощью другого представления и вызывает "render":
render: function() {
// create the svg offscreen/off dom
//document.createElementNS(d3.ns.prefix.svg, "svg")
var svg = this.svg = d3.select(this.el)
.append("svg:svg")
.attr('width', this.VIEW_WIDTH)
.attr('height', this.VIEW_HEIGHT)
this._drawTimeTicks.call(this, true);
return this;
},
_drawTimeTicks: function(includeLabels) {
var bounds = this.getDayBounds();
var min = bounds.start;
var date = new Date(min);
var hour = 1000 * 60 * 60;
var hourDiff = 60 * this.SCALE;
var graphX = (date.getTime() - min) / 1000 / 60;
var textMargin = 7;
var textVert = 11;
// Using for loop to draw multiple vertical lines
// and time labels.
var timeTicks = d3.select(this.el).select('svg');
var width = timeTicks.attr('width');
var height = timeTicks.attr('height');
for (graphX; graphX < width; graphX += hourDiff) {
timeTicks.append("svg:line")
.attr("x1", graphX)
.attr("y1", 0)
.attr("x2", graphX)
.attr("y2", height)
.classed('timeTick');
if (includeLabels) {
timeTicks.append("svg:text")
.classed("timeLabel", true)
.text(this.formatDate(date))
.attr("x", graphX + textMargin)
.attr("y", textVert);
}
date.setTime(date.getTime() + hour);
}
close: function() {
console.log("### closing the header");
this.svg.selectAll('*').remove();
this.svg.remove();
this.svg = null;
this.el.innerHTML = '';
this.unbind();
this.remove();
}
Как вы можете видеть, я не делаю ничего сложного с обработчиками событий или закрытием. С помощью нескольких взаимодействий масштабирования я могу протекать десятки узлов dom, которые никогда не восстанавливаются GC.
Является ли это утечкой памяти или d3 делает что-то за кулисами, чтобы оптимизировать построение/обновление будущего графика? Есть ли лучший способ уничтожить график, о котором я не знаю?
Любые идеи?