From 6005be1d04dd02000889d8be2faaf62969c4421f Mon Sep 17 00:00:00 2001 From: Julie Lala Date: Thu, 17 Apr 2014 10:17:09 -0400 Subject: stowing UI stuff in empty branch --- .gitignore | 31 + .nojekyll | 0 assets/fonts/ionicons.eot | Bin 0 -> 124752 bytes assets/fonts/ionicons.svg | 447 +++++++ assets/fonts/ionicons.ttf | Bin 0 -> 124588 bytes assets/fonts/ionicons.woff | Bin 0 -> 124664 bytes assets/img/MacPaint.gif | Bin 0 -> 20002 bytes assets/img/logo1.svg | 23 + assets/img/logo2.svg | 40 + assets/img/logo3.svg | 40 + assets/img/logo4-invert.svg | 49 + assets/img/logo4.svg | 49 + assets/img/paintbucket.png | Bin 0 -> 930 bytes assets/img/pattern.png | Bin 0 -> 6276 bytes assets/img/smalldetail.jpg | Bin 0 -> 7800 bytes assets/javascripts/app.js | 332 +++++ assets/javascripts/environment.js | 99 ++ assets/javascripts/minimap.js | 208 +++ assets/javascripts/mx/extensions/mx.movements.js | 160 +++ .../mx/extensions/mx.rotationControl.js | 266 ++++ assets/javascripts/mx/extensions/mx.scene.js | 161 +++ assets/javascripts/mx/mx.js | 497 +++++++ assets/javascripts/mx/mx.min.js | 1 + assets/javascripts/mx/primitives/mx.box.js | 62 + .../javascripts/mx/primitives/mx.boxDimensions.js | 88 ++ assets/javascripts/mx/primitives/mx.coords.js | 61 + assets/javascripts/mx/primitives/mx.door.js | 75 ++ assets/javascripts/mx/primitives/mx.face.js | 41 + assets/javascripts/mx/primitives/mx.iframe.js | 19 + assets/javascripts/mx/primitives/mx.image.js | 40 + assets/javascripts/mx/primitives/mx.texturedBox.js | 119 ++ assets/javascripts/mx/primitives/mx.video.js | 48 + assets/javascripts/util.js | 160 +++ assets/javascripts/vendor/jquery-1.10.1.min.js | 6 + assets/stylesheets/app.css | 1415 ++++++++++++++++++++ assets/stylesheets/ionicons.css | 1335 ++++++++++++++++++ assets/swfs/video-js.swf | Bin 0 -> 14059 bytes edit-profile.html | 125 ++ front.html | 163 +++ index.html | 281 ++++ package.json | 17 + profile.html | 179 +++ signed-out.html | 127 ++ 43 files changed, 6764 insertions(+) create mode 100644 .gitignore create mode 100644 .nojekyll create mode 100755 assets/fonts/ionicons.eot create mode 100755 assets/fonts/ionicons.svg create mode 100755 assets/fonts/ionicons.ttf create mode 100755 assets/fonts/ionicons.woff create mode 100644 assets/img/MacPaint.gif create mode 100644 assets/img/logo1.svg create mode 100644 assets/img/logo2.svg create mode 100644 assets/img/logo3.svg create mode 100644 assets/img/logo4-invert.svg create mode 100644 assets/img/logo4.svg create mode 100644 assets/img/paintbucket.png create mode 100644 assets/img/pattern.png create mode 100644 assets/img/smalldetail.jpg create mode 100644 assets/javascripts/app.js create mode 100644 assets/javascripts/environment.js create mode 100644 assets/javascripts/minimap.js create mode 100644 assets/javascripts/mx/extensions/mx.movements.js create mode 100644 assets/javascripts/mx/extensions/mx.rotationControl.js create mode 100644 assets/javascripts/mx/extensions/mx.scene.js create mode 100644 assets/javascripts/mx/mx.js create mode 100644 assets/javascripts/mx/mx.min.js create mode 100644 assets/javascripts/mx/primitives/mx.box.js create mode 100644 assets/javascripts/mx/primitives/mx.boxDimensions.js create mode 100644 assets/javascripts/mx/primitives/mx.coords.js create mode 100644 assets/javascripts/mx/primitives/mx.door.js create mode 100644 assets/javascripts/mx/primitives/mx.face.js create mode 100644 assets/javascripts/mx/primitives/mx.iframe.js create mode 100644 assets/javascripts/mx/primitives/mx.image.js create mode 100644 assets/javascripts/mx/primitives/mx.texturedBox.js create mode 100644 assets/javascripts/mx/primitives/mx.video.js create mode 100644 assets/javascripts/util.js create mode 100755 assets/javascripts/vendor/jquery-1.10.1.min.js create mode 100755 assets/stylesheets/app.css create mode 100755 assets/stylesheets/ionicons.css create mode 100755 assets/swfs/video-js.swf create mode 100644 edit-profile.html create mode 100755 front.html create mode 100755 index.html create mode 100644 package.json create mode 100644 profile.html create mode 100755 signed-out.html diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..54e537b --- /dev/null +++ b/.gitignore @@ -0,0 +1,31 @@ +lib-cov +*.seed +*.log +*.csv +*.dat +*.out +*.pid +*.gz + +pids +logs +results + +.DS_Store + +bower_components +node_modules + +.bundle +db/*.sqlite3 +log/*.log +tmp/ +.sass-cache +.#* +*~ +*.orig +*# +*.swp +*.mp4 +*.db + diff --git a/.nojekyll b/.nojekyll new file mode 100644 index 0000000..e69de29 diff --git a/assets/fonts/ionicons.eot b/assets/fonts/ionicons.eot new file mode 100755 index 0000000..6b33288 Binary files /dev/null and b/assets/fonts/ionicons.eot differ diff --git a/assets/fonts/ionicons.svg b/assets/fonts/ionicons.svg new file mode 100755 index 0000000..a1ee425 --- /dev/null +++ b/assets/fonts/ionicons.svg @@ -0,0 +1,447 @@ + + + +Generated by IcoMoon + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/assets/fonts/ionicons.ttf b/assets/fonts/ionicons.ttf new file mode 100755 index 0000000..573d5b3 Binary files /dev/null and b/assets/fonts/ionicons.ttf differ diff --git a/assets/fonts/ionicons.woff b/assets/fonts/ionicons.woff new file mode 100755 index 0000000..337b87f Binary files /dev/null and b/assets/fonts/ionicons.woff differ diff --git a/assets/img/MacPaint.gif b/assets/img/MacPaint.gif new file mode 100644 index 0000000..fc6bf0e Binary files /dev/null and b/assets/img/MacPaint.gif differ diff --git a/assets/img/logo1.svg b/assets/img/logo1.svg new file mode 100644 index 0000000..2465b1d --- /dev/null +++ b/assets/img/logo1.svg @@ -0,0 +1,23 @@ + + + +]> + + + + + + + + + + diff --git a/assets/img/logo2.svg b/assets/img/logo2.svg new file mode 100644 index 0000000..3978a1f --- /dev/null +++ b/assets/img/logo2.svg @@ -0,0 +1,40 @@ + + + +]> + + + + + + + + + + + + + + + + diff --git a/assets/img/logo3.svg b/assets/img/logo3.svg new file mode 100644 index 0000000..528518f --- /dev/null +++ b/assets/img/logo3.svg @@ -0,0 +1,40 @@ + + + +]> + + + + + + + + + + + + + + + + diff --git a/assets/img/logo4-invert.svg b/assets/img/logo4-invert.svg new file mode 100644 index 0000000..aaa550b --- /dev/null +++ b/assets/img/logo4-invert.svg @@ -0,0 +1,49 @@ + + + +]> + + + + + + + + + + diff --git a/assets/img/logo4.svg b/assets/img/logo4.svg new file mode 100644 index 0000000..72b904a --- /dev/null +++ b/assets/img/logo4.svg @@ -0,0 +1,49 @@ + + + +]> + + + + + + + + + + diff --git a/assets/img/paintbucket.png b/assets/img/paintbucket.png new file mode 100644 index 0000000..20eb81e Binary files /dev/null and b/assets/img/paintbucket.png differ diff --git a/assets/img/pattern.png b/assets/img/pattern.png new file mode 100644 index 0000000..7fbba5b Binary files /dev/null and b/assets/img/pattern.png differ diff --git a/assets/img/smalldetail.jpg b/assets/img/smalldetail.jpg new file mode 100644 index 0000000..f602843 Binary files /dev/null and b/assets/img/smalldetail.jpg differ diff --git a/assets/javascripts/app.js b/assets/javascripts/app.js new file mode 100644 index 0000000..bfca04e --- /dev/null +++ b/assets/javascripts/app.js @@ -0,0 +1,332 @@ + +var scene, + cam; + +var app = new function(){} +app.dragging = false + +app.init = function () { + + var mainbox, + coords, + box, size, + floor, + // controls = new MX.RotationControl(), + movements, + viewHeight = 350 + + scene = new MX.Scene().addTo('#scene') + scene.sizeToScreen() + + window.onresize = function () { + scene.sizeToScreen() + } + + cam = scene.camera + cam.y = viewHeight + + minimap = new MX.Minimap() + + movements = new MX.Movements(cam, viewHeight, minimap) + movements.init() + + animate() + + function animate () { + requestAnimationFrame(animate) + //controls.update() + movements.update() + // TWEEN.update() + scene.update() + } + + window.inAnimation = true + + environment.init() + minimap.update() + + bind() + +} + +var is_iphone = (navigator.userAgent.match(/iPhone/i)) || (navigator.userAgent.match(/iPod/i)); +var is_ipad = (navigator.userAgent.match(/iPad/i)); +var is_android = (navigator.userAgent.match(/Android/i)) +var is_mobile = is_iphone || is_ipad || is_android; + +function bind () { + + if(is_mobile) { + $("html").addClass("mobile"); + } + else { + $("html").addClass("desktop"); + } + + $.fn.clickToToggle = function(fn){ + $(this).click(function(e){ + e.stopPropagation() + var isActive = ! $(this).hasClass("icon-close") + disable_mode() + fn(isActive) + $(this).toggleClass("icon-close", isActive); + }) + } + + $(".addMedia").clickToToggle(function(isActive){ + $(".mediaDrawer").toggleClass("active", isActive); + $(".fileUpload").toggleClass("active", isActive); + }); + + $(".room1 .editBtn").click(function () { + var room = $(this).parent(); + room.addClass('editing'); + $(this).siblings('.formHolder').find('[type="submit"]').one('click', function (evt) { + evt.preventDefault(); + evt.stopPropagation(); + room.removeClass('editing'); + }); + }); + + // Place media logic + var $floatingImg = $('.floatingImg'); + + function placeMedia(evt, img) { + // JULES DO YO THANG + alert('Place media at (' + evt.pageX + ', ' + evt.pageY + ')'); + } + + $('.mediaContainer img').mousedown(function(e){ + e.preventDefault() + e.stopPropagation() + }) + $('.mediaContainer img').click(function (e) { + e.stopPropagation() + $(".mediaDrawer, .fileUpload, .addMedia").removeClass("active icon-close"); + $floatingImg.attr('src', $(this).attr('src')); + function _followCursor(e) { + $floatingImg.parent().css({ + top: (e.pageY - ($floatingImg.height() / 2)) + 'px', + left: (e.pageX - ($floatingImg.width() / 2)) + 'px' + }); + } + $(window).on('mousemove', _followCursor); + $(window, this).one('click', function () { + $floatingImg.attr('src', ''); + $(window).off('mousemove', _followCursor); + $floatingImg.parent().removeClass('edit'); + }); + $floatingImg.parent().addClass('edit'); + _followCursor(e); + }); + + $(".icon-arrow-resize").clickToToggle(function(isActive){ + $(".image").toggleClass("active", isActive); + }); + $(".icon-map").click(function(){ + $("#minimap").toggleClass("hide"); + $(this).toggleClass('hidden'); + }); + $(".icon-ios7-keypad-outline").clickToToggle(function(isActive){ + $(".wallpaper").toggleClass("active", isActive); + $("body").removeClass("pastePaper"); + }); + $(".paper1").click(function(){ + $("body").toggleClass("pastePaper"); + $(this).toggleClass("active"); + }); + + $(".icon-ios7-sunny-outline").clickToToggle(function(isActive){ + $(".lightcontrol").toggleClass("active", isActive); + }); + $(".delete-image-toggle").clickToToggle(function(isActive){ + $("body").toggleClass("deleteActive", isActive); + }); + $(".icon-key").clickToToggle(function(isActive){ + $(".settings").toggleClass("active", isActive); + }); + + + + $(".edit-text-toggle").clickToToggle(function(isActive){ + $(".image").toggleClass("editText", isActive); + }); + + + + $(".foundToggle").click(function(){ + $(".foundMedia").addClass("active"); + $(".myMedia").addClass("inactive"); + $('a').removeClass("active"); + $(this).addClass("active"); + }); + + $(".yourMedia").click(function(){ + $(".foundMedia").removeClass("active"); + $(".myMedia").removeClass("inactive"); + $('a').removeClass("active"); + $(this).addClass("active"); + }); + + $("#deleteMedia").click(function(){ + $("body").toggleClass("deleteArmed"); + }); + + $("#startpoint").click(function(){ + $(this).toggleClass("active"); + $("#startText").toggleClass("hide"); + $("#moveText").toggleClass("show"); + }); + + + $(".deleteArmed .mediaContainer").click(function(){ + $(this).addClass("deleted"); + }); + + + $("#createProject").click(function(){ + $(".mediaDrawer.newProject").toggleClass("active"); + $("body").addClass("noOverflow") + }); + + $(".templates span").click(function(){ + $(".templates span").removeClass("active"); + $(this).toggleClass("active"); + }); + + $(document).on("click", ".icon-close", disable_mode) + + function disable_mode(){ + $(".icon-close").removeClass("icon-close") + $('.mediaDrawer,.fileUpload,.image,.lightcontrol,.settings,.wallpaper').removeClass("active"); + $(".image").removeClass("editText") + $("body").removeClass("deleteArmed") + } + + $("#shadow-control").on({ + mousedown: function(){ app.dragging = true }, + change: function(){ + var hex = (~~($(this).int() / 100 * 0xff)).toString(10) + if (hex.length == 1) hex = "0" + hex; + var color = "rgba(" + [hex, hex, hex, "1.0"] + ")" + $(".face").css("border-color", color) + } + }) + + $("#brightness-control").on({ + mousedown: function(){ app.dragging = true }, + change: function(){ + var hex = (~~($(this).int() / 100 * 0xff)).toString(10) + var color = "rgba(" + [hex, hex, hex, "0.9"] + ")" + $("body,.face").css("background-color", color) + } + }) + + + // + // EDIT IMAGE HOVER MENU + + var hideEditImageMenuTimeout + environment.image.el.addEventListener('mouseover', function(e){ + environment.image.el.classList.add('hover') + var offset = $(".image").offset() + offset.left = max(0, offset.left + 30) + offset.top = max(0, offset.top + 50) + $(".edit-image.menu").show().offset( offset ) + clearTimeout(hideEditImageMenuTimeout) + }) + environment.image.el.addEventListener('mouseout', function(e){ + environment.image.el.classList.remove('hover') + hideEditImageMenuTimeout = setTimeout(function(){ + $(".edit-image.menu").hide() + }, 50) + }) + $(".edit-image.menu").on({ + mouseover: function(){ + clearTimeout(hideEditImageMenuTimeout) + }, + mouseout: function(){ + hideEditImageMenuTimeout = setTimeout(function(){ + $(".edit-image.menu").hide() + }, 50) + }, + mousedown: function(e){ + e.stopPropagation() + }, + mouseup: function(e){ + e.stopPropagation() + } + }) + + + // + // EDIT VIDEO HOVER MENU + + var hideEditVideoMenuTimeout + environment.video.el.addEventListener('mouseover', function(e){ + environment.video.el.classList.add('hover') + var offset = $(".video").offset() + offset.left = max(0, offset.left + 30) + offset.top = max(0, offset.top + 50) + $(".edit-video.menu").show().offset( offset ) + clearTimeout(hideEditImageMenuTimeout) + }) + environment.video.el.addEventListener('mouseout', function(e){ + environment.video.el.classList.remove('hover') + hideEditVideoMenuTimeout = setTimeout(function(){ + $(".edit-video.menu").hide() + }, 50) + }) + $(".edit-video.menu").on({ + mouseover: function(){ + clearTimeout(hideEditVideoMenuTimeout) + }, + mouseout: function(){ + hideEditVideoMenuTimeout = setTimeout(function(){ + $(".edit-video.menu").hide() + }, 50) + }, + mousedown: function(e){ + e.stopPropagation() + }, + mouseup: function(e){ + e.stopPropagation() + } + }) + $(".icon-ios7-reload,.ios7-arrow-forward").click(function(){ + $(this).toggleClass('toggled') + }) + + // + // ALL DONE + + $('body').removeClass('loading'); +} + + +$(function(){ + + $(".signIn").click(function(){ + $(".mediaDrawer.signin").addClass("active"); + }); + + $(".signUp").click(function(){ + $(".mediaDrawer.signup").addClass("active"); + }); + + $(".bigClose").click(function(){ + $(".mediaDrawer, .room1").removeClass("active editing"); + $("body").removeClass("noOverflow"); + }); + + var classes = ['one', 'two', 'three', 'four', 'five', 'six', 'seven', 'eight', 'nine', 'ten', 'eleven', 'twelve', 'thirteen']; + + $(".bio").addClass(choice(classes)); + + + function randomizeList(listObj) { + $(listObj).each(function() { + $(this).addClass(classes[Math.Random()*classes.size]); + }); + } +}) \ No newline at end of file diff --git a/assets/javascripts/environment.js b/assets/javascripts/environment.js new file mode 100644 index 0000000..513deea --- /dev/null +++ b/assets/javascripts/environment.js @@ -0,0 +1,99 @@ +var environment = new function(){} +environment.init = function () { + + cam.rotationY = -3.77 + //controls.init(cam, scene) + + cam.z = -200 + cam.x = 400 + + var borderColor = '#000' + + // set up objects + center = {} + center.z = 900 + + doorWidth = 300 + doorHeight = 450 + doorOffset = 0 + wallColor = 'rgba(255,255,255,0.85)' + + box = new MX.BoxDimensions({ + width: 2000, + height: 900, + depth: 2000, + color: wallColor, + borderColor: borderColor, + sides: "top bottom left right back", + tag: "bigroom" + }) + box.z = 500 - center.z + scene.add(box) + + box = new MX.BoxDimensions({ + width: 1000, + height: 900, + depth: 1000, + color: wallColor, + borderColor: borderColor, + sides: "top bottom left right front", + tag: "smallroom" + }) + box.z = -500 - 200 - 500 - center.z + scene.add(box) + + hall = new MX.BoxDimensions({ + width: doorWidth, + height: doorHeight, + depth: 200, + color: wallColor, + borderColor: borderColor, + sides: "top bottom left right", + tag: "hall" + }) + hall.z = -600- center.z + scene.add(hall) + + door = new MX.Door({ + width: 2000, + height: 900, + doorWidth: doorWidth, + doorHeight: doorHeight, + doorOffset: doorOffset, + color: wallColor, + borderColor: borderColor + }) + door.z = -500 - center.z + scene.add(door) + + door = new MX.Door({ + width: 1000, + height: 900, + doorWidth: doorWidth, + doorHeight: doorHeight, + doorOffset: doorOffset, + color: wallColor, + borderColor: borderColor + }) + door.z = -700 - center.z + scene.add(door) + + var image = environment.image = new MX.Image({ + src: "https://s3.amazonaws.com/luckyplop/f5b2c20e602cdfc86383910f294dcf23d91fa956.png", + x: -990, + y: 450, + z: 0 - center.z, + }) + image.rotationY = MX.toRad(90) + scene.add(image) + + var video = environment.video = new MX.Video({ + src: "//www.dotdash3.com/video/svvnDp9_Q1s.mp4", + x: 0, + y: 300, + z: -500 - 200 - 500 - 450 - center.z, + }) + video.rotationY = MX.toRad(180) + scene.add(video) + +} diff --git a/assets/javascripts/minimap.js b/assets/javascripts/minimap.js new file mode 100644 index 0000000..5dca676 --- /dev/null +++ b/assets/javascripts/minimap.js @@ -0,0 +1,208 @@ +MX.Minimap = function () { + var canvas = document.createElement("canvas") + var ctx = canvas.getContext("2d") + var w = canvas.width = 200 + var h = canvas.height = 200 + + var gridSpace; + var zoom = 2.7 + + var gridStroke = '#ddd' + var boxFill = '#fff' + var boxStroke = '#000' + var playerColor = '#888' + + var xmin, xmax, ymin, ymax, xpos, ypos, scale, side; + + this.update = function(){ + this.draw() + } + + this.bounds = function(){ + gridSpace = Math.pow(10, ~~(zoom-0.5)+0.5) + side = Math.pow(10, zoom+1) + scale = w / side + xpos = -cam.x + ypos = cam.z + + xmin = side/-2 - xpos + xmax = side/2 - xpos + ymin = side/-2 - ypos + ymax = side/2 - ypos + } + + this.draw = function(){ + ctx.clearRect(0,0,w,h) + + ctx.fillStyle = "#fff" + ctx.fillRect(0,0,w,h) + this.bounds() + this.grid() + this.boxes() + this.player() + } + + this.grid = function(){ + ctx.strokeStyle = gridStroke + ctx.lineWidth = 1 + ctx.fillStyle = "transparent" + + var xmod = xmin-(xmin % gridSpace) + var ymod = ymin-(ymin % gridSpace) + + for (var x = xmin; x < xmax+gridSpace; x += gridSpace) { + var xline = (x-xmod) * scale + line(xline, 0, xline, h) + } + for (var y = ymin; y < ymax+gridSpace; y += gridSpace) { + var yline = (y-ymod) * scale + line(0, yline, w, yline) + } + + function line(x0,y0,x1,y1) { + ctx.beginPath() + ctx.moveTo(x0, y0) + ctx.lineTo(x1, y1) + ctx.stroke() + } + } + this.player = function(){ + ctx.save() + + ctx.translate(~~(w/2),~~(h/2)); + ctx.rotate(-cam.rotationY) + + var radius = 5 + + ctx.fillStyle = playerColor; + + ctx.beginPath(); + ctx.arc(0, 0, radius, 0, 2*Math.PI, false); + ctx.fill(); + + ctx.beginPath(); + ctx.moveTo(0,0) + ctx.lineTo(-radius,0) + ctx.lineTo(0,radius*3) + ctx.lineTo(radius,0) + ctx.moveTo(0,0) + ctx.fill() + + ctx.fillStyle = "transparent" + ctx.restore() + } + + this.boxes = function(){ + + ctx.save() + ctx.translate(~~(w/2),~~(h/2)); + ctx.lineWidth = 0.5 + var tx = ((-xpos) * scale), + ty = ((-ypos) * scale); + ctx.translate(tx, ty) + + scene.inner.children.forEach(function(obj){ + if (obj.type == "Box" || obj.type == "BoxDimensions" || obj.type == "ScaleBox") { + + ctx.save() + ctx.fillStyle = obj.color + ctx.strokeStyle = "#222" + + var obj_scale = (obj.scale || 1) * scale + var tx = ~~((obj.x) * scale), + ty = ~~((obj.z) * scale); + ctx.translate(-tx, ty) + ctx.rotate(-obj.rotationY) + + var ww = ~~(obj.opt.width/2 * obj_scale) + var hh = ~~(obj.opt.depth/2 * obj_scale) + ctx.beginPath(); + ctx.moveTo(ww, hh) + + ctx.lineTo(ww, -hh) + ctx.lineTo(-ww, -hh) + ctx.lineTo(-ww, hh) + ctx.closePath() + ctx.fill() + ctx.stroke() + ctx.restore() + } + if (obj.type == "Image" || obj.type == "Video" || obj.type == "Cutout") { + ctx.save() + ctx.strokeStyle = "#444" + + var obj_scale = (obj.scale || 1) * scale + + var tx = ~~((obj.x) * scale), + ty = ~~((obj.z) * scale); + ctx.translate(-tx, ty) + ctx.rotate(-obj.rotationY) + + var ww = ~~(obj.width/2 * obj_scale) + + ctx.beginPath(); + ctx.moveTo(ww, 0) + ctx.lineTo(-ww, 0) + ctx.closePath() + ctx.stroke() + ctx.restore() + } + }) + ctx.restore() + } + + var dragging = false, mx = 0, my = 0, mdx = 0, mdy = 0, cx, cy; + canvas.addEventListener("mousedown", function(e){ + e.stopPropagation() + var rect = canvas.getBoundingClientRect() + dragging = true; + mx = e.pageX - rect.left + my = e.pageY - rect.top + mdx = (mx - w/2) / scale + mdy = (my - h/2) / scale + cx = cam.x // -= mdx + cy = cam.z // += mdy + + minimap.update() + }) + document.addEventListener("mousemove", function(e){ + if (dragging) { + e.stopPropagation() + var rect = canvas.getBoundingClientRect() + var mnx = e.pageX - rect.left + var mny = e.pageY - rect.top + mdx = (mnx - mx) / scale + mdy = (mny - my) / scale + + cam.x = cx + mdx + cam.z = cy - mdy + minimap.update() + } + }) + document.addEventListener("mouseup", function(e){ + dragging = false; + }) + + canvas.addEventListener( 'mousewheel', onDocumentMouseWheel, false ); + canvas.addEventListener( 'DOMMouseScroll', onDocumentMouseWheel, false); + function onDocumentMouseWheel (e) { + // WebKit + if ( event.wheelDeltaY ) { + zoom -= event.wheelDeltaY * 0.0003; + } + // Opera / Explorer 9 + else if ( event.wheelDelta ) { + zoom -= event.wheelDelta * 0.0003; + } + // Firefox + else if ( event.detail ) { + zoom += event.detail * 0.01; + } + minimap.update() + } + + this.draw() + $("#minimap .el").append(canvas) + + return this; +} \ No newline at end of file diff --git a/assets/javascripts/mx/extensions/mx.movements.js b/assets/javascripts/mx/extensions/mx.movements.js new file mode 100644 index 0000000..691ada7 --- /dev/null +++ b/assets/javascripts/mx/extensions/mx.movements.js @@ -0,0 +1,160 @@ + + +MX.Movements = function (cam, viewHeight, minimap) { + + var moveForward, + moveLeft, + moveBackward, + moveRight, + turnLeft, + turnRight, + jumping = false + + var v = 25, + vr = Math.PI * 0.015 + jumpV = 30, + vx = vy = vz = 0 + + return { + + init: function () { + + document.addEventListener('keydown', function (e) { + $(".edit-image.menu,.edit-video.menu").hide() + + switch ( e.keyCode ) { + case 38: // up + case 87: // w + moveForward = true + break + + case 37: // left + case 65: // a + turnLeft = true + break + + case 40: // down + case 83: // s + moveBackward = true + break + + case 39: // right + case 68: // d + turnRight = true + break + + case 32: // space + if (!jumping) vy += jumpV + jumping = true + break + } + }) + + document.addEventListener('keyup', function (e) { + $(".edit-image.menu,.edit-video.menu").hide() + + switch ( e.keyCode ) { + case 38: // up + case 87: // w + moveForward = false + break + + case 37: // left + case 65: // a + turnLeft = false + break + + case 40: // down + case 83: // s + moveBackward = false + break + + case 39: // right + case 68: // d + turnRight = false + break + } + }) + + var mouseX, mouseY, dx, dy, rotX, rotY, dragging = false + document.addEventListener('mousedown', function (e) { + $(".edit-image.menu,.edit-video.menu").hide() + + mouseX = e.pageX + mouseY = e.pageY + rotX = cam.rotationX + rotY = cam.rotationY + dragging = true + }) + document.addEventListener('mousemove', function (e) { + if (! dragging || app.dragging) return + var dx = (e.pageX - mouseX) / window.innerWidth * Math.PI/3 + var dy = (e.pageY - mouseY) / window.innerHeight * Math.PI/3 + cam.rotationY = rotY + dx + cam.rotationX = rotX - dy + minimap.update() + }) + document.addEventListener('mouseup', function (e) { + app.dragging = dragging = false + }) + + window.addEventListener('blur', function(e){ + $(".edit-image.menu,.edit-video.menu").hide() + moveForward = moveLeft= moveBackward = moveRight = turnLeft = turnRight = jumping = dragging = false + }) + + }, + + update: function () { + + var ry = cam.rotationY + + if (moveForward || moveBackward || moveRight || moveLeft || turnLeft || turnRight) { + + vx = vz = 0 + + if (moveForward) { + vx += v * Math.cos(ry + Math.PI / 2) + vz += v * Math.sin(ry + Math.PI / 2) + } + if (moveBackward) { + vx -= v * Math.cos(ry + Math.PI / 2) + vz -= v * Math.sin(ry + Math.PI / 2) + } + if (moveLeft) { + vx -= v * Math.cos(ry) + vz -= v * Math.sin(ry) + } + if (moveRight) { + vx += v * Math.cos(ry) + vz += v * Math.sin(ry) + } + + if (turnLeft) { + cam.rotationY += vr + } + if (turnRight) { + cam.rotationY -= vr + } + + cam.x += vx + cam.z += vz + + minimap.update() + + } + + vy -= 1 + + // update cam + cam.y += vy + + if (cam.y <= viewHeight) { + cam.y = viewHeight + vy = 0 + jumping = false + } + + } + } +} diff --git a/assets/javascripts/mx/extensions/mx.rotationControl.js b/assets/javascripts/mx/extensions/mx.rotationControl.js new file mode 100644 index 0000000..3bdc043 --- /dev/null +++ b/assets/javascripts/mx/extensions/mx.rotationControl.js @@ -0,0 +1,266 @@ +// Usage: +// +// var control = new MX.RotationControl() +// control.init( object{MX.Object3D} [, listener{HTMLElement}] ) +// +// In animation loop: +// +// control.update() +// +// The above code will register handler functions on `listener` +// and will be updating `object`s rotationX and rotationY +// If no `listener` is provided, will default to `object`s el. + +MX.RotationControl = function () { + + var object, + locked = false + + var down = false, + active = false, + lastX, + lastY + + var pointerLockPrefix = + 'pointerLockElement' in document ? '' : + 'mozPointerLockElement' in document ? 'moz' : + 'webkitPointerLockElement' in document ? 'webkit' : null, + hasPointerLock = !(pointerLockPrefix === null) + pointerLockEnabled = false + + var pub = { + + sensitivity : .5, + ease : 10, + drag : true, + + inverseX : false, + inverseY : false, + + disableX : false, + disableY : false, + + rotationX : 0, + rotationY : 0, + + upperBoundX : undefined, + lowerBoundX : undefined, + + upperBoundY : undefined, + lowerBoundY : undefined, + + usePreset: function (name) { + var ops = presets[name] + if (ops) { + if (currentPreset && presets[currentPreset].teardown) { + presets[currentPreset].teardown() + } + for (var op in ops) { + if (op !== 'setup' && op !== 'teardown') { + pub[op] = ops[op] + } + } + if (op.setup) ops.setup() + } + } + } + + var currentPreset + var presets = { + firstPerson: { + drag: false, + ease: 2, + sensitivity: .18, + inverseX: true, + inverseY: true, + upperBoundX: MX.rotationUnit === 'deg' ? 90 : Math.PI / 2, + lowerBoundX: MX.rotationUnit === 'deg' ? -90 : -Math.PI / 2 + }, + skybox: { + sensitivity: .18, + inverseX: true, + inverseY: true, + upperBoundX: MX.rotationUnit === 'deg' ? 90 : Math.PI / 2, + lowerBoundX: MX.rotationUnit === 'deg' ? -90 : -Math.PI / 2 + } + } + + function init (obj, lis) { + if (active) return + + object = obj + pub.rotationX = object.rotationX + pub.rotationY = object.rotationY + + if (lis instanceof HTMLElement) { + listener = lis + } else if (lis instanceof MX.Object3D) { + listener = lis.el + } else { + listener = window.document + } + + listener.addEventListener('mousedown', onDown) + listener.addEventListener('mousemove', onMove) + listener.addEventListener('mouseup', onUp) + listener.addEventListener('touchstart', onDown) + listener.addEventListener('touchmove', onMove) + listener.addEventListener('touchend', onUp) + + active = true + } + + function changeObject (obj) { + object = obj + pub.rotationX = object.rotationX + pub.rotationY = object.rotationY + } + + function changeListener (lis) { + remove() + active = false + init(object, lis) + if (pointerLockEnabled) { + initPointerLock() + } + } + + function remove () { + if (!active) return + listener.removeEventListener('mousedown', onDown) + listener.removeEventListener('mousemove', onMove) + listener.removeEventListener('mouseup', onUp) + listener.removeEventListener('touchstart', onDown) + listener.removeEventListener('touchmove', onMove) + listener.removeEventListener('touchend', onUp) + + if (hasPointerLock) { + document.removeEventListener(pointerLockPrefix + 'pointerlockchange', onPointerLockChange) + document.removeEventListener('mousemove', onPointerLockMove) + document.body[pointerLockPrefix + (pointerLockPrefix ? 'E' : 'e') + 'xitPointerLock']() + } + active = false + } + + function onDown (e) { + e = normalizeEvent(e) + if (!e) return + down = true + lastX = e.pageX + lastY = e.pageY + } + + function onMove (e) { + if (app.dragging) return; + if (e.type = 'touchmove') { + e.preventDefault() + } + if (pub.drag && !down) return + e = normalizeEvent(e) + if (!e) return + lastX = lastX || e.pageX + lastY = lastY || e.pageY + var dx = e.pageX - lastX, + dy = e.pageY - lastY + lastX = e.pageX + lastY = e.pageY + updateTarget(dx, dy) + } + + function onUp () { + app.dragging = down = false + } + + function initPointerLock () { + + if (pointerLockEnabled) return + + document.addEventListener(pointerLockPrefix + 'pointerlockchange', onPointerLockChange) + document.addEventListener('mousemove', onPointerLockMove) + + document.body[pointerLockPrefix + (pointerLockPrefix ? 'R' : 'r') + 'equestPointerLock']() + } + + function onPointerLockChange () { + var el = document.body + if (document[pointerLockPrefix + (pointerLockPrefix ? 'P' : 'p') + 'ointerLockElement'] === el) { + pointerLockEnabled = true + } else { + pointerLockEnabled = false + } + } + + function onPointerLockMove (e) { + if (!pointerLockEnabled) return + var dx = e[pointerLockPrefix + (pointerLockPrefix ? 'M' : 'm') + 'ovementX'], + dy = e[pointerLockPrefix + (pointerLockPrefix ? 'M' : 'm') + 'ovementY'] + updateTarget(dx, dy) + } + + function normalizeEvent (e) { + if (e.touches) { + return e.touches.length > 1 ? false : e.touches[0] + } else { + return e + } + } + + function updateTarget (dx, dy) { + if (pub.inverseX) dx = -dx + if (pub.inverseY) dy = -dy + if (MX.rotationUnit !== 'deg') { + dx = MX.toRad(dx) + dy = MX.toRad(dy) + } + + if (!pub.disableX) { + pub.rotationX -= dy * pub.sensitivity + if (pub.upperBoundX) pub.rotationX = Math.min(pub.rotationX, pub.upperBoundX) + if (pub.lowerBoundX) pub.rotationX = Math.max(pub.rotationX, pub.lowerBoundX) + } + + if (!pub.disableY) { + pub.rotationY += dx * pub.sensitivity + if (pub.upperBoundY) pub.rotationY = Math.min(pub.rotationY, pub.upperBoundY) + if (pub.lowerBoundY) pub.rotationY = Math.max(pub.rotationY, pub.lowerBoundY) + } + } + + function update () { + if (!object || locked) return + var dx = pub.rotationX - object.rotationX, + dy = pub.rotationY - object.rotationY + if (Math.abs(dx) < 0.0001) { + object.rotationX = pub.rotationX + } else { + object.rotationX += dx / pub.ease + } + if (Math.abs(dy) < 0.0001) { + object.rotationY = pub.rotationY + } else { + object.rotationY += dy / pub.ease + } + } + + function lock () { + locked = true + } + + function unlock () { + pub.rotationX = object.rotationX + pub.rotationY = object.rotationY + locked = false + } + + pub.init = init + pub.remove = remove + pub.update = update + pub.lock = lock + pub.unlock = unlock + pub.initPointerLock = initPointerLock + pub.changeObject = changeObject + pub.changeListener = changeListener + + return pub + +} \ No newline at end of file diff --git a/assets/javascripts/mx/extensions/mx.scene.js b/assets/javascripts/mx/extensions/mx.scene.js new file mode 100644 index 0000000..c1501f5 --- /dev/null +++ b/assets/javascripts/mx/extensions/mx.scene.js @@ -0,0 +1,161 @@ +// NOTE +// +// This is not a fully functional 3d scene as you might expect. +// The camera can only do pitch (rotationX) and yaw (rotationY), but no roll (rotationZ) +// because I haven't implemented alternative euler orders or quaternions. +// +// For serious 3D scenes with more functionalities you should use +// THREE.js with CSS3D Renderer. + +MX.Scene = (function () { + + var add = MX.Object3D.prototype.add, + remove = MX.Object3D.prototype.remove + + function Scene () { + + this.el = document.createElement('div') + this.el.classList.add('mx-scene') + + var s = this.el.style + + s[MX.transformProp] = 'preserve-3d' + + s.webkitPerspectiveOrigin = '50% 50%' + s.mozPerspectiveOrigin = '50% 50%' + s.perspectiveOrigin = '50% 50%' + + s.webkitUserSelect = 'none' + s.mozUserSelect = 'none' + s.userSelect = 'none' + + s.overflow = 'hidden' + + this.inner = new MX.Object3D().addTo(this.el) + this.inner.el.style.width = '0' + this.inner.el.style.height = '0' + + var self = this + var width, height, perspective + + Object.defineProperty(this, 'width', { + get: function () { + return width + }, + set: function (val) { + width = val + self.el.style.width = val + 'px' + } + }) + + Object.defineProperty(this, 'height', { + get: function () { + return height + }, + set: function (val) { + height = val + self.el.style.height = val + 'px' + } + }) + + Object.defineProperty(this, 'perspective', { + get: function () { + return perspective + }, + set: function (val) { + perspective = val + self.el.style[MX.perspectiveProp] = val + 'px' + self.inner.z = -val - self.camera.z + self.inner.rotationOrigin.z = -val + } + }) + + var cam = this.camera = new MX.Object3D() + cam.el = null + + // cam's lookAt is a bit different + // ignoring rotationZ + cam.getLookAtEuler = getCameraEuler.bind(cam) + + this.inner.rotationOrigin = { x:0, y:0, z:0 } + + this.perspective = 0 + } + + Scene.prototype = { + + constructor: Scene, + + add: function () { + add.apply(this.inner, arguments) + return this + }, + + remove: function () { + remove.apply(this.inner, arguments) + return this + }, + + addTo: function (target) { + if (typeof target === 'string') { + target = document.querySelector(target) + } + if (target instanceof HTMLElement && target.appendChild) { + target.appendChild(this.el) + } else { + console.warn('You can only add a Scene to an HTML element.') + } + return this + }, + + update: function () { + // update inner based on camera + + var i = this.inner, + c = this.camera + + c.update() + + i.z = -this.perspective - c.z + i.x = -c.x + i.y = -c.y + + i.rotationX = -c.rotationX + i.rotationY = -c.rotationY + //i.rotationZ = -c.rotationZ + + i.update() + return this + }, + + sizeToScreen: function(){ + scene.width = window.innerWidth + scene.height = window.innerHeight + if (is_mobile) { + scene.perspective = min(window.innerWidth, window.innerHeight) - 80 + } + else { + scene.perspective = min(window.innerWidth, window.innerHeight) + } + }, + + } + + function getCameraEuler (target) { + var dx = target.x - this.x, + dy = target.y - this.y, + dz = target.z - this.z + r = {} + r.y = Math.atan2(-dx, dz) + r.x = Math.atan2(-dy, Math.sqrt(dx*dx + dz*dz)) + r.z = 0 + if (MX.rotationUnit === 'deg') { + r.x = MX.toDeg(r.x) + r.y = MX.toDeg(r.y) + } + return r + } + + return Scene + +})() \ No newline at end of file diff --git a/assets/javascripts/mx/mx.js b/assets/javascripts/mx/mx.js new file mode 100644 index 0000000..a96274b --- /dev/null +++ b/assets/javascripts/mx/mx.js @@ -0,0 +1,497 @@ +/** + * Copyright (C) 2013 by Evan You + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +var MX = MX || (function (undefined) { + + var MX = { + version: '0.1.0', + prefix: undefined, + rotationUnit: 'rad' + } + + var floatPrecision = 5 + + // ======================================================================== + // Setup & Compatibility + // ======================================================================== + + var transformProp, + transitionProp, + transformOriginProp, + transformStyleProp, + perspectiveProp, + transitionEndEvent + + var positionAtCenter = true, // whether to auto center objects + centeringCSS // styles to inject for center positioning + + document.addEventListener('DOMContentLoaded', setup) + + function setup () { + + // sniff prefix + + var s = document.body.style + + MX.prefix = + 'webkitTransform' in s ? 'webkit' : + 'mozTransform' in s ? 'moz' : + 'msTransform' in s ? 'ms' : '' + + transformProp = MX.transformProp = addPrefix('transform') + transitionProp = MX.transitionProp = addPrefix('transition') + transformOriginProp = MX.transformOriginProp = addPrefix('transformOrigin') + transformStyleProp = MX.transformStyleProp = addPrefix('transformStyle') + perspectiveProp = MX.perspectiveProp = addPrefix('perspective') + transitionEndEvent = MX.transitionEndEvent = MX.prefix === 'webkit' ? 'webkitTransitionEnd' : 'transitionend' + + // shiv rAF + + var vendors = ['webkit', 'moz', 'ms'] + for(var x = 0; x < vendors.length && !window.requestAnimationFrame; ++x) { + window.requestAnimationFrame = window[vendors[x]+'RequestAnimationFrame'] + window.cancelAnimationFrame = + window[vendors[x]+'CancelAnimationFrame'] || + window[vendors[x]+'CancelRequestAnimationFrame'] + } + + // inject centering css + + centeringCSS = document.createElement('style') + centeringCSS.type = 'text/css' + centeringCSS.innerHTML = + '.mx-object3d {' + + 'position: absolute;' + + 'top: 50%;' + + 'left: 50%;}' + injectCenteringCSS() + + app.init() + window.scrollTo(0,0) + } + + function injectCenteringCSS () { + document.head.appendChild(centeringCSS) + } + + function removeCenteringCSS () { + document.head.removeChild(centeringCSS) + } + + // ======================================================================== + // Utils + // ======================================================================== + + function toDeg (rad) { + return rad / Math.PI * 180 + } + + function toRad (deg) { + return deg / 180 * Math.PI + } + + function buildRotationTranslation (obj) { + + // used when rotationOrigin is set + + var origin = obj.rotationOrigin + if (!origin) { + return + } else { + var dx = origin.x - obj.x, + dy = -(origin.y - obj.y), + dz = -(origin.z - obj.z) + return { + before: 'translate3d(' + dx.toFixed(floatPrecision) +'px,' + dy.toFixed(floatPrecision) + 'px,' + dz.toFixed(floatPrecision) + 'px) ', + after: 'translate3d(' + (-dx).toFixed(floatPrecision) + 'px,' + (-dy).toFixed(floatPrecision) + 'px,' + (-dz).toFixed(floatPrecision) + 'px) ' + } + } + } + + function addPrefix (string) { + if (MX.prefix) { + string = MX.prefix + string.charAt(0).toUpperCase() + string.slice(1) + } + return string + } + + // ======================================================================== + // Base Object3D + // ======================================================================== + + function Object3D (el) { + + this.setupDomElement(el) + this.setCSSTransformStyle('preserve-3d') + this.el.classList.add('mx-object3d') + + this.parent = undefined + this.children = [] + this.updateChildren = true + + this.inverseLookAt = false + + this.reset() + + var width, height, + self = this + + Object.defineProperty(this, 'width', { + get: function () { + return width + || parseInt(self.el.style.width, 10) + || 0 + }, + set: function (val) { + width = val + this.el.style.width = width + 'px' + } + }) + + Object.defineProperty(this, 'height', { + get: function () { + return height + || parseInt(self.el.style.height, 10) + || 0 + }, + set: function (val) { + height = val + this.el.style.height = height + 'px' + } + }) + } + + Object3D.prototype = { + + constructor: Object3D, + + reset: function () { + this.x = this.__x = 0 + this.y = this.__y = 0 + this.z = this.__z = 0 + this.rotationX = this.__rotationX = 0 + this.rotationY = this.__rotationY = 0 + this.rotationZ = this.__rotationZ = 0 + this.scaleX = this.__scaleX = 1 + this.scaleY = this.__scaleY = 1 + this.scaleZ = this.__scaleZ = 1 + this.scale = this.__scale = 1 + this.perspective = this.__perspective = 0 + this.rotationOrigin = undefined + this.followTarget = undefined + this.dirty = true + this.update() + }, + + setupDomElement: function (el) { + this.el = undefined + if (el instanceof HTMLElement) { + this.el = el + } else if (typeof el === 'string') { + var tag = el.match(/^[^.#\s]*/)[1], + id = el.match(/#[^.#\s]*/), + classes = el.match(/\.[^.#\s]*/g) + this.el = document.createElement(tag || 'div') + if (id) { + this.el.id = id[0].slice(1) + } + if (classes) { + var i = classes.length + while (i--) { + this.el.classList.add(classes[i].slice(1)) + } + } + } else { + this.el = document.createElement('div') + } + }, + + update: function () { + + if (this.updateChildren) { + var i = this.children.length + while (i--) { + this.children[i].update() + } + } + + if (this.followTarget) { + this.lookAt(this.followTarget, false) + } + + if (this.scaleX !== this.__scaleX || + this.scaleY !== this.__scaleY || + this.scaleZ !== this.__scaleZ) { + this.__scaleX = this.scaleX + this.__scaleY = this.scaleY + this.__scaleZ = this.scaleZ + this.dirty = true + } + + if (this.scale !== this.__scale) { + this.scaleX = + this.scaleY = + this.scaleZ = + this.__scaleX = + this.__scaleY = + this.__scaleZ = + this.__scale = + this.scale + this.dirty = true + } + + if (this.rotationX !== this.__rotationX || + this.rotationY !== this.__rotationY || + this.rotationZ !== this.__rotationZ) { + this.__rotationX = this.rotationX + this.__rotationY = this.rotationY + this.__rotationZ = this.rotationZ + this.dirty = true + } + + if (this.x !== this.__x || + this.y !== this.__y || + this.z !== this.__z) { + this.__x = this.x + this.__y = this.y + this.__z = this.z + this.dirty = true + } + + if (this.perspective !== this.__perspective) { + this.__perspective = this.perspective + this.dirty = true + } + + if (this.dirty && this.el) { + + var rotationTranslation = buildRotationTranslation(this), + rotation = 'rotateX(' + this.rotationX.toFixed(floatPrecision) + MX.rotationUnit + ') ' + + 'rotateY(' + this.rotationY.toFixed(floatPrecision) + MX.rotationUnit + ') ' + + 'rotateZ(' + this.rotationZ.toFixed(floatPrecision) + MX.rotationUnit + ') ' + + var transformString = + (MX.positionAtCenter ? 'translate3d(-50%, -50%, 0) ' : '') + + (this.perspective ? 'perspective(' + this.perspective + 'px) ' : '') + + 'translate3d(' + + this.x.toFixed(floatPrecision) + 'px,' + + (-this.y).toFixed(floatPrecision) + 'px,' + + (-this.z).toFixed(floatPrecision) + 'px) ' + + 'scale3d(' + + this.scaleX.toFixed(floatPrecision) + ',' + + this.scaleY.toFixed(floatPrecision) + ',' + + this.scaleZ.toFixed(floatPrecision) + ') ' + + if (rotationTranslation) { + transformString += rotationTranslation.before + + rotation + + rotationTranslation.after + + } else { + transformString += rotation + } + + this.el.style[transformProp] = transformString + this.dirty = false + } + + return this + + }, + + lookAt: function (target, update) { + var r = this.getLookAtEuler(target) + this.setRotation(r) + if (update !== false) this.update() + return this + }, + + getLookAtEuler: function (target) { + // euler order XYZ + var r = {}, + dx = target.x - this.x, + dy = target.y - this.y, + dz = target.z - this.z + if (this.inverseLookAt) { + dx = -dx + dy = -dy + dz = -dz + } + if (dz === 0) dz = 0.001 + r.x = -Math.atan2(dy, dz) + var flip = dz > 0 ? 1 : -1 + r.y = flip * Math.atan2(dx * Math.cos(r.x), dz * -flip) + r.z = Math.atan2(Math.cos(r.x), Math.sin(r.x) * Math.sin(r.y)) - Math.PI / 2 + if (MX.rotationUnit === 'deg') { + r.x = toDeg(r.x) + r.y = toDeg(r.y) + r.z = toDeg(r.z) + } + return r + }, + + add: function () { + if (!this.el) return + var parent = this + Array.prototype.forEach.call(arguments, function (child) { + if (!child instanceof Object3D) return + parent.el.appendChild(child.el) + if (!parent.children) parent.children = [] + parent.children.push(child) + child.parent = parent + }) + return this + }, + + remove: function () { + var parent = this + Array.prototype.forEach.call(arguments, function (child) { + var index = parent.children.indexOf(child) + if (index !== -1) { + parent.children.splice(index, 1) + child.parent = undefined + } + }) + return this + }, + + addTo: function (target) { + if (typeof target === 'string') { + target = document.querySelector(target) + } + if (target instanceof HTMLElement && target.appendChild) { + target.appendChild(this.el) + } else if (target instanceof Object3D || target instanceof Scene) { + target.add(this) + } + return this + }, + + removeElement: function () { + if (this.el.parentNode) { + this.el.parentNode.removeChild(this.el) + } + }, + + setPosition: function (tar) { + this.x = (tar.x || tar.x === 0) ? tar.x : this.x + this.y = (tar.y || tar.y === 0) ? tar.y : this.y + this.z = (tar.z || tar.z === 0) ? tar.z : this.z + }, + + setRotation: function (tar) { + this.rotationX = (tar.x || tar.x === 0) ? tar.x : this.rotationX + this.rotationY = (tar.y || tar.y === 0) ? tar.y : this.rotationY + this.rotationZ = (tar.z || tar.z === 0) ? tar.z : this.rotationZ + }, + + setScale: function (tar) { + this.scaleX = (tar.x || tar.x === 0) ? tar.x : this.scaleX + this.scaleY = (tar.y || tar.y === 0) ? tar.y : this.scaleY + this.scaleZ = (tar.z || tar.z === 0) ? tar.z : this.scaleZ + }, + + setCSSTransformOrigin: function (origin) { + this.el && (this.el.style[transformOriginProp] = origin) + return this + }, + + setCSSTransformStyle: function (style) { + this.el && (this.el.style[transformStyleProp] = style) + return this + }, + + setCSSTransition: function (trans) { + this.el && (this.el.style[transitionProp] = trans) + return this + }, + + setCSSPerspective: function (pers) { + this.el && (this.el.style[perspectiveProp] = pers) + return this + }, + + onTransitionEnd: function (callback) { + this.cancelTransitionEnd() + var el = this.el + el.addEventListener(transitionEndEvent, onEnd) + function onEnd () { + el.removeEventListener(transitionEndEvent, onEnd) + callback() + } + }, + + cancelTransitionEnd: function () { + this.el.removeEventListener(transitionEndEvent) + } + + } + + // ======================================================================== + // Inheritance + // ======================================================================== + + Object3D.extend = extend.bind(Object3D) + + function extend (props) { + var Super = this + var ExtendedObject3D = function () { + Super.call(this) + props.init && props.init.apply(this, arguments) + } + ExtendedObject3D.prototype = Object.create(Super.prototype) + for (var prop in props) { + if (props.hasOwnProperty(prop) && prop !== 'init') { + ExtendedObject3D.prototype[prop] = props[prop] + } + } + ExtendedObject3D.extend = extend.bind(ExtendedObject3D) + return ExtendedObject3D + } + + // ======================================================================== + // Expose API + // ======================================================================== + + MX.Object3D = Object3D + MX.toRad = toRad + MX.toDeg = toDeg + + // center positioning getter setter + Object.defineProperty(MX, 'positionAtCenter', { + get: function () { + return positionAtCenter + }, + set: function (val) { + if (typeof val !== 'boolean') return + positionAtCenter = val + if (positionAtCenter) { + injectCenteringCSS() + } else { + removeCenteringCSS() + } + } + }) + + return MX + +})() \ No newline at end of file diff --git a/assets/javascripts/mx/mx.min.js b/assets/javascripts/mx/mx.min.js new file mode 100644 index 0000000..b0f0cdd --- /dev/null +++ b/assets/javascripts/mx/mx.min.js @@ -0,0 +1 @@ +var MX=MX||function(undefined){var MX={prefix:undefined,rotationUnit:"rad"};var floatPrecision=5;var transformProp,transitionProp,transformOriginProp,transformStyleProp,perspectiveProp;var positionAtCenter=true,centeringCSS;document.addEventListener("DOMContentLoaded",setup);function setup(){var s=document.body.style;MX.prefix="webkitTransform"in s?"webkit":"mozTransform"in s?"moz":"msTransform"in s?"ms":"";transformProp=MX.transformProp=addPrefix("transform");transitionProp=MX.transitionProp=addPrefix("transition");transformOriginProp=MX.transformOriginProp=addPrefix("transformOrigin");transformStyleProp=MX.transformStyleProp=addPrefix("transformStyle");perspectiveProp=MX.perspectiveProp=addPrefix("perspective");var vendors=["webkit","moz","ms"];for(var x=0;x0?1:-1;r.y=flip*Math.atan2(dx*Math.cos(r.x),dz*-flip);r.z=Math.atan2(Math.cos(r.x),Math.sin(r.x)*Math.sin(r.y))-Math.PI/2;if(MX.rotationUnit==="deg"){r.x=toDeg(r.x);r.y=toDeg(r.y);r.z=toDeg(r.z)}return r},add:function(){if(!this.el)return;var parent=this;Array.prototype.forEach.call(arguments,function(child){if(!child instanceof Object3D)return;parent.el.appendChild(child.el);if(!parent.children)parent.children=[];parent.children.push(child);child.parent=parent});return this},remove:function(){var parent=this;Array.prototype.forEach.call(arguments,function(child){var index=parent.children.indexOf(child);if(index!==-1){parent.children.splice(index,1);child.parent=undefined}});return this},addTo:function(target){if(typeof target==="string"){target=document.querySelector(target)}if(target instanceof HTMLElement&&target.appendChild){target.appendChild(this.el)}else if(target instanceof Object3D||target instanceof Scene){target.add(this)}return this},removeElement:function(){if(this.el.parentNode){this.el.parentNode.removeChild(this.el)}},setPosition:function(tar){this.x=tar.x||tar.x===0?tar.x:this.x;this.y=tar.y||tar.y===0?tar.y:this.y;this.z=tar.z||tar.z===0?tar.z:this.z},setRotation:function(tar){this.rotationX=tar.x||tar.x===0?tar.x:this.rotationX;this.rotationY=tar.y||tar.y===0?tar.y:this.rotationY;this.rotationZ=tar.z||tar.z===0?tar.z:this.rotationZ},setScale:function(tar){this.scaleX=tar.x||tar.x===0?tar.x:this.scaleX;this.scaleY=tar.y||tar.y===0?tar.y:this.scaleY;this.scaleZ=tar.z||tar.z===0?tar.z:this.scaleZ},setCSSTransformOrigin:function(origin){this.el&&(this.el.style[transformOriginProp]=addPrefix(origin));return this},setCSSTransformStyle:function(style){this.el&&(this.el.style[transformStyleProp]=addPrefix(style));return this},setCSSTransition:function(trans){this.el&&(this.el.style[transitionProp]=addPrefix(trans));return this},setCSSPerspective:function(pers){this.el&&(this.el.style[perspectiveProp]=addPrefix(pers));return this}};Object3D.extend=extend.bind(Object3D);function extend(props){var Super=this;var ExtendedObject3D=function(){Super.call(this);props.init&&props.init.apply(this,arguments)};ExtendedObject3D.prototype=Object.create(Super.prototype);for(var prop in props){if(props.hasOwnProperty(prop)&&prop!=="init"){ExtendedObject3D.prototype[prop]=props[prop]}}ExtendedObject3D.extend=extend.bind(ExtendedObject3D);return ExtendedObject3D}MX.Object3D=Object3D;MX.toRad=toRad;MX.toDeg=toDeg;Object.defineProperty(MX,"positionAtCenter",{get:function(){return positionAtCenter},set:function(val){if(typeof val!=="boolean")return;positionAtCenter=val;if(positionAtCenter){injectCenteringCSS()}else{removeCenteringCSS()}}});return MX}(); \ No newline at end of file diff --git a/assets/javascripts/mx/primitives/mx.box.js b/assets/javascripts/mx/primitives/mx.box.js new file mode 100644 index 0000000..9f053da --- /dev/null +++ b/assets/javascripts/mx/primitives/mx.box.js @@ -0,0 +1,62 @@ +MX.Box = MX.Object3D.extend({ + + // this will be called within the contructor + init: function (size, color, borderColor) { + + this.type = "Box" + + size = size || 100 + color = color || 'rgba(0, 255, 122, .1)' + borderColor = borderColor || '#0f3' + + // an Object3D's associated DOM node is the "el" property + this.el.classList.add('box') + + var angle = MX.rotationUnit === 'deg' ? 90 : (Math.PI / 2) + + var top = this.top = new MX.Object3D('.face') + top.rotationX = angle + top.y = size / 2 + + var bottom = this.bottom = new MX.Object3D('.face') + bottom.rotationX = -angle + bottom.y = -size / 2 + + var left = this.left = new MX.Object3D('.face') + left.rotationY = -angle + left.x = -size / 2 + + var right = this.right = new MX.Object3D('.face') + right.rotationY = angle + right.x = size / 2 + + var front = this.front = new MX.Object3D('.face') + front.z = -size / 2 + + var back = this.back = new MX.Object3D('.face') + back.rotationY = angle * 2 + back.z = size / 2 + + // adding children, must also be instances of Object3D + this.add(top, bottom, left, right, front, back) + + this.children.forEach(function (face) { + face.width = size - 2 + face.height = size - 2 + face.el.style.backgroundColor = color + face.el.style.border = '1px solid ' + borderColor + }) + + // this applies the updated CSS style + // required for any change to take effect + // when a parent object's update() is called + // all its children will be updated as well + this.update() + + // if this object's children won't move by themselves + this.updateChildren = false + } + + // other properties will be mixed into the prototype of the new constructor + +}) \ No newline at end of file diff --git a/assets/javascripts/mx/primitives/mx.boxDimensions.js b/assets/javascripts/mx/primitives/mx.boxDimensions.js new file mode 100644 index 0000000..d1d507d --- /dev/null +++ b/assets/javascripts/mx/primitives/mx.boxDimensions.js @@ -0,0 +1,88 @@ +MX.BoxDimensions = MX.Object3D.extend({ + + // this will be called within the contructor + init: function (opt) { + + this.type = "BoxDimensions" + + this.opt = opt + + var width = opt.width || 100 + var height = opt.height || 100 + var depth = opt.depth || 100 + var color = this.color = opt.color || 'rgba(0, 255, 122, .1)' + var borderColor = this.borderColor = opt.borderColor || '#0f3' + var sides = this.sides = opt.sides || "top bottom left right back" + + // an Object3D's associated DOM node is the "el" property + this.el.classList.add('box') + + var angle = MX.rotationUnit === 'deg' ? 90 : (Math.PI / 2) + + var top = this.top = new MX.Object3D('.face.top') + top.rotationX = angle + top.width = width + top.height = depth + top.y = height + + var bottom = this.bottom = new MX.Object3D('.face.bottom') + bottom.rotationX = -angle + bottom.width = width + bottom.height = depth + bottom.y = 0 + + var left = this.left = new MX.Object3D('.face.left') + left.rotationY = -angle + left.width = depth + left.height = height + left.x = -width/2 + left.y = height/2 + + var right = this.right = new MX.Object3D('.face.right') + right.rotationY = angle + right.width = depth + right.height = height + right.x = width/2 + right.y = height/2 + + var front = this.front = new MX.Object3D('.face.front') + front.width = width + front.height = height + front.z = -depth/2 + front.y = height/2 + + var back = this.back = new MX.Object3D('.face.back') + back.width = width + back.height = height + back.rotationY = angle * 2 + back.z = depth/2 + back.y = height/2 + + // adding children, must also be instances of Object3D + if (-1 != sides.indexOf("top")) this.add(top) + if (-1 != sides.indexOf("bottom")) this.add(bottom) + if (-1 != sides.indexOf("left")) this.add(left) + if (-1 != sides.indexOf("right")) this.add(right) + if (-1 != sides.indexOf("front")) this.add(front) + if (-1 != sides.indexOf("back")) this.add(back) + + this.children.forEach(function (face) { + face.el.style.backgroundColor = color + face.el.style.border = '3px solid ' + borderColor + }) + + bottom.el.style.border = "0" + + // this applies the updated CSS style + // required for any change to take effect + // when a parent object's update() is called + // all its children will be updated as well + this.update() + + // if this object's children won't move by themselves + this.updateChildren = false + } + + // other properties will be mixed into the prototype of the new constructor + +}) \ No newline at end of file diff --git a/assets/javascripts/mx/primitives/mx.coords.js b/assets/javascripts/mx/primitives/mx.coords.js new file mode 100644 index 0000000..80b148c --- /dev/null +++ b/assets/javascripts/mx/primitives/mx.coords.js @@ -0,0 +1,61 @@ +MX.Coords = (function () { + + var colors = { + x: '#f33', + y: '#3f3', + z: '#66f' + } + + var Axis = MX.Object3D.extend({ + init: function (axis, size) { + + var label = document.createElement('span') + label.textContent = axis.toUpperCase() + label.style.position = 'absolute' + label.style.right = '0px' + label.style.bottom = '3px' + label.style.fontSize = Math.round(size / 10) + 'px' + this.el.appendChild(label) + + var faceA = new MX.Object3D(), + faceB = new MX.Object3D() + faceA.rotationX = 90 + this.add(faceA, faceB) + + this.el.style.color = + faceA.el.style.backgroundColor = + faceB.el.style.backgroundColor = colors[axis] + + this.width = + faceA.width = + faceB.width = size + + this.height = + faceA.height = + faceB.height = Math.round(size / 100) + + var angle = MX.rotationUnit === 'deg' ? 90 : (Math.PI / 2) + + if (axis === 'y') { + this.rotationZ = -angle + } else if (axis === 'z') { + this.rotationY = angle + } + } + }) + + var Coords = MX.Object3D.extend({ + init: function (size) { + size = size || 100 + var x = new Axis('x', size), + y = new Axis('y', size), + z = new Axis('z', size) + this.add(x, y, z) + this.update() + this.updateChildren = false + } + }) + + return Coords + +})() \ No newline at end of file diff --git a/assets/javascripts/mx/primitives/mx.door.js b/assets/javascripts/mx/primitives/mx.door.js new file mode 100644 index 0000000..12ff148 --- /dev/null +++ b/assets/javascripts/mx/primitives/mx.door.js @@ -0,0 +1,75 @@ + +borderThickness = 3 + +MX.Door = MX.Object3D.extend({ + + // this will be called within the contructor + init: function (opt) { + + width = opt.width || 100 + height = opt.height || 100 + doorOffset = opt.doorOffset || 0 + doorWidth = opt.doorWidth || 30 + doorHeight = opt.doorHeight || 20 + color = opt.color || 'rgba(0, 255, 122, .1)' + borderColor = opt.borderColor || '#0f3' + + // an Object3D's associated DOM node is the "el" property + this.el.classList.add('box') + + var angle = MX.rotationUnit === 'deg' ? 90 : (Math.PI / 2) + + var left = new MX.Object3D('.face.door.leftTop') + left.width = (width - doorWidth) / 2 + doorOffset + left.height = height-doorHeight-borderThickness + left.x = (width + doorWidth) / 4 + doorOffset + left.y = (height+doorHeight+borderThickness)/2 + left.el.style.backgroundColor = color + left.el.style.borderTop = borderThickness + 'px solid ' + borderColor + left.el.style.borderRight = borderThickness + 'px solid ' + borderColor + this.add(left) + + var leftBot = new MX.Object3D('.face.door.leftBot') + leftBot.width = (width - doorWidth) / 2 - doorOffset + leftBot.height = doorHeight + borderThickness + leftBot.x = (width + doorWidth) / 4 - doorOffset + leftBot.y = (doorHeight+borderThickness)/2 + leftBot.el.style.backgroundColor = color + leftBot.el.style.borderLeft = borderThickness + 'px solid ' + borderColor + leftBot.el.style.borderRight = borderThickness + 'px solid ' + borderColor + leftBot.el.style.borderBottom = borderThickness + 'px solid ' + borderColor + this.add(leftBot) + + var rightTop = new MX.Object3D('.face.door.rightTop') + rightTop.width = (width - doorWidth) / 2 - doorOffset + rightTop.height = height-doorHeight-borderThickness + rightTop.x = -(width+doorWidth)/4 - doorOffset + rightTop.y = (height+ doorHeight+borderThickness)/2 + rightTop.el.style.backgroundColor = color + rightTop.el.style.borderTop = borderThickness + 'px solid ' + borderColor + rightTop.el.style.borderLeft = borderThickness + 'px solid ' + borderColor + this.add(rightTop) + + var rightBot = new MX.Object3D('.face.door.rightBot') + rightBot.width = (width - doorWidth) / 2 - doorOffset + rightBot.height = doorHeight+borderThickness + rightBot.x = -(width + doorWidth)/4 - doorOffset + rightBot.y = (doorHeight+borderThickness)/2 + rightBot.el.style.backgroundColor = color + rightBot.el.style.borderLeft = borderThickness + 'px solid ' + borderColor + rightBot.el.style.borderRight = borderThickness + 'px solid ' + borderColor + rightBot.el.style.borderBottom = borderThickness + 'px solid ' + borderColor + this.add(rightBot) + + var top = new MX.Object3D('.face.door.top') + top.width = doorWidth + top.height = height-doorHeight + top.x = doorOffset + top.y = (height+ doorHeight)/2 + top.el.style.backgroundColor = color + top.el.style.borderTop = borderThickness + 'px solid ' + borderColor + top.el.style.borderBottom = borderThickness + 'px solid ' + borderColor + this.add(top) + + } +}) \ No newline at end of file diff --git a/assets/javascripts/mx/primitives/mx.face.js b/assets/javascripts/mx/primitives/mx.face.js new file mode 100644 index 0000000..ac47ab4 --- /dev/null +++ b/assets/javascripts/mx/primitives/mx.face.js @@ -0,0 +1,41 @@ +MX.Face = MX.Object3D.extend({ + + // this will be called within the contructor + init: function (size, color, borderColor) { + + size = size || 100 + color = color || 'rgba(0, 255, 122, .1)' + borderColor = borderColor || '#0f3' + + // an Object3D's associated DOM node is the "el" property + this.el.classList.add('face') + + var angle = MX.rotationUnit === 'deg' ? 90 : (Math.PI / 2) + + var top = this.top = new MX.Object3D('.face') + top.rotationX = angle + top.y = size / 2 + + // adding children, must also be instances of Object3D + this.add(top) + + this.children.forEach(function (face) { + face.width = size - 2 + face.height = size - 2 + face.el.style.backgroundColor = color + face.el.style.border = '1px solid ' + borderColor + }) + + // this applies the updated CSS style + // required for any change to take effect + // when a parent object's update() is called + // all its children will be updated as well + this.update() + + // if this object's children won't move by themselves + this.updateChildren = false + } + + // other properties will be mixed into the prototype of the new constructor + +}) diff --git a/assets/javascripts/mx/primitives/mx.iframe.js b/assets/javascripts/mx/primitives/mx.iframe.js new file mode 100644 index 0000000..76ce603 --- /dev/null +++ b/assets/javascripts/mx/primitives/mx.iframe.js @@ -0,0 +1,19 @@ +MX.Iframe = MX.Object3D.extend({ + init: function (ops) { + + var layer = this.layer = new MX.Object3D() + layer.width = ops.width + layer.height = ops.height + +// this.add(layer) + this.width = ops.width + this.height = ops.height + + this.el.innerHTML = "