2016-09-22 62 views
0

我是新來的d3和svg,我已經組合了來自各種示例的力向圖。重置d3的所有變量力量有向圖,javascript,svg

當我第一次調用d3Graph()函數時,它會正確繪製(第一幅圖像)。當我第二次打電話時,它不會(第二張圖片)。如果我刷新頁面並再次調用它,它可以正常工作。我已經明確地取消了所有的變量,所以我不明白爲什麼它不能正確繪製 - 也就是說我希望它和頁面重新加載一樣,因此每次調用都是全新的運行,重新讀取JSON並繪製從頭開始。

任何幫助將是巨大的

第一個呼叫不正確的平局:

d3 directed graph

無需刷新頁面問題,第二個呼叫:

enter image description here

D3代碼:

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

查看d3的輸入,退出和更新模式,有很多關於該主題的好博客文章 – StackOverMySoul

+0

感謝@Davidlrnt,但據我瞭解,輸入/退出是用於動態添加和刪除數據?我更喜歡重新讀取json並刷新/重繪圖表,因爲json數據可能會在後端更改。我可以看到enter()調用,但我認爲取消節點對象例如會擺脫所有引用 – Simon

回答

0

會更容易幫助,是否會有「在行動」鏈接到你的代碼。控制檯中是否有錯誤? 無論如何,我建議你在獲得迴應後也嘗試清理變量。我曾經有類似的問題,因爲當我重新請求數據時,即使您將force設置爲null,以前的force.tick()仍然在後臺運行。因此,嘗試這樣的:

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 
} 

希望它會有所幫助。