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

Javascript 在特定力布局D3中标记节点的问题,javascript,d3.js,Javascript,D3.js,我用D3做了一个算法来可视化一些数据。算法正在做我对他的期望。他使用Force布局在多个焦点中分离节点,动态显示和消失链接和节点 问题在于节点的标记。D3似乎完成了这项工作,但每个节点的时间都会成倍增加(当我用firebug查看它时) 这是我的密码: var actions = [ {"action":"arrivee","id":"001","service":1}, {"action":"arrivee","id":"002","service":1}, {"action":"arrivee

我用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()是一个大循环,可以动态移动,update()是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 + ")"; });
};

谢谢您的帮助。

经过几天的搜索,我可以发布工作代码作为答案

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 + ")"; });
};

感谢您的帮助。

文本锚定
不是有效的SVG元素。添加一个
text
元素,然后设置
text-anchor
属性。感谢您的更正,我将更新我的代码。您还希望为
节点
设置
transform
属性,而不是
cx
cy
(这不会起任何作用)。至于最初的问题,我不清楚为什么会发生这种情况。感谢您的帮助,我将发布我的新代码作为答案。
text-anchor
不是有效的SVG元素。添加一个
text
元素,然后设置
text-anchor
属性。感谢您的更正,我将更新我的代码。您还希望为
节点
设置
transform
属性,而不是
cx
cy
(这不会起任何作用)。至于最初的问题,我不清楚为什么会发生这种情况。谢谢你的帮助,我将发布我的新代码作为答案。