.each() with a filter

匿名 (未验证) 提交于 2019-12-03 01:00:01

问题:

I was looking at another stackoverflow question and I tried the following:

d3.selectAll(links.filter(function(db) {   return db.source.id == 'foo' })).each(function(p) {       console.log (p.source.id)     }) 

And found that it returned with a

TypeError: Cannot read property 'source' of undefined

even though the filtered selection comes back as a proper array of objects with .source.id values (this example uses the standard link notation found in D3's force-directed networks).

I'm just curious as to why this wouldn't work.

回答1:

Make sure you are clear on which of the two following methods you are using:

https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Array/filter https://github.com/mbostock/d3/wiki/Selections#wiki-filter

The d3.selectAll function accepts a selector string or an array of DOM nodes. Which one is it in your case?

https://github.com/mbostock/d3/wiki/Selections#wiki-d3_selectAll

Remember that the variable p in the selection.each() callback function corresponds to the datum bound to the elements in the selection.

https://github.com/mbostock/d3/wiki/Selections#wiki-each


UPDATE

Your links variable seems to be an array of regular JavaScript objects. This is not correct because the d3.selectAll function expects an array of DOM nodes (or a selector string). Interestingly, it will not complain if you use a regular array as argument; for example, you can still invoke the selection.each method:

selection.each(function)

Invokes the specified function for each element in the current selection, passing in the current datum d and index i, with the this context of the current DOM element. This operator is used internally by nearly every other operator, and can be used to invoke arbitrary code for each selected element. The each operator can be used to process selections recursively, by using d3.select(this) within the callback function.

However, because the selection is not a real selection of DOM nodes with data bound to them, you see that the first argument in the function (normally d, in your case p) will be undefined.

The second argument, the index i, will still correspond to the index of the original array that we are iterating over. That is the reason why d3.selectAll(links).each(function(p, i) { console.log(links[i].source.id); }) worked for you. It is basically doing the same as this (non-d3) JavaScript expression: links.forEach(function(v, i) { console.log(links[i].source.id); })

One more simplified example of what you were looking at:

// anti-pattern: var arr = ['a', 'b', 'c']; d3.selectAll(arr)     .each(function(d, i) {       console.log(d, i, arr[i]);     }); 

Which logs to the console:

undefined 0 "a" undefined 1 "b" undefined 2 "c" 

So, instead, if you're trying to inspect the links in a force-directed layout you could select the DOM nodes that represent those links. Take the standard force example included in the D3 library: http://d3-example.herokuapp.com/examples/force/force.htm and run the following from the console:

d3.selectAll('line')     .each(function(d, i) {       console.log(d.source.index);     }); 


文章来源: .each() with a filter
标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!