Javascript 为什么有些细胞不能完全移动

Javascript 为什么有些细胞不能完全移动,javascript,d3.js,Javascript,D3.js,我已经设置了这个JSFIDLE: } 在moveCell函数中,我选择一个随机单元,请求其当前的x和y坐标,然后加上或减去其宽度或高度,将其移动到相邻单元 我想知道的是:如果你观察细胞移动,一些细胞只会部分移动到下一个细胞。有一位女士能告诉我,为什么会这样吗?在这种情况下,首先要做的是放置。每个(“中断”,function(){console.log(“中断”)})在您的转换上。然后您将看到问题。 如果您将转换命名为selection.transition(“name”),则应该修复它,但这并不

我已经设置了这个JSFIDLE:

}

在moveCell函数中,我选择一个随机单元,请求其当前的x和y坐标,然后加上或减去其宽度或高度,将其移动到相邻单元


我想知道的是:如果你观察细胞移动,一些细胞只会部分移动到下一个细胞。有一位女士能告诉我,为什么会这样吗?

在这种情况下,首先要做的是放置
。每个(“中断”,function(){console.log(“中断”)})在您的转换上。然后您将看到问题。
如果您将转换命名为
selection.transition(“name”)
,则应该修复它,但这并不能修复它。
这意味着您必须按照@jcunod的建议进行操作,并排除正在移动的对象。一种惯用的方法是这样做

if (direction === 'x') {
    selectedCell.transition("x").duration(1500)
      .attr('x', newX)
      .each("start", function () { lock.call(this, "lockedX") })
      .each("end", function () { unlock.call(this, "lockedX") });
} else {
    selectedCell.transition("y").duration(1500)
      .attr('y', newY)
      .each("start", function () { lock.call(this, "lockedX") })
      .each("end", function () { unlock.call(this, "lockedX") });
}

function lock(lockClass) {
    var c = { cell: false }; c[lockClass] = true;
    d3.select(this).classed(c)
};
function unlock(lockClass) {
    var c = { cell: this.classList.length == 1 }; c[lockClass] = false;
    d3.select(this).classed(c);
};
是用来证明这个概念的小提琴


