Ich arbeite an einer Graph-Visualisierung mit D3 in einer Backbone-Ansicht. Ich erlaube dem Benutzer, den Graphen zu zoomen, mit Hilfe von Webkit-Transformationen fließend zu wechseln und bei der Veröffentlichung neu zu zeichnen. Um den Code einfach zu halten, zeichne ich die Grafik nur auf der neuen Skala neu, anstatt die neuen Positionen und Größen für die Elemente neu zu berechnen (dies war mein ursprünglicher Ansatz, aber mein Team hat die Neuzeichnungsroute angefordert).Wie funktioniert die DOM-Knotenbereinigung in d3?
[Ich sprach mit Bostock über Twitter. Dies ist eigentlich nicht die bevorzugte Art, Dinge zu tun]
Die Sache, die ich bemerke, ist, dass ich für jedes Neuzeichnen Tonnen von dom Knoten, die nicht aufgeräumt sind.
Dies bezieht sich nicht auf zirkuläre Verweise in Ereignishandlern/-schließungen, da ich alle außer meinen Labels deaktiviert habe (diese haben keine Handler angehängt), und das gleiche Verhalten tritt auf.
Ich habe versucht, aggressiv die Elemente aus dem Diagramm zu entfernen, aber die Dom-Knoten scheinen immer noch zu lecken.
Hier ist ein paar relevante Code. 'render' wird für einen neuen Etikettensatz aufgerufen. Beim Zoomen Beenden ‚schließen‘ wird auf dem alten Graphen genannt, und ein neues Geschäft mit einer anderen Ansicht Instanziierung erstellt und rufen zu ‚machen‘:
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();
}
Wie Sie sehen können, bin ich nichts zu tun heikel mit Event-Handlern oder Schließungen. Mit ein paar Zoom-Interaktionen kann ich Dutzende von dom-Knoten durchsickern lassen, die niemals von GC zurückgewonnen werden.
Ist dies ein Speicherleck, oder macht d3 etwas hinter den Kulissen, um zukünftige Grafikkonstruktionen/Aktualisierungen zu optimieren? Gibt es eine bessere Möglichkeit, eine Grafik zu zerstören, die mir nicht bekannt ist?
Irgendwelche Ideen?
Danke. Ich schaue mir die verschiedenen Zoom-Optionen an, aber der Grund, warum ich sie vorher nicht verwendet habe, war, dass mein Graph Text mit konstanter Schriftgröße innerhalb von Rechtecken enthält, und ich muss jede notwendige Beschneidung beim Vergrößern/Verkleinern bestimmen. Aber nochmal, danke für die Hilfe :) – Gopherkhan
Ja, es gibt viele Gründe, warum geometrisches Zoomen nicht ausreicht. Manchmal können Sie diese Probleme beheben, indem Sie die Schriftgröße verringern und gleichzeitig die Zoomstufe erhöhen. Oft ist es jedoch einfacher, Elemente programmatisch neu zu positionieren. – mbostock
Ich weiß, dass dies eine alte Frage ist, aber sieh dir hier einige IE-spezifische Anmerkungen zur DOM Knotenbereinigung an: http://StackOverflow.com/questions/18575452/why-do-my-svg-nodes-leak-memory-in -ie – explunit