Почему 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 объясняет это в своей концепции объединения. Я рассматриваю это здесь для полноты:

У вас есть два набора (массивы):

  1. набор данных, который управляет визуализацией;
  2. элементы HTML, которые представляют каждый элемент данных в этом наборе данных.

Эти наборы не могут быть точно такими же в любой момент времени при запуске приложения. Представьте себе набор данных в реальном времени (поток) - возможно, в прошлый раз мы получили только 98 элементов, теперь вместо этого у нас есть 100. На странице все еще есть 98 <div> s, но теперь нам нужно создать еще 2. Это то, что происходит автоматически, в вашем коде:

  1. Вызвав .selectAll("svg") вы говорите: "Создайте набор элементов <svg> даже если они не существуют". Другой способ выразить это: "Представьте себе, что мы можем выбрать набор <svg> который соответствует набору данных, который мы дали. Теперь идите и создайте этот набор".
  2. ... Это именно то, что .enter().append(...) тогда делает. И наоборот, если для нашего нового набора данных было слишком много элементов (потому что раньше мы имели больше элементов в наборе данных, чем сейчас), .exit().remove(...) справится с этим.

enter - набор элементов, которые нам нужно создать; exit - это те, которые нам нужно удалить.

Ваш .selectAll("svg") ничего не вернет, но поскольку это скорее предложение, чем императив, он затем создает то, что ему нужно в .enter().append("svg"), чтобы соответствовать заданному набору данных,