当相同类型的元素已经存在时,我可以使用 selectAll 创建新元素吗?
Can I use selectAll to create new element when elements of same type already exist?
我想使用两个不同的数据源将 g
元素添加到 svg
。但是,我最终将第二个数据源绑定到现有的 g
元素,而不是创建新的 g
元素。
这是一个例子
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html;charset=utf-8" />
<script src="http://d3js.org/d3.v3.min.js" charset="utf-8"></script>
</head>
<body>
<div id="body"></div>
<script type="text/javascript">
var canvas_w = 1280 - 80,
canvas_h = 800 - 180;
var svg = d3.select("#body").append("div")
.append("svg:svg")
.attr("width", canvas_w)
.attr("height", canvas_h)
var category_cells = svg.selectAll("g")
.data([0, 1, 2])
.enter().append("g")
.attr("class", "category")
.attr("transform", function(d) {console.log(d); return "translate(" + d*100 + ", 0)"; });
category_cells.append("rect")
.attr("y", 0)
.attr("x", 0)
.attr("width", 50)
.attr("height", 50)
.style("fill", "blue");
var cell = svg.selectAll("g")
.data([3, 4, 5])
.enter().append("g")
.attr("class", "cell")
.attr("transform", function(d) {console.log(d); return "translate(" + d*100 + ", 0)"; });
cell.append("rect")
.attr("y", 0)
.attr("x", 0)
.attr("width", 50)
.attr("height", 50)
.style("fill", "black");
</script>
</body>
</html>
此脚本显示三个框 class g.category
而不是六个框,其中三个 class g.category
和三个 class g.cell
.它还仅记录“1 2 3”,表明从未输入 g.cell
的 enter
语句之后的转换。此外,如果我通过添加
在脚本末尾更新转换
svg.selectAll("g.category")
.attr("transform", function(d) {console.log(d); return "translate(" + d*100 + ", 0)"; });
g.category
转换发生变化以反映数据 [3 4 5]
。很明显,新数据正在覆盖 g.category
数据,而不是分配给新的 g.cell
元素,但如何防止这种情况发生?
tutorials and documentation 我读过有关将数据绑定到尚不存在的元素的讨论,但它们不处理相同类型的元素已经存在的情况。
我的猜测是解决方案位于更新模式的某处。在文档中有几个地方我可以更改各种元素的属性。
var update_sel = svg.selectAll("g").data(data)
update_sel.attr(/* operate on old elements only */)
update_sel.enter().append("g").attr(/* operate on new elements only */)
update_sel.attr(/* operate on old and new elements */)
update_sel.exit().remove() /* complete the enter-update-exit pattern */
但它没有解释 data
调用如何更改旧元素的数据绑定。
Using selectAll() to create new elements while preserving existing elements 询问如何使用 selectAll
而不在彼此内部嵌套元素,这不是我面临的问题。
问题在于,默认情况下,D3 使用索引来匹配数据。也就是说,第一个数据匹配 selection 中的第一个 DOM 元素,第二个匹配第二个,依此类推。在你的代码中,你在两种情况下都 selecting g
元素,所以这段代码第二次是 运行,数据被反弹到元素,你得到一个你没有的结果期待。
解决方案很简单 - 只需 select 您指定的 类 元素,即在创建元素时使用 .selectAll("g.category")
和 .selectAll("g.class")
。或者,您可以向 .data()
提供一个关键函数来告诉 D3 如何匹配元素和数据以防止重新绑定,但恕我直言,这不太直观。
我想使用两个不同的数据源将 g
元素添加到 svg
。但是,我最终将第二个数据源绑定到现有的 g
元素,而不是创建新的 g
元素。
这是一个例子
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html;charset=utf-8" />
<script src="http://d3js.org/d3.v3.min.js" charset="utf-8"></script>
</head>
<body>
<div id="body"></div>
<script type="text/javascript">
var canvas_w = 1280 - 80,
canvas_h = 800 - 180;
var svg = d3.select("#body").append("div")
.append("svg:svg")
.attr("width", canvas_w)
.attr("height", canvas_h)
var category_cells = svg.selectAll("g")
.data([0, 1, 2])
.enter().append("g")
.attr("class", "category")
.attr("transform", function(d) {console.log(d); return "translate(" + d*100 + ", 0)"; });
category_cells.append("rect")
.attr("y", 0)
.attr("x", 0)
.attr("width", 50)
.attr("height", 50)
.style("fill", "blue");
var cell = svg.selectAll("g")
.data([3, 4, 5])
.enter().append("g")
.attr("class", "cell")
.attr("transform", function(d) {console.log(d); return "translate(" + d*100 + ", 0)"; });
cell.append("rect")
.attr("y", 0)
.attr("x", 0)
.attr("width", 50)
.attr("height", 50)
.style("fill", "black");
</script>
</body>
</html>
此脚本显示三个框 class g.category
而不是六个框,其中三个 class g.category
和三个 class g.cell
.它还仅记录“1 2 3”,表明从未输入 g.cell
的 enter
语句之后的转换。此外,如果我通过添加
svg.selectAll("g.category")
.attr("transform", function(d) {console.log(d); return "translate(" + d*100 + ", 0)"; });
g.category
转换发生变化以反映数据 [3 4 5]
。很明显,新数据正在覆盖 g.category
数据,而不是分配给新的 g.cell
元素,但如何防止这种情况发生?
tutorials and documentation 我读过有关将数据绑定到尚不存在的元素的讨论,但它们不处理相同类型的元素已经存在的情况。
我的猜测是解决方案位于更新模式的某处。在文档中有几个地方我可以更改各种元素的属性。
var update_sel = svg.selectAll("g").data(data)
update_sel.attr(/* operate on old elements only */)
update_sel.enter().append("g").attr(/* operate on new elements only */)
update_sel.attr(/* operate on old and new elements */)
update_sel.exit().remove() /* complete the enter-update-exit pattern */
但它没有解释 data
调用如何更改旧元素的数据绑定。
Using selectAll() to create new elements while preserving existing elements 询问如何使用 selectAll
而不在彼此内部嵌套元素,这不是我面临的问题。
问题在于,默认情况下,D3 使用索引来匹配数据。也就是说,第一个数据匹配 selection 中的第一个 DOM 元素,第二个匹配第二个,依此类推。在你的代码中,你在两种情况下都 selecting g
元素,所以这段代码第二次是 运行,数据被反弹到元素,你得到一个你没有的结果期待。
解决方案很简单 - 只需 select 您指定的 类 元素,即在创建元素时使用 .selectAll("g.category")
和 .selectAll("g.class")
。或者,您可以向 .data()
提供一个关键函数来告诉 D3 如何匹配元素和数据以防止重新绑定,但恕我直言,这不太直观。