Почему d3 select() и selectAll() ведут себя по-другому здесь?
Я играю с примером drag multiples, и я заметил то, что не могу объяснить.
В этом фрагменте:
var svg = d3.select("body").selectAll("svg")
.data(d3.range(16).map(function() { return {x: width / 2, y: height / 2}; }))
.enter().append("svg")
.attr("width", width)
.attr("height", height);
Я изменил selectAll
на select
. Он по-прежнему работает, но теперь элементы svg
добавляются после тега </body>
. Исходный код с selectAll
добавляет их после тега <body>
, как и следовало ожидать.
Поскольку исходный html не содержит жестко закодированного элемента <svg>
, я бы подумал, что оба select
и selectAll
просто возвращают пустой выбор. Поэтому я не могу понять, почему они приводят к другому поведению.
Я просто ищу объяснения. Спасибо!
Ответы
Ответ 1
Основное отличие между select и selectAll заключается в том, что select squash иерархии существующих выборов, а selectAll сохраняет его.
Поэтому, когда вы используете один selectAll после другого, результат будет очень похож на список вложенных циклов.
http://bost.ocks.org/mike/nest/
Ответ 2
Проверьте сообщение Майка Бостока о select/selectAll: Вложенные выборки
Цитата:
Существует важная разница между select и selectAll: select сохраняет существующую группировку, тогда как selectAll создает новую группировку. Таким образом, выбор вызова сохраняет данные, индекс и даже родительский node исходного выбора!
Ответ 3
Другие ответы здесь немного неактуальны и не приводят правильный источник; это касается только касательной к гнездованию. Автор D3 объясняет это в своей концепции объединения. Я рассматриваю это здесь для полноты:
У вас есть два набора (массивы):
- набор данных, который управляет визуализацией;
- элементы HTML, которые представляют каждый элемент данных в этом наборе данных.
Эти наборы не могут быть точно такими же в любой момент времени при запуске приложения. Представьте себе набор данных в реальном времени (поток) - возможно, в прошлый раз мы получили только 98 элементов, теперь вместо этого у нас есть 100. На странице все еще есть 98 <div>
s, но теперь нам нужно создать еще 2. Это то, что происходит автоматически, в вашем коде:
- Вызвав
.selectAll("svg")
вы говорите: "Создайте набор элементов <svg>
даже если они не существуют". Другой способ выразить это: "Представьте себе, что мы можем выбрать набор <svg>
который соответствует набору данных, который мы дали. Теперь идите и создайте этот набор". - ... Это именно то, что
.enter().append(...)
тогда делает. И наоборот, если для нашего нового набора данных было слишком много элементов (потому что раньше мы имели больше элементов в наборе данных, чем сейчас), .exit().remove(...)
справится с этим.
enter
- набор элементов, которые нам нужно создать; exit
- это те, которые нам нужно удалить.
Ваш .selectAll("svg")
ничего не вернет, но поскольку это скорее предложение, чем императив, он затем создает то, что ему нужно в .enter().append("svg")
, чтобы соответствовать заданному набору данных,