当相同类型的元素已经存在时,我可以使用 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.cellenter 语句之后的转换。此外,如果我通过添加

在脚本末尾更新转换
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 如何匹配元素和数据以防止重新绑定,但恕我直言,这不太直观。