在一个特定的力布局D3中标记节点的问题



我用D3做了一个算法来可视化一些数据。算法正在做我所期望的事情。他用Force布局分隔多个焦点中的节点,链接和节点动态地出现和消失。

问题来自于节点的标记。D3似乎做的工作,但多次为每个节点(当我看它与firebug)。

下面是我的代码:
var actions = [
{"action":"arrivee","id":"001","service":1},
{"action":"arrivee","id":"002","service":1},
{"action":"arrivee","id":"003","service":1},
{"action":"arrivee","id":"004","service":1},
{"action":"arrivee","id":"005","service":1},
{"action":"arrivee","id":"006","service":3},
{"action":"arrivee","id":"007","service":3},
{"action":"arrivee","id":"008","service":3},
{"action":"arrivee","id":"009","service":3},
{"action":"arrivee","id":"010","service":2},
{"action":"arrivee","id":"011","service":2},
{"action":"arrivee","id":"012","service":2},
{"action":"arrivee","id":"013","service":2},
{"action":"arrivee","id":"014","service":4},
{"action":"arrivee","id":"015","service":4},
{"action":"arrivee","id":"016","service":4},
{"action":"arrivee","id":"017","service":4},
{"action":"contact","id":"0","source":"001","target":"017"},
{"action":"contact","id":"1","source":"016","target":"012"},
{"action":"contact","id":"2","source":"004","target":"011"},
{"action":"contact","id":"3","source":"001","target":"010"},
{"action":"fincontact","id":"0"},
{"action":"depart","id":"017"},
{"action":"arrivee","id":"018","service":2},
{"action":"arrivee","id":"019","service":1},
{"action":"arrivee","id":"020","service":1},
{"action":"arrivee","id":"021","service":0},
{"action":"arrivee","id":"022","service":0},
{"action":"arrivee","id":"023","service":0},
{"action":"arrivee","id":"024","service":0},
{"action":"arrivee","id":"025","service":0},
{"action":"arrivee","id":"026","service":0},
{"action":"arrivee","id":"027","service":3},
{"action":"arrivee","id":"028","service":2},
{"action":"arrivee","id":"029","service":2},
{"action":"arrivee","id":"030","service":2},
{"action":"arrivee","id":"031","service":2},
{"action":"arrivee","id":"032","service":4},
{"action":"arrivee","id":"033","service":4},
{"action":"arrivee","id":"034","service":4},
{"action":"arrivee","id":"035","service":4},
{"action":"contact","id":"4","source":"013","target":"002"},
{"action":"contact","id":"5","source":"009","target":"008"},
{"action":"contact","id":"6","source":"005","target":"007"},
{"action":"contact","id":"7","source":"009","target":"014"},
{"action":"fincontact","id":"7"},
{"action":"fincontact","id":"6"},
{"action":"fincontact","id":"5"},
{"action":"fincontact","id":"4"},
{"action":"fincontact","id":"3"},
{"action":"fincontact","id":"2"},
{"action":"fincontact","id":"1"},
{"action":"depart","id":"016"},
{"action":"depart","id":"015"},
{"action":"depart","id":"014"},
{"action":"depart","id":"013"},
{"action":"depart","id":"012"},
{"action":"depart","id":"011"},
{"action":"depart","id":"010"},
{"action":"depart","id":"009"},
{"action":"depart","id":"008"},
{"action":"depart","id":"007"},
{"action":"depart","id":"006"},
{"action":"depart","id":"005"},
{"action":"depart","id":"004"},
{"action":"depart","id":"003"},
{"action":"depart","id":"002"},
{"action":"depart","id":"018"},
{"action":"depart","id":"019"},
{"action":"depart","id":"020"},
{"action":"depart","id":"021"},
{"action":"depart","id":"022"},
{"action":"depart","id":"023"},
{"action":"depart","id":"024"},
{"action":"depart","id":"025"},
{"action":"depart","id":"026"},
{"action":"depart","id":"027"},
{"action":"depart","id":"028"},
{"action":"depart","id":"029"},
{"action":"depart","id":"030"},
{"action":"depart","id":"031"},
{"action":"depart","id":"032"},
{"action":"depart","id":"033"},
{"action":"depart","id":"034"},
{"action":"depart","id":"035"},
{"action":"depart","id":"001"}]
var vv = window,
w = vv.innerWidth,
h = vv.innerHeight;
var rmax = 30;
foci = [{x: 500, y: 150}, {x: 200, y: 500}, {x: 700, y: 500}, {x: 400, y: 700}, {x: 600, y: 700}];
//canevas selection
var svg = d3.select("#animviz")
        .append("svg")
        .attr("width", w)
        .attr("height", h);
var fill = d3.scale.category10();
//link and node class creation
svg.append("g").attr("class", "links");
svg.append("g").attr("class", "nodes");
 //to know if the graphs are up to date
var uptodate = true;
var nIntervId;
//containers de noeuds et liens
var nodes = [], links = [];
 var force = d3.layout.force()
                 .nodes(nodes)
                 .links(links)
                 .size([w, h])
                 .friction(0.9)
                 .charge(-50)
                 .gravity(0.02)
                 .linkDistance(50)
                 .charge(-500)
                 .on("tick", tick);
 var iter = 0;
