D3强制布局 - .exit()。remove()只返回tick事件的错误

时间:2014-10-01 20:09:19

标签: javascript svg d3.js graph force-layout

我遇到了 link.exit()。remove(); node.exit()。remove(); 的问题。如果我在initializeGraph方法中设置它,那么我认为使用tick函数会出现几个错误。所以我的问题是如何或为什么我会得到这些错误:

Uncaught TypeError: undefined is not a function graph-d3.js:156initializeGraph graph-d3.js:156updateForceUsingNewNodes graph-d3.js:108createGraph graph-d3.js:18$.ajax.success ajax-stuff.js:106j jquery-2.1.1.min.js:2k.fireWith jquery-2.1.1.min.js:2x jquery-2.1.1.min.js:4n.prop.on.c jquery-2.1.1.min.js:4n.event.dispatch jquery-2.1.1.min.js:3r.handle jquery-2.1.1.min.js:3
3Error: Invalid value for <line> attribute x1="NaN" d3.min.js:1
3Error: Invalid value for <line> attribute y1="NaN" d3.min.js:1
3Error: Invalid value for <line> attribute x2="NaN" d3.min.js:1
3Error: Invalid value for <line> attribute y2="NaN" d3.min.js:1
Uncaught TypeError: Cannot read property 'attr' of undefined 

这是源代码的一个例外。不重要的行被删除:

var alreadyThere = false;
var nodeCircles = {};
var svg, link, node;
var force = d3.layout.force();
var width = 700, height = 200;
var boxIDName = "#main-rightinfo";
var currentJSON;
var container;
var zoom = d3.behavior.zoom()
    .scaleExtent([0.4, 5]);
var drag = force.drag();

function createGraph(newJSON){
    if (alreadyThere){
        svg.remove();
        nodeCircles = {};
    }
    updateForceUsingNewNodes(generateObjects(newJSON));
    alreadyThere = true;
    currentJSON = newJSON;
    force.start();
}

function updateGraph(newJSON){
    svg.remove();
    findDuplicatesAndSetEmpty(newJSON);
    deleteEmptyObjectsInJSON(newJSON);
    currentJSON = currentJSON.concat(newJSON);
    updateForceUsingNewNodes(generateObjects(currentJSON));
    force.start();
}

//here are some methods forming the json and array...

function initializeGraph(){
    zoom.on("zoom", zoomed);
    drag.on("dragstart", dragstart);

    force
        .size([width, height])
        .gravity(.1)
        .charge(-400)
        .friction(0.9)
        .theta(0.9) 
        .linkStrength(0.9)
        .distance(55)
        .alpha(0.1)
        .on("tick", tick);

    svg = d3.select("#main-right")
        .append("svg")
        .attr("width", width)
        .attr("height", height)
        .call(zoom).on("dblclick.zoom", null);
    svg
        .append("svg:defs").selectAll("marker")
        .data(["end"]) 
        .enter().append("svg:marker")   
        .attr("id", String)
        .attr("viewBox", "0 -5 10 10")
        .attr("refX", 32)
        .attr("refY", -0.05)
        .attr("markerWidth", 6)
        .attr("markerHeight", 6)
        .attr("orient", "auto")
        .append("svg:path")
        .attr("d", "M0,-5L10,0L0,5")
        .attr('fill', '#359AF4');

    container = svg.append("g");

    link = container.append("g")
        .attr("class", "links")
        .selectAll(".link")
        .data(force.links())
        .enter().append("line")
        .attr("class", "link")
        .attr("marker-end", "url(#end)");

    node = container.append("g")
        .attr("class", "nodes")
        .selectAll(".node")
        .data(force.nodes())
        .enter().append("g")
        .attr("class", "node")
        .on("mouseover", mouseover)
        .on("mouseout", mouseout)
        .on("click",        function(d) { click(d); })
        .on("dblclick",     function(d) { dblclick(d); })
        .on('contextmenu',  function(data, index) {
                                                d3.event.preventDefault();
                                                updateGraphByRemoveElement(data, index);
                                        })
        .call(drag);

    node
        .append("circle")
        .attr("r", 20)
        .attr("cx", 0)
        .attr("cy", 0)
        .style("fill", '#eee')
        .style("stroke", '#fff')
        .style("stroke-width", '0.5px');
    node
        .append("image")
        .attr("xlink:href", function(d) {
                                            if (d.class == "Person") {
                                                return "pics/node_person.svg";
                                            } else {
                                                return "pics/node_appln.svg";
                                        }} )
        .attr("x", -20)
        .attr("y", -20)
        .attr("width", 40)
        .attr("height", 40)
        .attr("color", "white");
    node
        .append("text")
        .attr("x", 20)
        .attr("y", 4)
        .style("fill", "#bbb")
        .text(function(d) { return d.name; });  
    node
        .append("circle")
        .attr("r", 7)
        .attr("cx", 0)
        .attr("cy", -16)
        .style("fill", '#359AF4');
    node
        .append("text")
        .attr("text-anchor", "center")
        .attr("x", -3)
        .attr("y", -13)
        .style("fill", "white")
        .text(function(d) { return d.linkCount; });

    function tick() {
      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; });
      node
          .attr("transform", function(d) { return "translate(" + d.x + "," + d.y + ")"; });
    }
}

