$(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() {
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();
});
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.5/d3.min.js"></script>
<div class="svg-container"></div>