D3.js .打开(“拖动”,拖动) 。在(“结束”,dragended)); 函数dragstarted(d){ d3.选择(this).raise().classed(“活动”,true); } 函数(d){ d3.选择(this).attr(“cx”,d.x=d3.event.x).attr(“cy”,d.y=d3.event.y); } 函数d(d){ d3.选择(此).classed(“活动”,false); } var lastIndex=0; var click=function(){ if(d3.event.defaultPrevented)返回; var p=d3.鼠标(此), x=p[0], y=p[1]; 圆[++lastIndex]={x:x,y:y}; append('circle') .基准面(圆[lastIndex]) .attr('cx',x) .attr('cy',y) .attr('r',半径) .style(“fill”,函数(d,i){返回颜色(lastIndex);}) .call(d3.drag() .on(“开始”,拖动开始) .打开(“拖动”,拖动) 。在(“结束”,dragended)); }; svg.on('click',click);

D3.js .打开(“拖动”,拖动) 。在(“结束”,dragended)); 函数dragstarted(d){ d3.选择(this).raise().classed(“活动”,true); } 函数(d){ d3.选择(this).attr(“cx”,d.x=d3.event.x).attr(“cy”,d.y=d3.event.y); } 函数d(d){ d3.选择(此).classed(“活动”,false); } var lastIndex=0; var click=function(){ if(d3.event.defaultPrevented)返回; var p=d3.鼠标(此), x=p[0], y=p[1]; 圆[++lastIndex]={x:x,y:y}; append('circle') .基准面(圆[lastIndex]) .attr('cx',x) .attr('cy',y) .attr('r',半径) .style(“fill”,函数(d,i){返回颜色(lastIndex);}) .call(d3.drag() .on(“开始”,拖动开始) .打开(“拖动”,拖动) 。在(“结束”,dragended)); }; svg.on('click',click);,d3.js,D3.js,这是Gerardo Furtado的正确补充,既不是替代品,也不是替代品。我决定提供更多的信息,并分享我对这一点的看法 正如Gerardo所指出的,您认为新添加的圆的拖动行为不活动的假设是错误的。拖动行为已成功附着,并且即使对于新圆也是活动的。但是,draugd()函数将中断,因为它试图访问和分配绑定到被拖动圆的数据。因为新添加的圆没有数据绑定到它们,这将导致一个错误,导致拖动行为不适用于这些圆。正如Gerardo所建议的,有两种方法可以解决这个问题,一种是使用.datum()将数据绑定到新的圆

这是Gerardo Furtado的正确补充,既不是替代品,也不是替代品。我决定提供更多的信息,并分享我对这一点的看法

正如Gerardo所指出的,您认为新添加的圆的拖动行为不活动的假设是错误的。拖动行为已成功附着,并且即使对于新圆也是活动的。但是,
draugd()
函数将中断,因为它试图访问和分配绑定到被拖动圆的数据。因为新添加的圆没有数据绑定到它们,这将导致一个错误,导致拖动行为不适用于这些圆。正如Gerardo所建议的,有两种方法可以解决这个问题,一种是使用
.datum()
将数据绑定到新的圆,另一种是取消拖动处理程序函数中的数据访问

虽然这两种方法都可以,但我更喜欢后者,因为它简单。如果除了跟踪圆的位置外,不需要任何其他目的的数据,则无需保持此模型的最新状态。因为SVGs DOM隐式地携带DOM中的定位信息,所以不需要在模型中显式地复制此信息,即在绑定到DOM元素的数据中

在图元上打印时,您肯定需要使用模型来跟踪位置更改。画布更像是一种“先画后忘”的方法,它不受分层DOM的支持。与SVG相比,它没有独特的、可选择的元素的内置概念,因此缺乏对将数据绑定到元素的支持。为了能够跟踪元素,您必须自己提供支持此视图的模型


我认为,牢记这一差异,可以更深入地了解为什么数据更新会进入链接示例,尽管Mike Bostock以其相当简洁的代码而闻名。但是块也链接到,这使用画布做同样的事情。请注意,这两个块是在同一天设置的,SVG演示,即圆圈拖动i,似乎从画布示例中得到了一些剩余代码。