//here are some functions tick, mousedown and so on...

您可以从代码中看到 svg.remove(); 。但是直到exit()。remove()不起作用,它才需要。所以是的,如何处理tickevent / .exit()。remove()。

感谢您的任何提示。

PS:我使用了这个非常基本的https://gist.github.com/mbostock/1095795 和另一个非常接近我的D3.js - exit() section does not remove all data 这也不起作用Why does d3.js v3 break my force graph when implementing zooming when v2 doesn't?

整个代码或让我们说我认为它应该如何运行,但目前会出现一些错误(与上面的代码不同,但只是更改了一些行)

var alreadyThere = false;
var nodeCircles = {};
var svg, link, node;
var force = d3.layout.force();
var width = 700, height = 400;
var boxIDName = "#main-rightinfo";
var currentJSON;
var container;
var zoom = d3.behavior.zoom()
    .scaleExtent([0.4, 5]);
var drag = force.drag();

function createGraph(newJSON){
    if (alreadyThere){
        //svg.remove();
        nodeCircles = {};
    }
    updateForceUsingNewNodes(generateObjects(newJSON));
    alreadyThere = true;
    currentJSON = newJSON;
    force.start();
}

function updateGraph(newJSON){
    //svg.remove();
    findDuplicatesAndSetEmpty(newJSON);
    deleteEmptyObjectsInJSON(newJSON);
    currentJSON = currentJSON.concat(newJSON);
    updateForceUsingNewNodes(generateObjects(currentJSON));
    force.start();
}

function findDuplicatesAndSetEmpty(newJSON){
    for (var i = 0; i < currentJSON.length; i++) {
        for (var o = 0; o < newJSON.length; o++) {
            if ((currentJSON[i].source.ID == newJSON[o].source) && (currentJSON[i].target.ID == newJSON[o].target)
            ||  (currentJSON[i].source.ID == newJSON[o].target) && (currentJSON[i].target.ID == newJSON[o].source)){
                newJSON[o] = {};
            }
        }
    }
}

function deleteEmptyObjectsInJSON(json){
    for (var i = 0; i < json.length; i++) {
        var y = json[i].source;
        if (y==="null" || y===null || y==="" || typeof y === "undefined"){
            json.splice(i,1);
            i--;
        }
    }
}

function updateGraphByRemoveElement(clickedNode, index){
    svg.remove();
    var json4Splicing = currentJSON;
    for (var i = 0; i < json4Splicing.length; i++) {
        if (json4Splicing[i].source.ID == clickedNode.ID){
            json4Splicing[i] = {};
        } else if (json4Splicing[i].target.ID == clickedNode.ID){
            json4Splicing[i] = {};
        }
    }
    deleteEmptyObjectsInJSON(json4Splicing);
    deleteNode(force.nodes(),clickedNode);  
    currentJSON = json4Splicing;
    updateForceRemoveElement(generateObjects(currentJSON)); 
}

function deleteNode(allNodes, clickedNode){
    allNodes.forEach(function(node) {
        if (node == clickedNode){
            force.links().forEach(function(link) {
                if (node.ID == link.source.ID){
                    link.target.linkCount--;
                }
                if (node.ID == link.target.ID){
                    link.source.linkCount--;
                }
            }); 
            node.linkCount = 0;
        }
    }); 
}

function generateObjects(json) {
    json.forEach(function(link) {
        if (typeof(link.source) == "string"){
            link.source = nodeCircles[link.source] || (nodeCircles[link.source] = {name: link.sourceName, ID: link.source, class: link.sourceClass, linkCount:0});
            link.source.linkCount++;
        }
        if (typeof(link.target) == "string"){
            link.target = nodeCircles[link.target] || (nodeCircles[link.target] = {name: link.targetName, ID: link.target, class: link.targetClass, linkCount:0});
            link.target.linkCount++;
        }
    });   
    return json;
}
function updateForceRemoveElement(links){
    force.nodes(d3.values(nodeCircles).filter(function(d){ return d.linkCount; }) );
    force.links(d3.values(links));
    initializeGraph();
}
function updateForceUsingNewNodes(links){
    force.nodes(d3.values(nodeCircles).filter(function(d){ return d.linkCount; }) );
    force.links(d3.values(links));
    initializeGraph();
}

