d3力中的阵列和节点映射

arrays and nodes mapping in d3 force

本文关键字:节点 映射 阵列 d3      更新时间:2023-09-26

假设在d3中,我有两个数据数组,如下所示:

节点:

var nodes = [
{"name": "abc", "type": "Db"},
{"name": "def", "type": "Db"},
{"name": "ghi", "type": "Db"},
{"name": "jkl", "type": "Db"}
]

链接:

var links = [
{source: nodes[0], target: nodes[1]},
{source: nodes[0], target: nodes[2]},
{source: nodes[1], target: nodes[3]}
]

有没有办法用名字代替数字?像这样:

var links = [
{source: nodes["abc"], target: nodes["def"]},
{source: nodes["abc"], target: nodes["ghi"]},
{source: nodes["def"], target: nodes["jkl"]}
]

但是得到这个错误:

未捕获的类型错误:无法读取未定义的属性"x"

此处:

link.attr("x1", function(d)   { return d.source.x; })

这是完整的代码:

<!doctype html>
<html>
<head>
    <title>D3 tutorial</title>
    <script src="https://d3js.org/d3.v3.min.js"></script>
</head>

<body>
<script>
var w = 4000,
    h = 4000;
var circleWidth = 5;
var fontFamily = 'Bree Serif',
    fontSizeHighlight = '1.5em',
    fontSizeNormal = '1em';
var palette = {
      "lightgray": "#819090",
      "gray": "#708284",
      "mediumgray": "#536870",
      "darkgray": "#475B62",
      "darkblue": "#0A2933",
      "darkerblue": "#042029",
      "paleryellow": "#FCF4DC",
      "paleyellow": "#EAE3CB",
      "yellow": "#A57706",
      "orange": "#BD3613",
      "red": "#D11C24",
      "pink": "#C61C6F",
      "purple": "#595AB7",
      "blue": "#2176C7",
      "green": "#259286",
      "yellowgreen": "#738A05"
  }
    var nodes = [
    {"name": "abc", "type": "Db"},
    {"name": "def", "type": "Db"},
    {"name": "ghi", "type": "Db"},
    {"name": "jkl", "type": "Db"}
    ]
    var links = [
    {source: nodes["abc"], target: nodes["def"]},
    {source: nodes["abc"], target: nodes["ghi"]},
    {source: nodes["def"], target: nodes["jkl"]}
    ]

var vis = d3.select("body")
    .append("svg:svg")
      .attr("class", "stage")
      .attr("width", w)
      .attr("height", h);
var force = d3.layout.force()
    .nodes(nodes)
    .links([])
    .gravity(0.1)
    .charge(-1000)
    .size([w, h]);
 var link = vis.selectAll(".link")
        .data(links)
        .enter().append("line")
          .attr("class", "link")
          .attr("stroke", "#CCC")
          .attr("fill", "none");
 var node = vis.selectAll("circle.node")
      .data(nodes)
      .enter().append("g")
      .attr("class", "node")
      //MOUSEOVER
      .on("mouseover", function(d,i) {
        if (i>0) {
          //CIRCLE
          d3.select(this).selectAll("circle")
          .transition()
          .duration(250)
          .style("cursor", "none")     
          .attr("r", circleWidth+3)
          .attr("fill",palette.black);
          //TEXT
          d3.select(this).select("text")
          .transition()
          .style("cursor", "none")     
          .duration(250)
          .style("cursor", "none")     
          .attr("font-size","1.5em")
          .attr("x", 15 )
          .attr("y", 5 )
          .text(function(d) { return d.name + "_" + d.type; })
        } else {
          //CIRCLE
          d3.select(this).selectAll("circle")
          .style("cursor", "none")     
          //TEXT
          d3.select(this).select("text")
          .style("cursor", "none")     
        }
      })
      //MOUSEOUT
      .on("mouseout", function(d,i) {
        if (i>0) {
          //CIRCLE
          d3.select(this).selectAll("circle")
          .transition()
          .duration(250)
          .attr("r", circleWidth)
          .attr("fill",palette.pink);
          //TEXT
          d3.select(this).select("text")
          .transition()
          .duration(250)
          .attr("font-size","1em")
          .attr("x", 8 )
          .attr("y", 4 )
          .text(function(d) { return d.name; })
        }
      })
      .call(force.drag);

    //CIRCLE
    node.append("svg:circle")
      .attr("cx", function(d) { return d.x; })
      .attr("cy", function(d) { return d.y; })
      .attr("r", circleWidth)
      .attr("fill", function(d, i) { if (i>0) { return  palette.pink; } else { return palette.black } } )
    //TEXT
    node.append("text")
      .text(function(d, i) { return d.name; })
      .attr("x",            function(d, i) { if (i>0) { return circleWidth + 5; }   else { return -10 } })
      .attr("y",            function(d, i) { if (i>0) { return circleWidth + 0 }    else { return 8 } })
      .attr("font-family",  "Bree Serif")
      .attr("fill",         function(d, i) { if (i>0) { return  palette.black; }        else { return palette.black } })
      .attr("font-size",    function(d, i) { if (i>0) { return  "1em"; }            else { return "1.8em" } })
      .attr("text-anchor",  function(d, i) { if (i>0) { return  "beginning"; }      else { return "end" } })

force.on("tick", function(e) {
  node.attr("transform", function(d, i) {     
        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; })
});
force.start();

    </script>
</body>


</html>

使节点成为一个对象,每个名称都作为一个属性/键:

var nodes = { 
    abc: {"name": "abc", "type": "Db"}, 
    def: {"name": "def", "type": "Db"}, 
    ghi: {"name": "ghi", "type": "Db"}, 
    jkl: {"name": "jkl", "type": "Db"} 
}

数组只能由索引(即array[3])访问,对象可以由属性访问(即object["propertyName"]object.propertyName

它返回undefined,因为方括号内的数字是数组内对象(在这种特殊情况下)的索引。使用nodes[0]时,引用的是数组nodes中的第一个对象(索引为零,即0是第一个对象,1是第二个对象,依此类推)。

如果您想引用关键字name的值为"abc"的对象,您必须首先找到它。请看这个答案:

如何在javascript 中通过对象的属性获取对象的索引