2016-09-22 3 views
0

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:

d3 directed graph

2. Anruf ohne erfrischende Seite Problem:

enter image description here

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)'; 
      } 
     }); 
    }); 
}); 
} 
+0

in die Eingabe, Exit und Update-Muster für d3, gibt es viele gute Blog-Beiträge zum Thema – StackOverMySoul

+0

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

Antwort

0

Wäre einfacher sein, zu helfen, wenn es würde Link zu Ihrem Code "in Aktion" sein. Gibt es Fehler in der Konsole? Wie auch immer, ich würde vorschlagen, dass Sie versuchen, Ihre Variablen zu reinigen, auch nachdem Sie eine Antwort bekommen. Ich hatte früher ein ähnliches Problem, da die force.tick() -Funktion immer noch im Hintergrund lief, obwohl ich die Daten erneut anforderte, obwohl Sie Force auf null gesetzt hatten. Versuchen Sie daher etwas wie folgt:

d3.json("/workflows/graph.json?id=1", function (error, dataset) { 

    if (error) 
      throw error; 

    if (force){ // check if force exists (should exist if you are calling it 2nd time) 
     force.stop(); 
     force = null; 

    // You can clean other variables here too, but with issue, which you show, looks more like force problem 

    } 

    //Here goes rest of your code 
} 

Hoffentlich wird es helfen.