2011-04-29 18:14:55 +04:00
|
|
|
// Based on http://vis.stanford.edu/protovis/ex/sort.html
|
2011-05-01 02:56:03 +04:00
|
|
|
// Based on work by Robert Sedgewick
|
2011-04-29 18:14:55 +04:00
|
|
|
|
2011-05-01 02:56:03 +04:00
|
|
|
var w = 960,
|
2011-04-29 18:14:55 +04:00
|
|
|
h = 50,
|
2011-05-01 02:56:03 +04:00
|
|
|
n = 240,
|
|
|
|
x = d3.scale.linear().domain([0, n]).range([h, w - h]),
|
|
|
|
a = d3.scale.linear().domain([0, n - 1]).range([90 + 60, 270 - 60]),
|
|
|
|
data = shuffle(d3.range(n)),
|
|
|
|
duration = 250;
|
2011-04-29 18:14:55 +04:00
|
|
|
|
|
|
|
var vis = d3.select("#chart").append("svg:svg")
|
2011-05-01 02:56:03 +04:00
|
|
|
.attr("width", w)
|
|
|
|
.attr("height", h);
|
2011-04-29 18:14:55 +04:00
|
|
|
|
2011-05-01 02:56:03 +04:00
|
|
|
var line = vis.selectAll("line")
|
|
|
|
.data(data)
|
|
|
|
.enter().append("svg:line")
|
|
|
|
.attr("x1", 0)
|
|
|
|
.attr("y1", 0)
|
|
|
|
.attr("x2", 0)
|
|
|
|
.attr("y2", h)
|
|
|
|
.attr("transform", transform);
|
2011-04-29 18:14:55 +04:00
|
|
|
|
2011-05-01 02:56:03 +04:00
|
|
|
start();
|
|
|
|
|
|
|
|
// Start the animation!
|
|
|
|
function start() {
|
|
|
|
var passes = mergesort(data).reverse();
|
2011-04-29 18:14:55 +04:00
|
|
|
|
|
|
|
update();
|
|
|
|
|
2011-05-01 02:56:03 +04:00
|
|
|
function update() {
|
|
|
|
var pass = passes.pop();
|
2011-04-29 18:14:55 +04:00
|
|
|
|
2011-05-01 02:56:03 +04:00
|
|
|
line.data(pass, Number)
|
|
|
|
.transition()
|
|
|
|
.duration(duration)
|
|
|
|
.attr("transform", transform);
|
|
|
|
|
|
|
|
if (passes.length) {
|
|
|
|
setTimeout(update, duration);
|
2011-04-29 19:09:56 +04:00
|
|
|
} else {
|
2011-05-01 02:56:03 +04:00
|
|
|
shuffle(data);
|
|
|
|
setTimeout(start, duration + 4000);
|
2011-04-29 18:14:55 +04:00
|
|
|
}
|
|
|
|
}
|
2011-05-01 02:56:03 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
function transform(d, i) {
|
|
|
|
return "translate(" + x(i) + "," + h + ")rotate(" + a(d) + ")";
|
|
|
|
}
|
|
|
|
|
|
|
|
// Fisher-Yates shuffle
|
|
|
|
function shuffle(array) {
|
|
|
|
var i = array.length, j, t;
|
|
|
|
while (--i > 0) {
|
|
|
|
j = ~~(Math.random() * (i + 1));
|
|
|
|
t = array[j];
|
|
|
|
array[j] = array[i];
|
|
|
|
array[i] = t;
|
|
|
|
}
|
|
|
|
return array;
|
|
|
|
}
|
|
|
|
|
|
|
|
//
|
|
|
|
// Sorts the specified array using bottom-up mergesort, returning an array of
|
|
|
|
// arrays representing the state of the specified array after each insertion for
|
|
|
|
// each parallel pass. The first pass is performed at size = 2.
|
|
|
|
//
|
|
|
|
function mergesort(array) {
|
|
|
|
var passes = [],
|
|
|
|
i,
|
|
|
|
j,
|
|
|
|
n = array.length,
|
|
|
|
m = 1;
|
|
|
|
|
|
|
|
// double the size each pass
|
|
|
|
while (m < array.length) {
|
|
|
|
i = j = 0; while (i < array.length) j += merge(i, i += m, i += m);
|
|
|
|
if (j) passes.push(array.slice());
|
|
|
|
else m <<= 1;
|
|
|
|
}
|
2011-04-29 18:14:55 +04:00
|
|
|
|
|
|
|
// Merges two adjacent sorted arrays in-place.
|
2011-05-01 02:56:03 +04:00
|
|
|
function merge(start, middle, end) {
|
|
|
|
middle = Math.min(array.length, middle);
|
|
|
|
end = Math.min(array.length, end);
|
2011-04-29 18:14:55 +04:00
|
|
|
for (; start < middle; start++) {
|
|
|
|
if (array[start] > array[middle]) {
|
|
|
|
var v = array[start];
|
|
|
|
array[start] = array[middle];
|
2011-05-01 02:56:03 +04:00
|
|
|
insert(middle, end, v);
|
|
|
|
return true;
|
2011-04-29 18:14:55 +04:00
|
|
|
}
|
|
|
|
}
|
2011-05-01 02:56:03 +04:00
|
|
|
return false;
|
2011-04-29 18:14:55 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
// Inserts the value v into the subarray specified by start and end.
|
2011-05-01 02:56:03 +04:00
|
|
|
function insert(start, end, v) {
|
2011-04-29 18:14:55 +04:00
|
|
|
while (start + 1 < end && array[start + 1] < v) {
|
|
|
|
var tmp = array[start];
|
|
|
|
array[start] = array[start + 1];
|
|
|
|
array[start + 1] = tmp;
|
|
|
|
start++;
|
|
|
|
}
|
|
|
|
array[start] = v;
|
|
|
|
}
|
|
|
|
|
|
|
|
return passes;
|
|
|
|
}
|