我正在尝试为D3中的单嵌套数据创建一个简单的矩形结构。我希望结果看起来像下图:
换句话说,每个组的项目都应调整大小,以便所有组占用相同的空间。
JSFiddle that I have made无法产生正确的结果:
var item_groups_enter = item_groups.enter()
.append("g")
.classed("item-group", true)
.attr("transform", function (d, i) {
return ("translate(0, " + 50 * i + ")"); // !!! THIS NEEDS TO CHANGE !!!
});
// Append a rectangle for each item
item_groups_enter.append("rect")
.attr("width", main_group_width)
.attr("height", 50) // !!! THIS NEEDS TO CHANGE !!!
.attr("fill", function (d, i) {
return colours(i)
});
// Also append a label for each item
item_groups_enter.append("text")
.text(function (d) {
return (d)
})
.attr("x", main_group_width * 0.5)
.attr("y", 25) // !!! THIS NEEDS TO CHANGE !!!
.style("text-anchor", "middle");
我意识到我会以某种方式需要通过main-group
s'到item_group
的数据(具体来说,孩子的数量),但我不确定如何做到这一点。我确实尝试在childCount
上设置自定义属性main_group
,但代码变得非常混乱,引用父节点(稍后是祖父节点)。
这样做的方法是什么?我不确定我是否应该考虑D3或CSS方面的解决方案?
答案 0 :(得分:1)
使用selection.attr
函数时,this
设置为当前DOM元素。您可以使用它来访问父选择,并通过它访问基础数据:
例如,
var item_groups_enter = item_groups.enter()
.append("g")
.classed("item-group", true)
.attr("transform", function (d, i) {
// this is the g node
var parentdatum = d3.select(this.parentNode).datum();
var itemY = available_height/parentdatum.values.length * i;
return ("translate(0, " + itemY + ")");
});
var data = [{
group: "Fruits",
values: ["Apple", "Banana", "Pear", "Plum"]
}, {
group: "Cakes",
values: ["Chocolate Cake", "Red Velvet Cake", "Carrot Cake"]
}, {
group: "Dogs",
values: ["Spaniel", "Chow", "Dachshund", "Bulldog", "Beagle", "Boxer", "Pug"]
}]
// Get a handle on the svg HTML element
var svg = d3.select("body").append("svg")
.attr("width", 500)
.attr("height", 500)
// Calculate spacing
var available_width = parseInt(svg.style("width"));
var available_height = parseInt(svg.style("height"));
var main_group_width = available_width / data.length;
// Define the colours to use
var colours = d3.scale.category10();
// Make an HTML group for each of the groups in the data
var main_groups = svg.selectAll("g")
.data(data);
// For each datum entered, append a new HTML group
main_groups.enter()
.append("g")
.classed("main-group", true)
.attr("transform", function (d, i) {
return ("translate(" + i * main_group_width + ", 0)");
})
// Append a new group, an "item group" for each of the values in each of the main groups
var item_groups = main_groups.selectAll("g")
.data(function (d) {
return (d.values)
});
var item_groups_enter = item_groups.enter()
.append("g")
.classed("item-group", true)
.attr("transform", function (d, i) {
var parentdatum = d3.select(this.parentNode).datum();
return ("translate(0, " + available_height/parentdatum.values.length * i + ")");
});
// Append a rectangle for each item
item_groups_enter.append("rect")
.attr("width", main_group_width)
.attr("height", function() {
// we want the grand parent node
var parentdatum = d3.select(this.parentNode.parentNode).datum();
return available_height/parentdatum.values.length;
})
.attr("fill", function (d, i) {
return colours(i)
});
// Also append a label for each item
item_groups_enter.append("text")
.text(function (d) {
return (d)
})
.attr("x", main_group_width * 0.5)
.attr("y", 25)
.style("text-anchor", "middle");

<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>
&#13;
您还可以遍历由item_groups
选项定义的组(main_groups.selectAll("g")
中每个父元素一个组)并分配您的属性。例如
item_groups_enter.forEach(function(g, i) {
var parentdatum = d3.select(g.parentNode).datum();
var h = available_height/parentdatum.values.length;
var selection = d3.selectAll(g);
selection.attr("transform", function (d, i) {
return ("translate(0, " + h * i + ")");
});
selection.select('rect')
.attr("height", h);
selection.select('text')
.attr("y", h/2);
});
您可以使用每个组中定义的parentNode
来确定正确的父数据。
var data = [{
group: "Fruits",
values: ["Apple", "Banana", "Pear", "Plum"]
}, {
group: "Cakes",
values: ["Chocolate Cake", "Red Velvet Cake", "Carrot Cake"]
}, {
group: "Dogs",
values: ["Spaniel", "Chow", "Dachshund", "Bulldog", "Beagle", "Boxer", "Pug"]
}]
// Get a handle on the svg HTML element
var svg = d3.select("body").append("svg")
.attr("width", 500)
.attr("height", 500)
// Calculate spacing
var available_width = parseInt(svg.style("width"));
var available_height = parseInt(svg.style("height"));
var main_group_width = available_width / data.length;
// Define the colours to use
var colours = d3.scale.category10();
// Make an HTML group for each of the groups in the data
var main_groups = svg.selectAll("g")
.data(data);
// For each datum entered, append a new HTML group
main_groups.enter()
.append("g")
.classed("main-group", true)
.attr("transform", function (d, i) {
return ("translate(" + i * main_group_width + ", 0)");
})
// Append a new group, an "item group" for each of the values in each of the main groups
var item_groups = main_groups.selectAll("g")
.data(function (d) {
return (d.values)
});
var item_groups_enter = item_groups.enter()
.append("g")
.classed("item-group", true);
item_groups_enter.append("rect")
.attr("width", main_group_width)
.attr("fill", function (d, i) {
return colours(i)
});
item_groups_enter.append("text")
.text(function (d) {
return (d)
})
.attr("x", main_group_width * 0.5)
.attr("y", 25)
.style("text-anchor", "middle");
item_groups_enter.forEach(function(g, i) {
var parentdatum = d3.select(g.parentNode).datum();
var h = available_height/parentdatum.values.length;
var selection = d3.selectAll(g);
selection.attr("transform", function (d, i) {
return ("translate(0, " + h * i + ")");
});
selection.select('rect')
.attr("height", h);
selection.select('text')
.attr("y", h/2);
});
&#13;
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>
&#13;