var currentTime = 60*(24*1+10.4);
var clients = [];
var context;
var width = 1024;
var height = 500;
var gridSize = 3;
var nearFieldRadius = 30;
var timeStep = 0.2;
var decay = Math.pow(0.8, 1/timeStep);
var stepSize = 50*timeStep;
var frameDuration = 40;
var radius = 1.4;
var jump = false;
var stepGridRadius = Math.ceil(stepSize/gridSize);
var nearFieldGridRadius = Math.ceil(nearFieldRadius/gridSize);
var interval;
var time2index = [];
var random = [];
var stepGrid = [];
var nearFieldGrid = [];
var grid = [];
for (var x = -nearFieldGridRadius; x < width/gridSize+nearFieldGridRadius; x++) grid[x] = [];
$(function () {
init();
start();
setTimeout(stop, 60000);
})
function init() {
context = $('#canvas')[0].getContext('2d');
clients = [];
data.matrix.forEach(function (times, index) {
clients[index] = {point:undefined, x:0, y:0, r:0, x0:0, y0:0, r0:0, index:index, lastEvent:0};
random[index] = Math.random();
});
var menu = $('#menu');
for (var i = 2; i < 16; i++) {
(function () {
var time = i*6*60;
var d = Math.floor(i/4);
var h = (i % 4)*6;
var node = $('T'+d+' '+h+':00');
node.click(function () {
currentTime = time;
jump = true;
start();
})
menu.append(node);
})();
}
var node = $('Stop');
node.click(stop);
menu.append(node);
var index = -1;
for (var time = -60; time <= (4*24+1)*60; time++) {
while (data.times[index+1] <= time) index++;
time2index[time] = index;
}
for (var x = -stepGridRadius; x <= stepGridRadius; x++) {
for (var y = -stepGridRadius; y <= stepGridRadius; y++) {
var r = Math.round(Math.sqrt(x*x + y*y)*100)/100;
if (r <= stepGridRadius+1) {
stepGrid.push({x:x, y:y, r:r});
}
}
}
stepGrid = stepGrid.sort( function (a,b) { return (a.r - b.r); } );
for (var x = -nearFieldGridRadius; x <= nearFieldGridRadius; x++) {
for (var y = -nearFieldGridRadius; y <= nearFieldGridRadius; y++) {
var r = Math.round(Math.sqrt(x*x + y*y)*100)/100;
var a = Math.atan2(y,x);
if (r <= nearFieldGridRadius) {
nearFieldGrid.push({x:x, y:y, r:r, a:a});
}
}
}
nearFieldGrid = nearFieldGrid.sort( function (a,b) { return (a.r == b.r) ? (a.a - b.a) : (a.r - b.r);} );
}
function start() {
if (!interval) interval = setInterval(update, frameDuration);
}
function stop() {
if (interval) {
clearInterval(interval);
interval = false;
}
}
function update() {
currentTime += timeStep;
if (currentTime >= 4*24*60) {
stop();
return;
}
renderTime();
updateData();
updatePosition();
renderCanvas();
}
function renderTime() {
var d = Math.floor(currentTime/1440);
var h = Math.floor(currentTime/60) % 24;
var m = Math.floor(currentTime) % 60;
h = (h+100+'').substr(1);
m = (m+100+'').substr(1);
$('#timer').html('Tag '+d+' - '+h+':'+m);
}
function updateData() {
data.matrix.forEach(function (times, index) {
var timeId = time2index[Math.floor(currentTime)];
var point = undefined;
var t0 = data.times[timeId]; if (isNaN(t0)) t0 = 0;
var t1 = data.times[timeId+1]; if (isNaN(t1)) t1 = 1e10;
var offset = (currentTime-t0)/(t1-t0);
if (offset < random[index]) {
point = times[timeId-1];
} else {
point = times[timeId];
}
var client = clients[index];
if (client.point != point) {
if (valid(point)) {
client.x0 = data.points[point].x*width;
client.y0 = data.points[point].y*height;
client.r0 = 1;
if (!valid(client.point)) client.x = undefined;
} else {
client.r0 = 0;
}
client.point = point;
client.lastEvent = currentTime;
client.settled = false;
}
});
}
function updatePosition() {
for (var x = -nearFieldGridRadius; x < width/gridSize + nearFieldGridRadius; x++) {
for (var y = -nearFieldGridRadius; y < height/gridSize + nearFieldGridRadius; y++) {
grid[x][y] = ((x >= 0) && (x < width/gridSize) && (y >= 0) && (y < height/gridSize));
}
}
clients.forEach(function (client) {
client.r += (client.r0 - client.r)*decay;
client.r = client.r0;
if (!valid(client.point) && (client.r < 1e-2)) {
client.valid = false;
return;
} else {
client.valid = true;
}
if (client.settled) {
var x = Math.round(client.x/gridSize);
var y = Math.round(client.y/gridSize);
if (grid[x][y]) {
grid[x][y] = false;
client.x = x*gridSize;
client.y = y*gridSize;
} else {
client.settled = false;
}
}
});
clients.forEach(function (client) {
if (!client.valid) return;
client.xo = client.x;
client.yo = client.y;
var gridx0 = Math.round(client.x0/gridSize);
var gridy0 = Math.round(client.y0/gridSize);
if (client.x === undefined) {
// Punkt ist neu, also finde einen neuen Ort zum settlen
for (var i = 0; i < nearFieldGrid.length; i++) {
var p = nearFieldGrid[i];
if (grid[gridx0+p.x][gridy0+p.y]) {
grid[gridx0+p.x][gridy0+p.y] = false;
client.x = (gridx0+p.x)*gridSize;
client.y = (gridy0+p.y)*gridSize;
client.settled = true;
break;
}
}
} else {
if (!client.settled) {
// Kommt gerade von wo anders her
var xn, yn;
var dx = (client.x0 - client.x);
var dy = (client.y0 - client.y);
var r = Math.sqrt(dx*dx + dy*dy);
if (r > 1e-2) {
var rn = Math.max(r-stepSize, 0);
var f = 1-rn/r;
xn = client.x + (client.x0 - client.x)*f;
yn = client.y + (client.y0 - client.y)*f;
} else {
xn = client.x0;
yn = client.y0;
}
var dx = (client.x0 - xn);
var dy = (client.y0 - yn);
var r = Math.sqrt(dx*dx + dy*dy);
if (r < nearFieldRadius) {
xn = Math.round(xn/gridSize);
yn = Math.round(yn/gridSize);
if (grid[xn][yn]) {
client.x = xn*gridSize;
client.y = yn*gridSize;
} else {
var rMin = 1e10;
var pMin = false;
var gridx = Math.round(client.xo/gridSize);
var gridy = Math.round(client.yo/gridSize);
for (var i = 0; i < stepGrid.length; i++) {
var p = stepGrid[i];
if (grid[gridx+p.x][gridy+p.y]) {
var dxn = client.x0 - (gridx + p.x)*gridSize;
var dyn = client.y0 - (gridy + p.y)*gridSize;
var rn = Math.sqrt(dxn*dxn + dyn*dyn);
if (rn < rMin) {
rMin = rn;
pMin = p;
}
}
}
if (pMin) {
grid[gridx+pMin.x][gridy+pMin.y] = false;
client.x = (gridx + pMin.x)*gridSize;
client.y = (gridy + pMin.y)*gridSize;
client.settled = true;
}
}
} else {
client.x = xn;
client.y = yn;
}
}
}
});
clients.forEach(function (client) {
if (!client.valid) return;
if (client.settled) {
var gridx0 = Math.round(client.x0/gridSize);
var gridy0 = Math.round(client.y0/gridSize);
var gridx = Math.round(client.x /gridSize);
var gridy = Math.round(client.y /gridSize);
var dxmin = 0;
var dymin = 0;
var dx = (gridx-gridx0);
var dy = (gridy-gridy0);
var rMin = dx*dx + dy*dy - 1e-5;
for (var dxg = -1; dxg <= 1; dxg++) {
for (var dyg = -1; dyg <= 1; dyg++) {
if (grid[gridx+dxg][gridy+dyg]) {
var dx = (gridx+dxg-gridx0);
var dy = (gridy+dyg-gridy0);
var r = dx*dx + dy*dy;
if (r < rMin) {
rMin = r;
dxmin = dxg;
dymin = dyg;
}
}
}
}
grid[gridx][gridy] = true;
grid[gridx + dxmin][gridy + dymin] = false;
client.x = (gridx + dxmin)*gridSize;
client.y = (gridy + dymin)*gridSize;
//nachrücken
}
});
}
function renderCanvas() {
context.clearRect(0, 0, width, height);
context.fillStyle = '#000';
clients.forEach(function (client) {
if (client.valid) {
var dx = client.x - client.xo;
var dy = client.y - client.yo;
var r = Math.sqrt(dx*dx + dy*dy);
if (r > 1) {
var a = Math.min(Math.pow(1/r, 0.8), 1);
context.strokeStyle = 'rgba(0,0,0,'+a+')';
context.lineWidth = client.r*2*radius;
context.beginPath();
context.moveTo(client.xo, client.yo);
context.lineTo(client.x, client.y );
context.stroke();
} else {
context.beginPath();
context.arc(client.x, client.y, client.r*radius, 0, 2*Math.PI, false);
context.fill();
}
}
});
/*
context.fillStyle = 'rgba(255,0,0,0.5)';
for (var x = 0; x < width/gridSize; x++) {
for (var y = 0; y < height/gridSize; y++) {
if (!grid[x][y]) {
context.beginPath();
context.arc(x*gridSize, y*gridSize, 1, 0, 2*Math.PI, false);
context.fill();
}
}
}
context.fillStyle = 'rgba(0,255,0,0.5)';
debugList.forEach(function (p) {
context.beginPath();
context.arc(p.x, p.y, 1, 0, 2*Math.PI, false);
context.fill();
});
*/
}
function valid(point) {
return (point != null) && (point !== undefined);
}