d3 的嵌套(分层)数据
Nested (hierarchical) data with d3
我已经阅读了 Bostock 的“Nested Selections”教程,但我无法完全理解如何使用嵌套数据。
我已将我的问题简化为这样的数据集:
var data = [{
"id": "foo",
"row": 0,
"col": 0,
"row_size": 200,
"col_size": 100,
"modules": [{
"id": "foo1",
"row": 0,
"col": 0
}, {
"id": "foo2",
"row": 1,
"col": 0
}]
}, {
"id": "bar",
"row": 0,
"col": 1,
"row_size": 200,
"col_size": 100,
"modules": [{
"id": "bar1",
"row": 0,
"col": 1
}, {
"id": "bar2",
"row": 1,
"col": 1
}]
}]
我正在尝试动态创建一个 svg
,如下所示:
<svg width="500" height="500">
<g transform="translate(20,20)">
<g transform="translate(0,0)" class="outside_box">
<rect x="0" y="0" width="100" height="200" fill="white" stroke="red" stroke-width="10"></rect>
<text x="50" y="100" text-anchor="middle" alignment-baseline="central" font-size="50">foo</text>
<g class="inside_box">
<g transform="translate(0,0)">
<rect x="0" y="0" width="100" height="100" fill-opacity="0.5" stroke="blue"></rect>
<text x="50" y="50" text-anchor="middle" alignment-baseline="central">foo1</text>
</g>
<g transform="translate(0,100)">
<rect x="0" y="0" width="100" height="100" fill-opacity="0.5" stroke="blue"></rect>
<text x="50" y="50" text-anchor="middle" alignment-baseline="central">foo2</text>
</g>
</g>
</g>
<g transform="translate(100,0)" class="outside_box">
<rect x="0" y="0" width="100" height="200" fill="white" stroke="red" stroke-width="10"></rect>
<text x="50" y="100" text-anchor="middle" alignment-baseline="central" font-size="50">bar</text>
<g class="inside_box">
<g transform="translate(0,0)">
<rect x="0" y="0" width="100" height="100" fill-opacity="0.5" stroke="blue"></rect>
<text x="50" y="50" text-anchor="middle" alignment-baseline="central">bar1</text>
</g>
<g transform="translate(0,100)">
<rect x="0" y="0" width="100" height="100" fill-opacity="0.5" stroke="blue"></rect>
<text x="50" y="50" text-anchor="middle" alignment-baseline="central">bar2</text>
</g>
</g>
</g>
</g>
</svg>
我的示例中的定位、大小和颜色是无关紧要的(我只是添加了额外的属性以使 SVG 清晰易懂);但是 <g>
、<text>
和 <rect>
的分组非常重要。我还想从头开始创建 SVG(空白 canvas),所以尝试做类似
的事情
d3.selectAll("g").data(data).enter().append("g")...
谢谢!
这应该可以做到。我没有测试过,所以可能有错误,但整体结构就是你所追求的。
var svg = d3.select("body").append("svg") // here you'll also want to apply width and height .attr's
var mainG = svg.append("g") // this you'll also want to translate(20,20) as your mockup suggests
// Now bind the outer level, to produce a 2-element selection bound to 'data'
var gOuter = mainG.selectAll("g.outside_box").data(data)
var gOuterEnter = gOuter.enter().append("g")
.attr("class", "outside_box")
// also to this you can apply translation as you wish
gOuterEnter.append("rect") // and set the rect's attributes as needed
gOuterEnter.append("text") // and set the text's attributes and text as needed
gOuterEnter.append("g")
.attr("class", "inside_box")
// Now comes the work with the nested data:
var gModules = gOuterEnter.select(".inside_box").selectAll("g").data(function(d) {
// here d is the outer datum, and lets you access
// its nested 'modules' array, which is what you want
// to return, as instructed by Bostocks "Nested Selections" tutorial
return d.modules
})
var gModulesEnter = gModules.enter()
.append("g")
gModulesEnter.append("rect") // and set attributes
gModulesEnter.append("text")
.text(function(m) {
// here m is each module's datum, so you can return its id
// to set the text to what you want
return d.id
})
我已经阅读了 Bostock 的“Nested Selections”教程,但我无法完全理解如何使用嵌套数据。
我已将我的问题简化为这样的数据集:
var data = [{
"id": "foo",
"row": 0,
"col": 0,
"row_size": 200,
"col_size": 100,
"modules": [{
"id": "foo1",
"row": 0,
"col": 0
}, {
"id": "foo2",
"row": 1,
"col": 0
}]
}, {
"id": "bar",
"row": 0,
"col": 1,
"row_size": 200,
"col_size": 100,
"modules": [{
"id": "bar1",
"row": 0,
"col": 1
}, {
"id": "bar2",
"row": 1,
"col": 1
}]
}]
我正在尝试动态创建一个 svg
,如下所示:
<svg width="500" height="500">
<g transform="translate(20,20)">
<g transform="translate(0,0)" class="outside_box">
<rect x="0" y="0" width="100" height="200" fill="white" stroke="red" stroke-width="10"></rect>
<text x="50" y="100" text-anchor="middle" alignment-baseline="central" font-size="50">foo</text>
<g class="inside_box">
<g transform="translate(0,0)">
<rect x="0" y="0" width="100" height="100" fill-opacity="0.5" stroke="blue"></rect>
<text x="50" y="50" text-anchor="middle" alignment-baseline="central">foo1</text>
</g>
<g transform="translate(0,100)">
<rect x="0" y="0" width="100" height="100" fill-opacity="0.5" stroke="blue"></rect>
<text x="50" y="50" text-anchor="middle" alignment-baseline="central">foo2</text>
</g>
</g>
</g>
<g transform="translate(100,0)" class="outside_box">
<rect x="0" y="0" width="100" height="200" fill="white" stroke="red" stroke-width="10"></rect>
<text x="50" y="100" text-anchor="middle" alignment-baseline="central" font-size="50">bar</text>
<g class="inside_box">
<g transform="translate(0,0)">
<rect x="0" y="0" width="100" height="100" fill-opacity="0.5" stroke="blue"></rect>
<text x="50" y="50" text-anchor="middle" alignment-baseline="central">bar1</text>
</g>
<g transform="translate(0,100)">
<rect x="0" y="0" width="100" height="100" fill-opacity="0.5" stroke="blue"></rect>
<text x="50" y="50" text-anchor="middle" alignment-baseline="central">bar2</text>
</g>
</g>
</g>
</g>
</svg>
我的示例中的定位、大小和颜色是无关紧要的(我只是添加了额外的属性以使 SVG 清晰易懂);但是 <g>
、<text>
和 <rect>
的分组非常重要。我还想从头开始创建 SVG(空白 canvas),所以尝试做类似
d3.selectAll("g").data(data).enter().append("g")...
谢谢!
这应该可以做到。我没有测试过,所以可能有错误,但整体结构就是你所追求的。
var svg = d3.select("body").append("svg") // here you'll also want to apply width and height .attr's
var mainG = svg.append("g") // this you'll also want to translate(20,20) as your mockup suggests
// Now bind the outer level, to produce a 2-element selection bound to 'data'
var gOuter = mainG.selectAll("g.outside_box").data(data)
var gOuterEnter = gOuter.enter().append("g")
.attr("class", "outside_box")
// also to this you can apply translation as you wish
gOuterEnter.append("rect") // and set the rect's attributes as needed
gOuterEnter.append("text") // and set the text's attributes and text as needed
gOuterEnter.append("g")
.attr("class", "inside_box")
// Now comes the work with the nested data:
var gModules = gOuterEnter.select(".inside_box").selectAll("g").data(function(d) {
// here d is the outer datum, and lets you access
// its nested 'modules' array, which is what you want
// to return, as instructed by Bostocks "Nested Selections" tutorial
return d.modules
})
var gModulesEnter = gModules.enter()
.append("g")
gModulesEnter.append("rect") // and set attributes
gModulesEnter.append("text")
.text(function(m) {
// here m is each module's datum, so you can return its id
// to set the text to what you want
return d.id
})