2013-02-16 3 views
2

Я использую 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() и т.д.,

  1. Как изменить внешний вид графика без переустройства каких-либо узлов ?
  2. Если я хочу перетащить узлы, могу ли я определить, какой набор узлов нужно перетащить? (Так что я могу сигнализировать пользователю, который Линкор узел имел их визуальное изменение внешнего вида.)

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) после применения атрибутов, потому что последующие тики захватывают новые атрибуты. Если график установлен, вызов начинает обновлять его, не перемещая узлы.

ответ

1
  1. вы пробовали вызов force.stop() перед блоком «обновление узлов», и force.resume() после?

  2. вы можете классифицировать их на основе их состояния - так что вы должны применить .attr("id", "changed") к обновляемым узлам, а затем использовать их в выборе d3, например. changedNodes = d3.select("#changed")

+0

Как я могу знать, какие узлы изменить (я бы, вероятно, использовать 'class' атрибут, а не' id'), чтобы сделать последующее '.select)' вызов работы (? Я предполагаю, что некоторые данные привязаны к некоторым элементам SVG; изменения данных ... как узнать, какие элементы нужно изменить? –

+0

Я просто сказал «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

+0

Спасибо за ответ на вопрос # 1: вызов 'force.start(); force.stop(); 'правильно обновил внешний вид. Что касается настройки узлов, которые изменились, это не сработало: когда я ограничил набор узлов и ребер выбранным набором, они были перемещены в середину диаграммы, игнорируя другие узлы. Думаю, я мог бы исправить весь набор узлов, а затем просто нагреть те, которые хочу выделить, но это кажется слишком сложным. Думаю, мне нужно лучшее решение. –

Смежные вопросы