const howManyLines = 50; const alwaysToEdge = true; const minDuration = 500; const maxDuration = 20000; class BouncingLine { constructor() { this.canvas = document.getElementById('line-test'); this.start = this.randomLineCoordinates(); this.dest = this.randomLineCoordinates(); this.duration = this.randomDuration(); this.setTime(); } now = () => new Date().valueOf(); elapsed = () => this.now() - this.startTime; setTime = () => this.startTime = this.now(); isComplete = () => this.startTime + this.elapsed() > this.startTime + this.duration; randomDuration = () => _.random(minDuration, maxDuration); randomX = () => _.random(0, this.canvas.width); randomY = () => _.random(0, this.canvas.height); coinFlip = (heads, tails) => _.random(0, 1) === 1 ? heads : tails; randomLineCoordinates() { let coordinates = { p1: { x: this.randomX(), y: this.randomY() }, p2: { x: this.randomX(), y: this.randomY() } }; if (alwaysToEdge) { const p = this.coinFlip('p1', 'p2'); const xY = this.coinFlip('x', 'y'); const lowerBound = 0; const upperBound = xY === 'x' ? this.canvas.width : this.canvas.height; coordinates[p][xY] = this.coinFlip(lowerBound, upperBound); } return coordinates; } getCurrentPosition(pointID, axis) { const start = this.start[pointID][axis], dest = this.dest[pointID][axis] return start + (dest - start) * this.elapsed() / this.duration;; } draw(clearFramePreDraw) { const ctx = this.canvas.getContext('2d'); if (clearFramePreDraw) ctx.clearRect(0, 0, this.canvas.width, this.canvas.height); ctx.beginPath(); ctx.moveTo(this.getCurrentPosition('p1', 'x'), this.getCurrentPosition('p1', 'y')); ctx.lineTo(this.getCurrentPosition('p2', 'x'), this.getCurrentPosition('p2', 'y')); ctx.closePath(); ctx.stroke(); this.update(); } update() { if (this.isComplete()) { this.start = this.dest; this.dest = this.randomLineCoordinates(); this.duration = this.randomDuration(); this.setTime(); } } } const lines = _.times(howManyLines, () => new BouncingLine()); const renderFrame = () => { _.forEach(lines, (line, i) => line.draw(i === 0 ? true : false)); window.requestAnimationFrame(renderFrame); } renderFrame();
<canvas id="line-test" width="500" height="210" />
#line-test { border: 1px solid black; }