我已经设置了这个jsfiddle:http://jsfiddle.net/386er/dhzq6q6f/14/
var moveCell = function(direction) {
var cellToBeMoved = pickRandomCell();
var currentX = cellToBeMoved.x.baseVal.value;
var currentY = cellToBeMoved.y.baseVal.value;
var change = getPlusOrMinus() * (cellSize + 1 );
var newX = currentX + change;
var newY = currentY + change;
var selectedCell = d3.select(cellToBeMoved);
if (direction === 'x') {
selectedCell.transition().duration(1500)
.attr('x', newX );
} else {
selectedCell.transition().duration(1500)
.attr('y', newY );
}
Run Code Online (Sandbox Code Playgroud)
}
在moveCell函数中,我选择一个随机单元格,请求其当前的x和y坐标,然后添加或减去其宽度或高度,以将其移动到相邻的单元格.
我想知道的是:如果你观察细胞移动,有些只会部分移动到下一个细胞.anoyne可以告诉我,为什么会这样?
在这种情况下要做的第一件事就是进行.each("interrupt", function() { console.log("interrupted!") });转换。然后你就会看到问题所在。
如果您将转换命名为 ,则应该可以修复它selection.transition("name"),但这并不能修复它。
这意味着您必须按照@jcuenod 的建议进行操作并排除正在移动的那些。一种惯用的方法是这样的......
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);
};
Run Code Online (Sandbox Code Playgroud)
这是一个证明这个概念的小提琴。
为了完整起见,这里使用 d3 方法。
我已尽力使其尽可能地惯用。要点是...
keyselection.data()xyfillselection.datum(). d3 使用key函数将数据值与 进行比较datum,以便将节点分类为更新、进入或退出。如果key创建了 a,这是数据/基准值的函数,则不会检测到数据更改。通过splice-ing 更改到数据数组中,所引用的值selection.datum()将与数据数组不同,因此数据更改将标记退出节点。d3.timer用于平滑动画和整理资源。d3Timer 在每个动画帧之前、更新转换之前回调以更新数据。d3.scale.ordinal()管理定位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);
};
Run Code Online (Sandbox Code Playgroud)
$(function () {
var container,
svg,
gridHeight = 800,
gridWidth = 1600,
cellSize, cellPitch,
cellsColumns = 100,
cellsRows = 50,
squares,
container = d3.select('.svg-container'),
svg = container.append('svg')
.attr('width', gridWidth)
.attr('height', gridHeight)
.style({ 'background-color': 'black', opacity: 1 }),
createRandomRGB = function () {
var red = Math.floor((Math.random() * 256)).toString(),
green = Math.floor((Math.random() * 256)).toString(),
blue = Math.floor((Math.random() * 256)).toString(),
rgb = 'rgb(' + red + ',' + green + ',' + blue + ')';
return rgb;
},
createGrid = function (width, height) {
var scaleHorizontal = d3.scale.ordinal()
.domain(d3.range(cellsColumns))
.rangeBands([0, width], 1 / 15),
rangeHorizontal = scaleHorizontal.range(),
scaleVertical = d3.scale.ordinal()
.domain(d3.range(cellsRows))
.rangeBands([0, height]),
rangeVertical = scaleVertical.range(),
squares = [];
rangeHorizontal.forEach(function (dh, i) {
rangeVertical.forEach(function (dv, j) {
var indx;
squares[indx = i + j * cellsColumns] = { x: dh, y: dv, c: createRandomRGB(), indx: indx }
})
});
cellSize = scaleHorizontal.rangeBand();
cellPitch = {
x: rangeHorizontal[1] - rangeHorizontal[0],
y: rangeVertical[1] - rangeVertical[0]
}
svg.selectAll("rect").data(squares, function (d, i) { return d.indx })
.enter().append('rect')
.attr('class', 'cell')
.attr('width', cellSize)
.attr('height', cellSize)
.attr('x', function (d) { return d.x })
.attr('y', function (d) { return d.y })
.style('fill', function (d) { return d.c });
return squares;
},
choseRandom = function (options) {
options = options || [true, false];
var max = options.length;
return options[Math.floor(Math.random() * (max))];
},
pickRandomCell = function (cells) {
var l = cells.size(),
r = Math.floor(Math.random() * l);
return l ? d3.select(cells[0][r]).datum().indx : -1;
};
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);
};
function permutateColours() {
var samples = Math.min(50, Math.max(~~(squares.length / 50),1)), s, ii = [], i, k = 0,
cells = d3.selectAll('.cell');
while (samples--) {
do i = pickRandomCell(cells); while (ii.indexOf(i) > -1 && k++ < 5 && i > -1);
if (k < 10 && i > -1) {
ii.push(i);
s = squares[i];
squares.splice(i, 1, { x: s.x, y: s.y, c: createRandomRGB(), indx: s.indx });
}
}
}
function permutatePositions() {
var samples = Math.min(20, Math.max(~~(squares.length / 100),1)), s, ss = [], d, m, p, k = 0,
cells = d3.selectAll('.cell');
while (samples--) {
do s = pickRandomCell(cells); while (ss.indexOf(s) > -1 && k++ < 5 && s > -1);
if (k < 10 && s > -1) {
ss.push(s);
d = squares[s];
m = { x: d.x, y: d.y, c: d.c, indx: d.indx };
m[p = choseRandom(["x", "y"])] = m[p] + choseRandom([-1, 1]) * cellPitch[p];
squares.splice(s, 1, m);
}
}
}
function updateSquares() {
//use a composite key function to transform the exit selection into
// an attribute update selection
//because it's the exit selection, d3 doesn't bind the new data
// that's done manually with the .each
var changes = svg.selectAll("rect")
.data(squares, function (d, i) { return d.indx + "_" + d.x + "_" + d.y + "_" + d.c; })
.exit().each(function (d, i, j) { d3.select(this).datum(squares[i]) })
changes.transition("x").duration(1500)
.attr('x', function (d) { return d.x })
.each("start", function () { lock.call(this, "lockedX") })
.each("end", function () { unlock.call(this, "lockedX") })
changes.transition("y").duration(1500)
.attr('y', function (d) { return d.y })
.each("start", function () { lock.call(this, "lockedY") })
.each("end", function () { unlock.call(this, "lockedY") });
changes.attr("stroke", "white")
.style("stroke-opacity", 0.6)
.transition("fill").duration(800)
.style('fill', function (d, i) { return d.c })
.style("stroke-opacity", 0)
.each("start", function () { lock.call(this, "lockedFill") })
.each("end", function () { unlock.call(this, "lockedFill") });
}
squares = createGrid(gridWidth, gridHeight);
d3.timer(function tick() {
permutateColours();
permutatePositions();
updateSquares();
});
});Run Code Online (Sandbox Code Playgroud)
注意:需要 d3 版本 3.5.5 才能运行位置转换。
编辑:修复了锁定和解锁的问题。标记数据可能比将类写入 DOM 更好,但无论如何……这种方式很有趣。
| 归档时间: |
|
| 查看次数: |
104 次 |
| 最近记录: |