纯粹且惯用的d3版本 为了完整起见,这里是d3的方法。
我试着使它尽可能地道。要点是

  • 纯数据驱动
    数据被更新,viz操作完全由d3声明完成
  • 使用d3检测svg元素属性的更改并对其采取行动
    这是通过在
    selection.data()
    方法中使用复合
    函数来实现的,并利用退出选择捕获更改的节点(其中
    x
    y
    fill
    属性与更新数据不匹配的方块)
  • 将更改的元素拼接到数据数组中,以便d3可以检测到更改
    由于对数据数组元素的引用绑定到DOM元素,因此对数据的任何更改也将反映在
    selection.datum()
    中。d3使用
    功能将数据值与
    基准
    进行比较,以便将节点分类为更新、进入或退出。如果按下
    ,这是数据/基准值的函数,则不会检测到数据的更改。通过
    splice
    -ing对数据数组的更改,由
    selection.datum()
    引用的值将不同于数据数组,因此数据更改将标记退出节点。
    通过简单地操作属性并在退出选择上放置转换,而不是将其删除,它实际上变成了一个“已更改”的选择。
    这仅在数据值为对象时有效
  • 并发转换
    命名转换用于确保x和y转换不会相互中断,但也有必要使用标记类属性锁定转换元素。这是使用转换开始和结束事件完成的
  • 动画帧
    d3.计时器
    用于平滑动画和封送资源。d3Timer在更新变换之前、在每个动画帧之前回调以更新数据
  • 使用
    d3.scale.ordinal()
    管理定位

    这很好,因为你知道它每次都有效,你甚至不必对此感到厌烦

  • $(函数(){
    var容器,
    svg,
    网格高度=800,
    网格宽度=1600,
    细胞大小,细胞间距,
    cellsColumns=100,
    cellsRows=50,
    正方形,
    container=d3.select('.svg container'),
    svg=container.append('svg')
    .attr('width',gridWidth)
    .attr('height',gridHeight)
    .style({“背景色”:“黑色”,不透明度:1}),
    createRandomRGB=函数(){
    var red=Math.floor((Math.random()*256)).toString(),
    绿色=Math.floor((Math.random()*256)).toString(),
    蓝色=Math.floor((Math.random()*256)).toString(),
    rgb='rgb('+红色+'、'+绿色+'、'+蓝色+)';
    返回rgb;
    },
    createGrid=函数(宽度、高度){
    var scaleHorizontal=d3.scale.ordinal()
    .域(d3.范围(单元格列))
    .范围带([0,宽度],1/15),
    rangeHorizontal=scaleHorizontal.range(),
    scaleVertical=d3.scale.ordinal()
    .域(d3.范围(cellsRows))
    .范围带([0,高度]),
    rangeVertical=scaleVertical.range(),
    平方=[];
    rangeHorizontal.forEach(函数(dh,i){
    rangeVertical.forEach(函数(dv,j){
    var-indx;
    正方形[indx=i+j*cellsColumns]={x:dh,y:dv,c:createRandomRGB(),indx:indx}
    })
    });
    cellSize=scaleHorizontal.rangeBand();
    细胞间距={
    x:rangeHorizontal[1]-rangeHorizontal[0],
    y:rangeVertical[1]-rangeVertical[0]
    }
    svg.selectAll(“rect”).data(正方形,函数(d,i){return d.indx})
    .enter().append('rect')
    .attr('类','单元')
    .attr('width',cellSize)
    .attr('height',cellSize)
    .attr('x',函数(d){return d.x})
    .attr('y',函数(d){返回d.y})
    .style('fill',函数(d){return d.c});
    返回方块;
    },
    choseRandom=功能(选项){
    选项=选项| |[对,错];
    var max=options.length;
    返回选项[Math.floor(Math.random()*(max))];
    },
    pickRandomCell=函数(单元格){
    var l=单元格。大小(),
    r=数学地板(数学随机()*l);
    返回l?d3.选择(单元格[0][r]).datum().indx:-1;
    };
    功能锁(锁类){
    var c={cell:false};c[lockClass]=true;
    d3.选择(本)。分类(c)
    };
    功能解锁(锁定类){
    var c={cell:this.classList.length==1};c[lockClass]=false;
    d3.选择(本)。分类(c);
    };
    函数置换颜色(){
    var samples=Math.min(50,Math.max(~~(squares.length/50),1)),s,ii=[],i,k=0,
    cells=d3。选择全部('.cell');
    而(样本--){
    doi=pickdrandomcell(cells);while(ii.indexOf(i)>-1&&k++<5&&i>-1);
    如果(k<10&&i>-1){
    ii.推动(i);
    s=平方[i];
    拼接(i,1,{x:s.x,y:s.y,c:createRandomRGB(),indx:s.indx});
    }
    }
    }
    函数置换位置(){
    变量样本=数学最小值(20,
    
    if (direction === 'x') {
        selectedCell.transition("x").duration(1500)
          .attr('x', newX)
          .each("start", function () { lock.call(this, "lockedX") })
          .each("end", function () { unlock.call(this, "lockedX") });
    } else {
        selectedCell.transition("y").duration(1500)
          .attr('y', newY)
          .each("start", function () { lock.call(this, "lockedX") })
          .each("end", function () { unlock.call(this, "lockedX") });
    }
    
    function lock(lockClass) {
        var c = { cell: false }; c[lockClass] = true;
        d3.select(this).classed(c)
    };
    function unlock(lockClass) {
        var c = { cell: this.classList.length == 1 }; c[lockClass] = false;
        d3.select(this).classed(c);
    };