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

javascript - D3 - Uncaught TypeError: Cannot read property 'length' of undefined - Stack Overflow

programmeradmin2浏览0评论

Error in code below. There is no issue with the data of the remaining fields.

<!DOCTYPE html>
<html>
<head>
<title>Data Entry</title>
<meta charset='utf-8'/>
<meta name="keywords" content="D3"/>
<script type="text/javascript" src="d3/d3.v3.js"></script>
<style type="text/css">
.table {border: 2px; text-align: center;}
.th {font-size: 12px; font-weight: bold; color: blue;}
.td {font-size: 12px;}
</style>
</head>
<body>
<script type="text/javascript">
var dataset;
d3.text('data.txt', function(d){dataset = d3.csv.parse(d, function(d){return {id: +d.id, name: d.name};});});
d3.select('body').append('table').attr('class','table').selectAll('tr').data(dataset).enter().append('tr');
</script>
</body>
</html>

Screenshot below:

Error in code below. There is no issue with the data of the remaining fields.

<!DOCTYPE html>
<html>
<head>
<title>Data Entry</title>
<meta charset='utf-8'/>
<meta name="keywords" content="D3"/>
<script type="text/javascript" src="d3/d3.v3.js"></script>
<style type="text/css">
.table {border: 2px; text-align: center;}
.th {font-size: 12px; font-weight: bold; color: blue;}
.td {font-size: 12px;}
</style>
</head>
<body>
<script type="text/javascript">
var dataset;
d3.text('data.txt', function(d){dataset = d3.csv.parse(d, function(d){return {id: +d.id, name: d.name};});});
d3.select('body').append('table').attr('class','table').selectAll('tr').data(dataset).enter().append('tr');
</script>
</body>
</html>

Screenshot below:

Share Improve this question asked Feb 13, 2014 at 22:33 codepkcodepk 6152 gold badges10 silver badges23 bronze badges 1
  • Error is in d3.select line and I suspect because of data(dataset). – codepk Commented Feb 13, 2014 at 22:38
Add a ment  | 

2 Answers 2

Reset to default 2

There are two things you need to consider, the first is that you've put the reference to dataset outside of your call back function. So while you've created the dataset variable as a global so that it can be accessed outside of the d3.text block it hasn't had time to be populated when the table is generated. So if you move your table generation code into the d3.text block you'll address this issue. You can also queue your data requests using queue.js.

The other thing was that you were trying to bind a single element array of objects, where you need an array of objects as d3 iterates over the array to create, in this case, table rows. The information in the objects is then used to populate your table.

Both of these issues are addressed in the following code, however, note that I haven't populated the tables cells with any thing, just created the rows. To do that I'd suggest reading d3noobs post and the referenced stackoverflow answer by Shawn Allen.

var dataset =[];
d3.text('data.txt', function(d) {
    d3.csv.parse(d, function(d) {
        var el = {
            id: +d.id,
            name: d.name
        };
        dataset.push(el)
    });
var table = d3.select('body')
    .append('table')
    .attr('class', 'table');

table.selectAll('tr')
    .data(dataset).enter()
    .append('tr')
    .attr("class", "rows");

});

One final thing is that you could just use d3.csv instead of d3.text and d3.csv.parse.

The d3.text(filename, callbackFunction) method (and all the other d3 file-reading functions) return immediately, and call the specified callback function asynchronously, when the file has been successfully loaded.

All parts of your script that require the data to function must be triggered from within the callback function. Otherwise, they will execute too soon, before the data is available. That was why dataset was undefined when the second line of code executed, even though it was there when you accessed it from the console.

Try:

d3.text('data.txt', function(d){
    dataset = d3.csv.parse(d, function(d){
                  return {id: +d.id, name: d.name};
              });
    d3.select('body').append('table')
          .attr('class','table')
      .selectAll('tr')
      .data(dataset)
      .enter()
          .append('tr');
});

Now, the code that uses dataset is inside the callback function, and is guaranteed not to execute until dataset is ready. Alternately, you could put all that code in a separate initialize() function and call that function from inside your data parsing function:

d3.text('data.txt', function(d){
    dataset = d3.csv.parse(d, function(d){
                  return {id: +d.id, name: d.name};
              });
    initialize();
});

function initialize() {
    d3.select('body').append('table')
          .attr('class','table')
      .selectAll('tr')
      .data(dataset)
      .enter()
          .append('tr');
}
发布评论

评论列表(0)

  1. 暂无评论