Я использую d3.js, чтобы выложить узел и график ссылок, используя схему силы. Узлы представлены кругами; ссылки по строкам. При определенных обстоятельствах я хотел бы изменить визуальные характеристики (например, цвет, размер, непрозрачность и т. Д.) Строки или узла, чтобы обозначить некоторое изменение состояния на графике. Я смог сделать это, перерисовывая график, но это смещает все узлы, что приводит к запутанности, а не ясности.Изменение свойств узла и края в d3.js
кода для создания графика:
force = d3.layout.force()
.charge(-120)
.gravity(0.2)
.linkDistance(30)
.size([width-pad, height-pad]);
nodeSet = svg.selectAll(".qNode");
// BIND NODE DATA
nodeSet = nodeSet.data(chartData.nodes);
// CREATE NODES
nodeSet.enter().append("circle")
.attr("class", "qNode")
.attr("r", function(d) { return d.size();})
.style('stroke-opacity', function(d) { return d.opacity(); })
.style('stroke', function(d) { return d.color(); })
.style("fill", function(d) { return color(1); });
//similarly for links.
force.nodes(chartData.nodes).links(chartData.links).start();
Чтобы обновить граф, я использую этот фрагмент:
// SELECT NODES
nodeSet = svg.selectAll('.qNode');
// JOIN NODES
nodeSet = nodeSet.data(force.nodes());
// UPDATE NODES
nodeSet.attr("class", "qNode")
.attr("r", function(d) { return d.size();})
.style("fill", function(d) { return color(1); })
.style('stroke', function(d) { return d.color(); })
.style('stroke-opacity', function(d) { return d.opacity(); })
.style('opacity', 1)
.call(force.drag);
// CREATE NODES
nodeSet.enter().append("circle")
.attr("class", "qNode")
.attr("r", function(d) { return d.size();})
.style("fill", function(d) { return color(1); })
.call(force.drag);
// DELETE NODES
nodeSet.exit().remove();
// START SHOW
force.start();
Когда это работает, весь граф покачивание немного раньше, то новые атрибуты обводки применяется.
Поэтому у меня есть два вопроса: Предположим, что изменение состояния в объекте данных будет возвращать разные значения для d.size()
, d.color()
и т.д.,
- Как изменить внешний вид графика без переустройства каких-либо узлов ?
- Если я хочу перетащить узлы, могу ли я определить, какой набор узлов нужно перетащить? (Так что я могу сигнализировать пользователю, который Линкор узел имел их визуальное изменение внешнего вида.)
EDITED
Я отказался от переустройства узлов на некоторое время, но следующий код (на основе предложений по @defenestrated), кажется, сделать трюк, чтобы обновить свойства некоторых узлов и ребер в графе:
var allLinks = ... // my links from a d3 selectAll
var allNodes = ... // my nodes from a d3 selectAll
force = ... // my d3 force layout
function updateGraph(graph, nodeSubset, linkSubset) {
for (var i=0; i<allLlinks.length; i++)
allLinks[i].selected = false;
for (var i=0; i<allNodes.length; i++)
allNodes[i].selected = false;
for (var i=0; i<linkSubset.length; i++)
linkSubset[i].selected = true;
for (var i=0; i<nodeSubset.length; i++)
nodeSubset[i].selected = true;
// these functions modify the selected nodes and links
linkSubset.call(setLinkAttributes);
nodeSubset.call(setNodeAttributes);
if (force.alpha() == 0) {
force.start();
force.stop();
}
}
function setLinkAttributes(links) {
link.style(...);
}
function setNodeAttributes(nodes) {
nodes.style(...);
}
мне не нужно называть start
/stop
или resume
, если график все еще перемещается (если alpha() > 0
) после применения атрибутов, потому что последующие тики захватывают новые атрибуты. Если график установлен, вызов начинает обновлять его, не перемещая узлы.
Как я могу знать, какие узлы изменить (я бы, вероятно, использовать 'class' атрибут, а не' id'), чтобы сделать последующее '.select)' вызов работы (? Я предполагаю, что некоторые данные привязаны к некоторым элементам SVG; изменения данных ... как узнать, какие элементы нужно изменить? –
Я просто сказал «id' beacuse, что у вас уже есть класс« qNode », который я не хотел испортить ... и что, если вы установите какой-то произвольный атрибут на данные, когда он изменится, - так, где бы вы ни изменялись или обновить данные, добавьте что-то вроде этого: 'nodes.forEach (function (d, i) {d.changed = true});' - тогда я думаю, что вы можете сделать свой выбор позже, выполнив регулярный вызов '.select' с функцией выбора: 'nodes.select (function (d, i) {return d.changed == true? this: null}' - см. [this] (https: // github.com/mbostock/d3/wiki/Selections # wiki-filter) для получения дополнительной информации о фильтрации – defenestrated
Спасибо за ответ на вопрос # 1: вызов 'force.start(); force.stop(); 'правильно обновил внешний вид. Что касается настройки узлов, которые изменились, это не сработало: когда я ограничил набор узлов и ребер выбранным набором, они были перемещены в середину диаграммы, игнорируя другие узлы. Думаю, я мог бы исправить весь набор узлов, а затем просто нагреть те, которые хочу выделить, но это кажется слишком сложным. Думаю, мне нужно лучшее решение. –