D3 - 使 children 填充 parent 组
D3 - Make children fill parent group
我正在尝试为 D3 中的 single-nested 数据创建一个简单的矩形结构。我希望结果如下图所示:
换句话说,每组项目的大小应使所有组占用相同的 space。
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
的数据(具体来说,children 的数量)传递给 item_group
,但我不确定这该怎么做。我确实尝试在 main_group
上设置自定义属性 childCount
,但是引用 parent 节点(然后是 grandparent 节点)的代码变得相当混乱。
有什么方法可以做到这一点?我不确定我是否应该根据 D3 或 CSS?
来考虑解决方案
当您使用带有 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>
您还可以遍历 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);
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>
我正在尝试为 D3 中的 single-nested 数据创建一个简单的矩形结构。我希望结果如下图所示:
换句话说,每组项目的大小应使所有组占用相同的 space。
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
的数据(具体来说,children 的数量)传递给 item_group
,但我不确定这该怎么做。我确实尝试在 main_group
上设置自定义属性 childCount
,但是引用 parent 节点(然后是 grandparent 节点)的代码变得相当混乱。
有什么方法可以做到这一点?我不确定我是否应该根据 D3 或 CSS?
来考虑解决方案当您使用带有 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>
您还可以遍历 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);
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>