Skip to content

Commit

Permalink
refactor scene code to components (canvas, fullscreen metatags, stats…
Browse files Browse the repository at this point in the history
…, vr mode, vr mode ui)
  • Loading branch information
ngokevin committed Jan 21, 2016
1 parent 14bafd3 commit bc51285
Show file tree
Hide file tree
Showing 19 changed files with 792 additions and 582 deletions.
40 changes: 24 additions & 16 deletions src/components/index.js
Original file line number Diff line number Diff line change
@@ -1,16 +1,24 @@
require('../components/camera');
require('../components/cursor');
require('../components/fog');
require('../components/geometry');
require('../components/light');
require('../components/loader');
require('../components/look-at');
require('../components/look-controls');
require('../components/material');
require('../components/position');
require('../components/raycaster');
require('../components/rotation');
require('../components/scale');
require('../components/sound');
require('../components/visible');
require('../components/wasd-controls');
require('./camera');
require('./cursor');
require('./geometry');
require('./light');
require('./loader');
require('./look-at');
require('./look-controls');
require('./material');
require('./position');
require('./raycaster');
require('./rotation');
require('./scale');
require('./sound');
require('./visible');
require('./wasd-controls');

require('./scene/canvas');
require('./scene/fog');
require('./scene/fullscreen');
require('./scene/meta-tags');
require('./scene/stats');
require('./scene/vr-mode');
require('./scene/vr-mode-ui');
require('./scene/wakelock');
5 changes: 3 additions & 2 deletions src/components/look-controls.js
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ module.exports.Component = registerComponent('look-controls', {
},

addEventListeners: function () {
var canvasEl = document.querySelector('a-scene').canvas;
var canvasEl = this.el.sceneEl.canvas;

// Mouse Events
canvasEl.addEventListener('mousedown', this.onMouseDown, false);
Expand Down Expand Up @@ -223,7 +223,8 @@ module.exports.Component = registerComponent('look-controls', {
var deltaY;
var yawObject = this.yawObject;
if (!this.touchStarted) { return; }
deltaY = 2 * Math.PI * (e.touches[0].pageX - this.touchStart.x) / this.canvasEl.clientWidth;
deltaY = 2 * Math.PI * (e.touches[0].pageX - this.touchStart.x) /
this.el.sceneEl.canvas.clientWidth;
// Limits touch orientaion to to yaw (y axis)
yawObject.rotation.y -= deltaY * 0.5;
this.touchStart = {
Expand Down
45 changes: 45 additions & 0 deletions src/components/scene/canvas.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
var register = require('../../core/component').registerComponent;

module.exports.Component = register('canvas', {
schema: {
canvas: {
type: 'selector',
default: undefined
},
height: {
default: 100
},
width: {
default: 100
}
},

update: function () {
var data = this.data;
var canvas = data.canvas;
var scene = this.el;

// No updating canvas.
if (scene.canvas) { return; }

// Inject canvas if one not specified with height and width.
if (!canvas) {
canvas = document.createElement('canvas');
canvas.classList.add('a-canvas');
canvas.style.height = data.height + '%';
canvas.style.width = data.width + '%';
scene.appendChild(canvas);
}

// Prevent overscroll on mobile.
canvas.addEventListener('touchmove', function (event) {
event.preventDefault();
});

// Set canvas on scene.
scene.canvas = canvas;
scene.emit('render-target-loaded', {
target: canvas
});
}
});
73 changes: 73 additions & 0 deletions src/components/scene/fog.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
var register = require('../../core/component').registerComponent;
var THREE = require('../../lib/three');
var debug = require('../../utils/debug');

var warn = debug('components:fog:warn');

/**
* Fog component.
* Applies only to the scene entity.
*/
module.exports.Component = register('fog', {
schema: {
color: { default: '#000' },
density: { default: 0.00025 },
far: { default: 1000, min: 0 },
near: { default: 1, min: 0 },
type: { default: 'linear', oneOf: ['linear', 'exponential'] }
},

update: function () {
var data = this.data;
var el = this.el;
var fog = this.el.object3D.fog;

if (!el.isScene) {
warn('Fog component can only be applied to <a-scene>');
return;
}

// (Re)create fog if fog doesn't exist or fog type changed.
if (!fog || data.type !== fog.name) {
el.object3D.fog = getFog(data);
el.updateMaterials();
return;
}

// Fog data changed. Update fog.
Object.keys(this.schema).forEach(function (key) {
var value = data[key];
if (key === 'color') { value = new THREE.Color(value); }
fog[key] = value;
});
},

/**
* Remove fog on remove (callback).
*/
remove: function () {
var fog = this.el.object3D.fog;
if (fog) {
fog.density = 0;
fog.far = 0;
fog.near = 0;
}
}
});

/**
* Creates a fog object. Sets fog.name to be able to detect fog type changes.
*
* @param {object} data - Fog data.
* @returns {object} fog
*/
function getFog (data) {
var fog;
if (data.type === 'exponential') {
fog = new THREE.FogExp2(data.color, data.density);
} else {
fog = new THREE.Fog(data.color, data.near, data.far);
}
fog.name = data.type;
return fog;
}
67 changes: 67 additions & 0 deletions src/components/scene/fullscreen.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
var registerComponent = require('../../core/component').registerComponent;
var isIframed = require('../../utils/').isIframed;

/**
* Fullscreen listener scene component.
*/
module.exports.Component = registerComponent('fullscreen', {
init: function () {
this.handler = this.fullscreenChangeHandler.bind(this);
document.addEventListener('mozfullscreenchange', this.handler);
document.addEventListener('webkitfullscreenchange', this.handler);

// Handles fullscreen behavior when inside an iframe.
if (isIframed()) {
window.addEventListener('message', this.iframedFullscreenChangeHandler.bind(this));
}
},

fullscreenChangeHandler: function (event) {
var fullscreenElement = document.fullscreenElement ||
document.mozFullScreenElement ||
document.webkitFullscreenElement;

// Lock to landscape orientation on mobile.
if (this.el.isMobile && window.screen.orientation) {
if (fullscreenElement) {
window.screen.orientation.lock('landscape');
} else {
window.screen.orientation.unlock();
}
}

if (fullscreenElement) {
this.enterFullscreenHandler();
} else {
this.exitFullscreenHandler();
}
},

iframedFullscreenChangeHandler: function (event) {
if (!event.data) { return; }
switch (event.data.type) {
case 'fullscreen': {
switch (event.data.data) {
case 'enter':
this.enterFullscreenHandler();
break;
case 'exit':
this.exitFullscreenHandler();
break;
}
}
}
},

enterFullscreenHandler: function () {
var scene = this.el;
scene.addState('fullscreen');
scene.emit('fullscreen-enter');
},

exitFullscreenHandler: function () {
var scene = this.el;
scene.removeState('fullscreen');
scene.emit('fullscreen-exit');
}
});
58 changes: 58 additions & 0 deletions src/components/scene/meta-tags.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
var register = require('../../core/component').registerComponent;

module.exports.Component = register('meta-tags', {
init: function () {
if (!this.el.isMobile) { return; }
this.metaTags = injectMetaTags();
},

remove: function () {
var metaTags = this.metaTags;
if (!metaTags) { return; }
metaTags.forEach(function (metaTag) {
metaTag.parentNode.removeChild(metaTag);
});
}
});

/**
* Injects the necessary metatags in the document for mobile support to:
* 1. Prevent the user to zoom in the document
* 2. Ensure that window.innerWidth and window.innerHeight have the correct
* values and the canvas is properly scaled
* 3. To allow fullscreen mode when pinning a web app on the home screen on
* iOS.
* Adapted from: https://www.reddit.com/r/web_design/comments/3la04p/
*
* @type {Object}
*/
function injectMetaTags () {
var headEl;
var meta = document.querySelector('meta[name="viewport"]');
var metaTags = [];

if (meta) { return; }

headEl = document.getElementsByTagName('head')[0];
meta = document.createElement('meta');
meta.name = 'viewport';
meta.content =
'width=device-width,initial-scale=1,shrink-to-fit=no,user-scalable=no';
headEl.appendChild(meta);
metaTags.push(meta);

// iOS-specific meta tags for fullscreen when pinning to homescreen.
meta = document.createElement('meta');
meta.name = 'apple-mobile-web-app-capable';
meta.content = 'yes';
headEl.appendChild(meta);
metaTags.push(meta);

meta = document.createElement('meta');
meta.name = 'apple-mobile-web-app-status-bar-style';
meta.content = 'black';
headEl.appendChild(meta);
metaTags.push(meta);

return metaTags;
}
55 changes: 55 additions & 0 deletions src/components/scene/stats.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
var registerComponent = require('../../core/component').registerComponent;
var RStats = require('../../../vendor/rStats');

var HIDDEN_CLASS = 'a-hidden';

/**
* Stats appended to document.body by RStats.
*/
module.exports.Component = registerComponent('stats', {
init: function () {
var scene = this.el;

this.stats = createStats();
this.statsEl = document.querySelector('.rs-base');

this.hideBound = this.hide.bind(this);
this.showBound = this.show.bind(this);

scene.addEventListener('enter-vr', this.hideBound);
scene.addEventListener('exit-vr', this.showBound);
},

remove: function () {
this.el.removeEventListener('enter-vr', this.hideBound);
this.el.removeEventListener('exit-vr', this.showBound);
this.statsEl.parentNode.removeChild(this.statsEl);
},

tick: function () {
var stats = this.stats;
stats('rAF').tick();
stats('FPS').frame();
stats().update();
},

hide: function () {
this.statsEl.classList.add(HIDDEN_CLASS);
},

show: function () {
this.statsEl.classList.remove(HIDDEN_CLASS);
}
});

function createStats () {
return new RStats({
CSSPath: '../../style/',
values: {
fps: { caption: 'fps', below: 30 }
},
groups: [
{ caption: 'Framerate', values: [ 'fps', 'raf' ] }
]
});
}
Loading

0 comments on commit bc51285

Please sign in to comment.