Ich bin neu zu d3 und Svg und ich habe eine Kraft gerichtete Grafik aus verschiedenen Beispielen zusammengestellt.Zurücksetzen aller Vars für d3 Kraft gerichtetes Diagramm, Javascript, Svg
Wenn ich die d3Graph() -Funktion unterhalb des ersten Mal aufrufen, wird es richtig gezeichnet (1. Bild). Wenn ich es ein zweites Mal anrufe, tut es das nicht (2. Bild). Wenn ich die Seite aktualisiere und sie erneut aufrufe, funktioniert sie korrekt. Ich habe explizit alle Variablen aufgehoben, so dass ich nicht sehen kann, warum es nicht korrekt neu gezeichnet wird - dh ich möchte, dass es genauso funktioniert wie ein Seiten-Reload, so dass jeder Aufruf ein komplett neuer Lauf ist, der den JSON neu liest und zeichnet von Grund auf neu.
Jede Hilfe wäre
1. groß sein Anruf tut richtig Unentschieden:
2. Anruf ohne erfrischende Seite Problem:
d3 Code:
function d3Graph() {
var linkDistance = 100;
var colors = d3.scale.category10();
var w = 1000;
var h = 600;
var links= null;
var nodes= null;
var force= null;
var edges= null;
var nodelabels= null;
var edgepaths= null;
var edgelabels= null;
var svg= null;
d3.select("svg").selectAll("*").remove();
$("#svg_container").empty();
svg = d3.select("#svg_container").append("svg").attr({
"width" : w,
"height" : h
});
d3.json("/workflows/graph.json?id=1", function(error, dataset) {
if (error)
throw error;
links = [];
dataset.edges.forEach(function(e) {
var sourceNode = dataset.nodes.filter(function(n) {
return n.id === e.source;
})[0], targetNode = dataset.nodes.filter(function(n) {
return n.id === e.target;
})[0];
links.push({
id : e.id,
edge_type : e.edge_type,
source : sourceNode,
target : targetNode
});
});
force = d3.layout.force().nodes(dataset.nodes).links(links).size([w, h]).linkDistance([linkDistance]).charge([-2000]).theta(0.1).gravity(0.05).start();
edges = svg.selectAll("line").data(links).enter().append("line").attr("id", function(d, i) {
return 'edge' + i
})
.attr('marker-end', function(d) {
if (d.edge_type == 'prerequisite') {
return 'url(#arrowhead)';
}
})
.attr('stroke', function(d) {
if (d.edge_type == 'prerequisite') {
return '#000';
} else {
return '#F00';
}
})
nodes = svg.selectAll("circle").data(dataset.nodes).enter().append("circle").attr({
"r" : 15
}).style("fill", function(d, i) {
return colors(i);
}).call(force.drag).on("click", function(d) {
$('#workflow_stage_id').val(d.id);
$('#workflow_stage_name').val(d.name);
});
nodelabels = svg.selectAll(".nodelabel").data(dataset.nodes).enter().append("text").attr({
"x" : function(d) {
return d.x;
},
"y" : function(d) {
return d.y;
},
"class" : "nodelabel",
"stroke" : "black"
}).text(function(d) {
return d.name + ' [ID:' + d.id + ']';
});
edgepaths = svg.selectAll(".edgepath").data(links).enter().append('path').attr({
'd' : function(d) {
return 'M ' + d.source.x + ' ' + d.source.y + ' L ' + d.target.x + ' ' + d.target.y
},
'class' : 'edgepath',
'fill-opacity' : 0,
'stroke-opacity' : 0,
'fill' : 'blue',
'stroke' : 'red',
'id' : function(d, i) {
return 'edgepath' + i
}
})
edgelabels = svg.selectAll(".edgelabel").data(links).enter().append('text').on("click", function(d) {
$('#workflow_stage_edge_id').val(d.id);
})
.attr({
'class' : 'edgelabel',
'id' : function(d, i) {
return 'edgelabel' + i
},
'dx' : 50,
'dy' : 0,
'font-size' : 14,
'fill' : '#000'
});
edgelabels.append('textPath').attr('xlink:href', function(d, i) {
return '#edgepath' + i
})
.text(function(d, i) {
return 'ID:' + d.id
});
svg.append('defs').append('marker').attr({
'id' : 'arrowhead',
'viewBox' : '-0 -5 10 10',
'refX' : 25,
'refY' : 0,
'orient' : 'auto',
'markerWidth' : 10,
'markerHeight' : 10,
'xoverflow' : 'visible'
}).append('svg:path').attr('d', 'M0 ,-5 L 10 ,0 L 0,5').attr('fill', '#000').attr('stroke', '#000');
force.on("tick", function() {
edges.attr({
"x1" : function(d) {
return d.source.x;
},
"y1" : function(d) {
return d.source.y;
},
"x2" : function(d) {
return d.target.x;
},
"y2" : function(d) {
return d.target.y;
}
});
nodes.attr({
"cx" : function(d) {
return d.x;
},
"cy" : function(d) {
return d.y;
}
});
nodelabels.attr("x", function(d) {
return d.x;
}).attr("y", function(d) {
return d.y;
});
edgepaths.attr('d', function(d) {
var path = 'M ' + d.source.x + ' ' + d.source.y + ' L ' + d.target.x + ' ' + d.target.y;
return path
});
edgelabels.attr('transform', function(d, i) {
if (d.target.x < d.source.x) {
bbox = this.getBBox();
rx = bbox.x + bbox.width/2;
ry = bbox.y + bbox.height/2;
return 'rotate(180 ' + rx + ' ' + ry + ')';
} else {
return 'rotate(0)';
}
});
});
});
}
in die Eingabe, Exit und Update-Muster für d3, gibt es viele gute Blog-Beiträge zum Thema – StackOverMySoul
Dank @Davidlrnt, aber wie ich es verstehe die Eingabe/Exit ist für das dynamische Hinzufügen und Entfernen von Daten? Ich würde eine komplette Neu-Lesen von JSON und Refresh/Neuzeichnen des Graphen bevorzugen, da die JSON-Daten am Back-End geändert werden können. Ich kann die enter() -Aufrufe sehen, aber ich dachte, das Nullen-Objekt würde zum Beispiel annullieren alle Referenzen werden – Simon