从动态 json 数据更新力有向图上的链接 [英] Updating links on a force directed graph from dynamic json data

查看:23
本文介绍了从动态 json 数据更新力有向图上的链接的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我是 D3 的新手,正在研究一个力有向图,其中 json 数据是动态的.我能够在收到新数据时更改力图,但这会产生弹性效果.创建我的力图的代码是:

<脚本>无功 w = 660,h = 700,r = 10;var vis = d3.select(".graph").append("svg:svg").attr("宽度", w).attr("高度", h).attr("指针事件", "所有").append('svg:g').call(d3.behavior.zoom().on("zoom", redraw)).append('svg:g');vis.append('svg:rect').attr('宽度', w).attr('高度', h).attr('填充', 'rgba(1,1,1,0)');函数重绘(){console.log("这里", d3.event.translate, d3.event.scale);vis.attr("transform", "translate(" + d3.event.translate + ")" +" scale(" + d3.event.scale + ")");};var force = d3.layout.force().重力(.05).charge(-200).linkDistance(260).size([w, h]);var svg = d3.select(".text").append("svg").attr("宽度", w).attr("高度", h);d3.json(图形,函数(json){var nodeList = json.nodes;var link = vis.selectAll("line").data(json.links).进入().append("行").attr(笔画不透明度",函数(d){if(d.label == 'is a') {返回'0.8';} 别的 {返回'0.2';};}).attr(笔画宽度",函数(d){if(d.value !== null) {返回 d.value;} 别的 {返回2;};}).style("stroke", function(d) {if(d.color !== null) {返回 d.color;};}).on(鼠标悬停",函数(){d3.select(this).style("中风", "#999999").attr("笔画不透明度", "1.0");}).on("mouseout", function() {d3.select(this).style("stroke", function(d) {if(d.color !== null) {返回 d.color;};}).attr(笔画不透明度",函数(d){if(d.label == 'is a') {返回'0.8';} 别的 {返回'0.2';};})});link.append("title").text(function(d) { return d.label } );var node = vis.selectAll("g.node").data(json.nodes).进入().append("svg:g").attr(类",节点").call(force.drag);node.append("svg:circle").attr(r",函数(d){如果 (d.size > 0) {返回 10+(d.size*2);} 别的 {返回 10;}}).attr("id", function(d) { return "Node;"+d.id; } ).style(填充",功能(d){如果(d.style == '填充'){返回 d.color;};}).style("stroke", function(d) {if(d.style !== '填充') {返回 d.color;};}).style("笔画宽度", "2").on(鼠标悬停",函数(){d3.select(this).style("fill", "#999");淡入淡出(.1);}).on("mouseout", function(d) {如果(d.style == '填充'){d3.select(this).style("fill",d.color);fade(1);} 别的 {d3.select(this).style("stroke",d.color);d3.select(this).style("fill","black");}淡入淡出(1);});node.append("title").text(function(d) { return d.Location; } );force.nodes(json.nodes).links(json.links).on("tick", 勾号).alpha(1).开始();功能滴答(){node.attr("cx", function(d) { return d.x; }).attr("cy", function(d) { return d.y; }).attr(转换",函数(d){返回 "translate(" + d.x + "," + d.y + ")";});link.attr("x1", function(d) { return d.source.x; }).attr("y1", function(d) { return d.source.y; }).attr("x2", function(d) { return d.target.x; }).attr("y2", function(d) { return d.target.y; });}});

通过再次调用整个函数,我可以在收到新的 json 字符串时创建新图.这会创建一个新图形来代替旧图形.我无法在收到值时使用新值集更新旧图;我图中的节点没有变化,只是它们之间的关系发生了变化.

我确实偶然发现了一个示例 (http://bl.ocks.org/1095795),其中一个新节点被删除并重新创建,但实现有点不同.

任何指示或帮助将不胜感激.

解决方案

好吧,我可以通过浏览找到解决方案,将其张贴在此处以供在此主题上需要帮助的任何人使用.这个想法是创建图形的对象并使用节点和链接数组.JS代码如下:

var 图;函数 myGraph(el) {//添加和删除图形对象上的元素this.addNode = 函数(id){节点.push({"id":id});更新();};this.removeNode = 函数(id){变量 i = 0;var n = findNode(id);而(我<链接.长度){if ((links[i]['source'] == n)||(links[i]['target'] == n)){链接.拼接(i,1);}否则我++;}节点.splice(findNodeIndex(id),1);更新();};this.removeLink = 函数(源,目标){for(var i=0;i

I am new to D3 and working on a force directed graph where the json data is dynamic. I am able to change the force graph upon receiving new data but that happens with a springing effect. The code that creates my force graph is :

<div class="graph"></div>
<script>
var w = 660,
    h = 700,
    r = 10;
var vis = d3.select(".graph")
    .append("svg:svg")
    .attr("width", w)
    .attr("height", h)
    .attr("pointer-events", "all")
    .append('svg:g')
    .call(d3.behavior.zoom().on("zoom", redraw))
    .append('svg:g');
vis.append('svg:rect')
    .attr('width', w)
    .attr('height', h)
    .attr('fill', 'rgba(1,1,1,0)');
function redraw() {
    console.log("here", d3.event.translate, d3.event.scale);
    vis.attr("transform", "translate(" + d3.event.translate + ")" +
                          " scale(" + d3.event.scale + ")");
};  

var force = d3.layout.force()
    .gravity(.05)
    .charge(-200)
    .linkDistance( 260 )
    .size([w, h]);

var svg = d3.select(".text")
    .append("svg")
    .attr("width", w)
    .attr("height", h);

d3.json(graph, function(json) {

    var nodeList = json.nodes;
    var link = vis.selectAll("line")
        .data(json.links)
       .enter()
        .append("line")
        .attr("stroke-opacity", function(d) {
            if(d.label == 'is a') {
                return '0.8';
            } else {
                return '0.2';
            };
        })
        .attr("stroke-width", function(d) {
            if(d.value !== null) {
                return d.value;
            } else {
                return 2;
            };
        })
        .style("stroke", function(d) {
            if(d.color !== null) {
                return d.color;
            };
        })
        .on("mouseover", function() {
            d3.select(this)
                .style("stroke", "#999999")
                .attr("stroke-opacity", "1.0");
        })
        .on("mouseout", function() {
            d3.select(this)
                .style("stroke", function(d) {
                    if(d.color !== null) {
                        return d.color;
                    };
                })
                .attr("stroke-opacity", function(d) {
                    if(d.label == 'is a') {
                        return '0.8';
                    } else {
                        return '0.2';
                    };
                })
            });

    link.append("title")
        .text(function(d) { return d.label } );         

    var node = vis.selectAll("g.node")
        .data(json.nodes)
       .enter()
        .append("svg:g")
        .attr("class","node")
        .call(force.drag);

    node.append("svg:circle")
        .attr("r", function(d) {
            if (d.size > 0) {
                return 10+(d.size*2);
            } else {
                return 10;
            }
        })
        .attr("id", function(d) { return "Node;"+d.id; } )
        .style("fill", function(d) {
            if(d.style == 'filled') {
               return d.color;
            };
        })
        .style("stroke", function(d) {
            if(d.style !== 'filled') {
                return d.color;
            };
        })
        .style("stroke-width", "2")
        .on("mouseover", function() {
            d3.select(this).style("fill", "#999");
            fade(.1);
        })
        .on("mouseout", function(d) {
            if (d.style == 'filled') {
                d3.select(this).style("fill",d.color);fade(1);
            } else {
                d3.select(this).style("stroke",d.color);
                d3.select(this).style("fill","black");
            }
            fade(1);
        });

    node.append("title")
        .text(function(d) { return d.Location; } );         

    force.nodes(json.nodes)
        .links(json.links)
        .on("tick", tick)
        .alpha(1)
        .start();

    function tick() {
    node.attr("cx", function(d) { return d.x; })
        .attr("cy", function(d) { return d.y; })
        .attr("transform", function(d) {
            return "translate(" + d.x + "," + d.y + ")";
    });

    link.attr("x1", function(d) { return d.source.x; })
        .attr("y1", function(d) { return d.source.y; })
        .attr("x2", function(d) { return d.target.x; })
        .attr("y2", function(d) { return d.target.y; });
    }

});
</script>

I am able to create a new graph when a new json string is received by recalling the whole function again. This creates a new graph in place of the old. I am unable to update the old graph with the new set of values as the values are received; the nodes in my graph do not change, just the relation among them changes.

I did stumble upon an example (http://bl.ocks.org/1095795) where a new node is deleted and recreated, but the implementation is a bit different.

Any pointers or help will be really appreciated.

解决方案

Well I could find the solution browsing through, posting it here for anyone needing help on this topic. The idea is to create an object of the graph and playing around with the nodes and links arrays. The JS code goes as:

var graph;
function myGraph(el) {

// Add and remove elements on the graph object
this.addNode = function (id) {
    nodes.push({"id":id});
    update();
};

this.removeNode = function (id) {
    var i = 0;
    var n = findNode(id);
    while (i < links.length) {
        if ((links[i]['source'] == n)||(links[i]['target'] == n))
        {
            links.splice(i,1);
        }
        else i++;
    }
    nodes.splice(findNodeIndex(id),1);
    update();
};

this.removeLink = function (source,target){
    for(var i=0;i<links.length;i++)
    {
        if(links[i].source.id == source && links[i].target.id == target)
        {
            links.splice(i,1);
            break;
        }
    }
    update();
};

this.removeallLinks = function(){
    links.splice(0,links.length);
    update();
};

this.removeAllNodes = function(){
    nodes.splice(0,links.length);
    update();
};

this.addLink = function (source, target, value) {
    links.push({"source":findNode(source),"target":findNode(target),"value":value});
    update();
};

var findNode = function(id) {
    for (var i in nodes) {
        if (nodes[i]["id"] === id) return nodes[i];};
};

var findNodeIndex = function(id) {
    for (var i=0;i<nodes.length;i++) {
        if (nodes[i].id==id){
            return i;
        }
        };
};

// set up the D3 visualisation in the specified element
var w = 500,
    h = 500;
var vis = d3.select("#svgdiv")
    .append("svg:svg")
    .attr("width", w)
    .attr("height", h)
    .attr("id","svg")
    .attr("pointer-events", "all")
    .attr("viewBox","0 0 "+w+" "+h)
    .attr("perserveAspectRatio","xMinYMid")
    .append('svg:g');

var force = d3.layout.force();

var nodes = force.nodes(),
    links = force.links();

var update = function () {
      var link = vis.selectAll("line")
        .data(links, function(d) {
            return d.source.id + "-" + d.target.id; 
            });

    link.enter().append("line")
        .attr("id",function(d){return d.source.id + "-" + d.target.id;})
        .attr("class","link");
    link.append("title")
    .text(function(d){
        return d.value;
    });
    link.exit().remove();

    var node = vis.selectAll("g.node")
        .data(nodes, function(d) { 
            return d.id;});

    var nodeEnter = node.enter().append("g")
        .attr("class", "node")
        .call(force.drag);

    nodeEnter.append("svg:circle")
    .attr("r", 16)
    .attr("id",function(d) { return "Node;"+d.id;})
    .attr("class","nodeStrokeClass");

    nodeEnter.append("svg:text")
    .attr("class","textClass")
    .text( function(d){return d.id;}) ;

    node.exit().remove();
    force.on("tick", function() {

        node.attr("transform", function(d) { return "translate(" + d.x + "," + d.y         + ")"; });

        link.attr("x1", function(d) { return d.source.x; })
          .attr("y1", function(d) { return d.source.y; })
          .attr("x2", function(d) { return d.target.x; })
          .attr("y2", function(d) { return d.target.y; });
    });

    // Restart the force layout.
    force
    .gravity(.05)
    .distance(50)
    .linkDistance( 50 )
    .size([w, h])
    .start();
};


// Make it all go
update();
}

function drawGraph()
{
graph = new myGraph("#svgdiv");
graph.addNode('A');
graph.addNode('B');
graph.addNode('C');
graph.addLink('A','B','10');
graph.addLink('A','C','8');
graph.addLink('B','C','15');
}

这篇关于从动态 json 数据更新力有向图上的链接的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