最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - d3.js - Uncaught TypeError: Object has no method 'exit' - Stack Overflow

programmeradmin2浏览0评论

I am trying to draw a series of line after every 5 seconds by changing the lineData array which I feed to the d3 line function:

Here are the excerpts of the code relevant:

var svg = d3.select("body").append("svg:svg")
      .attr("width", width + margin.left + margin.right)
      .attr("height", height + margin.top + margin.bottom)
      .attr("id", "svgMain")
      .append("g")
      .attr("transform", "translate(" + margin.left + "," + margin.top + ")")
      .call(drag);

var lines = svg.append("g")
      .attr("id", "lines");

function changingLines() {
      lines.selectAll("line")
        .data(lineData)
        .enter().append("line")
        .attr("x1", function(d, i) { console.log(d[0][0]); return d[0][0];})
        .attr("y1", function(d, i) { console.log(d[0][1]); return d[0][1];})
        .attr("x2", function(d, i) { return d[1][0];})
        .attr("y2", function(d, i) { return d[1][1];})
        .style("stroke", "#000")
        .style("stroke-width", "0.5")
        .attr("class", "lines");

     lines.selectAll("line").exit().remove();
     setTimeout(changingLines, 2000);
 }

I call the function changingLines() once every 2 seconds with different values for lineData array.

I get the error: Uncaught TypeError: Object has no method 'exit

What am I doing wrong?

I am trying to draw a series of line after every 5 seconds by changing the lineData array which I feed to the d3 line function:

Here are the excerpts of the code relevant:

var svg = d3.select("body").append("svg:svg")
      .attr("width", width + margin.left + margin.right)
      .attr("height", height + margin.top + margin.bottom)
      .attr("id", "svgMain")
      .append("g")
      .attr("transform", "translate(" + margin.left + "," + margin.top + ")")
      .call(drag);

var lines = svg.append("g")
      .attr("id", "lines");

function changingLines() {
      lines.selectAll("line")
        .data(lineData)
        .enter().append("line")
        .attr("x1", function(d, i) { console.log(d[0][0]); return d[0][0];})
        .attr("y1", function(d, i) { console.log(d[0][1]); return d[0][1];})
        .attr("x2", function(d, i) { return d[1][0];})
        .attr("y2", function(d, i) { return d[1][1];})
        .style("stroke", "#000")
        .style("stroke-width", "0.5")
        .attr("class", "lines");

     lines.selectAll("line").exit().remove();
     setTimeout(changingLines, 2000);
 }

I call the function changingLines() once every 2 seconds with different values for lineData array.

I get the error: Uncaught TypeError: Object has no method 'exit

What am I doing wrong?

Share Improve this question edited Oct 10, 2016 at 21:27 Nancy 4,0895 gold badges35 silver badges53 bronze badges asked Dec 12, 2012 at 4:10 shilpanbshilpanb 1553 silver badges10 bronze badges
Add a ment  | 

1 Answer 1

Reset to default 18

You've got a couple related problems with this code actually. When you call changingLines, the only elements which will have their attributes updated are the elements in the enter selection (calling .enter() returns the enter selection`).

Remember that by default, .data() will only add elements to the enter selection if there are new elements in the array you pass into it, e.g.

// Old data array:
var data = [1, 2, 3, 4];

// New data array:
var newData = [5, 6, 7, 8, 9];

/*
The first 4 elements in newData will replace the first 4 elements of oldData.
The number of new elements (which will be in the enter() selection) is only 1.
*/

What you should do is save the join puted by your data call, and use it to individually access enter, exit, and update selections.

var linesContainer = svg.append("g").attr("id", "lines");

function changingLines() {

    /* Compute the data join */
    var lines = linesContainer.selectAll("line").data(lineData);

    /* Enter */
    lines.enter().append("line");

    /* Exit */
    lines.exit().remove();

    /* Update */
    lines
         .attr("x1", function(d, i) { console.log(d[0][0]); return d[0][0];})
         .attr("y1", function(d, i) { console.log(d[0][1]); return d[0][1];})
         .attr("x2", function(d, i) { return d[1][0];})
         .attr("y2", function(d, i) { return d[1][1];})
         .style("stroke", "#000")
         .style("stroke-width", "0.5")
         .attr("class", "lines");

    setTimeout(changingLines, 2000);
}

This will remove old line elements and add new line elements to before it updates the attributes and styles.

https://github./mbostock/d3/wiki/Selections#wiki-enter

The enter selection merges into the update selection when you append or insert. This approach reduces code duplication between enter and update. Rather than applying operators to both the enter and update selection separately, you can now apply them to the update selection after entering the nodes. In the rare case that you want to run operators only on the updating nodes, you can run them on the update selection before entering new nodes.

This should also fix your problem with not being able to call exit(). When you were calling lines.selectAll("line") the second time, you were creating a new selection, and therefore you wouldn't have access to the selections puted when you did your previous join.

Read, and reread this article: http://bost.ocks/mike/join/

发布评论

评论列表(0)

  1. 暂无评论