var node = svg.select(".nodes").selectAll(".node");
var link = svg.select(".links").selectAll(".link");
//repeat an action every "interval"
var interval = 0.2;
 nIntervId = setInterval(function() {
var action = readData();
addData(action);
if(!uptodate){
    update();
}
}, interval*1000);
function addData(action) {
uptodate = false;
switch(action.action) {
case "arrivee":
    nodes.push({id: action.id, service: action.service});
    break;
case "depart":
    for (var i = nodes.length - 1; i >= 0; i--) {
        if(nodes[i].id == action.id){
            nodes.splice(i, 1);
        }
    };
    break;
case "contact":
    var source;
    var target;
    for (var i = nodes.length - 1; i >= 0; i--) {
        if(nodes[i].id == action.source){
            source = nodes[i];
        }
        if(nodes[i].id == action.target){
            target = nodes[i];
        }
    };
    links.push({source:source, target:target, id:action.id});
    break;
case "fincontact":
    for (var i = links.length - 1; i >= 0; i--) {
        if(links[i].id == action.id){
            links.splice(i, 1);
        }
    };
    break;
default:
    uptodate = true;
} 
}
 function readData(){
var n = iter;
iter++;
var data = actions[n];
return data;
}
function update() {
force.start();
link = link.data(force.links(), function(d) { return d.source.id+"-"+d.target.id; });
link.enter()
.append("line")
.attr("class", "link")
.attr("stroke", "#ccc")
.attr("stroke-width", 2);
link.exit().remove();
var r = d3.scale.sqrt()
.domain(d3.extent(force.nodes(), function(d) {return d.weight; }))
.range([15, rmax]);
node = node.data(force.nodes(), function(d) { return d.id; });
node.enter()
    .append("g")
    .attr("class", "node")
    .call(force.drag);
node.append("circle")
    .attr("r", 20)
    .style("stroke-width", "10")
    .style("fill", "white")//function(d, i) { return fill(d.service ); })
    .style("stroke", function(d, i) { return d3.rgb(i & 1 ? "red" : "green") })
node.append("text")
    .attr("text-anchor","middle")
    .text(function(d) {return d.id});
node.exit().remove();
}
function tick(e) {
var k = 0.5 * e.alpha;
nodes.forEach(function(o, i) {
    o.y += (foci[o.service].y - o.y) * k;
    o.x += (foci[o.service].x - o.x) * k;
});
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;});
node.attr("cx", function(d) { return d.x = Math.max(rmax, Math.min(w - rmax, d.x)); })
    .attr("cy", function(d) { return d.y = Math.max(rmax, Math.min(h - rmax, d.y)); });
 }

readData()读取数据帧,addData()是一个大循环有动态移动和更新()是D3部分,我试图标记我的节点。

我错过了一些明显的东西。

谢谢你。

经过几天的搜索,我能够发布工作代码作为答案。

