5

最初に必要なノードとリンクを含むページをレンダリングし、次に ajax を介して定期的に新しい情報をチェックする、作成中の d3 強制指向マップで厄介な問題が発生しています。新しいノードとリンクが必要な場合は、それらを描画します。これで問題ありません

ただし、SVG レイヤー要素の方法により、新しいリンクは古いノードの上に描画されるため、ノードが円としてあり、それらの間に線を引く場合、追加された新しいノードは古いノードの円の上に描画されます。下の画像を参照してください。

レイヤリングの問題

( http://i40.tinypic.com/4fx25j.gif )

技術的には d3 の問題ではないことはわかっていますが、これを修正する方法が必要です。すべての円を削除して再描画しようとしましたが、問題は、それが接続されている svg:g ノードがレイヤー内で低すぎるため、まだ描画されていることです。

jsfiddle でのデモ - 次のセクションを見てください

draw() {
   ...
}

それが魔法が起こる場所だからです。 http://jsfiddle.net/zuzzy/uwAhy/

5 秒のタイマーを使用して ajax をシミュレートしました。デモの方が簡単でした。

何か案は?

4

3 に答える 3

4

私の知る限り、SVG 要素の深さは、DOM 内の位置によってのみ制御できます。

したがって、2 つのグループ<g id='lines'>とを作成するとうまくいく場合があり<g id='circles'>ます。

要素を作成するときはappend、すべての線を最初のグループに追加し、すべての円を 2 番目のグループに追加する必要があります。

lines要素を追加する方法を変更する必要があるかもしれませんが、グループがグループの前に表示されることを確認する限り、circlesゴールデンになるはずです。

これがあなたの実装に完全に合わない場合は申し訳ありません。私は非常によく似た問題に遭遇し、唯一の解決策は最初に「下の」要素を描画することであることがわかりました。

于 2013-05-29T13:49:51.333 に答える
3

この問題を解決する別の方法はinsert、次のコードに示すようにメソッドを使用することです。

 link.enter().insert("line",".node"); //Inserts link element before the first DOM element with class node.

この質問の解決策を検索する他のユーザーに役立つ可能性があるという理由だけで投稿します。

//Settings:
//width, height and the default radius of the circles
var w = 1024,
  h = 768,
  r = 10;




//test data - usually this is recieved via ajax
//Initial Data:
var hosts = eval({
  "ITEM003": {
    "name": "ITEM003",
    "parents": [],
    "status": 0,
    "hostgroup": "Secure"
  },
  "ITEM004": {
    "name": "ITEM004",
    "parents": [],
    "status": 0,
    "hostgroup": "Secure"
  },
  "CORE": {
    "name": "CORE",
    "parents": ["ITEM004", "ITEM003"],
    "status": 0,
    "hostgroup": "DMZ"
  }
});

var mylinks = eval({
  "0": ["CORE", "ITEM004"],
  "1": ["CORE", "ITEM003"]
});

//Data after update
var updated_hosts = eval({
  "ITEM003": {
    "name": "ITEM003",
    "parents": [],
    "status": 0,
    "hostgroup": "Secure"
  },
  "ITEM004": {
    "name": "ITEM004",
    "parents": [],
    "status": 0,
    "hostgroup": "Secure"
  },
  "CORE": {
    "name": "CORE",
    "parents": ["ITEM004", "ITEM003"],
    "status": 0,
    "hostgroup": "DMZ"
  },
  "REMOTE": {
    "name": "REMOTE",
    "parents": [],
    "status": 0,
    "hostgroup": ""
  }
});

var updated_mylinks = eval({
  "0": ["CORE", "ITEM004"],
  "1": ["CORE", "ITEM003"],
  "2": ["CORE", "REMOTE"]
});



//I define these here so they carry between functions - not really necessary in this jsfiddle probably
window.link = undefined;
window.node = undefined;




//make up my node object
window.nodeArray = [];
window.node_hash = [];

for (var key in hosts) {
  var a = {
    id: "node_" + hosts[key].name,
    labelText: hosts[key].name,
    status: hosts[key].status,
    hostgroup: hosts[key].hostgroup,
    class: "node realnode",
    iconimage: hosts[key].iconimage,
    added: true
  };
  nodeArray.push(a);
  node_hash[key] = a;
}

//make up my link object
window.linkArray = [];

for (var key in mylinks) {
  var linkcolor = "#47CC60";

  var a = {
    source: node_hash[mylinks[key][0]],
    target: node_hash[mylinks[key][1]],
    color: linkcolor,
    class: "link reallink"
  };
  linkArray.push(a);
}


//make up my node text objects
//these are just more nodes with a different class
//we will append text to them later
//we also add the links to the linkArray now to bind them to their real nodes
window.text_hash = [];

for (var key in hosts) {
  var a = {
    id: "label_" + hosts[key].name,
    text: hosts[key].name,
    color: "#ffffff",
    size: "6",
    class: "node label",
    added: true
  };
  nodeArray.push(a);
  text_hash[key] = a;
}

//because the text labels are in the same order as the
//original nodes we know that node_hash[0] has label text_hash[0]
//it doesn't matter which we iterate through here

for (var key in text_hash) {
  var a = {
    source: node_hash[key],
    target: text_hash[key],
    class: "link label"
  };
  linkArray.push(a);
}



//set up the environment in a div called graph using the settings baove 
window.vis = d3.select("body")
  .append("svg:svg")
  .attr("height", 500)
  .attr("width", 500)
  .attr("pointer-events", "all")
  .append('svg:g')




//object to interact with the force libraries in d3
//the settings here set how the nodes interact
//seems a bit overcomplicated but it stops the diagram going nuts!
window.force = d3.layout.force()
  .friction("0.7")
  .gravity(function(d, i) {
    if (d.class == "link reallink") {
      return "0.95";
    } else {
      return "0.1";
    }

  })
  .charge(function(d, i) {
    if (d.class == "link reallink") {
      return "-1500";
    } else {
      return "-300";
    }

  })
  .linkDistance(function(d) {
    if (d.class == "link reallink") {
      return "120";
    } else {
      return "35";
    }

  })
  .linkStrength(function(d) {
    if (d.class == "link reallink") {
      return "8";
    } else {
      return "6";
    }
  })
  .nodes(nodeArray)
  .links(linkArray)
  .on("tick", tick)

node = vis.selectAll(".node");
link = vis.selectAll(".link");

//create the objects and run it
draw();

for (key in nodeArray) {
  nodeArray[key].added = false;
}

//wait 5 seconds then update the diagram TO ADD A NODE
setTimeout(function() {
  //update the objects
  //vis.selectAll("g.node").data(nodeArray).exit().transition().ease("elastic").remove();
  //vis.selectAll("line").data(linkArray).exit().transition().ease("elastic").remove();


  var a = {
    id: "node_REMOTE",
    labelText: "REMOTE",
    status: "0",
    hostgroup: "",
    class: "node realnode",
    iconimage: "",
    added: true
  };
  nodeArray.push(a);
  node_hash["REMOTE"] = a;



  var linkcolor = "#47CC60";
  var a = {
    source: node_hash["CORE"],
    target: node_hash["REMOTE"],
    color: linkcolor,
    class: "link reallink"
  };
  linkArray.push(a);



  //make up my node text objects


  var a = {
    id: "label_REMOTE",
    text: "REMOTE",
    color: "#000000",
    size: "6",
    class: "node label",
    added: true
  };
  nodeArray.push(a);
  text_hash["REMOTE"] = a;


  var a = {
    source: node_hash["REMOTE"],
    target: text_hash["REMOTE"],
    class: "link label"
  };
  linkArray.push(a);


  //redraw it
  draw();

}, 5000);




//----- functions for drawing and tick below


function draw() {

  link = link.data(force.links(), function(d) {
    return d.source.id + "-" + d.target.id;
  });
  node = node.data(force.nodes(), function(d) {
    return d.id;
  });


  //create the link object using the links object in the json
  //link = vis.selectAll("line").data(linkArray);
  link.enter().insert("line", ".node")
    .attr("stroke-width", '0')
    .transition()
    .duration(1000)
    .ease("bounce")
    .attr("stroke-width", function(d, i) {
      if (d.class == 'link reallink') {
        return '3';
      } else {
        return '0';
      };
    })
    .style("stroke", function(d, i) {
      return d.color;
    })
    .attr("class", function(d, i) {
      return d.class;
    });


  //node = vis.selectAll("g").data(nodeArray);
  node.enter().append("svg:g")
    .attr("class", function(d) {
      return d.class
    })
    .attr("id", function(d) {
      return d.id
    })
    .call(force.drag);


  //append to each node an svg circle element
  vis.selectAll(".realnode").filter(function(d) {
      return d.added;
    })
    .append("svg:circle")
    .attr("r", "0")
    .transition()
    .duration(1000)
    .ease("bounce")
    .attr("r", "6")
    .style("fill", "#000000")
    .style("stroke", function(d) {
      return d.color;
    })
    .style("stroke-width", "4");



  //append to each node the attached text desc
  vis.selectAll(".label").filter(function(d) {
      return d.added;
    })
    .append("svg:text")
    .attr("text-anchor", "middle")
    .attr("fill", "black")
    .style("pointer-events", "none")
    .attr("font-size", "9px")
    .attr("font-weight", "100")
    .text(function(d) {
      return d.text;
    })
    .attr("transform", "rotate(180)")
    .transition()
    .duration(1000)
    .ease("bounce")
    .attr("transform", "rotate(0)");


  node.exit().transition().ease("elastic").remove();
  link.exit().transition().ease("elastic").remove();

  //activate it all - initiate the nodes and links
  force.start();

}





function tick() {
  node.attr("cx", function(d) {
      return d.x = Math.max(r + 15, Math.min(w - r - 15, d.x));
    })
    .attr("cy", function(d) {
      return d.y = Math.max(r + 15, Math.min(h - r - 15, d.y));
    })
    .attr("transform", function(d) {
      return "translate(" + d.x + "," + d.y + ")";
    });


  link.data(linkArray).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 src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>

于 2016-05-18T05:56:25.490 に答える
3

初めて働いた!すでにすべての要素を 1 つにグループ化していたので、次のように置き換えました。

var vis = d3.select("body")    
.append("svg:svg")  
.attr("pointer-events", "all");  
.append('svg:g')

リンクとサークルの両方をレンダリングするために vis.xxxx を使用しました。

var vis = d3.select("body") 
.append("svg:svg")   
.attr("pointer-events", "all");  

var linkvis = vis.append('svg:g')  
.attr("id","link_elements");   

vis = vis.append('svg:g')   
.attr("id","node_elements");   

リンクを描画するときは linkvis を参照し、円を描画するときは vis を参照します。

(注:これはコメントである必要があることはわかっていますが、うまく収まらず、誰かにとって役立つかもしれないと思いました.@Paulの回答は回答としてマークされています)

于 2013-05-29T15:08:19.967 に答える