Данные раздела солнечных лучей перезаписываются вторыми солнечными лучами на той же странице

Публикация вопроса и ответа здесь, чтобы спасти кого-то еще от этой проблемы позже...

Когда я создаю две диаграммы солнечных лучей, используя d3.layout.partition, пропорции среза первого солнечного луча перезаписываются пропорциями среза второго солнечного луча при изменении размера срезов.

Два графика проходят разные .value функции доступа в макет раздела, например

d3.layout.partition()
.sort(null)
.value(function(d) { return 1; });

против

d3.layout.partition()
.sort(null)
.value(function(d) { return d.size; });

И они генерируют свой собственный список узлов, которые не используются двумя солнечными вспышками. Однако, если я перезвоню d3.svg.arc Генератор для изменения размера до большего радиуса (но не изменения общих пропорций), углы среза внезапно перезаписываются.

Смотрите пример здесь: http://bl.ocks.org/explunit/ab8cf15534f7fec5ac6d

2 ответа

Проблема в том, что пока partition.nodes() кажется, генерирует новую структуру данных (например, если вы даете ей некоторые .key функции, он записывает дополнительные свойства (например, .x, .y, .dx, dy) к базовым данным и не делает копию данных. Таким образом, если структура данных разделяется между двумя графиками, эти .x, .y, .dx, dy свойства будут распространяться на другие графики.

Мне кажется, что это ошибка, но при чтении этой старой проблемы с GitHub она воспринимается как "намеренно". Возможно, это будет пересмотрено в будущих версиях.

Один из способов - использовать что-то вроде Lodash/Underscore cloneDeep или ангулярный copy чтобы каждая диаграмма имела свою собственную копию данных.

makeSunburst(null, _.cloneDeep(root), countAccessorFn);
makeSunburst(null, _.cloneDeep(root), sizeAccessorFn);

Смотрите пример здесь: http://bl.ocks.org/explunit/e9efb830439247eea1be

Альтернативой копированию всего набора данных для каждой диаграммы может быть просто пересчет раздела перед повторным рендерингом.

Вместо того, чтобы иметь makeSunburst() быть функцией доступа, сделать его функцией раздела. Передайте различные функции разделения для каждого графика:

// create separate partition variables
var countPartition = d3.layout.partition().sort(null).value(countAccessorFn);
var sizePartition = d3.layout.partition().sort(null).value(sizeAccessorFn);

// make the charts as a function of partition
charts.push(makeSunburst(root, countPartition));
charts.push(makeSunburst(root, sizePartition));

Затем, прежде чем применять переход, просто обновите nodes переменная для отображения связанного раздела:

addToRadius: function(radiusChange) {
  radius += radiusChange;
  ringRadiusScale.range([0, radius]);

  // update the data before re-rendering each chart
  nodes = partition.nodes(dataRoot);
  path.transition().attr('d', arc);
}

Теперь, когда вы обновляете каждый график, он использует правильный раздел.

Вот обновленный пример.

Другие вопросы по тегам