var actions = [
    {"action":"arrivee","id":"001","service":1},
    {"action":"arrivee","id":"002","service":1},
    {"action":"arrivee","id":"003","service":1},
    {"action":"arrivee","id":"004","service":1},
    {"action":"arrivee","id":"005","service":1},
    {"action":"arrivee","id":"006","service":3},
    {"action":"arrivee","id":"007","service":3},
    {"action":"arrivee","id":"008","service":3},
    {"action":"arrivee","id":"009","service":3},
    {"action":"arrivee","id":"010","service":2},
    {"action":"arrivee","id":"011","service":2},
    {"action":"arrivee","id":"012","service":2},
    {"action":"arrivee","id":"013","service":2},
    {"action":"arrivee","id":"014","service":4},
    {"action":"arrivee","id":"015","service":4},
    {"action":"arrivee","id":"016","service":4},
    {"action":"arrivee","id":"017","service":4},
    {"action":"contact","id":"0","source":"001","target":"017"},
    {"action":"contact","id":"1","source":"016","target":"012"},
    {"action":"contact","id":"2","source":"004","target":"011"},
    {"action":"contact","id":"3","source":"001","target":"010"},
  {"action":"fincontact","id":"0"},
  {"action":"depart","id":"017"},
  {"action":"arrivee","id":"018","service":2},
    {"action":"arrivee","id":"019","service":1},
    {"action":"arrivee","id":"020","service":1},
    {"action":"arrivee","id":"021","service":0},
    {"action":"arrivee","id":"022","service":0},
    {"action":"arrivee","id":"023","service":0},
    {"action":"arrivee","id":"024","service":0},
    {"action":"arrivee","id":"025","service":0},
    {"action":"arrivee","id":"026","service":0},
    {"action":"arrivee","id":"027","service":3},
    {"action":"arrivee","id":"028","service":2},
    {"action":"arrivee","id":"029","service":2},
    {"action":"arrivee","id":"030","service":2},
    {"action":"arrivee","id":"031","service":2},
    {"action":"arrivee","id":"032","service":4},
    {"action":"arrivee","id":"033","service":4},
    {"action":"arrivee","id":"034","service":4},
    {"action":"arrivee","id":"035","service":4},
    {"action":"contact","id":"4","source":"013","target":"002"},
    {"action":"contact","id":"5","source":"009","target":"008"},
    {"action":"contact","id":"6","source":"005","target":"007"},
    {"action":"contact","id":"7","source":"009","target":"014"},
    {"action":"fincontact","id":"7"},
    {"action":"fincontact","id":"6"},
    {"action":"fincontact","id":"5"},
    {"action":"fincontact","id":"4"},
    {"action":"fincontact","id":"3"},
    {"action":"fincontact","id":"2"},
    {"action":"fincontact","id":"1"},
    {"action":"depart","id":"016"},
    {"action":"depart","id":"015"},
    {"action":"depart","id":"014"},
    {"action":"depart","id":"013"},
    {"action":"depart","id":"012"},
    {"action":"depart","id":"011"},
    {"action":"depart","id":"010"},
    {"action":"depart","id":"009"},
    {"action":"depart","id":"008"},
    {"action":"depart","id":"007"},
    {"action":"depart","id":"006"},
    {"action":"depart","id":"005"},
    {"action":"depart","id":"004"},
    {"action":"depart","id":"003"},
    {"action":"depart","id":"002"},
    {"action":"depart","id":"018"},
    {"action":"depart","id":"019"},
    {"action":"depart","id":"020"},
    {"action":"depart","id":"021"},
    {"action":"depart","id":"022"},
    {"action":"depart","id":"023"},
    {"action":"depart","id":"024"},
    {"action":"depart","id":"025"},
    {"action":"depart","id":"026"},
    {"action":"depart","id":"027"},
    {"action":"depart","id":"028"},
    {"action":"depart","id":"029"},
    {"action":"depart","id":"030"},
    {"action":"depart","id":"031"},
    {"action":"depart","id":"032"},
    {"action":"depart","id":"033"},
    {"action":"depart","id":"034"},
    {"action":"depart","id":"035"},
    {"action":"depart","id":"001"}]
var vv = window,
    w = vv.innerWidth,
    h = vv.innerHeight;
foci = [{x: 500, y: 150}, {x: 200, y: 500}, {x: 700, y: 500}, {x: 400, y: 700}, {x: 600, y: 700}];
var svg = d3.select("body").append("svg")
    .attr("width", w)
    .attr("height", h);
var links = [], nodes = [];
var force = d3.layout.force()
           .nodes(nodes)
           .links(links)
           .size([w, h])
           .friction(0.9)
           .charge(-50)
           .gravity(0.02)
           .linkDistance(50)
           .charge(-500)
           .on("tick", tick);
var link;
var node;
var iter = 0;
var interval = 0.2;
var uptodate = true;
var nIntervId;
 nIntervId = setInterval(function() {
  //alert("je passe");
  var action = readData();
  addData(action);
  if(!uptodate){
    update();
  }
}, interval*1000);
function addData(action) {
uptodate = false;
  switch(action.action) {
    case "arrivee":
        nodes.push({id: action.id, service: action.service});
        break;
    case "depart":
        for (var i = nodes.length - 1; i >= 0; i--) {
          if(nodes[i].id == action.id){
            nodes.splice(i, 1);
          }
        };
        break;
    case "contact":
      var source;
      var target;
      for (var i = nodes.length - 1; i >= 0; i--) {
        if(nodes[i].id == action.source){
          source = nodes[i];
        }
        if(nodes[i].id == action.target){
          target = nodes[i];
        }
      };
        links.push({source:source, target:target, id:action.id});
        break;
    case "fincontact":
        for (var i = links.length - 1; i >= 0; i--) {
          if(links[i].id == action.id){
            links.splice(i, 1);
          }
        };
        break;
    default:
        uptodate = true;
  } 
}
function readData(){
  var n = iter;
  iter++;
  var data = actions[n];
  return data;
}
function update(){
  force.start();
  link = svg.selectAll(".link")
      .data(force.links());
  link.enter().append("line")
      .attr("class", "link");
  link.exit().remove();
  node = svg.selectAll(".node")
      .data(force.nodes());
  node.enter().append("g")
      .attr("class", "node")
      .call(force.drag);

  node.append("circle")
      .attr("r", 20)
      .style("stroke-width", "10")
      .style("fill", "white")//function(d, i) { return fill(d.service ); })
      .style("stroke", function(d, i) { return d3.rgb(i & 1 ? "red" : "green") });
  node.append("text")
  .attr("text-anchor","middle")
      .text(function(d) { return d.id });
  node.exit().remove();
}

function tick(e) {

    var k = 0.5 * e.alpha;
    nodes.forEach(function(o, i) {
        o.y += (foci[o.service].y - o.y) * k;
        o.x += (foci[o.service].x - o.x) * k;
    });
    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; });
    node.attr("transform", function(d) { return "translate(" + d.x + "," + d.y + ")"; });
};

谢谢你的帮助

最新更新