(function ($) { var Vector = function (x, y) { this.x = x || 0; this.y = y || 0; }; Vector.prototype = { add: function (v) { this.x += v.x; this.y += v.y; return this; }, length: function () { return Math.sqrt(this.x * this.x + this.y * this.y); }, rotate: function (theta) { var x = this.x; var y = this.y; //this.x = Math.cos(theta) * this.x - Math.sin(theta) * this.y; //this.y = Math.sin(theta) * this.x + Math.cos(theta) * this.y; this.x = Math.cos(theta) * x - Math.sin(theta) * y; this.y = Math.sin(theta) * x + Math.cos(theta) * y; return this; }, mult: function (f) { this.x *= f; this.y *= f; return this; } }; var Branch = function (p, v, r, c, t) { this.p = p || null; this.v = v || null; this.r = r || 0; this.length = 0; this.generation = 1; this.tree = t || null; this.color = c || 'rgba(255,255,255,1.0)'; this.register(); // Config Vars ************************************************************************ this.branchMin = t.canvas.height / 9; // minimum length at which to start a new branch this.branchMax = t.canvas.height / 5; this.degrades = 0.999; this.minGenerations = 3; this.maxGenerations = 9; this.minWidth = 0.75; this.branchAngle = 0.2; this.centerOffset = Branch.random(-400, 400); this.minBranches = 1; this.maxBranches = 3; var speedc = Branch.random(10, 20); // must be multiples of 100, with 2000 as the max this.speed = speedc * 100; this.die = false; }; Branch.prototype = { register: function () { this.tree.addBranch(this); }, draw: function () { var ctx = this.tree.ctx; ctx.beginPath(); ctx.fillStyle = this.color; ctx.moveTo(this.p.x, this.p.y); // ctx.arc(this.p.x, this.p.y, this.r, 0, Branch.circle, true); var cpx = this.p.x; var cpy = this.p.y; this.modify(); ctx.bezierCurveTo(cpx, cpy, cpx + 0.5, cpy + 0.5, this.p.x, this.p.y); ctx.lineWidth = 1; // line color ctx.strokeStyle = this.color; ctx.stroke(); ctx.fill(); }, modify: function () { var angle = this.branchAngle - (0.1 / this.generation); this.p.add(this.v); this.length += this.v.length(); this.r *= this.degrades; this.v.rotate(Branch.random(-angle, angle)); //.mult(0.996); if (this.r < this.minWidth || this.generation > this.maxGenerations) { this.tree.removeBranch(this); } }, grow: function () { this.draw(); // this.modify(); this.fork(); }, fork: function () { var p = this.length - Branch.random(this.branchMin, this.branchMax); // + (this.generation * 5); if (p > 0) { var n = Math.round(Branch.random(this.minBranches, this.maxBranches)); this.tree.stat.fork += n - 1; for (var i = 0; i < n; i++) { Branch.clone(this); } this.tree.removeBranch(this); } } }; Branch.circle = 2 * Math.PI; Branch.random = function (min, max) { return Math.random() * (max - min) + min; }; Branch.clone = function (b) { var r = new Branch(new Vector(b.p.x, b.p.y), new Vector(b.v.x, b.v.y), b.r, b.color, b.tree); r.generation = b.generation + 1; return r; }; Branch.rgba = function (r, g, b, a) { return 'rgba(' + r + ',' + g + ',' + b + ',' + a + ')'; }; Branch.randomrgba = function (min, max, a) { // return Branch.rgba(Math.round(Branch.random(min, max)), Math.round(Branch.random(min, max)), Math.round(Branch.random(min, max)), a); //return Branch.rgba(Math.round(Branch.random(150, 225)), Math.round(Branch.random(150, 200)), Math.round(Branch.random(120, 150)), 0.01); return Branch.rgba(160, 160, 130, 0.1); }; var Tree = function () { var branches = []; var deadbranches = 0; var timer; this.stat = { fork: 0, length: 0 }; this.iteration = 1; this.addBranch = function (b) { branches.push(b); }; this.removeBranch = function (b) { deadbranches++; for (var i = 0; i < branches.length; i++) { if (branches[i] === b) { branches.splice(i, 1); return; } } }; this.render = function (fn) { var that = this; timer = setInterval(function () { fn.apply(that, arguments); if (branches.length > 0) { for (var i = 0; i < branches.length; i++) { speed = that.iteration * 100; if(branches[i].speed <= speed) { branches[i].grow(); } } } else { clearInterval(); } that.iteration++; if(that.iteration > 20) { that.iteration = 1; $('#total-branches').html(branches.length + deadbranches); $('#dead-branches').html(deadbranches); $('#live-branches').html(branches.length); } }, 10); }; this.init = function (ctx, canvas, ctx2) { this.ctx = ctx; this.canvas = canvas; }; this.abort = function () { branches = []; this.stat = { fork: 0, length: 0 }; }; // get mouse position func this.getMousePosition = function(e) { if (!e) { var e = window.event; } if (e.pageX || e.pageY) { return new vector2d(e.pageX, e.pageY); } else if (e.clientX || e.clientY) { return new vector2d(e.clientX, e.clientY); } }; }; function init() { // create a canvas element var globalWrapper = $('#globalWrapper'); var canvasItem = ''; globalWrapper.append(canvasItem); var $window = $(window); var $body = $("body"); // get css background color var bgColor = rgb2hex($body.css('background-color')); var canvas_width = $window.width(); var canvas_height = $window.height(); var center_x = canvas_width / 2; var stretch_factor = 600 / canvas_height; var y_speed = 1 / stretch_factor; var canvas = $('#canvas')[0]; canvas.width = canvas_width; canvas.height = canvas_height; var ctx = canvas.getContext("2d"); ctx.globalCompositeOperation = "lighter"; ctx.rect(0,0,canvas_width,canvas_height); ctx.fillStyle=bgColor; ctx.fill(); ctx.save(); var t = new Tree(); t.init(ctx, canvas, null); for (var i = -4; i < 4; i++) { new Branch(new Vector(center_x + (Branch.random(canvas_width/12, canvas_width/8) * i), canvas_height), new Vector(Math.random(-1, 1), -y_speed), 5, Branch.randomrgba(0, 255, 0.3), t); } t.render(function () { // $statMsg.html(this.stat.fork); }); // events $("#drawArea").click(function (e) { //e.preventDefault(); var x, y; x = e.pageX - this.offsetLeft; y = e.pageY - this.offsetTop; // new Branch(new Vector(x, canvas_height), new Vector(0, -y_speed), 10 / stretch_factor, Branch.randomrgba(0, 255, 0.3), t); new Branch(new Vector(x, canvas_height), new Vector(0, -y_speed), 5, Branch.randomrgba(0, 255, 0.3), t); }); } $(function () { init(); }); })(jQuery); var hexDigits = new Array ("0","1","2","3","4","5","6","7","8","9","a","b","c","d","e","f"); //Function to convert hex format to a rgb color function rgb2hex(rgb) { rgb = rgb.match(/^rgb\((\d+),\s*(\d+),\s*(\d+)\)$/); return "#" + hex(rgb[1]) + hex(rgb[2]) + hex(rgb[3]); } function hex(x) { return isNaN(x) ? "00" : hexDigits[(x - x % 16) / 16] + hexDigits[x % 16]; } (function() { function createPlayer(jqe, video, options) { var ifr = $('iframe', jqe); if (ifr.length === 0) { ifr = $('