Wachstum eines Sechsecks
Wenn am Ende einer Liste von Kreisen immer wieder ein neuer Kreis hinzugefügt wird, entsteht nicht etwa ein Kreis sondern ein Sechseck!
Der Code für die Animation
class Circle { constructor( x, y, r ) { this.x = x ; this.y = y ; this.r = r ; this.color = "#0000CC" ; } draw( ctx ) { ctx.fillStyle = this.color ; ctx.beginPath() ; ctx.arc( this.x, this.y, this.r, 0, 2*Math.PI ) ; ctx.fill() ; ctx.stroke() ; } } class Animation { CENTERX = 250 ; CENTERY = 250 ; RADIUS = 7 ; // Control points for the bezier curve points = [ { x: this.CENTERX, y: 0 }, { x: 0, y: 0 }, { x: 0, y: 0 }, { x: 0, y: 0 } ] ; // Parameter for the bezier curve t = 1 ; // List of the circles circles = [] ; // Moving circle circle = new Circle( this.CENTERX, this.CENTERY, this.RADIUS ) ; ctx = document.querySelector( "#canvas" ).getContext( "2d" ) ; bezier( a, b, c, d, t ) { let ti = 1 - t ; return a * ti * ti * ti + 3 * b * ti * ti * t + 3 * c * ti * t * t + d * t * t * t ; } moveCircle() { this.circle.x = this.bezier( this.points[0].x, this.points[1].x, this.points[2].x, this.points[3].x, this.t ) ; this.circle.y = this.bezier( this.points[0].y, this.points[1].y, this.points[2].y, this.points[3].y, this.t ) ; } addCircle( circles ) { if( circles.length == 0 ) circles.push( this.circle ) ; else if( circles.length == 1 ) { this.circle.y = this.CENTERY - this.RADIUS ; this.circle = new Circle( this.CENTERX, this.CENTERY+this.RADIUS, this.RADIUS ) ; circles.push( this.circle ) ; } else { const last = this.circle ; let cb = circles[0] ; let xmin = 250 ; let ymin = 250 ; for( let i = 0; i < circles.length - 2; i++ ) { let c = circles[i] ; if( xmin > c.x ) xmin = c.x ; if( ymin > c.y ) ymin = c.y ; if( Math.hypot(last.x-c.x,last.y-c.y) < 2 * this.RADIUS + 1 ) { cb = c ; } } const wx = this.CENTERX - xmin ; const pivot = { x: (last.x + cb.x) / 2, y: (last.y + cb.y) / 2 } ; const vect = { dx: last.x - pivot.x, dy: last.y - pivot.y } ; this.points[3].x = pivot.x + vect.dy * Math.sqrt(3) ; this.points[3].y = pivot.y - vect.dx * Math.sqrt(3) ; this.circle = new Circle( this.CENTERX, 0, this.RADIUS ) ; if( Math.abs(last.x-this.points[3].x) < 3 ) { if( this.points[3].y < last.y ) { this.points[1].x = this.points[3].x + 50 ; this.points[1].y = ymin / 2 ; this.points[2].x = this.points[3].x + 50 ; this.points[2].y = this.points[3].y ; } else { this.points[1].x = this.points[3].x - 50 ; this.points[1].y = ymin / 2 ; this.points[2].x = this.points[3].x - 50 ; this.points[2].y = this.points[3].y ; } } else { if( this.points[3].y < last.y ) { if( this.points[3].x < last.x ) { this.points[1].x = this.points[3].x ; this.points[1].y = this.points[3].y / 2 ; this.points[2].x = this.points[3].x + 20 ; this.points[2].y = this.points[3].y - 20 ; } else { this.points[1].x = this.CENTERX + wx + 100 ; this.points[1].y = ymin / 3 ; this.points[2].x = this.points[3].x + wx + 50 ; this.points[2].y = this.points[3].y + 100 ; } } else { if( this.points[3].x < last.x ) { this.points[1].x = this.points[3].x ; this.points[1].y = this.points[3].y / 2 ; this.points[2].x = this.points[3].x - 20 ; this.points[2].y = this.points[3].y - 20 ; } else { this.points[1].x = this.CENTERX - wx - 100 ; this.points[1].y = ymin / 3 ; this.points[2].x = this.points[3].x - wx - 50 ; this.points[2].y = this.points[3].y + 100 ; } } } circles.push( this.circle ) ; this.t = 0 ; } } update() { if( this.circles.length < 271 ) { this.ctx.fillStyle = "#FFFFFF" ; this.ctx.fillRect( 0, 0, 500, 500 ) ; if( this.t >= 1 ) this.addCircle( this.circles ) ; else { this.t += 0.01 ; this.moveCircle() ; } this.ctx.strokeStyle = "#FFFF00" ; this.circles.forEach( c => c.draw(this.ctx) ) ; requestAnimationFrame( update ) ; } else { if( this.t < 1 ) { this.ctx.fillStyle = "#FFFFFF" ; this.ctx.fillRect( 0, 0, 500, 500 ) ; this.t += 0.01 ; this.moveCircle() ; this.ctx.strokeStyle = "#FFFF00" ; this.circles.forEach( c => c.draw(this.ctx) ) ; requestAnimationFrame( update ) ; } } } } function update() { animation.update() ; } const animation = new Animation() ; requestAnimationFrame( update ) ;