• you see
  • How would you know the difference between the dream world and the real world?
  • Sources

  • Main html file: dhtml/scene-3D-room-menu.html
    ge1doot mini library: /library/ge1doot.js
    CANVAS image projection: /library/imageTransform.js
  • CSS

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

  • 
    <canvas id="canvas">HTML5 CANVAS IS REQUIRED</canvas>
    
  • JS

  • 
    /* 
     * ======================================================
     * CANVAS 3D experiment - you see
     * http://www.dhteumeuleu.com/you-see 
     * Author Gerard Ferrandez - 14 Feb 2012
     * ---------------------------------------------------
     * Released under the MIT license
     * http://www.dhteumeuleu.com/LICENSE.html
     * Last updated: 19 Nov 2012
     * ======================================================
     */
    
    "use strict";
    
    (function () {
    	// ======== private vars ========
    	var faces = [], tweens, camera;
    	var scr, ctx, pointer, target, targetold, faceOver, isMoving;
    	var globalRX = 0, globalRY = 0;
    	// ======== points constructor ========
    	var Point = function (parentFace, point, rotate) {
    		this.face = parentFace;
    		this.x = point[0];
    		this.y = point[1];
    		this.z = point[2];
    		this.scale = 0;
    		this.X = 0;
    		this.Y = 0;
    		if (rotate) {
    			this.x += rotate.x;
    			this.y += rotate.y;
    			this.z += rotate.z;
    		}
    		return this;
    	}
    	// ======== points projection ========
    	Point.prototype.project = function () {
    		// ---- 3D rotation ----
    		var p = camera.rotate(
    			this.x - camera.x.value,
    			this.y - camera.y.value,
    			this.z - camera.z.value
    		)
    		// ---- distance to the camera ----
    		if (this.face) {
    			var z = p.z + camera.focalLength;
    			var distance = Math.sqrt(p.x * p.x + p.y * p.y + z * z);
    			if (distance > this.face.distance) this.face.distance = distance;
    		}
    		// --- 2D projection ----
    		this.scale = (camera.focalLength / (p.z + camera.focalLength)) * camera.zoom.value;
    		this.X = (scr.width  * 0.5) + (p.x * this.scale);
    		this.Y = (scr.height * 0.5) + (p.y * this.scale);
    		// --- project next point ---
    		this.next && this.next.project();
    	}
    	// ======= faces constructor ========
    	var Face = function (path, f) {
    		this.f = f;
    		var w  = f.w * 0.5;
    		var h  = f.h * 0.5;
    		var ax = f.rx * Math.PI * 0.5;
    		var ay = f.ry * Math.PI * 0.5;
    		this.locked   = false;
    		this.hidden   = f.hidden || null;
    		this.visible  = true;
    		this.distance = 0;
    		// ---- center point ----
    		this.pc = new Point(this, [f.x, f.y, f.z]);
    		// ---- 3D rotation ----
    		var rotate = function (x, y, z, ax, ay) {
    			var tz = z * Math.cos(ay) + x * Math.sin(ay);
    			var ty = y * Math.cos(ax) + tz * Math.sin(ax);
    			return {
    				x: x * Math.cos(ay) - z * Math.sin(ay),
    				y: ty,
    				z: tz * Math.cos(ax) - y * Math.sin(ax)
    			}
    		}
    		// ---- quad points ----
    		this.p0 = new Point(this, [f.x, f.y, f.z], rotate(-w, -h, 0, ax, ay));
    		this.p1 = new Point(this, [f.x, f.y, f.z], rotate( w, -h, 0, ax, ay));
    		this.p2 = new Point(this, [f.x, f.y, f.z], rotate( w,  h, 0, ax, ay));
    		this.p3 = new Point(this, [f.x, f.y, f.z], rotate(-w,  h, 0, ax, ay));
    		// ---- corner points ----
    		this.c0 = new Point(false, [f.x, f.y, f.z], rotate(-w, -h, -15, ax, ay));
    		this.c1 = new Point(false, [f.x, f.y, f.z], rotate( w, -h, -15, ax, ay));
    		this.c2 = new Point(false, [f.x, f.y, f.z], rotate( w,  h, -15, ax, ay));
    		this.c3 = new Point(false, [f.x, f.y, f.z], rotate(-w,  h, -15, ax, ay));
    		// ---- target angle ----
    		var r = rotate(ax, ay, 0, ax, ay, 0);
    		this.ax = r.x + Math.PI / 2;
    		this.ay = r.y + Math.PI / 2;
    		// ---- create 3D image ----
    		this.img = new ge1doot.transform.Image(path + f.src, f.tl || 2, {
    			isLoaded: function(img) {
    				// --- disable borders ---
    				img.stroke = false;
    			}
    		});
    		this.img.stroke = "RGB(128,128,128)";
    	}
    	// ======== face projection ========
    	Face.prototype.project = function () {
    		this.visible = true;
    		this.distance = -99999;
    		// ---- points projection ----
    		this.p0.project();
    		this.p1.project();
    		this.p2.project();
    		this.p3.project();
    		// ---- back face culling ----
    		if (!(
    			((this.p1.Y - this.p0.Y) / (this.p1.X - this.p0.X) - 
    			(this.p2.Y - this.p0.Y) / (this.p2.X - this.p0.X) < 0) ^ 
    			(this.p0.X <= this.p1.X == this.p0.X > this.p2.X)
    		) || this.hidden) {
    			this.visible = false;
    			this.distance = -99999;
    			if (!this.locked && this.hidden === false) this.hidden = true;
    		}
    	}
    	// ======== face border ========
    	Face.prototype.border = function () {
    		this.c0.project();
    		this.c1.project();
    		this.c2.project();
    		this.c3.project();
    		this.pc.project();
    		ctx.beginPath();
    		ctx.moveTo(this.c0.X, this.c0.Y);
    		ctx.lineTo(this.c1.X, this.c1.Y);
    		ctx.lineTo(this.c2.X, this.c2.Y);
    		ctx.lineTo(this.c3.X, this.c3.Y);
    		ctx.closePath();
    		ctx.lineWidth = this.pc.scale * this.f.w / 30;
    		ctx.strokeStyle = "rgb(255,255,255)";
    		ctx.lineJoin = "round";
    		ctx.stroke();
    	}
    	// ======== is pointer inside ? =========
    	var selectFace = function () {
    		isMoving = false;
    		target = false;
    		for (var i = 0, f; f = faces[i++];) {
    			if (f.visible) {
    				if (
    					f.img.isPointerInside(
    						pointer.X,
    						pointer.Y,
    						f.p0, f.p1, f.p2, f.p3
    					)
    				) target = f;	
    			} else break;
    		}
    		if (target && target.f.select != false && !pointer.isDraging) {
    			faceOver = target;
    			scr.setCursor("pointer");
    		} else scr.setCursor("move");
    	}
    	// ======== onclick ========
    	var click = function () {
    		selectFace();
    		// ---- target image ----
    		if (target && target.f.select != false) {
    			if (target == targetold) {
    				// ---- reset scene ----
    				camera.center();
    				targetold = false;
    			} else {
    				targetold = target;
    				target.locked = false;
    				// ---- target redirection ----
    				if (target.f.target != "") {
    					for (var i = 0, f; f = faces[i++];) {
    						if (f.f.id && f.f.id == target.f.target) {
    							target = f;
    							targetold = f;
    							if (f.hidden) {
    								f.hidden = false;
    								f.locked = true;
    								targetold = false;
    							}
    							break;
    						}
    					}
    				}
    				// ---- move camera ----
    				target.pc.project();
    				camera.setTarget(target);
    			}
    		}
    	}
    	var init = function (json) {
    		// ---- init script ----
    		scr = new ge1doot.Screen({
    			container: "canvas"
    		});
    		ctx = scr.ctx;
    		pointer = new ge1doot.Pointer({
    			tap: click,
    			move: function () {
    				isMoving = true;
    			}
    		});
    		// ---- tweens engine ----
    		tweens = new ge1doot.Tweens();
    		// ---- init camera ----
    		camera = {
    			x:  new tweens.Add(100),
    			y:  new tweens.Add(100),
    			z:  new tweens.Add(100, 0,0),
    			rx: new tweens.Add(100, 0,0, true),
    			ry: new tweens.Add(100, 0,0, true),
    			zoom: new tweens.Add(100, 0.1, 1),
    			focalLength: 500,
    			centered: false,
    			cosX: 0,
    			cosY: 0,
    			sinX: 0,
    			sinY: 0,
    			setTarget: function (target) {
    				// ---- set position ----
    				this.x.setTarget(target.pc.x);
    				this.y.setTarget(target.pc.y);
    				this.z.setTarget(target.pc.z);
    				// ---- set view angles ----
    				this.rx.setTarget((Math.PI * 0.5) - target.ax - globalRX);
    				this.ry.setTarget((Math.PI * 0.5) - target.ay - globalRY);
    				// ---- zoom ----
    				this.zoom.setTarget(target.f.zoom ? target.f.zoom : 2);
    				this.centered = false;
    			},
    			center: function () {
    				this.x.setTarget(0);
    				this.y.setTarget(0);
    				this.z.setTarget(0);
    				this.zoom.setTarget(1);
    				this.centered = true;
    			},
    			move: function () {
    				// ---- easing camera position and view angle ----
    				tweens.iterate();
    				// ---- additional drag/touch rotations ----
    				globalRX += (((-pointer.Yi * 0.01) - globalRX) * 0.1);
    				globalRY += (((-pointer.Xi * 0.01) - globalRY) * 0.1);
    				if (!this.centered && pointer.isDraging) {
    					// ---- reset zoom & position ----
    					this.center();
    					targetold = false;
    				}
    				// ---- pre calculate trigo ----
    				this.cosX = Math.cos(this.rx.value + globalRX);
    				this.sinX = Math.sin(this.rx.value + globalRX);
    				this.cosY = Math.cos(this.ry.value + globalRY);
    				this.sinY = Math.sin(this.ry.value + globalRY);
    			},
    			rotate: function (x, y, z) {
    				// ---- 3D rotation ----
    				var r = this.cosY * z + this.sinY * x;
    				return {
    					x: this.cosY * x - this.sinY * z,
    					y: this.sinX * r + this.cosX * y,
    					z: this.cosX * r - this.sinX * y	
    				}
    			}
    		}
    		// ---- create faces ----
    		for (var i = 0, f; f = json.faces[i++];) {
    			faces.push(
    				new Face(json.path, f)
    			);
    		}
    		// ---- engine start ----
    		run();
    	}
    	// ===== main loop =====
    	var run = function () {
    		var i, f;
    		// ---- clear screen ----
    		ctx.clearRect(0,0, scr.width, scr.height);
    		// ---- 3D projection ----
    		for (i = 0; f = faces[i++];) {
    			f.project();
    		}
    		// ---- faces depth sorting ----
    		faces.sort(function (p0, p1) {
    			return p1.distance - p0.distance;
    		});
    		// ---- drawing ----
    		for (i = 0; f = faces[i++];) {
    			if (f.visible) {
    				// ---- draw image ----
    				f.img.transform(f.p0, f.p1, f.p2, f.p3);
    				if (f.locked && pointer.isDraging) f.locked = false;
    				if (f === faceOver) faceOver.border();
    			} else break;
    		}
    		// ---- pointer over ----
    		isMoving && selectFace();
    		// ---- camera ----
    		camera.move();
    		// ---- loop ----
    		requestAnimFrame(run);
    	}
    	return {    
    		// ---- onload event ----
    		load : function (json) {
    			window.addEventListener('load', function () {
    				// --- load additional lib components ---
    				ge1doot.loadJS([
    					"../library/imageTransform.js",
    					"../library/ease.js"
    					], init, json);
    			}, false);
    		}
    	}
    })().load({
    	path: "../images/",
    	faces: [
    		// ---- main images ----
    		{id: "1", src:"N3.jpg",    x:0,    y:0,    z:200,  rx:0,  ry:0,  w: 300, h: 200, select: false},
    		{id: "2", src:"go21.jpg",  x:200,  y:0,    z:0,    rx:0,  ry:-1, w: 300, h: 200},
    		{id: "3", src:"sf42.jpg",  x:0,    y:150,  z:0,    rx:1,  ry:0,  w: 300, h: 200},
    		{id: "4", src:"go26.jpg",  x:0,    y:-150, z:0,    rx:-1, ry:0,  w: 300, h: 200},
    		{id: "5", src:"ct133.jpg", x:-200, y:0,    z:0,    rx:0,  ry:1,  w: 300, h: 200},
    		{id: "6", src:"ct132.jpg", x:0,    y:0,    z:-200, rx:0,  ry:-2, w: 300, h: 200},
    		// ---- special hidden image :) ----
    		{id: "7", target: "1", src:"ct15.jpg", x:0, y:0, z:200, rx:0, ry:-2, w: 300, h: 200, hidden: true},
    		// ---- small targets ----
    		{src:"ct132.jpg", target: "6", x:0,    y:-40, z:170, rx:0, ry:0, w: 80, h: 60, tl: 1},
    		{src:"ct133.jpg", target: "5", x:-100, y:-40, z:170, rx:0, ry:0, w: 80, h: 60, tl: 1},
    		{src:"go26.jpg",  target: "4", x:100,  y:-40, z:170, rx:0, ry:0, w: 80, h: 60, tl: 1},
    		{src:"sf42.jpg",  target: "3", x:0,    y:40,  z:170, rx:0, ry:0, w: 80, h: 60, tl: 1},
    		{src:"go21.jpg",  target: "2", x:-100, y:40,  z:170, rx:0, ry:0, w: 80, h: 60, tl: 1},
    		{src:"N3.jpg",    target: "7", x:100,  y:40,  z:170, rx:0, ry:0, w: 80, h: 60, tl: 1}
    	]
    });
    
    © www.dhteumeuleu.com 2004-2015