Я разработал последовательный шаблон для использования нового слияния выбора, который отлично подходит для многоразовых диаграмм, где данные и / или масштабы могут изменяться.

Я также успешно использую ключевую функцию.

Однако у меня, похоже, возникают проблемы при вводе и добавлении группы с несколькими элементами. Данные успешно обновлены в группе, но не в добавленных элементах.

Я обошел это, добавив исправление (см. Ниже), но я уверен, что это что-то действительно очевидное, что нужно изменить, чтобы решить эту проблему.

Любые мысли?

//define data group 
var my_group = svg.selectAll(".data_group")
                  .data(my_data,function(d){return d.id});

//enter new groups
var enter = my_group.enter()
                    .append("g")
                    .attr("class","data_group");

//append items to group
enter.append("text").attr("class","group_item group_text")
enter.append("circle").attr("class","group_item group_circle");

//merge and remove
my_group.merge(enter);
my_group.exit().remove();

//fix added to reset changing data for bars.
d3.selectAll(".group_item").each(function(d){
  d3.select(this)._groups[0][0].__data__ = d3.select(this)._groups[0][0].parentElement.__data__;
});

d3.selectAll(".group_text")
  .... add properties to text - ie x,y,fill,text-anchor,text 

d3.selectAll(".group_circle")
     .... add properties to circle - ie cx,cy,fill,stroke,radius
1
Bmil 25 Сен 2018 в 16:00

2 ответа

Лучший ответ

Нет абсолютно никакой необходимости в выборе родительской группы, получении ее данных и повторной привязке к дочерним элементам, как это делают код в вашем вопросе и другом ответе. Это наклон назад. Кроме того, не удаляйте / не добавляйте элементы повторно, как это предлагается, что не идиоматический подход D3.

Все просто: новые данные есть для дочерних элементов в выборе «ввод». Вам просто нужно использовать родительский выбор (с select()) для их распространения.

Вот базовая демонстрация с использованием (большей части) вашего кода. Код генерирует от 1 до 5 объектов данных со случайным свойством, называемым someProperty. Вы увидите, что с помощью each() изменяются только дочерние элементы в выбранном "вводе":

var svg = d3.select("svg");
d3.interval(function() {
  var data = d3.range(1 + ~~(Math.random() * 4)).map(function(d) {
    return {
      id: "id" + d,
      "someProperty": ~~(Math.random() * 100)
    }
  });
  update(data);
}, 2000);

function update(my_data) {
  var my_group = svg.selectAll(".data_group")
    .data(my_data, function(d) {
      return d.id
    });

  my_group.exit().remove();

  var enter = my_group.enter()
    .append("g")
    .attr("class", "data_group");

  enter.append("text").attr("class", "group_item group_text")
  enter.append("circle").attr("class", "group_item group_circle");

  my_group = my_group.merge(enter);


  console.log("---")

  d3.selectAll(".group_text").each(function(d) {
    console.log(JSON.stringify(d))
  });
}
.as-console-wrapper { max-height: 100% !important;}
<script src="https://d3js.org/d3.v5.min.js"></script>
<svg></svg>

Теперь, если мы воспользуемся выбором вашего родителя ...

my_group.select(".group_text").each(function(d) {
    console.log(d)
})

... вы увидите, что все свойства обновлены:

var svg = d3.select("svg");
d3.interval(function() {
  var data = d3.range(1 + ~~(Math.random() * 4)).map(function(d) {
    return {
      id: "id" + d,
      "someProperty": ~~(Math.random() * 100)
    }
  });
  update(data);
}, 2000);

function update(my_data) {
  var my_group = svg.selectAll(".data_group")
    .data(my_data, function(d) {
      return d.id
    });

  my_group.exit().remove();

  var enter = my_group.enter()
    .append("g")
    .attr("class", "data_group");

  enter.append("text").attr("class", "group_item group_text")
  enter.append("circle").attr("class", "group_item group_circle");

  my_group = my_group.merge(enter);


  console.log("---")

  my_group.select(".group_text").each(function(d) {
    console.log(d)
  })
}
<script src="https://d3js.org/d3.v5.min.js"></script>
<svg></svg>

Наконец, в вашем теперь удаленном ответе вы используете my_group.selectAll(). Проблема в том, что selectAll() не распространяет данные.

Взгляните на эту таблицу, которую я составил:

+------------------+----------------------------------+----------------------------+
| Method           |              select()            |         selectAll()        |
+------------------+----------------------------------+----------------------------+
| Selection        | selects the first element        | selects all elements that  |
|                  | that matches the selector string | match the selector string  |
+------------------+----------------------------------+----------------------------+
| Grouping         | Does not affect grouping         | Affects grouping           |
+------------------+----------------------------------+----------------------------+
| Data propagation | Propagates data                  | Doesn't propagate data     |
+------------------+----------------------------------+----------------------------+

Обратите внимание на то, что распространяет данные , а не не распространяет данные .

1
Gerardo Furtado 26 Сен 2018 в 02:32

Более d3 способ копирования данных, связанных с родительскими элементами g

Не нужно добавлять исправление

d3.selectAll(".group_text")
    .datum(function () { return d3.select(this.parentNode).datum(); } )
    //   .... add properties to text - ie x,y,fill,text-anchor,text 

d3.selectAll(".group_circle")
    .datum(function () { return d3.select(this.parentNode).datum(); } )
    //   .... add properties to circle - ie cx,cy,fill,stroke,radius
0
rioV8 25 Сен 2018 в 13:59