[英]A more elegant way to bind new elements using data bound to multiple group elements
When working with d3.js I often encounter the situation where I would like to create some groups that contain specific parts of my data set.在使用 d3.js 时,我经常遇到这样的情况:我想创建一些包含数据集特定部分的组。 These groups are then used to bound some other elements to it after transforming the data contained by the groups with some function.
然后,在使用某些函数转换组包含的数据之后,这些组用于将一些其他元素绑定到它。 I have been searching for an elegant situation for a while, but haven't found one yet.
我一直在寻找一种优雅的情况,但还没有找到。 I now use the each function, but I reckon there must be a better way to do this.
我现在使用 each 函数,但我认为必须有更好的方法来做到这一点。 If anyone knows of a better way to do this, it would be greatly appreciated.
如果有人知道更好的方法来做到这一点,将不胜感激。
d3.json("example.json").then(data => {
d3.select("#A")
.append("svg")
.attr("id", "A_SVG")
.attr("width", width)
.attr("height",height);
d3.select("#A_SVG")
.append("g")
.attr("transform", `translate(${margin.left},${margin.top})`)
.attr("id", "A_CHART");
d3.select("#A_CHART")
.selectAll(".stateProperty")
.data(Object.entries(data["A"]))
.enter()
.append("g")
.attr("class", "stateProperty")
.attr("transform", (d, i) => `translate(0,${i * rowSpacing})`);
d3.select("#A_CHART")
.selectAll(".stateProperty")
.each(function(d) {
d3.select(this)
.selectAll("rect")
.data(getNotHoldsRectValues(d[1]))
.enter()
.append("rect");
});
});
function getNotHoldsRectValues(data) {
return [data[0],data[1]]
}
example.json:示例.json:
{
"A": {
"tick_update": [
{ "holds": 1535602060 },
{ "not_holds": 1535602070 },
{ "holds": 1535602120 },
{ "not_holds": 1535602130 }
],
"some_property": []
},
"B": {
"tick_update": [
{ "holds": 1535602060 },
{ "not_holds": 1535602070 },
{ "holds": 1535602120 },
{ "not_holds": 1535602130 },
{ "holds": 1535602180 },
{ "not_holds": 1535602610 }
],
"some_property": []
}
}
It turns out that the "elegant" way is just the default, idiomatic way.事实证明, “优雅”的方式只是默认的、惯用的方式。
First, avoid selecting elements all the time.首先,避免一直选择元素。 That's a slow process.
这是一个缓慢的过程。 Instead of that, name your selections and use them.
取而代之的是,命名您的选择并使用它们。
So, this...所以这...
d3.select("#A")
.append("svg")
.attr("id", "A_SVG")
.attr("width", width)
.attr("height",height);
d3.select("#A_SVG")
.append("g")
.attr("transform", `translate(${margin.left},${margin.top})`)
.attr("id", "A_CHART");
Becomes:变成:
const svg = d3.select("#A")
.append("svg")
.attr("id", "A_SVG")
.attr("width", width)
.attr("height",height);
svg.append("g")
.attr("transform", `translate(${margin.left},${margin.top})`)
.attr("id", "A_CHART");
That way, you just need to use your new const svg
whenever you want to refer to that selection.这样,您只需要在想要引用该选择时使用新的 const
svg
。 That can be applied to all sub-selections.这可以应用于所有子选择。
Secondly, there is no need for an each
here, simply call the enter selection in the group you want.其次,这里不需要
each
,只需在您想要的组中调用输入选择即可。
All that being said, this could be your code:话虽如此,这可能是您的代码:
d3.json("example.json").then(data => {
const svg = d3.select("#A")
.append("svg")
.attr("id", "A_SVG")
.attr("width", width)
.attr("height", height);
const g = svg.append("g")
.attr("transform", `translate(${margin.left},${margin.top})`)
.attr("id", "A_CHART");
const myGroups = g.selectAll(null)
.data(Object.entries(data["A"]))
.enter()
.append("g")
.attr("class", "stateProperty")
.attr("transform", (d, i) => `translate(0,${i * rowSpacing})`);
const rects = myGroups.selectAll(null)
.data(getNotHoldsRectValues(d[1]))
.enter()
.append("rect");
});
Here I'm using selectAll(null)
, assuming you don't have an update selection.这里我使用
selectAll(null)
,假设您没有更新选择。
Finally, it's not clear to me why you are using Object.entries()
and that getNotHoldsRectValues
function.最后,我不清楚您为什么使用
Object.entries()
和getNotHoldsRectValues
函数。 That might be worth a new question.这可能值得一个新问题。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.