Понимание того, как D3.js связывает данные с узлами
Я читаю документацию D3.js, и мне трудно понять метод selection.data
из документации.
Это пример кода, приведенного в документации:
var matrix = [
[11975, 5871, 8916, 2868],
[ 1951, 10048, 2060, 6171],
[ 8010, 16145, 8090, 8045],
[ 1013, 990, 940, 6907]
];
var tr = d3.select("body").append("table").selectAll("tr")
.data(matrix)
.enter().append("tr");
var td = tr.selectAll("td")
.data(function(d) { return d; })
.enter().append("td")
.text(function(d) { return d; });
Я понимаю большую часть этого, но что происходит с секцией .data(function(d) { return d; })
оператора var td
?
Мое лучшее предположение заключается в следующем:
- Оператор
var tr
привязал четырехэлементный массив к каждому tr node
- Затем оператор
var td
использует этот четырехэлементный массив в качестве своих данных, как-то
Но как .data(function(d) { return d; })
действительно получает эти данные и что он возвращает?
Ответы
Ответ 1
Когда вы пишете:
….data(someArray).enter().append('foo');
D3 создает кучу элементов <foo>
, по одному для каждой записи в массиве. Что еще более важно, он также связывает данные для каждой записи в массиве с этим элементом DOM как свойство __data__
.
Попробуйте следующее:
var data = [ {msg:"Hello",cats:42}, {msg:"World",cats:17} ];
d3.select("body").selectAll("q").data(data).enter().append("q");
console.log( document.querySelector('q').__data__ );
То, что вы увидите (в консоли), является объектом {msg:"Hello",cats:42}
, так как это было связано с первым созданным элементом q
.
Если вы позже выполните:
d3.selectAll('q').data(function(d){
// stuff
});
значение d
оказывается тем свойством __data__
. (В этот момент вам нужно заменить // stuff
кодом, который возвращает новый массив значений.)
Вот еще один пример, показывающий данные, связанные с элементом HTML, и возможность повторного связывания подмножеств данных с нижними элементами:
![no description]()
Ответ 2
Ключом к пониманию того, что делает этот код, является распознавание того, что выбраны массивы массивов элементов DOM. Самый внешний массив называется "выбором", внутренний массив называется "группами", и эти группы содержат элементы DOM. Вы можете проверить это, зайдя в консоль на d3js.org и сделав выбор, например d3.selectAll('p'), вы увидите массив, содержащий массив, содержащий элементы "p".
В вашем примере, когда вы сначала вызываете selectAll ('tr'), вы получаете выделение с одной группой, содержащей все элементы tr. Затем каждый элемент из matrix
сопоставляется каждому элементу tr.
Но когда вы вызываете selectAll ('td') в этом выборе, выбор уже содержит группу элементов 'tr'. На этот раз каждый из этих элементов будет становиться группой элементов 'td'. Группа - это всего лишь массив, но также имеет свойство parentNode, которое ссылается на старый выбор, в данном случае на элементы tr.
Теперь, когда вы вызываете data(function(d) { return d; })
в этом новом выборе элементов 'td', d
представляет данные, привязанные к каждой родительской группе node. Таким образом, в примере "td в первой группе будет связан с массивом [11975, 5871, 8916, 2868]. Вторая группа" td связана с [1951, 10048, 2060, 6171].
Вы можете прочитать mike bostock собственное отличное объяснение выбора и привязки данных здесь: http://bost.ocks.org/mike/selection/
Ответ 3
Используйте счетчик i, чтобы показать индекс используемых данных.
var tr = d3.select("body").append("table").selectAll("tr")
.data(matrix)
.enter().append("tr") //create a row for each data entry, first index
.text(function(d, i) { return i}); // show the index i.e. d[0][] then d[1][] etc.
var td = tr.selectAll("td")
.data(function(d) { return d; })
.enter().append("td")
.style("background-color", "yellow") //show each cell
.text(function(d,i) { return i + " " + d; }); // i.e d[from the tr][0] then d[from the tr][1]...