Я пытаюсь создать полностью динамический график Sunburst, используя d3.js. Примеры и учебные пособия, которые я обнаружил, имеют тенденцию использовать существующие/полностью заполненные структуры данных, которые могут иметь возможность изменять значение существующих дуг, но не позволяют добавлять дочерние дуги по мере необходимости.d3.js sunburst с динамически построенной обновляемой структурой данных
Подобным образом у меня есть учебные пособия, которые позволяют новым наборам данных просто заменять существующую структуру и начинать рисовать с нуля. Это не то поведение, которое я пытаюсь реализовать.
Мне нужен динамически построенный граф, основанный на поступающих данных, поскольку он предоставляется.
Я могу добавить детей в конец набора данных, перейти и отобразить результаты без проблем. Проблема возникает всякий раз, когда я вставляю дочерний объект где-то в существующую структуру, d3 selectAll() не работает должным образом. Он включает новую дугу (которая еще не нарисована), в результате чего любые оставшиеся дуги отображаются неправильно. Затем при переходе дуг, кажется, получается дуги Dom ID, и данные, которые он предположительно представляет, смешиваются. Новая дуга не видна, и существует пустое пространство, где должна быть размещена новая дуга.
Чтобы быть ясно, мое намерение состоит в том:
- Добавить в существующую структуру данных, позволяя новые дети, которые будут добавлены, когда новая информация предоставляется
- Для перехода существующих дуг открытия пространства для новых дуг до они создаются и нарисовано
Сломался в четыре шага jsfiddle например:
Инициализация графа (рисует невидимый «корень» дуги)
{имя: "A_0", дети: []}
Добавление первых данных по уходу за детьми и это дети корень
{имя: "A_0", дети: [ {имя: "A_1", дети: [{имя: "a_2", дети: [{имя: "a_3"}]}]} ]}
Добавление второго ребенка и основных детей к корню
{name: "a_0", children: [ {name: "a_1", children: [{name: "a_2", children: [{name: "a_3" }]}]}, {имя: "A_4", дети: [{имя: "A_5", дети: [{имя: "a_6"}]}]} ]}
Вставка другого ребенка в течение существующая дуга a_2
{имя: "A_0", дети: [ {имя: "a_1", дети: [ {имя: "a_2", дети: [ {имя: "a_3"}, {Имя: "a_7"} ]} ]}, {имя: "A_4", дети: [ {имя: "A_5", дети: [ {имя: "a_6"} ]} ]} ]}
Шаг 1 работает нормально
Шаг 2 рисует дуги должным образом
Шаг 3 переходы существующих дуг и добавляет новые дуги к графу
Шаг 4 некоторые неожиданные результаты поведения.
При переходе существующих и ввода новых дуг некоторые из дуг «прыгать вокруг» потерять правильную ассоциацию с их соответствующими данными Конечный результат, как представляется:
- A_0 - правильно
- a_1 & a_2 - выглядеть правильно
- a_3 - сократилась до размещения нового родственный a_7 - ожидаемое поведение
- A_4 - исчезает
- A_5 - прыгает вниз, где A_4 должен быть
- a_6 - (похоже) она дублируется и существует лишь однажды, где он должен быть и где A_5 должны быть
- a_7 - не отображается, место, где оно должно быть пустое пространство и представляется связанным с данными a_6
Как выглядит конечный результат и что происходит на самом деле, это не то же самое.
- В попытке обновить график SelectAll() для существующих дуг включает в себя (A_0, a_1, a_2, a_3, A_4, A_5, a_7). Если существующий a_6 не включен в selectAll(), но a_7 (который не был нарисован).
- ввода() функция, как представляется, работать на существующих a_6, который затем рассматривается как новая дуга
Похоже, я был на правильном пути, получить всю дорогу до a_6, но я не понял, из-за причины поведения при добавлении a_7.
jsFidde выполняет шаги, как описано выше, в том числе:
- Уникальные цвета для каждой дуги
- таблица отображения названия каждой дуги,
- Если дуга обрабатывается с помощью d3js 'selectAll() (т. е. «существующий») или введите() (т.е. «новый»),
- Указатель d3, который в настоящее время назначается при рисовании существующих или новых дуг.
- Ожидаемого конечное положения, где каждая дуга должна появиться после любого перехода,
- Arctween информации как дуга осуществляется переход от своего прежнего места на новое место и
Вопросы:
- Что происходит, это может привести к такому поведению на шаге 4?
- Есть ли способ обеспечить целостность между каждой дугой и данными, которые она представляет?
- Есть ли способ вставить детей в существующую структуру или обновить график в этой динамичной усадьбе?
Рабочий пример на jsfiddle https://jsfiddle.net/mfitzgerald/j2eowwya/
var dataObj = { name:"a_0", color: "none" };
var height = 300;
var width = 500;
var radius = Math.min(width, height)/2;
var graph = d3.select("#graph")
.attr('height', height)
.attr('width', width)
.append("g")
.attr("transform", "translate(" + width/2 + "," + height/2 + ")");
var partition = d3.layout.partition()
.sort(null)
.size([2 * Math.PI, radius * radius])
.value(function(d, i) { return 1; });
var arc = d3.svg.arc()
.startAngle(function(d) { if (isNaN(d.x)) { d.x = 0; } d.x0 = d.x; return d.x; })
.endAngle(function(d) { if (isNaN(d.dx)) { d.dx = 0; } d.dx0 = d.dx; return d.x + d.dx; })
.innerRadius(function(d) { if (isNaN(d.y)) { d.y = 0; } d.y0 = d.y; return Math.sqrt(d.y); })
.outerRadius(function(d) { if (isNaN(d.dy)) { d.dy = 0; } d.dy0 = d.dy; return Math.sqrt(d.y + d.dy); });
var arcTween = function(a) {
var i = d3.interpolate({x: a.x0, dx: a.dx0, y: a.y0, dy: a.dy0}, a);
return function(t) {
var b = i(t);
a.x0 = b.x;
a.dx0 = b.dx;
a.y0 = b.y;
a.dy0 = b.dy;
displayStats("arctween", b);
return arc(b);
};
}
// Root Arc
graph.datum(dataObj).selectAll('path.arc')
.data(partition.nodes)
.enter()
.append('path')
.attr('class', function(d) { return "arc " + d.name; })
.attr("d", arc)
.attr("id", function(d, i) { return "path_"+i; })
.attr("name", function(d) { return d.name; })
.style("fill", "none");
function updateGraph() {
console.log("Update Graph");
console.log(dataObj);
var update = graph.datum(dataObj).selectAll('path.arc')
.data(partition.nodes);
// Move existing Arcs
update.each(function(d, i) {
displayStats("target", d, i, "existing");
var domId = $(this).attr("id");
console.log("["+i+"] Exist Arc name:"+d.name+", dom_id:"+domId);
})
.transition()
.delay(function(d, i) { return i * 250; })
.duration(1500)
.attrTween("d", arcTween);
// Add New Arcs
update.enter().append('path')
.attr('class', function(d, i) { return "arc "+d.name; })
.attr("d", arc)
.attr("id", function(d, i) {
var domId = "path_"+i;
console.log("["+i+"] NEW Arc name:"+d.name+", dom_id:"+domId);
displayStats("target", d, i, "new");
return domId;
})
.style("stroke", "#fff")
.style("fill", function(d) { return d.color; })
.style("opacity", 0)
.transition()
.delay(function(d, i) { return i * 250; })
.duration(1500)
.style("opacity", .5)
.attrTween("d", arcTween);
}
Похоже, вам понадобится [использовать ключевую функцию] (https://bost.ocks.org/mike/constancy/) при присоединении данных к '.data()', чтобы старые данные привязывались к старые объекты и новые данные привязаны к новым объектам, а не просто привязываются индексом в массиве. – Gordon
Это трюк! Я разработал jsfiddle с исправлением [здесь] (https://jsfiddle.net/mfitzgerald/qvwcc4cf/). Переходы должны быть изменены. Но большая проблема была решена! Спасибо за помощь –