D3.js动画与jQuery更新相结合

好的,所以我使用了这里列出的大部分代码。 记住动画,我想要做的是使用jQuery动态加载数据。 但是,因为我把它包装在一个函数中,就像这样:

function dataGrab(){ $.ajax({ type: "POST", contentType: "application/json; charset=utf-8", url: 'somelink.php?param=someparam', dataType: 'text', async: true, data: "", success: function (data) { buildGraph(data); }, error: function (result) { alert("error"); } }) }; 

构建图表托管问题代码的副本,如下所示:

 function buildGraph(pureData) { var temp = pureData; var data = JSON.parse(temp); var width = 500, height = 500; var force = d3.layout.force() .size([width, height]) .charge(function(d){ var charge = -500; if (d.index === 0) charge = 10 * charge; return charge; }) .linkDistance(d => d.distance) .on("tick", tick); d3.selectAll("svg").remove(); var svg = d3.select("#orb") .append("svg") .attr("width", width) .attr("height", height) .attr("class", "mainsvg"); var link = svg.selectAll(".link"), node = svg.selectAll(".node"), path = svg.selectAll(".path"); force.nodes(data.nodes) .links(data.links) .start(); var edges = link.data(data.links) .enter() .append("line") .attr("class", "link") .style("stroke", "grey") .style("pointer-events", "none"); node = node.data(data.nodes) .enter() .append("g"); node.append("circle") .attr("class", "circle") .attr("r", function(d) { if(dr){ return dr; } else { return "18";} }) .attr("fill", function(d) { if(d.color) { return d.color; } else { return "#24b8e3";} }) .attr("stroke", function(d) { if(d.color) { return d.color; } else { return "#24b8e3";} }); var linkwrap = node.append("a") .attr("href", "3"); linkwrap.append("image") .attr("class", "srcico") .attr("height", "16px") .attr("width", "16px") .attr("xlink:href", function(d) { if(d.icon.length > 25) { return d.icon; } }); function tick() { var link = svg.selectAll("line"); var edgepaths = svg.selectAll(".edgepath"); var edgelabels = svg.selectAll(".edgelabel"); link.attr("x1", function(d) { return d.source.x; }) .attr("y1", function(d) { return d.source.y; }) .attr("x2", function(d) { return d.target.x; }) .attr("y2", function(d) { return d.target.y; }); svg.selectAll(".circle") .attr("cx", function(d) { return dx; }) .attr("cy", function(d) { return dy; }); svg.selectAll(".srcico") .attr("x", function(d) { return dx-5; }) .attr("y", function(d) { return dy-8; }); svg.selectAll(".notecap") .attr("x", function(d) { return dx; }) .attr("y", function(d) { return dy; }); } } dataGrab(); var inter = setInterval(function() { dataGrab(); setTimeout(function() { force.linkDistance(20); force.start().alpha(0.01); }, 2000); }, 5000); 

我有各种各样的问题,考虑到我的所有变量如svgforce都在dataGrab()范围内进行了dataGrab() 。 我试过在外面声明它们,我尝试在setInterval中以相同的方式重新声明它们,但无论我做什么,发生了什么事情,或者我没有得到任何错误,但它不起作用。 我还尝试构建1个根节点(链接问题中的示例中的灰色节点)并通过写入的ajax仅更新其他节点,但它不起作用。 所以我想要做的就是问题的答案,只使用jQuery 。 如果运行一次,此代码将运行正常,但是,更新部分是我遇到问题的地方。 谢谢!

