motor.js
Version:
A rendering Engine for the web.
540 lines (461 loc) • 15.8 kB
JavaScript
'use strict';
var _get = require('babel-runtime/helpers/get')['default'];
var _inherits = require('babel-runtime/helpers/inherits')['default'];
var _createClass = require('babel-runtime/helpers/create-class')['default'];
var _classCallCheck = require('babel-runtime/helpers/class-call-check')['default'];
var _Object$defineProperties = require('babel-runtime/core-js/object/define-properties')['default'];
var _getIterator = require('babel-runtime/core-js/get-iterator')['default'];
var _interopRequireDefault = require('babel-runtime/helpers/interop-require-default')['default'];
Object.defineProperty(exports, '__esModule', {
value: true
});
var _three = require('three');
var _three2 = _interopRequireDefault(_three);
var _lodash = require('lodash');
var _lodash2 = _interopRequireDefault(_lodash);
var _tweenJs = require('tween.js');
var _tweenJs2 = _interopRequireDefault(_tweenJs);
var _Curve = require('./Curve');
var _Curve2 = _interopRequireDefault(_Curve);
var _Utility = require('./Utility');
var _Utility2 = _interopRequireDefault(_Utility);
var CSS_CLASS_NODE = 'infamous-dom-node';
/**
* Node Class
*
* @class Node
* @return {Node} A new instance of Node
*/
var Node = (function (_THREE$Object3D) {
_inherits(Node, _THREE$Object3D);
/**
* @constructor
*
* @param {Object} properties Properties object -- see example
*
* @example
* var node = new Node({
* classes: ['open'],
* position: [200, 300, 0],
* rotation: [3, 0, 0],
* scale: [1, 1, 1],
* size: {
* modes: ['absolute', 'relative'],
* absolute: [300, null],
* proportional: [null, .5]
* },
* opacity: .9
* })
*/
function Node(properties) {
_classCallCheck(this, Node);
_get(Object.getPrototypeOf(Node.prototype), 'constructor', this).call(this);
// DOM representation of Node
this.element = document.createElement('div');
this._mounted = false;
// Class Cache
this._classes = [CSS_CLASS_NODE];
// Force initial class set;
this.setClasses();
// Property Cache
this._propertyCache = {
opacity: 1,
origin: [0.5, 0.5],
mountPoint: [0.5, 0.5],
align: [.5, .5, 0],
size: {
modes: ['absolute', 'absolute'],
absolute: [100, 100],
proportional: [1, 1]
}
};
// Style Cache
this._styleCache = {
transform: {
matrix3d: []
}
};
// Tweens
this._tweens = {
opacity: null,
position: null,
rotation: null,
scale: null
};
_Object$defineProperties(this, {
opacity: {
set: (function (value) {
this._styleCache.opacity = value;
this._applyStyle('opacity', value);
}).bind(this),
get: (function () {
return this._styleCache.opacity;
}).bind(this)
}
});
this.addEventListener('removed', function (event) {
if (this.element.parentNode !== null) {
this.element.parentNode.removeChild(this.element);
}
});
if (properties) this.setProperties(properties);
}
/**
* [applySize description]
*
* @method
* @private
* @memberOf Node
*/
_createClass(Node, [{
key: '_applySize',
value: function _applySize() {
var modes = this._propertyCache.size.modes;
var absolute = this._propertyCache.size.absolute;
var proportional = this._propertyCache.size.proportional;
if (modes[0] === 'absolute') this._applyStyle('width', absolute[0] + 'px');else if (modes[0] === 'relative') this._applyStyle('width', proportional[0] * 100 + '%');
if (modes[1] === 'absolute') this._applyStyle('height', absolute[1] + 'px');else if (modes[1] === 'relative') this._applyStyle('height', proportional[1] * 100 + '%');
}
/**
* [applyTransform description]
*
* @method
* @private
* @memberOf Node
*/
}, {
key: '_applyTransform',
value: function _applyTransform() {
var matrix3d = this._styleCache.transform.matrix3d;
var transform = '\n matrix3d(\n ' + _Utility2['default'].epsilon(matrix3d[0]) + ',\n ' + _Utility2['default'].epsilon(matrix3d[1]) + ',\n ' + _Utility2['default'].epsilon(matrix3d[2]) + ',\n ' + _Utility2['default'].epsilon(matrix3d[3]) + ',\n ' + _Utility2['default'].epsilon(-matrix3d[4]) + ',\n ' + _Utility2['default'].epsilon(-matrix3d[5]) + ',\n ' + _Utility2['default'].epsilon(-matrix3d[6]) + ',\n ' + _Utility2['default'].epsilon(-matrix3d[7]) + ',\n ' + _Utility2['default'].epsilon(matrix3d[8]) + ',\n ' + _Utility2['default'].epsilon(matrix3d[9]) + ',\n ' + _Utility2['default'].epsilon(matrix3d[10]) + ',\n ' + _Utility2['default'].epsilon(matrix3d[11]) + ',\n ' + _Utility2['default'].epsilon(matrix3d[12]) + ',\n ' + _Utility2['default'].epsilon(matrix3d[13]) + ',\n ' + _Utility2['default'].epsilon(matrix3d[14]) + ',\n ' + _Utility2['default'].epsilon(matrix3d[15]) + '\n )\n ';
this._applyStyle('transform', transform);
}
/**
* [applyStyle description]
*
* @method
* @private
* @memberOf Node
* @param {String} property [description]
* @param {String} value [description]
*/
}, {
key: '_applyStyle',
value: function _applyStyle(property, value) {
this.element.style[property] = value;
}
/**
* [setMatrix3d description]
*
* @method
* @private
* @memberOf Node
* @param {Array} matrix [description]
*/
}, {
key: '_setMatrix3d',
value: function _setMatrix3d(matrix) {
if (true || !_lodash2['default'].isEqual(this._styleCache.transform.matrix3d, matrix)) {
this._styleCache.transform.matrix3d = matrix;
this._applyTransform();
}
}
/**
* [setPosition description]
*
* @method
* @memberOf Node
* @param {Array} position [description]
* @param {Object} transition [description]
*/
}, {
key: 'setPosition',
value: function setPosition(position, transition) {
if (!transition) this.position.set(position[0], position[1], position[2]);else {
if (!this._tweens.position) this._tweens.position = new _tweenJs2['default'].Tween(this.position);
this._tweens.position.stop().to({ x: position[0], y: position[1], z: position[2] }, transition.duration).easing(new _Curve2['default'](transition.curve).get()).start();
}
}
/**
* [setRotation description]
*
* @method
* @memberOf Node
* @param {Array} rotation [description]
* @param {Object} transition [description]
*/
}, {
key: 'setRotation',
value: function setRotation(rotation, transition) {
if (!transition) this.rotation.set(rotation[0], rotation[1], rotation[2]);else {
if (!this._tweens.rotation) this._tweens.rotation = new _tweenJs2['default'].Tween(this.rotation);
this._tweens.rotation.stop().to({ x: rotation[0], y: rotation[1], z: rotation[2] }, transition.duration).easing(new _Curve2['default'](transition.curve).get()).start();
}
}
/**
* [setScale description]
*
* @method
* @memberOf Node
* @param {Array} scale [description]
* @param {Object} transition [description]
*/
}, {
key: 'setScale',
value: function setScale(scale, transition) {
if (!transition) this.scale.set(scale[0], scale[1], scale[2]);else {
if (!this._tweens.scale) this._tweens.scale = new _tweenJs2['default'].Tween(this.scale);
this._tweens.scale.stop().to({ x: scale[0], y: scale[1], z: scale[2] }, transition.duration).easing(new _Curve2['default'](transition.curve).get()).start();
}
}
/**
* [setOpacity description]
*
* @method
* @memberOf Node
* @param {Number} opacity [description]
* @param {Object} transition [description]
*/
}, {
key: 'setOpacity',
value: function setOpacity(opacity, transition) {
if (!transition) this.opacity = opacity;else {
if (!this._tweens.opacity) this._tweens.opacity = new _tweenJs2['default'].Tween(this);
this._tweens.opacity.stop().to({ opacity: opacity }, transition.duration).easing(new _Curve2['default'](transition.curve).get()).start();
}
}
/**
* [setSizeModes description]
*
* @method
* @memberOf Node
* @param {Array} modes [description]
*/
}, {
key: 'setSizeModes',
value: function setSizeModes(modes) {
if (!_lodash2['default'].isEqual(modes, this._propertyCache.size.modes)) {
this._propertyCache.size.modes = modes;
this._applySize();
}
}
/**
* [setAbsolute description]
*
* @method
* @memberOf Node
* @param {Array} size [description]
* @param {Object} transition [description]
*/
}, {
key: 'setAbsoluteSize',
value: function setAbsoluteSize(size, transition) {
if (!transition) {
if (!_lodash2['default'].isEqual(size, this._propertyCache.size.absolute)) {
this._propertyCache.size.absolute = size;
if (this._propertyCache.size.modes.indexOf('absolute') > -1) this._applySize();
}
} else {
// Handle transition
}
}
/**
* [setProportionalSize description]
*
* @method
* @memberOf Node
* @param {Array} size [description]
* @param {Object} transition [description]
*/
}, {
key: 'setProportionalSize',
value: function setProportionalSize(size, transition) {
if (!transition) {
if (!_lodash2['default'].isEqual(size, this._propertyCache.size.proportional)) {
this._propertyCache.size.proportional = size;
if (this._propertyCache.size.modes.indexOf('relative') > -1) this._applySize();
}
} else {
// Handle transition
}
}
/**
* [setAlign description]
*
* @method
* @memberOf Node
* @param {Array} alignment [description]
* @param {Object} transition [description]
*/
}, {
key: 'setAlign',
value: function setAlign(alignment, transition) {
if (!transition) {
if (!_lodash2['default'].isEqual(alignment, this._propertyCache.align)) {
this._propertyCache.align = alignment;
this._applyTransform();
}
} else {
// Handle transition
}
}
/**
* [setClasses description]
*
* @todo check to see if updating classes name causes layout thrashing
*
* @method
* @memberOf Node
* @param {Array} classses [description]
*/
}, {
key: 'setClasses',
value: function setClasses() {
var classes = arguments.length <= 0 || arguments[0] === undefined ? [] : arguments[0];
var changed = false;
var _iteratorNormalCompletion = true;
var _didIteratorError = false;
var _iteratorError = undefined;
try {
for (var _iterator = _getIterator(classes), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) {
var c = _step.value;
// If the class isn't already in the class cache add it
if (this._classes.indexOf(c) == -1) {
this._classes.push(c);
changed = true;
}
}
// If the classes have changed update element
} catch (err) {
_didIteratorError = true;
_iteratorError = err;
} finally {
try {
if (!_iteratorNormalCompletion && _iterator['return']) {
_iterator['return']();
}
} finally {
if (_didIteratorError) {
throw _iteratorError;
}
}
}
if (changed) this.element.className = this._classes.join(" ");
}
/**
* Set all properties of the Node in one method with optional transition
*
* @todo Maybe make the second parameter a Transition class
*
* @method
* @memberOf Node
* @param {Object} properties Properties object - see example
* @param {String} transition Transition
*
* @example
* node.setProperties({
* classes: ['open'],
* position: [200, 300, 0],
* rotation: [3, 0, 0],
* scale: [1, 1, 1],
* size: {
* modes: ['absolute', 'relative'],
* absolute: [300, null],
* proportional: [null, .5]
* },
* opacity: .9
* }, {
* duration: 2000,
* curve: 'ExponentialIn'
* })
*/
}, {
key: 'setProperties',
value: function setProperties(properties, transition) {
// Classes
if (properties.classes) this.setClasses(properties.classes);
// Position
if (properties.position && properties.position.length === 3) this.setPosition(properties.position, transition);
// Rotation
if (properties.rotation && properties.rotation.length === 3) this.setRotation(properties.rotation, transition);
// Scale
if (properties.scale && properties.scale.length === 3) this.setScale(properties.scale, transition);
// Align
if (properties.align && properties.align.length === 3) this.setAlign(properties.align);
// Size
if (properties.size) {
// Size Modes
if (properties.size.modes && properties.size.modes.length === 2) this.setSizeModes(properties.size.modes);
// Absolute Size
if (properties.size.absolute && properties.size.absolute.length === 2) this.setAbsoluteSize(properties.size.absolute);
// Relative Size
if (properties.size.proportional && properties.size.proportional.length === 2) this.setProportionalSize(properties.size.proportional);
}
// Opacity
if (typeof properties.opacity != 'undefined') this.setOpacity(properties.opacity, transition);
}
/**
* Method to add child Node
*
* @method
* @memberof Node
* @param {Node} node [description]
*/
}, {
key: 'addChild',
value: function addChild(node) {
this.add(node);
}
/**
* [render description]
*
* @method
* @memberOf Node
* @param {Scene} scene [description]
*/
}, {
key: 'render',
value: function render(scene) {
this._setMatrix3d(this.matrixWorld.elements);
//If Node isn't mounted.. mount it to the camera element
if (!this._mounted) {
// Mount to parent if parent is a Node
if (this.parent instanceof Node) {
this.parent.element.appendChild(this.element);
this._mounted = true;
// Mount to camera if top level Node
} else {
scene.camera.element.appendChild(this.element);
this._mounted = true;
}
}
// Render Children
var _iteratorNormalCompletion2 = true;
var _didIteratorError2 = false;
var _iteratorError2 = undefined;
try {
for (var _iterator2 = _getIterator(this.children), _step2; !(_iteratorNormalCompletion2 = (_step2 = _iterator2.next()).done); _iteratorNormalCompletion2 = true) {
var child = _step2.value;
child.render(scene);
}
} catch (err) {
_didIteratorError2 = true;
_iteratorError2 = err;
} finally {
try {
if (!_iteratorNormalCompletion2 && _iterator2['return']) {
_iterator2['return']();
}
} finally {
if (_didIteratorError2) {
throw _iteratorError2;
}
}
}
}
}]);
return Node;
})(_three2['default'].Object3D);
exports['default'] = Node;
module.exports = exports['default'];
//# sourceMappingURL=Node.js.map