这是Gerardo Furtado正确的补充,不是替代品,也不是替代品。我决定提供更多的信息,并分享我对这一点的看法

正如Gerardo所指出的,您认为新添加的圆的拖动行为不活动的假设是错误的。拖动行为已成功附着,并且即使对于新圆也是活动的。但是,
draugd()
函数将中断,因为它试图访问和分配绑定到被拖动圆的数据。因为新添加的圆没有数据绑定到它们,这将导致一个错误,导致拖动行为不适用于这些圆。正如Gerardo所建议的,有两种方法可以解决这个问题,一种是使用
.datum()
将数据绑定到新的圆,另一种是取消拖动处理程序函数中的数据访问

虽然这两种方法都可以,但我更喜欢后者,因为它简单。如果除了跟踪圆的位置外,不需要任何其他目的的数据,则无需保持此模型的最新状态。因为SVGs DOM隐式地携带DOM中的定位信息,所以不需要在模型中显式地复制此信息,即在绑定到DOM元素的数据中

在图元上打印时,您肯定需要使用模型来跟踪位置更改。画布更像是一种“先画后忘”的方法,它不受分层DOM的支持。与SVG相比,它没有独特的、可选择的元素的内置概念,因此缺乏对将数据绑定到元素的支持。为了能够跟踪元素,您必须自己提供支持此视图的模型


我认为,牢记这一差异,可以更深入地了解为什么数据更新会进入链接示例,尽管Mike Bostock以其相当简洁的代码而闻名。但是块也链接到,这使用画布做同样的事情。请注意,这两个块是在同一天设置的,SVG演示(即圆形拖动i)似乎从画布示例中得到了一些剩余代码。

您的想法有点不正确。仅包含新引入的记录,以前未被
d3
跟踪。它并不是包含每一条记录。@MatthewHerbst我明白你的意思。但是为了找到这些额外的元素,D3将圆的元素与现有的SVG圆进行匹配。让我换一种说法。假设
circles
最初为空,因此初始的
svg.selectAll(“circle”).data(circles)
变得多余,我们是否能够通过svg.append('circle')…调用(d3.drag().on…`并获得正确的sync-i
<!DOCTYPE html>
<meta charset="utf-8">
<style>

    .active {
        stroke: #000;
        stroke-width: 2px;
    }

</style>
<svg width="960" height="500"></svg>
<script src="https://d3js.org/d3.v4.min.js"></script>
<script>

    var svg = d3.select("svg"),
        width = +svg.attr("width"),
        height = +svg.attr("height"),
        radius = 32;

    var circles = [
        {x: 100, y: 100},
        {x: 100, y: 200},
        {x: 100, y: 300}
    ];
    var lastIndex = 2;

    var color = d3.scaleOrdinal()
                  .range(d3.schemeCategory20);

    svg.selectAll("circle")
       .data(circles)
       .enter().append("circle")
       .attr("cx", function(d) { return d.x; })
       .attr("cy", function(d) { return d.y; })
       .attr("r", radius)
       .style("fill", function(d, i) { return color(i); })
       .call(d3.drag()
               .on("start", dragstarted)
               .on("drag", dragged)
               .on("end", dragended));

    function dragstarted(d) {
        d3.select(this).raise().classed("active", true);
    }

    function dragged(d) {
        d3.select(this).attr("cx", d.x = d3.event.x).attr("cy", d.y = d3.event.y);
    }

    function dragended(d) {
        d3.select(this).classed("active", false);
    }
    //----------------Addition----------------
    var click = function() {
        if (d3.event.defaultPrevented) return;

        var p = d3.mouse(this),
            x = p[0],
            y = p[1];
        circles[++lastIndex] = {x: x, y: y};

        svg.append('circle')
           .attr('cx', x)
           .attr('cy', y)
           .attr('r', radius)
           .style("fill", function(d, i) { return color(lastIndex); })
           .call(d3.drag()
                   .on("start", dragstarted)
                   .on("drag", dragged)
                   .on("end", dragended));
    };

    svg.on('click', click);

</script>
svg.append('circle')
    .datum(circles[lastIndex])
    //etc...