Обновление layout.pack в d3.js
Я пытаюсь обратить внимание на макет d3 pack (http://bl.ocks.org/4063530).
У меня есть основной макет, но я хотел бы обновить его новыми данными. т.е. собирать новые данные, привязывать их к текущему layout.pack и соответственно обновлять (update/exit/enter).
Мои попытки здесь (http://jsfiddle.net/emepyc/n4xk8/14/):
var bPack = function(vis) {
var pack = d3.layout.pack()
.size([400,400])
.value(function(d) {return d.time});
var node = vis.data([data])
.selectAll("g.node")
.data(pack.nodes)
.enter()
.append("g")
.attr("class", function(d) { return d.children ? "node" : "leaf node"; })
.attr("transform", function(d) { return "translate(" + d.x + "," + d.y + ")"; });
node.append("circle")
.attr("r", function(d) { return d.r });
node.filter(function(d) { return !d.children; }).append("text")
.attr("text-anchor", "middle")
.attr("dy", ".3em")
.text(function(d) { return d.analysis_id });
bPack.update = function(new_data) {
console.log("UPDATE");
node
.data([new_data])
.selectAll("g.node")
.data(pack.nodes);
node
.transition()
.duration(1000)
.attr("class", function(d) { return d.children ? "node" : "leaf node" })
.attr("transform", function(d) { return "translate(" + d.x + "," + d.y + ")" });
node.selectAll("circle")
.data(new_data)
.transition()
.duration(1000)
.attr("r", function(d) { return d.r; });
};
Конкретные вопросы...
Как мне привязать данные? (поскольку данные не являются сложной структурой, а не массивом данных)
Как добавить новые узлы/листья в макет? А старые удалены?
Указатели на рабочий пример будут очень благодарны.
Ответы
Ответ 1
Рабочий пример здесь.
В принципе, есть код для начальной загрузки, где все круги, всплывающие подсказки и т.д. создаются и размещаются в начальных местах. Кроме того, создается макет (пакет).
Затем, при каждом нажатии кнопки новые данные загружаются в пакет, а пакет пересчитывается. Этот важный код здесь:
Здесь вы связываете (загружаете) теперь данные в макет пакета: (в моем примере его случайные данные, конечно, у вас будут данные из json или кода или аналогичные):
pack.value(function(d) { return 1 +
Math.floor(Math.random()*501); });
Здесь вычисляется новый макет:
pack.nodes(data);
После этого элементы переходят в новые позиции, а его атрибуты изменяются по мере их определения.
Я просто хочу подчеркнуть, что я не использую шаблон ввода/обновления/выхода или преобразования (что вы можете увидеть в других решениях), так как я считаю, что это приводит к излишней сложности для таких примеров.
Вот несколько фото с переходом в действии:
Начало:
![start]()
Переход:
![transition]()
Конец:
![end]()
Ответ 2
У меня была такая же проблема в последнее время, и натолкнулся на учебные пособия General Update Pattern. Это не помогло моей цели. У меня было несколько сотен элементов DOM на графике (ForceLayout), и я возвращал данные REST со свойствами для каждого отдельного node. Обновление с помощью перезаписи данных привело к восстановлению всего графика, как вы сказали в ответ на предложение mg1075. Потребовалось несколько минут, чтобы закончить обновление DOM в моем случае.
В конце концов я назначил уникальные идентификаторы элементам, которые нуждаются в обновлении позже, и я вишневый взял их с помощью JQuery. Вся моя настройка графика использует D3, но тогда мои обновления не работают. Это плохо, но все работает отлично. Вместо того, чтобы тратить минуты на уничтожение и воссоздание большей части моего DOM, требуется примерно 3 секунды (исключая время для вызовов REST). Я не вижу причины, что в D3 невозможно сделать что-то вроде обновлений свойств.
Возможно, если бы Майк Босток добавил функцию remove() или правильную функцию подсекремента к выбору enter(), мы могли бы следовать за чистым шаблоном D3, чтобы делать обновления. Выяснив это, я пытался связать подмножество данных, данные с новыми добавленными свойствами, а затем подбирать элементы для обновления, но это не сработало из-за ограниченности и специфики ввода().
Ответ 3
Актуальность, если вы еще не просмотрели:
http://bl.ocks.org/3808218 - Общий шаблон обновления, я
http://bl.ocks.org/3808221 - общий шаблон обновления, II
http://bl.ocks.org/3808234 - общий шаблон обновления, III
В этом примере скрипта нет переходов, но здесь есть хотя бы один подход для обновления данных.
http://jsfiddle.net/jmKH6/
// VISUALIZATION
var svg = d3.select("#kk")
.append("svg")
.attr("width", 500)
.attr("height", 600)
.attr("class", "pack");
var g = svg.append("g")
.attr("transform", "translate(2,2)");
var pack = d3.layout.pack()
.size([400,400])
.value(function(d) {return d.time});
function update(data) {
var nodeStringLenth = d3.selectAll("g.node").toString().length;
if ( nodeStringLenth > 0) {
d3.selectAll("g.node")
.remove();
}
var node = g.data([data]).selectAll("g.node")
.data(pack.nodes);
node.enter()
.append("g")
.attr("class", function(d) { return d.children ? "node" : "leaf node"; })
.attr("transform", function(d) { return "translate(" + d.x + "," + d.y + ")"; });
node.append("circle")
.attr("r", function(d) { return d.r });
node.filter(function(d) { return !d.children; }).append("text")
.attr("text-anchor", "middle")
.attr("dy", ".3em")
.text(function(d) { return d.analysis_id });
node
.exit()
.remove();
}
var myData = [data1, data2, data3];
update(data1);
setInterval(function() {
update( myData[Math.floor(Math.random() * myData.length)] ); // http://stackoverflow.com/info/4550505/getting-random-value-from-an-array?lq=1
}, 1500);