draw = (ctx, t, config) => {
let scale = config.scale;
let width = config.width;
let height = config.height;
let cellX = config.cellX;
let cellY = config.cellY;
let cellRadius = config.cellRadius;
let mutationRadius = config.mutationRadius;
let numMutations = config.numMutations;
let nucleusX = config.nucleusX;
let nucleusY = config.nucleusY;
let nucleusRadius = config.nucleusRadius;
let startColor = config.startColor;
let endColor = config.endColor;
let cellX0 = cellX - cellRadius;
let cellX1 = cellX + cellRadius;
let cellY0 = cellY - cellRadius;
let cellY1 = cellY + cellRadius;
let c1offsetX = scale*30;
let c2offsetX = scale*-30;
ctx.fillStyle = "#fff";
ctx.fillRect(0, 0, width, height);
if(t === 0) {
// Move registration point to the center of the canvas
ctx.translate(width/2, height/2);
// Rotate
ctx.rotate(20 * Math.PI / 180);
// Move registration point back to the top left corner of canvas
ctx.translate(-width/2, -height/2);
}
if(t > 50) {
// Turn transparency on
ctx.globalAlpha = 1.0 - (Math.min(t, 60) - 50) / 10;
}
// bottom arc
ctx.strokeStyle = "#000";
let currColor = getColor(startColor, endColor, Math.min(t*2, 99));
ctx.fillStyle = "rgb(" + currColor[0] + "," + currColor[1] + "," + currColor[2] + ")";
ctx.beginPath();
ctx.moveTo(cellX0, cellY);
ctx.bezierCurveTo(cellX0+c1offsetX, cellY+scale*190, cellX1+c2offsetX, cellY+scale*190, cellX1, cellY);
ctx.fill();
ctx.stroke();
// top arc
ctx.beginPath();
ctx.moveTo(cellX0, cellY);
ctx.bezierCurveTo(cellX0-scale*10, cellY0-scale*50, cellX1+scale*10, cellY0-scale*50, cellX1, cellY);
ctx.fill();
ctx.stroke();
// nucleus
ctx.strokeStyle = "#000";
ctx.fillStyle = "#FFF";
ctx.moveTo(cellX, cellY);
ctx.beginPath();
ctx.arc(nucleusX, nucleusY, nucleusRadius, 0, Math.PI*2);
ctx.fill();
ctx.stroke();
// other organelles
// stack of 3 horizontal ellipses on left
ctx.beginPath();
ctx.ellipse(cellX-scale*25, cellY+scale*72, scale*36, scale*7, Math.PI*0.05, 0, Math.PI*2);
ctx.fill();
ctx.stroke();
ctx.beginPath();
ctx.ellipse(cellX-scale*25, cellY+scale*(72+14+1), scale*36, scale*7, Math.PI*0.05, 0, Math.PI*2);
ctx.fill();
ctx.stroke();
ctx.beginPath();
ctx.ellipse(cellX-scale*25, cellY+scale*(72+14+1+14+1), scale*36, scale*7, Math.PI*0.05, 0, Math.PI*2);
ctx.fill();
ctx.stroke();
// double-stroked vertical ellipse on right
ctx.beginPath();
ctx.ellipse(cellX+scale*40, cellY+scale*90, scale*20, scale*30, Math.PI*0.15, 0, Math.PI*2);
ctx.fill();
ctx.stroke();
ctx.beginPath();
ctx.ellipse(cellX+scale*40, cellY+scale*90, scale*14, scale*24, Math.PI*0.15, 0, Math.PI*2);
ctx.fill();
ctx.stroke();
ctx.globalAlpha = 1.0;
// mutations
if(t <= numMutations) {
for(let i = 0; i < Math.min(t, numMutations); i++) {
ctx.fillStyle = mutationColors[config.mutationPositions[i].mutColorIndex];
ctx.beginPath();
ctx.arc(config.mutationPositions[i].mutX, config.mutationPositions[i].mutY, mutationRadius, 0, Math.PI*2);
ctx.fill();
ctx.stroke();
}
} else if(t <= 45) {
for(let i = 0; i < numMutations; i++) {
ctx.fillStyle = mutationColors[config.mutationPositions[i].mutColorIndex];
ctx.beginPath();
ctx.arc(config.mutationPositions[i].mutX - scale*Math.random()*(t-45), config.mutationPositions[i].mutY - scale*Math.random()*(t-45), mutationRadius, 0, Math.PI*2);
ctx.fill();
ctx.stroke();
}
} else if (t <= 60){
ctx.globalAlpha = 1.0 - (t - 60) / (80-60);
for(let i = 0; i < numMutations; i++) {
ctx.fillStyle = mutationColors[config.mutationPositions[i].mutColorIndex];
ctx.beginPath();
let mutX = config.mutationPositions[i].mutX + scale*6*(t-40) * Math.cos(config.mutationPositions[i].mutTheta);
let mutY = config.mutationPositions[i].mutY + scale*6*(t-40) * Math.sin(config.mutationPositions[i].mutTheta);
ctx.arc(mutX, mutY, mutationRadius, 0, Math.PI*2);
ctx.fill();
ctx.stroke();
}
} else {
ctx.translate(width/2, height/2);
// Rotate
ctx.rotate(-20 * Math.PI / 180);
// Move registration point back to the top left corner of canvas
ctx.translate(-width/2, -height/2);
ctx.fillStyle = "#fff";
ctx.fillRect(0, 0, width, height);
}
return ctx;
}