<canvas id=c></canvas>
body {
overflow-x: hidden;
}
canvas {
position: absolute;
top: 0;
left: 0;
}
var w = c.width = window.innerWidth - 10,
h = c.height = 0,
ctx = c.getContext( '2d' ),
opts = {
maxSteps: 25,
allowNeg: false, // includes 0
allowFlo: false,
stepHeight: 40
},
nums = [1],
coords = [ {x: 20 + w/2, y: opts.stepHeight / 2 } ],
step = 0;
h = c.height = opts.maxSteps * opts.stepHeight;
function isValid( n ){
return ( n === Math.floor( n ) || opts.allowFlo ) &&
( n > 0 || opts.allowNeg ) &&
n !== 1; // avoid 4 → 1 loop
}
function anim(){
if( step <= opts.maxSteps )
window.requestAnimationFrame( anim );
ctx.lineWidth = 1;
ctx.strokeStyle = '#ccc';
ctx.beginPath();
ctx.moveTo( 40.5, step * opts.stepHeight );
ctx.lineTo( 40.5, ( step + 1 ) * opts.stepHeight );
ctx.stroke();
ctx.font = '20px monospace';
var indexLen = ctx.measureText( step ).width;
ctx.fillStyle = '#222';
ctx.fillText( step, 20 - indexLen / 2, ( step + .5 ) * opts.stepHeight );
var curNums = [],
curRelations = [];
for( var i = 0; i < nums.length; ++i ){
var doubl = 2 * nums[ i ],
third = ( nums[ i ] - 1 ) / 3;
if( isValid( doubl ) ){
curNums.push( doubl );
curRelations.push( { formula: 2, parentInd: i } ); // 2 = 2a, 1 = (a-1)/3
}
if( isValid( third ) && third % 2 === 1 ){
curNums.push( third );
curRelations.push( { formula: 1, parentInd: i } );
}
}
var curCoords = [];
for( var i = 0; i < curNums.length; ++i ){
var x = 40 + ( ( i + 1 ) / ( curNums.length + 1 ) ) * ( w - 40 ), // +1s are for space-around effect
y = ( step + 1.5 ) * opts.stepHeight;
curCoords.push( { x: x, y: y } );
}
var size = Math.max( Math.min( 20, ( w - 40 ) / 4 / curNums.length ), 5 );
ctx.lineWidth = size + 5;
ctx.lineCap = 'round';
// draw relations first
for( var i = 0; i < curRelations.length; ++i ){
var rel = curRelations[ i ];
ctx.strokeStyle = rel.formula === 1 ? '#fa8' : '#a8f';
ctx.beginPath();
ctx.moveTo( curCoords[ i ].x, curCoords[ i ].y );
ctx.lineTo( coords[ rel.parentInd ].x, coords[ rel.parentInd ].y );
ctx.stroke();
}
// then draw nums
ctx.font = size / 2 + 'px monospace';
for( var i = 0; i < nums.length; ++i ){
ctx.fillStyle = '#eee';
ctx.beginPath();
ctx.arc( coords[ i ].x, coords[ i ].y, size / 2, 0, Math.PI * 2 );
ctx.fill();
ctx.fillStyle = '#222';
var len = ctx.measureText( nums[ i ] ).width;
ctx.fillText( nums[ i ], coords[ i ].x - len / 2, coords[ i ].y + size / 8 );
}
debugger;
coords = curCoords;
nums = curNums;
++step;
}
anim();
This Pen doesn't use any external CSS resources.
This Pen doesn't use any external JavaScript resources.