Reputation: 2677
I have an array of objects which I bind to a g-element. For each g-element I generate a rect-element. It works so far but now I want to have a dynamic number of "parts" in each g-element which should generate a new rect and text element inside the existing rect.
Here you will find my example or on fiddle.net/tnnomejg/
var config = {
width: 600
};
var data = [
{
height: 150,
y: 0,
parts: [
{
title: "Hello",
x: 50,
y: 60,
},
{
title: "World",
x: 350,
y: 60,
}
],
},
{
height: 150,
y: 155,
parts: [
{
title: "Demo",
x: 280,
y: 215,
}
],
},
];
var svg = d3.select("body").append("svg").attr("width", config.width).attr("height", 500);
var g = svg.selectAll("g")
.data(data)
.enter()
.append("g");
g.append("rect")
.attr("x", 1)
.attr("y", function(d) { return d.y; })
.attr("width", config.width)
.attr("height", function(d) { return d.height; });
Thx.
Upvotes: 0
Views: 520
Reputation: 21578
You could use a subselection binding your parts' data to the corresponding elements using an accessor function like this:
var parts = g.selectAll("g.part")
.data(function(d) { return d.parts; })
.enter()
.append("g")
.attr("class", "part");
Having this subselection at your hands you may insert/append content accessing the corresponding data bound to each group/part.
var config = {
width: 600
};
var data = [
{
height: 150,
y: 0,
parts: [
{
title: "Hello",
x: 50,
y: 60
},
{
title: "World",
x: 350,
y: 60
}
]
},
{
height: 150,
y: 155,
parts: [
{
title: "Demo",
x: 280,
y: 215
}
]
}
];
var svg = d3.select("body").append("svg").attr("width", config.width).attr("height", 500);
var g = svg.selectAll("g")
.data(data)
.enter()
.append("g");
g.append("rect")
.attr("x", 1)
.attr("y", function(d) { return d.y; })
.attr("width", config.width)
.attr("height", function(d) { return d.height; });
var parts = g.selectAll("g.part")
.data(function(d) { return d.parts; })
.enter()
.append("g")
.attr("class", "part");
parts.append("rect")
.attr({
"class": "part",
"x": function(d) { return d.x; },
"y": function(d) { return d.y; },
"width": 200,
"height":80
});
parts.append("text")
.attr({
"class": "part",
"x": function(d) { return d.x; },
"y": function(d) { return d.y; }
})
.text(function(d) { return d.title; });
g.part rect {
fill:white;
}
g.part text {
fill: red;
stroke: none;
font-size:20px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>
Upvotes: 3
Reputation: 14591
Use d3 selector each
method.
g.each(function(d, i) {
var rect = d3.select(this);
d.parts.forEach(function(p) {
rect.append("rect")
.style("fill", "aliceblue")
.attr("x", p.x)
.attr("y", p.y)
.attr("width", config.width / 3)
.attr("height", d.height / 2);
rect.append("text")
.style("stroke", "brown")
.attr("x", p.x)
.attr("y", p.y)
.text(p.title);
});
});
var config = {
width: 600
};
var data = [{
height: 150,
y: 0,
parts: [{
title: "Hello",
x: 50,
y: 60,
}, {
title: "World",
x: 350,
y: 60,
}],
}, {
height: 150,
y: 155,
parts: [{
title: "Demo",
x: 280,
y: 215,
}],
}, ];
var svg = d3.select("body").append("svg").attr("width", config.width).attr("height", 500);
var g = svg.selectAll("g")
.data(data)
.enter()
.append("g");
g.append("rect")
.attr("x", 1)
.attr("y", function(d) {
return d.y;
})
.attr("width", config.width)
.attr("height", function(d) {
return d.height;
});
g.each(function(d, i) {
var rect = d3.select(this);
d.parts.forEach(function(p) {
rect.append("rect")
.style("fill", "aliceblue")
.attr("x", p.x)
.attr("y", p.y)
.attr("width", config.width / 3)
.attr("height", d.height / 2);
rect.append("text")
.style("stroke", "brown")
.attr("x", p.x)
.attr("y", p.y)
.text(p.title);
});
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>
Upvotes: 0