PS,为了澄清,或者为了避免必须点击链接,这是所需的结果,只有jQuery

 var data = { nodes: [ {"x": 250, "y": 250, "color": "green", "name":"TEST", "r":"28", "fixed":true}, {"x": 120, "y": 150, "name":"forums.macrumors", "score": -12.2, "icon": ""}, {"x": 140, "y": 150, "name":"delhidailynews", "score": -0.08, "icon": ""}, {"x": 280, "y": 150, "name":"4-traders", "score": -0.055, "icon": ""}, {"x": 300, "y": 150, "name":"phonearena", "score": 0.45, "icon": ""}, {"x": 40, "y": 200, "name":"inga3.wordpress", "score": -0.27, "icon": ""}, {"x": 70, "y": 200, "name":"kahinaweb.wordpress", "score": -0.28, "icon": ""}, {"x": 100, "y": 200, "name":"bilqueessite.wordpress", "score": -0.3, "icon": ""}, {"x": 130, "y": 200, "name":"beforeitsnews", "score": -0.72, "icon": ""}, {"x": 380, "y": 200, "name":"yahoo", "score": -0.66, "icon": ""} ], links: [ {"source": 0, "target": 1, "distance": 180, "label": ""}, {"source": 0, "target": 2, "distance": 180, "label": ""}, {"source": 0, "target": 3, "distance": 180, "label": ""}, {"source": 0, "target": 4, "distance": 180, "label": ""}, {"source": 0, "target": 5, "distance": 180, "label": ""}, {"source": 0, "target": 6, "distance": 180, "label": ""}, {"source": 0, "target": 7, "distance": 180, "label": ""}, {"source": 0, "target": 8, "distance": 180, "label": ""}, {"source": 0, "target": 9, "distance": 180, "label": ""} ] }; var width = 500, height = 500; var force = d3.layout.force() .size([width, height]) .charge(function(d){ var charge = -500; if (d.index === 0) charge = 10 * charge; return charge; }) .linkDistance(d => d.distance) .on("tick", tick); var svg = d3.select("#orb") .append("svg") .attr("width", width) .attr("height", height) .attr("class", "mainsvg"); var link = svg.selectAll(".link"), node = svg.selectAll(".node"), path = svg.selectAll(".path"); force.nodes(data.nodes) .links(data.links) .start(); var edges = link.data(data.links) .enter() .append("line") .attr("class", "link") .style("stroke", "grey") .style("pointer-events", "none"); node = node.data(data.nodes) .enter() .append("g"); node.append("circle") .attr("class", "circle") .attr("r", function(d) { if(dr){ return dr; } else { return "18";} }) .attr("fill", function(d) { if(d.color) { return d.color; } else { return "orange";} }) .attr("stroke", function(d) { if(d.color) { return d.color; } else { return "orange";} }); var linkwrap = node.append("a") .attr("href", "3"); linkwrap.append("image") .attr("class", "srcico") .attr("height", "16px") .attr("width", "16px") .attr("xlink:href", function(d) { return d.icon; }); linkwrap.append("text") .attr("fill", "white") .attr("stroke", "none") .attr("x", "232") .attr("y", "255") .text(function(d) { return d.ticker; }); function tick() { var link = svg.selectAll("line"); var edgepaths = svg.selectAll(".edgepath"); var edgelabels = svg.selectAll(".edgelabel"); link.attr("x1", function(d) { return d.source.x; }) .attr("y1", function(d) { return d.source.y; }) .attr("x2", function(d) { return d.target.x; }) .attr("y2", function(d) { return d.target.y; }); svg.selectAll(".circle") .attr("cx", function(d) { return dx; }) .attr("cy", function(d) { return dy; }); svg.selectAll(".srcico") .attr("x", function(d) { return dx-5; }) .attr("y", function(d) { return dy-8; }); svg.selectAll(".notecap") .attr("x", function(d) { return dx; }) .attr("y", function(d) { return dy; }); } var inter = setInterval(function() { updateData(); setTimeout(function(){ force.linkDistance(20); force.start().alpha(0.01); },2000); }, 5000); function updateData() { var data = { nodes: [ {"x": 250, "y": 250, "color": "grey", "name":"TEST", "r":"28", "fixed":true}, {"x": 120, "y": 210, "name":"", "score": -12.2, "icon": ""}, {"x": 140, "y": 210, "name":"", "score": -0.08, "icon": ""}, {"x": 280, "y": 210, "name":"", "score": -0.055, "icon": ""}, {"x": 300, "y": 210, "name":"", "score": 0.45, "icon": ""}, {"x": 40, "y": 200, "name":"", "score": -0.27, "icon": ""}, {"x": 70, "y": 200, "name":"", "score": -0.28, "icon": ""}, {"x": 100, "y": 200, "name":"", "score": -0.3, "icon": ""}, {"x": 130, "y": 200, "name":"", "score": -0.72, "icon": ""}, {"x": 380, "y": 200, "name":"", "score": -0.66, "icon": ""}, {"x": 160, "y": 200, "name":"", "score": -0.317, "icon": ""}, {"x": 280, "y": 200, "name":"", "score": -0.37, "icon": ""}, {"x": 270, "y": 200, "name":"", "score": -0.49, "icon": ""}, {"x": 340, "y": 200, "name":"", "score": -0.62, "icon": ""}, {"x": 100, "y": 300, "name":"", "score": -0.31, "icon": ""}, {"x": 140, "y": 300, "name":"", "score": -0.457, "icon": ""}, {"x": 180, "y": 300, "name":"", "score": -0.472, "icon": ""}, {"x": 280, "y": 300, "name":"", "score": -0.66, "icon": ""}, {"x": 320, "y": 300, "name":"", "score": -0.68, "icon": ""}, {"x": 410, "y": 300, "name":"", "score": -0.8, "icon": ""}, {"x": 260, "y": 300, "name":"", "score": -0.86, "icon": ""} ], links: [ {"source": 0, "target": 1, "distance": 180, "label": ""}, {"source": 0, "target": 2, "distance": 180, "label": ""}, {"source": 0, "target": 3, "distance": 180, "label": ""}, {"source": 0, "target": 4, "distance": 180, "label": ""}, {"source": 0, "target": 5, "distance": 180, "label": ""}, {"source": 0, "target": 6, "distance": 180, "label": ""}, {"source": 0, "target": 7, "distance": 180, "label": ""}, {"source": 0, "target": 8, "distance": 180, "label": ""}, {"source": 0, "target": 9, "distance": 180, "label": ""}, {"source": 0, "target": 10, "distance": 180, "label": ""}, {"source": 0, "target": 11, "distance": 180, "label": ""}, {"source": 0, "target": 12, "distance": 180, "label": ""}, {"source": 0, "target": 13, "distance": 180, "label": ""}, {"source": 0, "target": 14, "distance": 180, "label": ""}, {"source": 0, "target": 15, "distance": 180, "label": ""}, {"source": 0, "target": 16, "distance": 180, "label": ""}, {"source": 0, "target": 17, "distance": 180, "label": ""}, {"source": 0, "target": 18, "distance": 180, "label": ""}, {"source": 0, "target": 19, "distance": 180, "label": ""}, {"source": 0, "target": 20, "distance": 180, "label": ""} ] }; d3.selectAll(".mainsvg > *").remove(); var link = svg.selectAll(".link"), node = svg.selectAll(".node"), path = svg.selectAll(".path"); force.linkDistance(d=>d.distance); force.nodes(data.nodes) .links(data.links) .start(); var edges = link.data(data.links) .enter() .append("line") .attr("class", "link") .style("stroke", "grey") .style("pointer-events", "none"); node = node.data(data.nodes) .enter() .append("g"); node.append("circle") .attr("class", "circle") .attr("r", function(d) { if(dr){ return dr; } else { return "18";} }) .attr("fill", function(d) { if(d.color) { return d.color; } else { return "orange";} }) .attr("stroke", function(d) { if(d.color) { return d.color; } else { return "orange";} }); var linkwrap = node.append("a") .attr("href", "3"); linkwrap.append("image") .attr("class", "srcico") .attr("height", "16px") .attr("width", "16px") .attr("xlink:href", function(d) { return d.icon; }); linkwrap.append("text") .attr("fill", "white") .attr("stroke", "none") .attr("x", "232") .attr("y", "255") .text(function(d) { return d.ticker; }); } 
  

