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>

当收到新的json字符串时,我可以通过再次调用整个函数来创建新的图形.这将在旧图形的位置创建一个新图形.当接收到值时,我无法用新的值集更新旧图;我的图中的 node 没有改变,只是它们之间的关系改变了.

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

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相关问答推荐

使用JSONata将具有相同键的字典合并

处理输入数据并转换为更简单的格式-PowerBI

集成wix.comstore API|变音符号问题

在 python 中循环 JSON 数组

Golang jsonrpc2 服务器在哪里监听?

Jolt 转换数组对象并将某些字段移动到嵌套数组

JSON 的自定义编组器,可以是字符串或 map[string]string / map[string]bool

为什么解析的字典相等而腌制的字典不相等?

我如何将 JSON 格式与 flutter 一起使用?帮助使用 Gamebanana api

使用带有逗号的字段名称构建 struct

如何在 Dart 中与多个 map (字典)相交

使用 BASH 和 JQ 我想将 json 文件与 bash 数组进行比较

如果 jq 数组中的字符串是对象或字符串,则获取值

使用 Jolt 使用键中的值创建带有硬编码键和值的 JSON 数组

在 Bash 中访问 JSON 对象 - 关联数组/列表/另一个模型

应该使用什么标头将 GZIP 压缩 JSON 从 Android 客户端发送到服务器?

Spring MVC 4:application/json内容类型设置不正确

在 Rails 中使用 JSON 创建嵌套对象

使用 JSON.Net 的 C# 到 JSON 序列化

waitUntilAllTask​​sAreFinished 错误 Swift