function Dot(x, y, radius, color) { this.x = x; this.y = y; this.radius = radius; this.color = color; this.angle = Math.random() * 360; this.speed = 10; this.vx = Math.sin(this.angle) * this.speed; this.vy = Math.cos(this.angle) * this.speed; } Dot.prototype.draw = function(ctx) { ctx.save(); ctx.fillStyle = this.color; ctx.beginPath(); ctx.arc(this.x, this.y, this.radius, 0, Math.PI * 2, true); ctx.closePath(); ctx.fill(); ctx.restore(); } var canvas, ctx, width, height, dots, positions; init(); function init() { canvas = document.querySelector('canvas'); ctx = canvas.getContext('2d'); width = canvas.width = window.innerWidth; height = canvas.height = window.innerHeight; dots = []; positions = []; generateDots(4); generatePositions(20); drawFrame(); } function generateDots(len) { for (var i = 0; i < len; i++) { dots.push(new Dot(Math.random() * width / 1.2, Math.random() * height / 2, 10, '#f39c12')); } } function generatePositions(range) { for (var i = 0; i <= range; i++) positions.push(new Dot(Math.random() * width, Math.random() * height, 3, '#d35400')); } function updatePos(pos1, pos2) { var x, y, len, pos; len = positions.length - 1; for (var i = 0; i <= len; i++) { pos = positions[i]; x = (pos2.x - (pos2.x - pos1.x) * (i / 20)); y = (pos2.y - (pos2.y - pos1.y) * (i / 20)); pos.x = x; pos.y = y; pos.angle += 0.03; pos.draw(ctx); } } function drawFrame() { window.requestAnimationFrame(drawFrame, canvas); ctx.fillStyle = '#17293a'; ctx.fillRect(0, 0, width, height); updatePos(dots[0], dots[1]); updatePos(dots[1], dots[2]); updatePos(dots[2], dots[3]); updatePos(dots[3], dots[0]); dots.forEach(updateDot); }; function updateDot(dot) { dot.x += dot.vx; dot.y += dot.vy; if (dot.x + dot.radius >= width || dot.x - dot.radius <= 0) dot.vx *= -1; if (dot.y + dot.radius >= height || dot.y - dot.radius <= 0) dot.vy *= -1; dot.draw(ctx); }