function initializeGraph(){
    zoom.on("zoom", zoomed);
    drag.on("dragstart", dragstart);

    force
        .size([width, height])
        .gravity(.1)
        .charge(-400)
        .friction(0.9)
        .theta(0.9) 
        .linkStrength(0.9)
        .distance(55)
        .alpha(0.1)
        .on("tick", tick);

    svg = d3.select("#main-right")
        .append("svg")
        .attr("width", width)
        .attr("height", height)
        .call(zoom).on("dblclick.zoom", null);
    svg
        .append("svg:defs").selectAll("marker")
        .data(["end"]) 
        .enter().append("svg:marker")   
        .attr("id", String)
        .attr("viewBox", "0 -5 10 10")
        .attr("refX", 32)
        .attr("refY", -0.05)
        .attr("markerWidth", 6)
        .attr("markerHeight", 6)
        .attr("orient", "auto")
        .append("svg:path")
        .attr("d", "M0,-5L10,0L0,5")
        .attr('fill', '#359AF4');

    container = svg.append("g");

    link = container.append("g")
        .attr("class", "links")
        .selectAll(".link")
        .data(force.links())
        .enter().append("line")
        .attr("class", "link")
        .attr("marker-end", "url(#end)");
    link.exit().remove();
    node = container.append("g")
        .attr("class", "nodes")
        .selectAll(".node")
        .data(force.nodes())
        .enter().append("g")
        .attr("class", "node")
        .on("mouseover", mouseover)
        .on("mouseout", mouseout)
        .on("click",        function(d) { click(d); })
        .on("dblclick",     function(d) { dblclick(d); })
        .on('contextmenu',  function(data, index) {
                                                d3.event.preventDefault();
                                                updateGraphByRemoveElement(data, index);
                                        })
        .call(drag);

    node
        .append("circle")
        .attr("r", 20)
        .attr("cx", 0)
        .attr("cy", 0)
        .style("fill", '#eee')
        .style("stroke", '#fff')
        .style("stroke-width", '0.5px');
    node
        .append("image")
        .attr("xlink:href", function(d) {
                                            if (d.class == "Person") {
                                                return "pics/node_person.svg";
                                            } else {
                                                return "pics/node_appln.svg";
                                        }} )
        .attr("x", -20)
        .attr("y", -20)
        .attr("width", 40)
        .attr("height", 40)
        .attr("color", "white");
    node
        .append("text")
        .attr("x", 20)
        .attr("y", 4)
        .style("fill", "#bbb")
        .text(function(d) { return d.name; });  
    node
        .append("circle")
        .attr("r", 7)
        .attr("cx", 0)
        .attr("cy", -16)
        .style("fill", '#359AF4');
    node
        .append("text")
        .attr("text-anchor", "center")
        .attr("x", -3)
        .attr("y", -13)
        .style("fill", "white")
        .text(function(d) { return d.linkCount; });

    node.exit().remove();


}
function tick() {
      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; });
      node
          .attr("transform", function(d) { return "translate(" + d.x + "," + d.y + ")"; });
    }
d3.selection.prototype.moveToFront = function() {
  return this.each(function(){
    this.parentNode.appendChild(this);
  });
};
function zoomed() {
    d3.event.sourceEvent.stopPropagation(); 
    container.attr("transform", "translate(" + d3.event.translate + ")scale(" + d3.event.scale + ")");
}
function dragstart(d) {
    d3.event.sourceEvent.stopPropagation();
    d3.select(this).classed("fixed", d.fixed = true);
}
function mouseover() {
    d3.select(this).select("text").transition()
      .duration(750)
      .style("font-size","15px")
      .style("fill","black");
    d3.select(this).moveToFront();
}
function mouseout() {
    d3.select(this).select("text").transition()
      .duration(750)
      .style("font-size","10px")
      .style("fill","#ccc");
}
function click(d) {
    $(boxIDName).empty();
    if (d.class == "Person"){
        $(boxIDName).append("<h2>Person/Company</h2>");
        getNodeInfoPerson(d.ID);
    }
    if (d.class == "Appln"){
        $(boxIDName).append("<h2>Application</h2>");
        getNodeInfoAppln(d.ID);
    }
}
function dblclick(d) {
    entryClicked(d.ID+"|"+d.class,false);
}

0 个答案:

没有答案