使用密钥时无法获取d3选择的更新数据

时间:2017-02-23 14:56:49

标签: javascript d3.js

我尝试使用 d3.js 创建排序算法的可视化。为此,我想创建几个具有不同半径的圆,然后逐个交换它们作为排序算法的工作。为了做到这一点,我遇到了以下问题:当我更新与d3选择相关的数据然后尝试使用.data()将其恢复时,我得到了未更改的数据(因为我没有更新它)。仅当我使用key函数跟踪对象时才会出现此问题。

代码如下。如果单击"选中",您将在控制台中获得[1, 3, 2],这是正确的初始状态。如果您点击"执行",update功能将被调用,圈子将根据新数据更改其位置。但是,如果你点击那么"检查"再次,您仍然按预期获得[1, 3, 2]而不是[3, 2, 1]

所以,有两个问题:

  1. 为什么它会以这种方式表现?
  2. 如何克服这个问题,即从选择中获取更新数据?
  3. 
    
      
        function key(d) {
            return d
          }
        
        function update(data) { 
          return d3.select("#picture")
            .selectAll("circle")
            .data(data, key)
            .transition()
            .attr("cx", function(d, i) {return (i+1)*50;});
        }
        
        $(function() {
          d3.select("#picture")
            .selectAll("circle")
            .data([1, 3, 2], key)
            .enter()
            .append("circle")
            .attr("cx", function(d, i) {return (i+1)*50;})
            .attr("cy", 100)
            .attr("r", function(d) {return (d+1)*10;})
            .style("fill", "none")
            .style("stroke", "steelblue");
          
          $("#do_it").click(function() {
             update([3, 2, 1]);   
          });
          $("#check").click(function() {
             console.log(d3.select("#picture")
                      .selectAll("circle").data());
          });
        });
    
    <script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
       <button id="check">check</button>
       <button id="do_it">do</button><br/>
       <svg id="picture" width=300 height=150></svg>
    &#13;
    &#13;
    &#13;

2 个答案:

答案 0 :(得分:2)

由于您使用了密钥,因此数据的顺序不会改变正好。如果您没有使用密钥,则订单会发生变化。

使用以下关系创建圆圈:

  • 01为基准
  • 13为基准
  • 22为基准。

每个数据用作键,用于标识圆圈。更新数据时,此关系不会再次发生变化,因为您已设置密钥。

当您在更新(&#34;执行&#34;)功能后对数据进行console.log时,您无法获取有关圈子的新位置的数据。当你在更新后console.log数据时,事实上,你得到同样的东西:

  • 01为基准
  • 13为基准
  • 22为基准。

这些不是圈子的位置,而是它们的创建顺序。

但是,如果在update函数中放置console.log,则可以看到位置正在改变:

console.log("circle at position " + i + ", data: " + d)

检查演示,点击&#34;执行&#34;并查看与不同位置的圈子相关联的数据:

&#13;
&#13;
function key(d) {
        return d
      }
    
    function update(data) { 
      return d3.select("#picture")
        .selectAll("circle")
        .data(data, key)
        .transition()
        .attr("cx", function(d, i) {
        console.log("circle at position " + i + ", data: " + d)   
        return (i+1)*50;});
    }
    
    $(function() {
      d3.select("#picture")
        .selectAll("circle")
        .data([1, 3, 2], key)
        .enter()
        .append("circle")
        .attr("cx", function(d, i) {return (i+1)*50;})
        .attr("cy", 100)
        .attr("r", function(d) {return (d+1)*10;})
        .style("fill", "none")
        .style("stroke", "steelblue");
      
      $("#do_it").click(function() {
         update([3, 2, 1]);   
      });
      $("#check").click(function() {
         console.log(d3.select("#picture")
                  .selectAll("circle").data());
      });
    });
&#13;
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
   <button id="check">check</button>
   <button id="do_it">do</button><br/>
   <svg id="picture" width=300 height=150></svg>
&#13;
&#13;
&#13;

答案 1 :(得分:1)

Gerardo Furtado的回答解释了这种行为的原因,这里是我问题第二部分的答案:如何克服这一点。

我将元素的实际位置存储在其data-position属性中,然后从该位置信息中恢复原始数据。

我不确定这是一个最优雅的解决方案,因此非常感谢评论和替代方案。

&#13;
&#13;
function key(d) {
  return d
}

function update(data) {
  return d3.select("#picture")
    .selectAll("circle")
    .data(data, key)
    .transition()
    .attr("cx", function(d, i) {
      return (i + 1) * 50;
    })
    .attr("data-position", function(d, i) {
      return i;
    });
}

function get_data(initial_array) {
  // BASED ON: http://stackoverflow.com/a/22118052/3025981
  var indexes = []
  d3.select("#picture")
    .selectAll("circle").each(function(d, i) {
      indexes.push(+d3.select(this).attr('data-position'))
    });
  // END BASED
  var data = []
  for (i = 0; i < initial_array.length; i++) {
    data[indexes[i]] = initial_array[i];
  }
  return data;
}

$(function() {
  initial_array = [1, 3, 2]
  d3.select("#picture")
    .selectAll("circle")
    .data(initial_array, key)
    .enter()
    .append("circle")
    .attr("cx", function(d, i) {
      return (i + 1) * 50;
    })
    .attr("cy", 100)
    .attr("r", function(d) {
      return (d + 1) * 10;
    })
    .attr("data-position", function(d, i) {
      return i;
    })
    .style("fill", "none")
    .style("stroke", "steelblue");

  $("#do_it").click(function() {
    update([3, 2, 1]);
  });
  $("#check").click(function() {
    console.log(get_data(initial_array));
  });
});
&#13;
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<button id="check">check</button>
<button id="do_it">do</button>
<br/>
<svg id="picture" widht=300 height=300></svg>
&#13;
&#13;
&#13;