0

To illustrate this issue let's take the following simple data example where I have a list of objects to display. Each object is composed of a shape and a variable list of lines

var data = [
    {
        "shape": "circle",
        "x": 10,
        "y": 20,
        "lines": [
            {x1: "-10", y1: "-10", x2: "10", y2: "10"}
        ]
    },
    {
        "shape": "rect",
        "x": 30,
        "y": 20,
        "lines": [
            {x1: "-10", y1: "-10", x2: "10", y2: "10"}
        ]
    },
    {
        "shape": "circle",
        "x": 50,
        "y": 20,
        "lines": [
            {x1: "-10", y1: "-10", x2: "10", y2: "10"},
            {x1: "-10", y1: "10", x2: "10", y2: "-10"}
        ]
    },
    {
        "shape": "rect",
        "x": 70,
        "y": 20,
        "lines": [
            {x1: "-10", y1: "-10", x2: "10", y2: "10"},
            {x1: "-10", y1: "10", x2: "10", y2: "-10"}
        ]
    }
];

I know I can use the filter() function to differenciate the shapes so I can create the shapes like this:

var shapes = svg.selectAll(".shape")
        .data(data)
        .enter()
        .append("g")
        .attr("transform", function (d) {
            return "translate(" + d.x + "," + d.y + ")";
        });

var circles = shapes.filter(function (d) {
    return d.shape == "circle"
})
        .append("circle")
        .attr("r", 10);

var rect = shapes.filter(function (d) {
    return d.shape == "rect"
})
        .append("rect")
        .attr("transform", "translate(-5, -5)")
        .attr("width", 10)
        .attr("height", 10);

My issue then is to also append the variable amount of lines depending on data.

I see how I could happend only the first line like this:

shapes.append("line")
        .attr("stroke", "red")
        .attr("x1", function (d) {
            return d.lines[0].x1
        })
        .attr("y1", function (d) {
            return d.lines[0].y1
        })
        .attr("x2", function (d) {
            return d.lines[0].x2
        })
        .attr("y2", function (d) {
            return d.lines[0].y2
        })

But I don't see how to do if the number of lines are variable.

What would be the correct way to achive this?

I created a fiddle with this example here: http://jsfiddle.net/Lm8XB/1/

Popoto
  • 153
  • 5

1 Answers1

0

The right way to do this is to use a nested selection. That is, you bind the lines data again to line elements, referencing the data you bound earlier:

shapes.selectAll("line").data(function(d) { return d.lines; })
      .enter().append("line")

Then you can reference the coordinates directly when setting the parameters:

.attr("x1", function (d) {
            return d.x1
        })
        .attr("y1", function (d) {
            return d.y1
        })
        .attr("x2", function (d) {
            return d.x2
        })
        .attr("y2", function (d) {
            return d.y2
        })

Complete example here.

Lars Kotthoff
  • 107,425
  • 16
  • 204
  • 204
  • Thanks for your answer. how would you do if you need to access parent data, for example if I want to change the line stroke color to red for circle and green for rect? – Popoto Feb 06 '14 at 13:32
  • I would make this information part of the line objects to have a clean separation. To access information in the parent, you can use [the secret third argument](http://stackoverflow.com/questions/20437116/third-variable-in-d3-anonymous-function). – Lars Kotthoff Feb 06 '14 at 13:35
  • Ok good to know, I also found [here](http://stackoverflow.com/questions/15417340/how-to-get-data-of-parent-node-in-d3-js) that I can use d3.select(this.parentNode).datum() to get parent data. – Popoto Feb 06 '14 at 13:58