function Vector(a, b) { this.x = a; this.y = b } Vector.prototype = { rotate: function (b) { var a = this.x; var c = this.y; this.x = Math.cos(b) * a - Math.sin(b) * c; this.y = Math.sin(b) * a + Math.cos(b) * c; return this }, mult: function (a) { this.x *= a; this.y *= a; return this }, clone: function () { return new Vector(this.x, this.y) }, length: function () { return Math.sqrt(this.x * this.x + this.y * this.y) }, subtract: function (a) { this.x -= a.x; this.y -= a.y; return this }, set: function (a, b) { this.x = a; this.y = b; return this } }; function Petal(a, f, b, e, c, d) { this.stretchA = a; this.stretchB = f; this.startAngle = b; this.angle = e; this.bloom = d; this.growFactor = c; this.r = 1; this.isfinished = false } Petal.prototype = { draw: function () { var a = this.bloom.garden.ctx; var e, d, c, b; e = new Vector(0, this.r).rotate(Garden.degrad(this.startAngle)); d = e.clone().rotate(Garden.degrad(this.angle)); c = e.clone().mult(this.stretchA); b = d.clone().mult(this.stretchB); a.strokeStyle = this.bloom.c; a.beginPath(); a.moveTo(e.x, e.y); a.bezierCurveTo(c.x, c.y, b.x, b.y, d.x, d.y); a.stroke() }, render: function () { if (this.r <= this.bloom.r) { this.r += this.growFactor; this.draw() } else { this.isfinished = true } } }; function Bloom(e, d, f, a, b) { this.p = e; this.r = d; this.c = f; this.pc = a; this.petals = []; this.garden = b; this.init(); this.garden.addBloom(this) } Bloom.prototype = { draw: function () { var c, b = true; this.garden.ctx.save(); this.garden.ctx.translate(this.p.x, this.p.y); for (var a = 0; a < this.petals.length; a++) { c = this.petals[a]; c.render(); b *= c.isfinished } this.garden.ctx.restore(); if (b == true) { this.garden.removeBloom(this) } }, init: function () { var c = 360 / this.pc; var b = Garden.randomInt(0, 90); for (var a = 0; a < this.pc; a++) { this.petals.push(new Petal(Garden.random(Garden.options.petalStretch.min, Garden.options.petalStretch.max), Garden.random(Garden.options.petalStretch.min, Garden.options.petalStretch.max), b + a * c, c, Garden.random(Garden.options.growFactor.min, Garden.options.growFactor.max), this)) } } }; function Garden(a, b) { this.blooms = []; this.element = b; this.ctx = a } Garden.prototype = { render: function () { for (var a = 0; a < this.blooms.length; a++) { this.blooms[a].draw() } }, addBloom: function (a) { this.blooms.push(a) }, removeBloom: function (a) { var d; for (var c = 0; c < this.blooms.length; c++) { d = this.blooms[c]; if (d === a) { this.blooms.splice(c, 1); return this } } }, createRandomBloom: function (a, b) { this.createBloom(a, b, Garden.randomInt(Garden.options.bloomRadius.min, Garden.options.bloomRadius.max), Garden.randomrgba(Garden.options.color.rmin, Garden.options.color.rmax, Garden.options.color.gmin, Garden.options.color.gmax, Garden.options.color.bmin, Garden.options.color.bmax, Garden.options.color.opacity), Garden.randomInt(Garden.options.petalCount.min, Garden.options.petalCount.max)) }, createBloom: function (a, f, d, e, b) { new Bloom(new Vector(a, f), d, e, b, this) }, clear: function () { this.blooms = []; this.ctx.clearRect(0, 0, this.element.width, this.element.height) } }; Garden.options = { petalCount: {min: 8, max: 15}, petalStretch: {min: 0.1, max: 3}, growFactor: {min: 0.1, max: 1}, bloomRadius: {min: 8, max: 10}, density: 10, growSpeed: 1000 / 60, color: {rmin: 128, rmax: 255, gmin: 0, gmax: 128, bmin: 0, bmax: 128, opacity: 0.1}, tanAngle: 60 }; Garden.random = function (b, a) { return Math.random() * (a - b) + b }; Garden.randomInt = function (b, a) { return Math.floor(Math.random() * (a - b + 1)) + b }; Garden.circle = 2 * Math.PI; Garden.degrad = function (a) { return Garden.circle / 360 * a }; Garden.raddeg = function (a) { return a / Garden.circle * 360 }; Garden.rgba = function (f, e, c, d) { return "rgba(" + f + "," + e + "," + c + "," + d + ")" }; Garden.randomrgba = function (i, n, h, m, l, d, k) { var c = Math.round(Garden.random(i, n)); var f = Math.round(Garden.random(h, m)); var j = Math.round(Garden.random(l, d)); var e = 5; if (Math.abs(c - f) <= e && Math.abs(f - j) <= e && Math.abs(j - c) <= e) { return Garden.rgba(i, n, h, m, l, d, k) } else { return Garden.rgba(c, f, j, k) } };