D3 force layout -.exit (). Remove () just returns errors in the tick event

I have a problem with link.exit (). remove (); and node.exit (). remove (); ... If I set it in the initializeGraph method then I get several errors with the tick function I think. So my question is how and why I am getting these errors:

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 

      

Here is a sample source code. Unimportant lines are deleted:

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...

      

Well, as you can see svg.remove (); from the code is not required. But before exiting (). Remove () doesn't work, it is necessary. So yes, how to do it with tickevent / .exit (). Remove ().

Thanks for any advice.

PS: I used this very basic one https://gist.github.com/mbostock/1095795 and another one that is very close to my D3.js section - exit () does not delete all data and this does not work, too Why d3. js v3 crashes my force graph when implementing scaling when v2 fails?

The whole code or let's say how I think it should work, but currently getting some errors (not identical to the above code, but just changing some lines)

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);
}

      

+3


source to share





All Articles