• the bust out
  • Exploiting you -- exploding me.
  • Sources

  • Main html file: dhtml/fractal-3D-spheres.html
    ge1doot mini library: /library/ge1doot.js
  • CSS

  • 
    html {
    	overflow: hidden;
    	-ms-touch-action: none;
    	-ms-content-zooming: none;
    }
    body {
    	position: absolute;
    	margin: 0;
    	padding: 0;
    	background: #000;
    	width: 100%;
    	height: 100%;
    }
    #screen {
    	position: absolute;
    	width: 100%;
    	height: 100%;
    }
    #sphere {
    	visibility: hidden;
    }
    
  • HTML

  • 
    <canvas id="screen">HTML5 CANVAS Fractal Spheres demo</canvas>
    <img id="sphere" src="../images/sphere-hr.png" alt="">
    
  • JS

  • 
    /* =======================================================
     *  ---- HTML5 CANVAS 3D spheres ----
     * script: Gerard Ferrandez - 3 February 2013
     * Released under the MIT license
     * http://www.dhteumeuleu.com/LICENSE.html
     * ======================================================= */
     
    "use strict";
    
    (function () {
    	var scr, ctx, pointer, over, img, spheres = [], divide = [];
    	// ==== Easing function ====
    	var Ease = function () {
    		this.target = 0;
    		this.position = 0;
    	};
    	Ease.prototype.move = function (speed) {
    		this.position += (this.target - this.position) * (speed || 0.05);
    	};
    	// ==== angles ====
    	var angle = {
    		x: new Ease(),
    		y: new Ease()
    	};
    	// ==== sphere constructor ====
    	var Sphere = function (x, y, z, w, l, root) {
    		this.x = x;
    		this.y = y;
    		this.z = z;
    		this.w = w;
    		this.xp = 0;
    		this.yp = 0;
    		this.zi = 0;
    		this.root = root;
    		this.level = l;
    		this.visible = true;
    		// ---- lighten image ----
    		this.img = document.createElement('canvas');
    		this.img.width  = img.width / l;
    		this.img.height = img.height / l;
    		var ict = this.img.getContext('2d');
    		ict.drawImage(img, 0, 0, this.img.width, this.img.height);
    		var imageData = ict.getImageData(0, 0, this.img.width, this.img.height);
    		var d = imageData.data;
    		var dist = (x * x + y * y + z * z) / 100000;
    		for (var i = 0, l = d.length; i < l; i += 4) {
    			d[i]   *= dist;
    			d[i+1] *= dist;
    			d[i+2] *= dist;
    		}
    		ict.putImageData(imageData, 0, 0);
    	}
    	// ==== projection 2D to 3D ====
    	Sphere.prototype.projection = function () {
    		this.visible = true;
    		// ---- rotation ----
    		var xy = angle.cx * this.y - angle.sx * this.z;
    		var xz = angle.sx * this.y + angle.cx * this.z;
    		var yz = angle.cy * xz  - angle.sy * this.x;
    		var yx = angle.sy * xz  + angle.cy * this.x;
    		// ---- projection ----
    		this.pers = 300 / (600 + yz);
    		this.xp = (scr.width * 0.5) + yx * this.pers;
    		this.yp = (scr.height * 0.5) + xy * this.pers;
    		this.zi = yz;
    	}
    	// ==== draw sphere ====
    	Sphere.prototype.draw = function () {
    		var w = this.pers * this.w;
    		// ---- pointer over detection ----
    		ctx.beginPath();
    		ctx.arc(this.xp, this.yp, w, 0, Math.PI * 2, false);
    		if (
    			ctx.isPointInPath(
    				pointer.X,
    				pointer.Y
    			)
    		) over = this;
    		// ---- draw sphere ----
    		ctx.drawImage(this.img, this.xp - w, this.yp - w, w * 2, w * 2);
    	}
    	// ==== divide sphere ====
    	var divideSphere = function (parent, x, y, z, w) {
    		var d = w * 0.5;
    		if (parent) {
    			var level = parent.level + 0.5;
    			var root = (parent.level === 1) ? parent : parent.root;
    			// ---- delete parent ----
    			var i = 0, o;
    			while ( o = spheres[i++] ) {
    				if (o === parent) {
    					spheres.splice(--i, 1);
    					break;
    				}
    			}
    		} else {
    			var level = 1;
    			var root = false;
    		}
    		// ---- create children spheres ----
    		var dx = [ 1,-1, 1,-1, 1,-1, 1,-1];
    		var dy = [-1,-1, 1, 1,-1,-1, 1, 1];
    		var dz = [-1,-1,-1,-1, 1, 1, 1, 1];
    		for (var i = 0; i < 8; i++) {
    			spheres.push(
    				new Sphere(
    					x + d * dx[i], 
    					y - d * dy[i], 
    					z - d * dz[i], 
    					d, level, root
    				)
    			);
    		}
    	}
    	// ==== init script ====
    	var init = function () {
    		// ---- screen ----
    		scr = new ge1doot.Screen({
    			container: "screen"
    		});
    		ctx = scr.ctx;
    		// ---- pointer events ----
    		pointer = new ge1doot.Pointer({
    			tap: function () {
    				if (over) {
    					if (over.level > 1 && Math.random() > 0.97) {
    						// ---- 3% chance to destroy a bloc ----
    						var root = over.root;
    						var i = 0, o;
    						while ( o = spheres[i++] ) {
    							if (o.root == root) {
    								spheres.splice(--i, 1);
    							}
    						}
    						spheres.push(root);
    					} else {
    						// ---- push division ----
    						divide.push(over);
    					}
    				}
    			},
    			move: function () {
    				angle.x.target = (pointer.Yi - (scr.height * 0.5)) * .008;
    				angle.y.target = (pointer.Xi - (scr.width  * 0.5)) * .008;
    			}
    		});
    		// ---- original png image ----
    		img = document.getElementById("sphere");
    		// ---- engine start ----
    		divideSphere(false, 0, 0, 0, 300);
    		run();
    	}
    	// ======== main loop ========
    	var run = function () {
    		ctx.clearRect(0, 0, scr.width, scr.height);
    		// ---- camera ----
    		angle.x.move();
    		angle.y.move();
    		angle.cx = Math.cos(angle.x.position);
    		angle.sx = Math.sin(angle.x.position);
    		angle.cy = Math.cos(angle.y.position);
    		angle.sy = Math.sin(angle.y.position);
    		// ---- 3D to 2D projection ----
    		var i = 0, o;
    		while ( o = spheres[i++] ) o.projection();
    		// ---- zIndex ----
    		spheres.sort(function (p0, p1) {
    			return p1.zi - p0.zi;
    		});
    		// ---- drawing ----
    		over = false;
    		i = 0;
    		while ( o = spheres[i++] ) o.draw();
    		// ---- divide ----
    		if (divide.length) {
    			var o = divide.shift();
    			divideSphere(o, o.x, o.y, o.z, o.w);
    		}
    		// ---- cursor ----
    		if (over) {
    			scr.setCursor("pointer");
    		} else {
    			scr.setCursor("default");
    		}
    		// ---- animation loop ----
    		requestAnimFrame(run);
    	}
    	return {
    		// ---- onload event ----
    		load : function () {
    			window.addEventListener('load', function () {
    				init();
    			}, false);
    		}
    	}
    })().load();
    
    © www.dhteumeuleu.com 2004-2015