lightweight
lightweight

Reputation: 3337

arrays and nodes mapping in d3 force

lets say in d3 I have a couple data arrays like this:

Nodes:

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

Links:

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

is there a way that I can use names instead of the number? Like this:

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

but get this error:

Uncaught TypeError: Cannot read property 'x' of undefined

here:

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

here is the full code:

<!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>

Upvotes: 2

Views: 796

Answers (2)

Bless Yahu
Bless Yahu

Reputation: 1341

Make node an object, with each name as a property/key:

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

Arrays can only be accessed by index (ie. array[3]), objects can be accessed by property (ie. object["propertyName"] or object.propertyName).

Upvotes: 1

Gerardo Furtado
Gerardo Furtado

Reputation: 102188

It's returning undefined because that number inside the square bracket is the index of the object (in this particular case) inside an array. When you use nodes[0] you are referencing the first object inside the array nodes (the index is zero-based, that is, 0 is the first object, 1 is the second and so on).

If you want to reference the object which value for the key name is "abc" you'll have to find it first. Please see this answer:

How to get index of object by its property in javascript

Upvotes: 0

Related Questions