所以这就是我设法解决它的方法。 我已将构建图移到函数外部,以便仅正确定义变量。 所以想象一下函数外面完全相同的代码。 之后,使用完全相同的代码来创建更新函数,例如update(pureData){并使其看起来像这样(完整的绘制/更新代码):

 var data = { // insert root node here or leave empty doesn't matter, we're keeping this outside the functions only to set d3 vars proper } var width = 500, height = 500; var force = d3.layout.force() .size([width, height]) .charge(function(d){ var charge = -500; if (d.index === 0) charge = 10 * charge; return charge; }) .linkDistance(d => d.distance) .on("tick", tick); var svg = d3.select("#holderIdHere") .append("svg") .attr("width", width) .attr("height", height) .attr("class", "mainsvg"); var link = svg.selectAll(".link"), node = svg.selectAll(".node"), path = svg.selectAll(".path"); force.nodes(data.nodes) .links(data.links) .start(); var edges = link.data(data.links) .enter() .append("line") .attr("class", "link") .style("stroke", "grey") .style("pointer-events", "none"); node = node.data(data.nodes) .enter() .append("g"); node.append("circle") .attr("class", "circle") .attr("r", function(d) { if(dr){ return dr; } else { return "18";} }) .attr("fill", function(d) { if(d.color) { return d.color; } else { return "#24b8e3";} }) .attr("stroke", function(d) { if(d.color) { return d.color; } else { return "#24b8e3";} }); var linkwrap = node.append("a") .attr("href", "3"); linkwrap.append("image") .attr("class", "srcico") .attr("height", "16px") .attr("width", "16px") .attr("xlink:href", function(d) { if(d.icon.length > 25) { return d.icon; } }); function tick() { var link = svg.selectAll("line"); var edgepaths = svg.selectAll(".edgepath"); var edgelabels = svg.selectAll(".edgelabel"); link.attr("x1", function(d) { return d.source.x; }) .attr("y1", function(d) { return d.source.y; }) .attr("x2", function(d) { return d.target.x; }) .attr("y2", function(d) { return d.target.y; }); svg.selectAll(".circle") .attr("cx", function(d) { return dx; }) .attr("cy", function(d) { return dy; }); svg.selectAll(".srcico") .attr("x", function(d) { return dx-5; }) .attr("y", function(d) { return dy-8; }); svg.selectAll(".notecap") .attr("x", function(d) { return dx; }) .attr("y", function(d) { return dy; }); } function updateMe(newData) { var data = newData; d3.selectAll("#holderIdHere").remove(); var link = svg.selectAll(".link"), node = svg.selectAll(".node"), path = svg.selectAll(".path"); force.nodes(data.nodes) .links(data.links) .start(); var edges = link.data(data.links) .enter() .append("line") .attr("class", "link") .style("stroke", "grey") .style("pointer-events", "none"); node = node.data(data.nodes) .enter() .append("g"); node.append("circle") .attr("class", "circle") .attr("r", function(d) { if(dr){ return dr; } else { return "18";} }) .attr("fill", function(d) { if(d.color) { return d.color; } else { return "#24b8e3";} }) .attr("stroke", function(d) { if(d.color) { return d.color; } else { return "#24b8e3";} }); var linkwrap = node.append("a") .attr("href", "3"); linkwrap.append("image") .attr("class", "srcico") .attr("height", "16px") .attr("width", "16px") .attr("xlink:href", function(d) { if(d.icon.length > 25) { return d.icon; } }); function tick() { var link = svg.selectAll("line"); var edgepaths = svg.selectAll(".edgepath"); var edgelabels = svg.selectAll(".edgelabel"); link.attr("x1", function(d) { return d.source.x; }) .attr("y1", function(d) { return d.source.y; }) .attr("x2", function(d) { return d.target.x; }) .attr("y2", function(d) { return d.target.y; }); svg.selectAll(".circle") .attr("cx", function(d) { return dx; }) .attr("cy", function(d) { return dy; }); svg.selectAll(".srcico") .attr("x", function(d) { return dx-5; }) .attr("y", function(d) { return dy-8; }); svg.selectAll(".notecap") .attr("x", function(d) { return dx; }) .attr("y", function(d) { return dy; }); } } 

在此之后,您所要做的就是抛出AJAX并获取数据,如下所示:

 function graphUp(){ $.ajax({ type: "POST", contentType: "application/json; charset=utf-8", url: 'somelink', dataType: 'text', async: true, data: "", success: function (data) { var freshdata = data; var newData= jQuery.parseJSON(freshdata); updateData(newData); }, error: function (result) { } } )}; 

并将更新动画设置为看起来很漂亮,如下所示:

 var inter = setInterval(function() { graphUp(); setTimeout(function() { force.linkDistance(20); force.start().alpha(0.01); }, 2000); }, 5000); 

非常感谢Gerardo和他在这里找到动画修复的答案

现在很自然,我确信这不是最优雅的解决方案,因为我不是最优雅的开发人员,但它确实有效。 该方法几乎可以重新渲染完整的数据,所以如果有人愿意投入并添加更新方法,请随意