sorton9999
sorton9999

Reputation: 182

Confused by data binding and selecting specific data

I'm new to d3 and am confused by the notion of joining data to DOM elements. I have a non-trivial data store in JSON of which I'm having difficulty segregating out different sections. Here is my JSON:

var data ={ 
    "groups" :
    [{
        "name": "group1",
        "atts":
        [{
            "nodes": 
             [
             {"id": "root", "name": "Plaintext Router" },
             { "id": "B", "name": "Ethernet Switch" },
             { "id": "C", "name": "1.10" },
             { "id": "D", "name": "1.1" },
             { "id": "E", "name": "1.2" }
             ], 
            "links": 
             [{ "source": "root", "target": "B" },
              { "source": "root", "target": "C" },
              { "source": "root", "target": "D" },
              { "source": "root", "target": "E" },
             ]
        }]
    },
    {
        "name": "group2",
        "atts":
        [{
            "nodes":
             [
             { "id": "root", "name": "Plaintext Router" },
             { "id": "B", "name": "Ethernet Switch" },
             { "id": "C", "name": "1.1" },
             { "id": "D", "name": "1.2" }
             ],
            "links":
             [{ "source": "root", "target": "B" },
              { "source": "root", "target": "C" },
              { "source": "root", "target": "D" },
             ]

        }]
    }
]
}

So, I have two groups that I want to create a network map for. The root node is a the center with links emanating out in a spoke pattern to the other nodes surrounding the center.

I want to be able to choose which group to visualize. I don't want them both visualized at the same time.

The code I have to try to do that is as follows.

var height = 600;
var width = 600;

var svg = d3.select("body").append("svg")
  .attr("width",width)
  .attr("height",height);

var simulation = d3.forceSimulation()
    .force("link", d3.forceLink().id(function(d) { return d.id; }).distance(300))
    .force("charge", d3.forceManyBody())
    .force("center", d3.forceCenter(width / 2, height / 2));

var link = svg.append("g")
  .selectAll("line")
  .data(data.groups, key)

[[need to get to links array of the selected group]]

  .enter()
  .append("line")
  .attr("stroke","green");

var groups = svg.selectAll(".node")
    .data(data.groups, key)

[[Need to get to nodes array of selected group]]

    .enter()
    .append("g");

var node = groups.append("rect")
    .attr("width", function(d) { return d.w * 2; })
    .attr("height", function(d) { return d.h * 2; })
    .style("fill", function(d) { return "url(#" + d.icon + ")"; });

function key(d) {
    return ((d.groups.name === "group1") ? d.groups.atts : null);
}

The above key function indicates that I want to map the 'group1' group. The problem I'm having is I don't know how to get to the "atts" array of "nodes" and "links" tied to the chosen group. I want to be able to assign the nodes and links where needed.

The error I'm getting now is: "Unable to get property 'name' of undefined or null reference" in the 'key' function.

I left other directives out such as svg:patterns and others to try to keep things simple. I hope this example gets my point across.

I appreciate any help you can give on this.

Upvotes: 1

Views: 62

Answers (1)

otto
otto

Reputation: 2043

With .filter((d) => {...} you can filter your data and make a condition which data should be set. I hope this is what you mean...

Filter Example:

const words = ["spray", "limit", "elite", "exuberant", "destruction", "present", "happy"];
let longWords = words.filter(word => word.length > 6)

JS

var data ={ 
    "groups" :
    [{
        "name": "group1",
        "atts":
        [{
            "nodes": 
             [
             {"id": "root", "name": "Plaintext Router" },
             { "id": "B", "name": "Ethernet Switch" },
             { "id": "C", "name": "1.10" },
             { "id": "D", "name": "1.1" },
             { "id": "E", "name": "1.2" }
             ], 
            "links": 
             [{ "source": "root", "target": "B" },
              { "source": "root", "target": "C" },
              { "source": "root", "target": "D" },
              { "source": "root", "target": "E" },
             ]
        }]
    },
    {
        "name": "group2",
        "atts":
        [{
            "nodes":
             [
             { "id": "root", "name": "Plaintext Router" },
             { "id": "B", "name": "Ethernet Switch" },
             { "id": "C", "name": "1.1" },
             { "id": "D", "name": "1.2" }
             ],
            "links":
             [{ "source": "root", "target": "B" },
              { "source": "root", "target": "C" },
              { "source": "root", "target": "D" },
             ]

        }]
    }
]
}





var height = 600;
var width = 600;

var svg = d3.select("body").append("svg")
  .attr("width",width)
  .attr("height",height);

var simulation = d3.forceSimulation()
    .force("link", d3.forceLink().id(function(d) { return d.id; }).distance(300))
    .force("charge", d3.forceManyBody())
    .force("center", d3.forceCenter(width / 2, height / 2));

var link = svg.append("g")
  .selectAll("line")
  .data(data.groups.filter((d)=>{
    console.log("link")
    console.log(d)
    }))
  .enter()
  .append("line")
  .attr("stroke","green");

var groups = svg.selectAll(".node")
    .data(data.groups.filter((d)=>{
    console.log("group")
    console.log(d)
    }))
    .enter()
    .append("g");

var node = groups.append("rect")
    .attr("width", function(d) { return d.w * 2; })
    .attr("height", function(d) { return d.h * 2; })
    .style("fill", function(d) { return "url(#" + d.icon + ")"; });

function key(d) {
    return ((d.name === "group1") ? d.atts : null);
}

JS Fiddle

Upvotes: 1

Related Questions