<canvas id="canvas"></canvas>
body {
overflow: hidden;
}
#canvas {
position: absolute;
top: 50%;
left: 50%;
transform: translate( -50%, -50% );
}
View Compiled
var TAU = Math.PI * 2;
var config = {
space: 40,
lineWidth: 10,
color: "#FFFFFF",
backgroundColor: "#8a319d",
tailDelay: 0.2,
timeDelta: 0.01,
size: 500
};
var canvas = document.getElementById( "canvas" );
var context = canvas.getContext( "2d" );
var center = config.size / 2;
var lines;
var time = 0;
var gui = new dat.GUI();
function init() {
setupGUI();
refresh();
updateBackground();
requestAnimationFrame( render );
}
function setupGUI() {
gui.add( config, "space", 5, 100 ).name( "Gap Size" ).onChange( refresh );
gui.add( config, "lineWidth", 1, 100 ).name( "Line Width" );
gui.add( config, "timeDelta", 0.001, 0.2 ).name( "Speed" );
gui.add( config, "tailDelay", 0, 1 ).name( "Line Length" );
gui.add( config, "size", 100, 1000 ).name( "Radius" ).onChange( refresh );
gui.addColor( config, "color" ).name( "Color" );
gui.addColor( config, "backgroundColor" ).name( "Background Color" ).onChange( updateBackground );
gui.close();
}
function updateBackground() {
document.body.style.backgroundColor = config.backgroundColor;
}
function refresh() {
lines = [];
center = config.size / 2;
var amount = ~~( ( center - 50 ) / config.space );
var max = center - 50;
for (var i = 0; i < amount; i++) {
lines.push( circle( ( 1 - i / amount ) * max, i / ( amount * 2 ) ) );
};
}
function clear() {
canvas.width = config.size;
canvas.height = config.size;
}
function render() {
clear();
context.translate( center, center );
context.rotate( - TAU / 4 );
context.translate( -center, -center );
context.beginPath();
lines.forEach( function( line ) {
line.draw( time );
} );
context.strokeStyle = config.color;
context.lineWidth = config.lineWidth;
context.stroke();
time += config.timeDelta;
time %= 1;
requestAnimationFrame( render );
}
function getCartesian( angle, distance ) {
return {
x: Math.cos( angle ) * distance,
y: Math.sin( angle ) * distance
};
}
function ease( t ) {
return 1 - ( Math.cos( t * Math.PI ) / 2 + 0.5 );
}
function circle( radius, delay ) {
function getTailValue( t ) {
var s = t - config.tailDelay;
if ( s < 0 ) s += 1;
return Math.pow( ease( s ), 2 ) * TAU;
}
function getHeadValue( t ) {
return Math.pow( ease( t ), 2 ) * TAU;
}
return {
draw: function( t ) {
t -= delay;
if ( t < 0 ) t += 1;
var tailAngle = getTailValue( t );
var tail = getCartesian( tailAngle, radius );
context.moveTo( center + tail.x, center + tail.y );
context.arc( center, center, radius, tailAngle, getHeadValue( t ) );
}
}
}
init();
This Pen doesn't use any external CSS resources.