Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

famous

Package Overview
Dependencies
Maintainers
2
Versions
22
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

famous - npm Package Compare versions

Comparing version 0.2.3-beta0 to 0.3.0-alpha.0

35

CONTRIBUTING.md

@@ -101,38 +101,3 @@ # Contributing to Famo.us

## Issues
Famo.us is composed of several repositories, and it helps if bugs are filed in
the issues section of the right repository. To help you check if your issue has
already been filed or to help you file it in the right place in case it hasn't
we've created the following guidelines:
Below is a list of links to the issues page for all the famous framework
repositories.
* [famous][famous-issues]
* [core][core-issues]
* [events][events-issues]
* [inputs][inputs-issues]
* [math][math-issues]
* [modifiers][modifiers-issues]
* [physics][physics-issues]
* [surfaces][surfaces-issues]
* [transitions][transitions-issues]
* [utilities][utilities-issues]
* [views][views-issues]
* [widgets][widgets-issues]
[famous-issues]: https://github.com/famous/famous/issues
[core-issues]: https://github.com/famous/core/issues
[events-issues]: https://github.com/famous/events/issues
[inputs-issues]: https://github.com/famous/inputs/issues
[math-issues]: https://github.com/famous/math/issues
[modifiers-issues]: https://github.com/famous/modifiers/issues
[physics-issues]: https://github.com/famous/physics/issues
[surfaces-issues]: https://github.com/famous/surfaces/issues
[transitions-issues]: https://github.com/famous/transitions/issues
[utilities-issues]: https://github.com/famous/utilities/issues
[views-issues]: https://github.com/famous/views/issues
[widgets-issues]: https://github.com/famous/widgets/issues

@@ -139,0 +104,0 @@ [famous]: https://github.com/famous/famous

6

core/Context.js

@@ -16,3 +16,3 @@ /* This Source Code Form is subject to the terms of the Mozilla Public

var _originZeroZero = [0, 0];
var _zeroZero = [0, 0];

@@ -48,4 +48,4 @@ function _getElementSize(element) {

opacity: 1,
origin: _originZeroZero,
align: null,
origin: _zeroZero,
align: _zeroZero,
size: this._size

@@ -52,0 +52,0 @@ };

@@ -286,3 +286,3 @@ /* This Source Code Form is subject to the terms of the Mozilla Public

this._matrix = matrix;
var aaMatrix = this.size ? Transform.thenMove(matrix, [-this._size[0]*origin[0], -this._size[1]*origin[1], 0]) : matrix;
var aaMatrix = this._size ? Transform.thenMove(matrix, [-this._size[0]*origin[0], -this._size[1]*origin[1], 0]) : matrix;
_setMatrix(target, aaMatrix);

@@ -289,0 +289,0 @@ this._transformDirty = false;

@@ -28,3 +28,3 @@ /* This Source Code Form is subject to the terms of the Mozilla Public

* @method get
* @param {Number} id entity reigstration id
* @param {Number} id entity registration id
* @return {Surface} entity in the global index

@@ -41,4 +41,4 @@ */

* @method set
* @param {Number} id entity reigstration id
* @return {Surface} entity to add to the global index
* @param {Number} id entity registration id
* @param {Surface} entity to add to the global index
*/

@@ -68,3 +68,3 @@ function set(id, entity) {

* @method unregister
* @param {Number} id entity reigstration id
* @param {Number} id entity registration id
*/

@@ -71,0 +71,0 @@ function unregister(id) {

module.exports = {
Context: require('./Context'),
ElementOutput: require('./ElementOutput'),
ElementAllocator: require('./ElementAllocator'),
ElementOutput: require('./ElementOutput'),
Engine: require('./Engine'),
Entity: require('./Entity'),
EventEmitter: require('./EventEmitter'),
Group: require('./Group'),
EventHandler: require('./EventHandler'),
Group: require('./Group'),
Modifier: require('./Modifier'),

@@ -14,7 +14,7 @@ OptionsManager: require('./OptionsManager'),

Scene: require('./Scene'),
Surface: require('./Surface'),
SpecParser: require('./SpecParser'),
Transform: require('./Transform'),
Surface: require('./Surface'),
View: require('./View'),
ViewSequence: require('./ViewSequence')
};

@@ -37,2 +37,3 @@ /* This Source Code Form is subject to the terms of the Mozilla Public

this._sizeGetter = null;
this._proportionGetter = null;

@@ -48,2 +49,3 @@ /* TODO: remove this when deprecation complete */

size: null,
proportions: null,
target: null

@@ -58,2 +60,3 @@ };

if (options.size) this.sizeFrom(options.size);
if (options.proportions) this.proportionsFrom(options.proportions);
}

@@ -155,2 +158,20 @@ }

/**
* Set function, object, or numerical array to provide proportions, as [percent of width, percent of height].
*
* @method proportionsFrom
*
* @param {Object} proportions provider object
* @return {Modifier} this
*/
Modifier.prototype.proportionsFrom = function proportionsFrom(proportions) {
if (proportions instanceof Function) this._proportionGetter = proportions;
else if (proportions instanceof Object && proportions.get) this._proportionGetter = proportions.get.bind(proportions);
else {
this._proportionGetter = null;
this._output.proportions = proportions;
}
return this;
};
/**

@@ -274,2 +295,24 @@ * Deprecated: Prefer transformFrom with static Transform, or use a TransitionableTransform.

/**
* Deprecated: Prefer proportionsFrom with static origin array, or use a Transitionable with those proportions.
* @deprecated
* @method setProportions
* @param {Array.Number} proportions two element array of [percent of width, percent of height]
* @param {Transitionable} transition Valid transitionable object
* @param {Function} callback callback to call after transition completes
* @return {Modifier} this
*/
Modifier.prototype.setProportions = function setProportions(proportions, transition, callback) {
if (proportions && (transition || this._legacyStates.proportions)) {
if (!this._legacyStates.proportions) {
this._legacyStates.proportions = new Transitionable(this._output.proportions || [0, 0]);
}
if (!this._proportionGetter) this.proportionsFrom(this._legacyStates.proportions);
this._legacyStates.proportions.set(proportions, transition, callback);
return this;
}
else return this.proportionsFrom(proportions);
};
/**
* Deprecated: Prefer to stop transform in your provider object.

@@ -285,2 +328,3 @@ * @deprecated

if (this._legacyStates.size) this._legacyStates.size.halt();
if (this._legacyStates.proportions) this._legacyStates.proportions.halt();
this._transformGetter = null;

@@ -291,2 +335,3 @@ this._opacityGetter = null;

this._sizeGetter = null;
this._proportionGetter = null;
};

@@ -354,2 +399,12 @@

/**
* Deprecated: Prefer to use your provided proportions or output of your proportions provider.
* @deprecated
* @method getProportions
* @return {Object} proportions provider object
*/
Modifier.prototype.getProportions = function getProportions() {
return this._proportionGetter ? this._proportionGetter() : this._output.proportions;
};
// call providers on tick to receive render spec elements to apply

@@ -362,2 +417,3 @@ function _update() {

if (this._sizeGetter) this._output.size = this._sizeGetter();
if (this._proportionGetter) this._output.proportions = this._proportionGetter();
}

@@ -364,0 +420,0 @@

@@ -83,3 +83,3 @@ /* This Source Code Form is subject to the terms of the Mozilla Public

var _originZeroZero = [0, 0];
var _zeroZero = [0, 0];

@@ -103,3 +103,3 @@ // From the provided renderSpec tree, recursively compose opacities,

transform = parentContext.transform;
align = parentContext.align || parentContext.origin;
align = parentContext.align || _zeroZero;
if (parentContext.size && align && (align[0] || align[1])) {

@@ -112,4 +112,4 @@ var alignAdjust = [align[0] * parentContext.size[0], align[1] * parentContext.size[1], 0];

opacity: parentContext.opacity,
origin: parentContext.origin || _originZeroZero,
align: parentContext.align || parentContext.origin || _originZeroZero,
origin: parentContext.origin || _zeroZero,
align: parentContext.align || _zeroZero,
size: parentContext.size

@@ -142,13 +142,22 @@ };

if (spec.align) align = spec.align;
if (spec.size) {
var parentSize = parentContext.size;
size = [
spec.size[0] !== undefined ? spec.size[0] : parentSize[0],
spec.size[1] !== undefined ? spec.size[1] : parentSize[1]
];
if (spec.size || spec.proportions) {
var parentSize = size;
size = [size[0], size[1]];
if (spec.size) {
if (spec.size[0] !== undefined) size[0] = spec.size[0];
if (spec.size[1] !== undefined) size[1] = spec.size[1];
}
if (spec.proportions) {
if (spec.proportions[0] !== undefined) size[0] = size[0] * spec.proportions[0];
if (spec.proportions[1] !== undefined) size[1] = size[1] * spec.proportions[1];
}
if (parentSize) {
if (!align) align = origin;
if (align && (align[0] || align[1])) transform = Transform.thenMove(transform, _vecInContext([align[0] * parentSize[0], align[1] * parentSize[1], 0], sizeContext));
if (origin && (origin[0] || origin[1])) transform = Transform.moveThen([-origin[0] * size[0], -origin[1] * size[1], 0], transform);
}
nextSizeContext = parentContext.transform;

@@ -155,0 +164,0 @@ origin = null;

@@ -33,2 +33,3 @@ /* This Source Code Form is subject to the terms of the Mozilla Public

this.properties = {};
this.attributes = {};
this.content = '';

@@ -40,4 +41,6 @@ this.classList = [];

this._stylesDirty = true;
this._attributesDirty = true;
this._sizeDirty = true;
this._contentDirty = true;
this._trueSizeCheck = true;

@@ -56,2 +59,28 @@ this._dirtyClasses = [];

/**
* Set HTML attributes on this Surface. Note that this will cause
* dirtying and thus re-rendering, even if values do not change.
*
* @method setAttributes
* @param {Object} attributes property dictionary of "key" => "value"
*/
Surface.prototype.setAttributes = function setAttributes(attributes) {
for (var n in attributes) {
if (n === 'style') throw new Error('Cannot set styles via "setAttributes" as it will break Famo.us. Use "setProperties" instead.');
this.attributes[n] = attributes[n];
}
this._attributesDirty = true;
};
/**
* Get HTML attributes on this Surface.
*
* @method getAttributes
*
* @return {Object} Dictionary of this Surface's attributes.
*/
Surface.prototype.getAttributes = function getAttributes() {
return this.attributes;
};
/**
* Set CSS-style properties on this Surface. Note that this will cause

@@ -61,2 +90,3 @@ * dirtying and thus re-rendering, even if values do not change.

* @method setProperties
* @chainable
* @param {Object} properties property dictionary of "key" => "value"

@@ -69,2 +99,3 @@ */

this._stylesDirty = true;
return this;
};

@@ -89,2 +120,3 @@

* @method addClass
* @chainable
* @param {string} className name of class to add

@@ -97,2 +129,3 @@ */

}
return this;
};

@@ -106,2 +139,3 @@

* @method removeClass
* @chainable
* @param {string} className name of class to remove

@@ -115,2 +149,3 @@ */

}
return this;
};

@@ -133,2 +168,3 @@

}
return this;
};

@@ -139,2 +175,3 @@

* @method setClasses
* @chainable
* @param {Array.string} classList

@@ -151,2 +188,3 @@ */

for (i = 0; i < classList.length; i++) this.addClass(classList[i]);
return this;
};

@@ -169,2 +207,3 @@

* @method setContent
* @chainable
* @param {string|Document Fragment} content HTML content

@@ -177,2 +216,3 @@ */

}
return this;
};

@@ -195,2 +235,3 @@

* @method setOptions
* @chainable
* @param {Object} [options] overrides for default options. See constructor.

@@ -202,3 +243,5 @@ */

if (options.properties) this.setProperties(options.properties);
if (options.attributes) this.setAttributes(options.attributes);
if (options.content) this.setContent(options.content);
return this;
};

@@ -228,2 +271,18 @@

// Apply values of all Famous-managed attributes to the document element.
// These will be deployed to the document on call to #setup().
function _applyAttributes(target) {
for (var n in this.attributes) {
target.setAttribute(n, this.attributes[n]);
}
}
// Clear all Famous-managed attributes from the document element.
// These will be deployed to the document on call to #setup().
function _cleanupAttributes(target) {
for (var n in this.attributes) {
target.removeAttribute(n);
}
}
function _xyNotEquals(a, b) {

@@ -255,7 +314,10 @@ return (a && b) ? (a[0] !== b[0] || a[1] !== b[1]) : a !== b;

this.attach(target);
this._opacity = null;
this._currentTarget = target;
this._stylesDirty = true;
this._classesDirty = true;
this._attributesDirty = true;
this._sizeDirty = true;
this._contentDirty = true;
this._originDirty = true;
this._transformDirty = true;

@@ -283,2 +345,3 @@ };

this._classesDirty = false;
this._trueSizeCheck = true;
}

@@ -289,4 +352,11 @@

this._stylesDirty = false;
this._trueSizeCheck = true;
}
if (this._attributesDirty) {
_applyAttributes.call(this, target);
this._attributesDirty = false;
this._trueSizeCheck = true;
}
if (this.size) {

@@ -296,5 +366,26 @@ var origSize = context.size;

if (size[0] === undefined) size[0] = origSize[0];
else if (size[0] === true) size[0] = target.clientWidth;
if (size[1] === undefined) size[1] = origSize[1];
else if (size[1] === true) size[1] = target.clientHeight;
if (size[0] === true || size[1] === true) {
if (size[0] === true && (this._trueSizeCheck || this._size[0] === 0)) {
var width = target.clientWidth;
if (this._size && this._size[0] !== width) {
this._size[0] = width;
this._sizeDirty = true;
}
size[0] = width;
} else {
if (this._size) size[0] = this._size[0];
}
if (size[1] === true && (this._trueSizeCheck || this._size[1] === 0)) {
var height = target.clientHeight;
if (this._size && this._size[1] !== height) {
this._size[1] = height;
this._sizeDirty = true;
}
size[1] = height;
} else {
if (this._size) size[1] = this._size[1];
}
this._trueSizeCheck = false;
}
}

@@ -314,2 +405,3 @@

}
this._eventOutput.emit('resize');
this._sizeDirty = false;

@@ -322,2 +414,3 @@ }

this._contentDirty = false;
this._trueSizeCheck = true;
}

@@ -343,6 +436,7 @@

target.style.display = 'none';
target.style.opacity = '';
target.style.width = '';
target.style.height = '';
this._size = null;
_cleanupStyles.call(this, target);
_cleanupAttributes.call(this, target);
var classList = this.getClassList();

@@ -409,2 +503,3 @@ _cleanupClasses.call(this, target);

* @method setSize
* @chainable
* @param {Array.Number} size as [width, height]

@@ -415,4 +510,5 @@ */

this._sizeDirty = true;
return this;
};
module.exports = Surface;

@@ -43,2 +43,4 @@ /* This Source Code Form is subject to the terms of the Mozilla Public

if (options.trackSize !== undefined) this._.trackSize = options.trackSize;
this._previousNode = null;

@@ -55,2 +57,5 @@ this._nextNode = null;

this.lastNode = null;
this.cumulativeSizes = [[0, 0]];
this.sizeDirty = true;
this.trackSize = false;
};

@@ -70,2 +75,30 @@

// Get sequence size from backing up to index
// TODO: remove from viewSequence with proper abstraction
ViewSequence.Backing.prototype.getSize = function getSize(index) {
return this.cumulativeSizes[index];
};
// Calculates cumulative size
// TODO: remove from viewSequence with proper abstraction
ViewSequence.Backing.prototype.calculateSize = function calculateSize(index) {
index = index || this.array.length;
var size = [0, 0];
for (var i = 0; i < index; i++) {
var nodeSize = this.array[i].getSize();
if (!nodeSize) return undefined;
if (size[0] !== undefined) {
if (nodeSize[0] === undefined) size[0] = undefined;
else size[0] += nodeSize[0];
}
if (size[1] !== undefined) {
if (nodeSize[1] === undefined) size[1] = undefined;
else size[1] += nodeSize[1];
}
this.cumulativeSizes[i + 1] = size.slice();
}
this.sizeDirty = false;
return size;
};
// After splicing into the backing store, restore the indexes of each node correctly.

@@ -112,2 +145,3 @@ ViewSequence.Backing.prototype.reindex = function reindex(start, removeCount, insertCount) {

}
if (this._.trackSize) this._.sizeDirty = true;
};

@@ -190,2 +224,3 @@

this._.firstIndex -= arguments.length;
if (this._.trackSize) this._.sizeDirty = true;
};

@@ -201,2 +236,3 @@

this._.array.push.apply(this._.array, arguments);
if (this._.trackSize) this._.sizeDirty = true;
};

@@ -253,2 +289,3 @@

else if (other.index === this._.firstIndex + this._.array.length - 1) this._.lastNode = other;
if (this._.trackSize) this._.sizeDirty = true;
};

@@ -285,2 +322,3 @@

ViewSequence.prototype.render = function render() {
if (this._.trackSize && this._.sizeDirty) this._.calculateSize();
var target = this.get();

@@ -287,0 +325,0 @@ return target ? target.render.apply(target, arguments) : null;

module.exports = {
core: require('./core'),
inputs: require('./inputs'),
events: require('./events'),
math: require('./math'),
physics: require('./physics'),
modifiers: require('./modifiers'),
physics: require('./physics'),
surfaces: require('./surfaces'),
inputs: require('./inputs'),
transitions: require('./transitions'),
surfaces: require('./surfaces'),
views: require('./views'),
widgets: require('./widgets'),
utilities: require('./utilities')
utilities: require('./utilities'),
widgets: require('./widgets')
};

@@ -18,50 +18,52 @@ /* This Source Code Form is subject to the terms of the Mozilla Public

*/
if (!window.CustomEvent) return;
var clickThreshold = 300;
var clickWindow = 500;
var potentialClicks = {};
var recentlyDispatched = {};
var _now = Date.now;
(function() {
if (!window.CustomEvent) return;
var clickThreshold = 300;
var clickWindow = 500;
var potentialClicks = {};
var recentlyDispatched = {};
var _now = Date.now;
window.addEventListener('touchstart', function(event) {
var timestamp = _now();
for (var i = 0; i < event.changedTouches.length; i++) {
var touch = event.changedTouches[i];
potentialClicks[touch.identifier] = timestamp;
}
});
window.addEventListener('touchstart', function(event) {
var timestamp = _now();
for (var i = 0; i < event.changedTouches.length; i++) {
var touch = event.changedTouches[i];
potentialClicks[touch.identifier] = timestamp;
}
});
window.addEventListener('touchmove', function(event) {
for (var i = 0; i < event.changedTouches.length; i++) {
var touch = event.changedTouches[i];
delete potentialClicks[touch.identifier];
}
});
window.addEventListener('touchmove', function(event) {
for (var i = 0; i < event.changedTouches.length; i++) {
var touch = event.changedTouches[i];
delete potentialClicks[touch.identifier];
}
});
window.addEventListener('touchend', function(event) {
var currTime = _now();
for (var i = 0; i < event.changedTouches.length; i++) {
var touch = event.changedTouches[i];
var startTime = potentialClicks[touch.identifier];
if (startTime && currTime - startTime < clickThreshold) {
var clickEvt = new window.CustomEvent('click', {
'bubbles': true,
'detail': touch
});
recentlyDispatched[currTime] = event;
event.target.dispatchEvent(clickEvt);
}
delete potentialClicks[touch.identifier];
}
});
window.addEventListener('touchend', function(event) {
var currTime = _now();
for (var i = 0; i < event.changedTouches.length; i++) {
var touch = event.changedTouches[i];
var startTime = potentialClicks[touch.identifier];
if (startTime && currTime - startTime < clickThreshold) {
var clickEvt = new window.CustomEvent('click', {
'bubbles': true,
'detail': touch
});
recentlyDispatched[currTime] = event;
event.target.dispatchEvent(clickEvt);
}
delete potentialClicks[touch.identifier];
}
});
window.addEventListener('click', function(event) {
var currTime = _now();
for (var i in recentlyDispatched) {
var previousEvent = recentlyDispatched[i];
if (currTime - i < clickWindow) {
if (event instanceof window.MouseEvent && event.target === previousEvent.target) event.stopPropagation();
}
else delete recentlyDispatched[i];
}
}, true);
window.addEventListener('click', function(event) {
var currTime = _now();
for (var i in recentlyDispatched) {
var previousEvent = recentlyDispatched[i];
if (currTime - i < clickWindow) {
if (event instanceof window.MouseEvent && event.target === previousEvent.target) event.stopPropagation();
}
else delete recentlyDispatched[i];
}
}, true);
})();

@@ -9,3 +9,2 @@ /* This Source Code Form is subject to the terms of the Mozilla Public

*/
var EventHandler = require('../core/EventHandler');

@@ -12,0 +11,0 @@

@@ -11,5 +11,5 @@ module.exports = {

ScrollSync: require('./ScrollSync'),
TouchSync: require('./TouchSync'),
TouchTracker: require('./TouchTracker'),
TouchSync: require('./TouchSync'),
TwoFingerSync: require('./TwoFingerSync')
};

@@ -9,4 +9,4 @@ /* This Source Code Form is subject to the terms of the Mozilla Public

*/
var EventHandler = require('../core/EventHandler');
var OptionsManager = require('../core/OptionsManager');

@@ -29,2 +29,4 @@ /**

this.options = Object.create(MouseSync.DEFAULT_OPTIONS);
this._optionsManager = new OptionsManager(this.options);
if (options) this.setOptions(options);

@@ -66,3 +68,4 @@

scale: 1,
propogate: true // events piped to document on mouseleave
propogate: true, // events piped to document on mouseleave
preventDefault: true
};

@@ -80,3 +83,3 @@

var velocity;
event.preventDefault(); // prevent drag
if (this.options.preventDefault) event.preventDefault(); // prevent drag

@@ -220,8 +223,5 @@ var x = event.clientX;

MouseSync.prototype.setOptions = function setOptions(options) {
if (options.direction !== undefined) this.options.direction = options.direction;
if (options.rails !== undefined) this.options.rails = options.rails;
if (options.scale !== undefined) this.options.scale = options.scale;
if (options.propogate !== undefined) this.options.propogate = options.propogate;
return this._optionsManager.setOptions(options);
};
module.exports = MouseSync;

@@ -9,4 +9,4 @@ /* This Source Code Form is subject to the terms of the Mozilla Public

*/
var TwoFingerSync = require('./TwoFingerSync');
var OptionsManager = require('../core/OptionsManager');

@@ -28,2 +28,3 @@ /**

this.options = Object.create(PinchSync.DEFAULT_OPTIONS);
this._optionsManager = new OptionsManager(this.options);
if (options) this.setOptions(options);

@@ -94,5 +95,5 @@

PinchSync.prototype.setOptions = function setOptions(options) {
if (options.scale !== undefined) this.options.scale = options.scale;
return this._optionsManager.setOptions(options);
};
module.exports = PinchSync;

@@ -9,4 +9,4 @@ /* This Source Code Form is subject to the terms of the Mozilla Public

*/
var TwoFingerSync = require('./TwoFingerSync');
var OptionsManager = require('../core/OptionsManager');

@@ -28,2 +28,3 @@ /**

this.options = Object.create(RotateSync.DEFAULT_OPTIONS);
this._optionsManager = new OptionsManager(this.options);
if (options) this.setOptions(options);

@@ -95,5 +96,5 @@

RotateSync.prototype.setOptions = function setOptions(options) {
if (options.scale !== undefined) this.options.scale = options.scale;
return this._optionsManager.setOptions(options);
};
module.exports = RotateSync;

@@ -9,4 +9,4 @@ /* This Source Code Form is subject to the terms of the Mozilla Public

*/
var TwoFingerSync = require('./TwoFingerSync');
var OptionsManager = require('../core/OptionsManager');

@@ -28,2 +28,3 @@ /**

this.options = Object.create(ScaleSync.DEFAULT_OPTIONS);
this._optionsManager = new OptionsManager(this.options);
if (options) this.setOptions(options);

@@ -102,5 +103,5 @@

ScaleSync.prototype.setOptions = function setOptions(options) {
if (options.scale !== undefined) this.options.scale = options.scale;
return this._optionsManager.setOptions(options);
};
module.exports = ScaleSync;

@@ -9,5 +9,5 @@ /* This Source Code Form is subject to the terms of the Mozilla Public

*/
var EventHandler = require('../core/EventHandler');
var Engine = require('../core/Engine');
var OptionsManager = require('../core/OptionsManager');

@@ -36,2 +36,3 @@ /**

this.options = Object.create(ScrollSync.DEFAULT_OPTIONS);
this._optionsManager = new OptionsManager(this.options);
if (options) this.setOptions(options);

@@ -67,3 +68,4 @@

stallTime: 50,
lineHeight: 40
lineHeight: 40,
preventDefault: true
};

@@ -96,3 +98,3 @@

function _handleMove(event) {
event.preventDefault();
if (this.options.preventDefault) event.preventDefault();

@@ -194,9 +196,5 @@ if (!this._inProgress) {

ScrollSync.prototype.setOptions = function setOptions(options) {
if (options.direction !== undefined) this.options.direction = options.direction;
if (options.minimumEndSpeed !== undefined) this.options.minimumEndSpeed = options.minimumEndSpeed;
if (options.rails !== undefined) this.options.rails = options.rails;
if (options.scale !== undefined) this.options.scale = options.scale;
if (options.stallTime !== undefined) this.options.stallTime = options.stallTime;
return this._optionsManager.setOptions(options);
};
module.exports = ScrollSync;

@@ -9,5 +9,5 @@ /* This Source Code Form is subject to the terms of the Mozilla Public

*/
var TouchTracker = require('./TouchTracker');
var EventHandler = require('../core/EventHandler');
var OptionsManager = require('../core/OptionsManager');

@@ -30,2 +30,3 @@ /**

this.options = Object.create(TouchSync.DEFAULT_OPTIONS);
this._optionsManager = new OptionsManager(this.options);
if (options) this.setOptions(options);

@@ -167,5 +168,3 @@

TouchSync.prototype.setOptions = function setOptions(options) {
if (options.direction !== undefined) this.options.direction = options.direction;
if (options.rails !== undefined) this.options.rails = options.rails;
if (options.scale !== undefined) this.options.scale = options.scale;
return this._optionsManager.setOptions(options);
};

@@ -172,0 +171,0 @@

@@ -9,3 +9,2 @@ /* This Source Code Form is subject to the terms of the Mozilla Public

*/
var EventHandler = require('../core/EventHandler');

@@ -12,0 +11,0 @@

@@ -9,3 +9,2 @@ /* This Source Code Form is subject to the terms of the Mozilla Public

*/
var EventHandler = require('../core/EventHandler');

@@ -12,0 +11,0 @@

@@ -5,4 +5,4 @@ module.exports = {

Random: require('./Random'),
Vector: require('./Vector'),
Utilities: require('./Utilities')
Utilities: require('./Utilities'),
Vector: require('./Vector')
};

@@ -32,2 +32,3 @@ /* This Source Code Form is subject to the terms of the Mozilla Public

* @param {Array.Number} [options.size] size to apply to descendants
* @param {Array.Number} [options.propportions] proportions to apply to descendants
*/

@@ -40,2 +41,3 @@ function StateModifier(options) {

this._sizeState = new Transitionable([0, 0]);
this._proportionsState = new Transitionable([0, 0]);

@@ -47,3 +49,4 @@ this._modifier = new Modifier({

align: null,
size: null
size: null,
proportions: null
});

@@ -54,2 +57,3 @@

this._hasSize = false;
this._hasProportions = false;

@@ -62,2 +66,3 @@ if (options) {

if (options.size) this.setSize(options.size);
if (options.proportions) this.setProportions(options.proportions);
}

@@ -73,3 +78,5 @@ }

* @param {Transform} transform Transform to transition to.
* @param {Transitionable} [transition] Valid transitionable object
* @param {Transitionable} transition object of type {duration: number, curve:
* f[0,1] -> [0,1] or name}. If transition is omitted, change will be
* instantaneous.
* @param {Function} [callback] callback to call after transition completes

@@ -90,3 +97,5 @@ * @return {StateModifier} this

* @param {Number} opacity Opacity value to transition to.
* @param {Transitionable} transition Valid transitionable object
* @param {Transitionable} transition object of type {duration: number, curve:
* f[0,1] -> [0,1] or name}. If transition is omitted, change will be
* instantaneous.
* @param {Function} callback callback to call after transition completes

@@ -107,3 +116,5 @@ * @return {StateModifier} this

* @param {Array.Number} origin two element array with values between 0 and 1.
* @param {Transitionable} transition Valid transitionable object
* @param {Transitionable} transition object of type {duration: number, curve:
* f[0,1] -> [0,1] or name}. If transition is omitted, change will be
* instantaneous.
* @param {Function} callback callback to call after transition completes

@@ -135,3 +146,5 @@ * @return {StateModifier} this

* @param {Array.Number} align two element array with values between 0 and 1.
* @param {Transitionable} transition Valid transitionable object
* @param {Transitionable} transition object of type {duration: number, curve:
* f[0,1] -> [0,1] or name}. If transition is omitted, change will be
* instantaneous.
* @param {Function} callback callback to call after transition completes

@@ -162,4 +175,6 @@ * @return {StateModifier} this

*
* @param {Array.Number} size two element array with values between 0 and 1.
* @param {Transitionable} transition Valid transitionable object
* @param {Array.Number} size two element array of [width, height]
* @param {Transitionable} transition object of type {duration: number, curve:
* f[0,1] -> [0,1] or name}. If transition is omitted, change will be
* instantaneous.
* @param {Function} callback callback to call after transition completes

@@ -185,2 +200,29 @@ * @return {StateModifier} this

/**
* Set the proportions of this modifier, either statically or
* through a provided Transitionable.
*
* @method setProportions
*
* @param {Array.Number} proportions two element array with values between 0 and 1.
* @param {Transitionable} transition Valid transitionable object
* @param {Function} callback callback to call after transition completes
* @return {StateModifier} this
*/
StateModifier.prototype.setProportions = function setSize(proportions, transition, callback) {
if (proportions === null) {
if (this._hasProportions) {
this._modifier.proportionsFrom(null);
this._hasProportions = false;
}
return this;
}
else if (!this._hasProportions) {
this._hasProportions = true;
this._modifier.proportionsFrom(this._proportionsState);
}
this._proportionsState.set(proportions, transition, callback);
return this;
};
/**
* Stop the transition.

@@ -196,2 +238,3 @@ *

this._sizeState.halt();
this._proportionsState.halt();
};

@@ -260,2 +303,12 @@

/**
* Get the current state of the propportions component.
*
* @method getProportions
* @return {Object} size provider object
*/
StateModifier.prototype.getProportions = function getProportions() {
return this._hasProportions ? this._proportionsState.get() : null;
};
/**
* Return render spec for this StateModifier, applying to the provided

@@ -262,0 +315,0 @@ * target component. This is similar to render() for Surfaces.

{
"name": "famous",
"version": "0.2.3-beta0",
"version": "0.3.0-alpha.0",
"description": "A JavaScript framework for everyone who wants to build beautiful experiences on any device.",

@@ -5,0 +5,0 @@ "main": "./index.js",

@@ -15,8 +15,9 @@ /* This Source Code Form is subject to the terms of the Mozilla Public

var Matrix = require('../../math/Matrix');
var Integrator = require('../integrators/SymplecticEuler');
/**
* A unit controlled by the physics engine which extends the zero-dimensional
* Particle to include geometry. In addition to maintaining the state
* of a Particle its state includes orientation, angular velocity
* and angular momentum and responds to torque forces.
* Particle to include geometry. In addition to maintaining the state
* of a Particle its state includes orientation, angular velocity
* and angular momentum and responds to torque forces.
*

@@ -41,7 +42,6 @@ * @class Body

this.angularVelocity.w = 0; //quaternify the angular velocity
this.setMomentsOfInertia();
this.angularVelocity.w = 0; //quaternify the angular velocity
//registers
// registers
this.pWorld = new Vector(); //placeholder for world space position

@@ -51,9 +51,5 @@ }

Body.DEFAULT_OPTIONS = Particle.DEFAULT_OPTIONS;
Body.DEFAULT_OPTIONS.orientation = [0,0,0,1];
Body.DEFAULT_OPTIONS.angularVelocity = [0,0,0];
Body.DEFAULT_OPTIONS.orientation = [0, 0, 0, 1];
Body.DEFAULT_OPTIONS.angularVelocity = [0, 0, 0];
Body.AXES = Particle.AXES;
Body.SLEEP_TOLERANCE = Particle.SLEEP_TOLERANCE;
Body.INTEGRATOR = Particle.INTEGRATOR;
Body.prototype = Object.create(Particle.prototype);

@@ -71,3 +67,3 @@ Body.prototype.constructor = Body;

* Setter for moment of inertia, which is necessary to give proper
* angular inertia depending on the geometry of the body.
* angular inertia depending on the geometry of the body.
*

@@ -92,3 +88,3 @@ * @method setMomentsOfInertia

* Determine world coordinates from the local coordinate system. Useful
* if the Body has rotated in space.
* if the Body has rotated in space.
*

@@ -116,3 +112,3 @@ * @method toWorldCoordinates

* Extends Particle.reset to reset orientation, angular velocity
* and angular momentum.
* and angular momentum.
*

@@ -166,3 +162,3 @@ * @method reset

* Extends Particle.applyForce with an optional argument
* to apply the force at an off-centered location, resulting in a torque.
* to apply the force at an off-centered location, resulting in a torque.
*

@@ -191,3 +187,3 @@ * @method applyForce

* Extends Particle.getTransform to include a rotational component
* derived from the particle's orientation.
* derived from the particle's orientation.
*

@@ -206,3 +202,3 @@ * @method getTransform

* Extends Particle._integrate to also update the rotational states
* of the body.
* of the body.
*

@@ -227,3 +223,3 @@ * @method getTransform

Body.prototype.integrateAngularMomentum = function integrateAngularMomentum(dt) {
Body.INTEGRATOR.integrateAngularMomentum(this, dt);
Integrator.integrateAngularMomentum(this, dt);
};

@@ -238,5 +234,5 @@

Body.prototype.integrateOrientation = function integrateOrientation(dt) {
Body.INTEGRATOR.integrateOrientation(this, dt);
Integrator.integrateOrientation(this, dt);
};
module.exports = Body;

@@ -18,19 +18,17 @@ /* This Source Code Form is subject to the terms of the Mozilla Public

* position and velocity states that are updated by the Physics Engine.
* Ultimately, a particle is a _special type of modifier, and can be added to
* the Famous render tree like any other modifier.
* Ultimately, a particle is a special type of modifier, and can be added to
* the Famo.us Scene Graph like any other modifier.
*
* @constructor
* @class Particle
* @uses EventHandler
* @uses Modifier
* @extensionfor Body
* @param {Options} [options] An object of configurable options.
* @param {Array} [options.position] The position of the particle.
* @param {Array} [options.velocity] The velocity of the particle.
* @param {Number} [options.mass] The mass of the particle.
* @param {Hexadecimal} [options.axis] The axis a particle can move along. Can be bitwise ORed e.g., Particle.AXES.X, Particle.AXES.X | Particle.AXES.Y
*
* @param [options] {Options} An object of configurable options.
* @param [options.position] {Array} The position of the particle.
* @param [options.velocity] {Array} The velocity of the particle.
* @param [options.mass] {Number} The mass of the particle.
*/
function Particle(options) {
options = options || {};
var defaults = Particle.DEFAULT_OPTIONS;

@@ -40,11 +38,9 @@ // registers

this.velocity = new Vector();
this.force = new Vector();
this.force = new Vector();
var defaults = Particle.DEFAULT_OPTIONS;
// state variables
this._engine = null;
this._isSleeping = true;
this._eventOutput = null;
// set vectors
this.setPosition(options.position || defaults.position);
this.setVelocity(options.velocity || defaults.velocity);
this.force.set(options.force || [0,0,0]);
// set scalars

@@ -55,13 +51,8 @@ this.mass = (options.mass !== undefined)

this.axis = (options.axis !== undefined)
? options.axis
: defaults.axis;
this.inverseMass = 1 / this.mass;
// state variables
this._isSleeping = false;
this._engine = null;
this._eventOutput = null;
this._positionGetter = null;
// set vectors
this.setPosition(options.position || defaults.position);
this.setVelocity(options.velocity || defaults.velocity);
this.force.set(options.force || [0,0,0]);

@@ -72,4 +63,8 @@ this.transform = Transform.identity.slice();

this._spec = {
transform : this.transform,
target : null
size : [true, true],
target : {
transform : this.transform,
origin : [0.5, 0.5],
target : null
}
};

@@ -79,50 +74,37 @@ }

Particle.DEFAULT_OPTIONS = {
position : [0,0,0],
velocity : [0,0,0],
mass : 1,
axis : undefined
position : [0, 0, 0],
velocity : [0, 0, 0],
mass : 1
};
//Catalogue of outputted events
var _events = {
start : 'start',
update : 'update',
end : 'end'
};
// Cached timing function
var now = Date.now;
/**
* Kinetic energy threshold needed to update the body
*
* @property SLEEP_TOLERANCE
* @type Number
* @attribute isBody
* @type Boolean
* @static
* @default 1e-7
*/
Particle.SLEEP_TOLERANCE = 1e-7;
Particle.prototype.isBody = false;
/**
* Axes by which a body can translate
* Determines if particle is active
*
* @property AXES
* @type Hexadecimal
* @static
* @default 1e-7
* @method isActive
* @return {Boolean}
*/
Particle.AXES = {
X : 0x00, // hexadecimal for 0
Y : 0x01, // hexadecimal for 1
Z : 0x02 // hexadecimal for 2
Particle.prototype.isActive = function isActive() {
return !this._isSleeping;
};
// Integrator for updating the particle's state
// TODO: make this a singleton
Particle.INTEGRATOR = new Integrator();
//Catalogue of outputted events
var _events = {
start : 'start',
update : 'update',
end : 'end'
};
// Cached timing function
var now = (function() {
return Date.now;
})();
/**
* Stops the particle from updating
*
* @method sleep

@@ -138,2 +120,3 @@ */

* Starts the particle update
*
* @method wake

@@ -146,13 +129,8 @@ */

this._prevTime = now();
if (this._engine) this._engine.wake();
};
/**
* @attribute isBody
* @type Boolean
* @static
*/
Particle.prototype.isBody = false;
/**
* Basic setter for position
*
* @method setPosition

@@ -167,2 +145,3 @@ * @param position {Array|Vector}

* 1-dimensional setter for position
*
* @method setPosition1D

@@ -177,2 +156,3 @@ * @param x {Number}

* Basic getter function for position
*
* @method getPosition

@@ -182,7 +162,3 @@ * @return position {Array}

Particle.prototype.getPosition = function getPosition() {
if (this._positionGetter instanceof Function)
this.setPosition(this._positionGetter());
this._engine.step();
return this.position.get();

@@ -193,2 +169,3 @@ };

* 1-dimensional getter for position
*
* @method getPosition1D

@@ -203,12 +180,4 @@ * @return value {Number}

/**
* Defines the position from outside the Physics Engine
* @method positionFrom
* @param positionGetter {Function}
*/
Particle.prototype.positionFrom = function positionFrom(positionGetter) {
this._positionGetter = positionGetter;
};
/**
* Basic setter function for velocity Vector
*
* @method setVelocity

@@ -219,3 +188,4 @@ * @function

this.velocity.set(velocity);
this.wake();
if (!(velocity[0] === 0 && velocity[1] === 0 && velocity[2] === 0))
this.wake();
};

@@ -225,2 +195,3 @@

* 1-dimensional setter for velocity
*
* @method setVelocity1D

@@ -231,3 +202,3 @@ * @param x {Number}

this.velocity.x = x;
this.wake();
if (x !== 0) this.wake();
};

@@ -237,2 +208,3 @@

* Basic getter function for velocity Vector
*
* @method getVelocity

@@ -246,3 +218,15 @@ * @return velocity {Array}

/**
* Basic setter function for force Vector
*
* @method setForce
* @return force {Array}
*/
Particle.prototype.setForce = function setForce(force) {
this.force.set(force);
this.wake();
};
/**
* 1-dimensional getter for velocity
*
* @method getVelocity1D

@@ -257,2 +241,3 @@ * @return velocity {Number}

* Basic setter function for mass quantity
*
* @method setMass

@@ -268,2 +253,3 @@ * @param mass {Number} mass

* Basic getter function for mass quantity
*
* @method getMass

@@ -278,2 +264,3 @@ * @return mass {Number}

* Reset position and velocity
*
* @method reset

@@ -290,2 +277,3 @@ * @param position {Array|Vector}

* Add force vector to existing internal force Vector
*
* @method applyForce

@@ -302,2 +290,3 @@ * @param force {Vector}

* Add impulse (change in velocity) Vector to this Vector's velocity.
*
* @method applyImpulse

@@ -314,2 +303,3 @@ * @param impulse {Vector}

* Update a particle's velocity from its force accumulator
*
* @method integrateVelocity

@@ -319,3 +309,3 @@ * @param dt {Number} Time differential

Particle.prototype.integrateVelocity = function integrateVelocity(dt) {
Particle.INTEGRATOR.integrateVelocity(this, dt);
Integrator.integrateVelocity(this, dt);
};

@@ -325,2 +315,3 @@

* Update a particle's position from its velocity
*
* @method integratePosition

@@ -330,3 +321,3 @@ * @param dt {Number} Time differential

Particle.prototype.integratePosition = function integratePosition(dt) {
Particle.INTEGRATOR.integratePosition(this, dt);
Integrator.integratePosition(this, dt);
};

@@ -336,2 +327,3 @@

* Update the position and velocity of the particle
*
* @method _integrate

@@ -348,2 +340,3 @@ * @protected

* Get kinetic energy of the particle.
*
* @method getEnergy

@@ -358,2 +351,3 @@ * @function

* Generate transform from the current position state
*
* @method getTransform

@@ -366,21 +360,7 @@ * @return Transform {Transform}

var position = this.position;
var axis = this.axis;
var transform = this.transform;
if (axis !== undefined) {
if (axis & ~Particle.AXES.X) {
position.x = 0;
}
if (axis & ~Particle.AXES.Y) {
position.y = 0;
}
if (axis & ~Particle.AXES.Z) {
position.z = 0;
}
}
transform[12] = position.x;
transform[13] = position.y;
transform[14] = position.z;
return transform;

@@ -391,2 +371,3 @@ };

* The modify interface of a Modifier
*
* @method modify

@@ -397,6 +378,6 @@ * @param target {Spec}

Particle.prototype.modify = function modify(target) {
var _spec = this._spec;
var _spec = this._spec.target;
_spec.transform = this.getTransform();
_spec.target = target;
return _spec;
return this._spec;
};

@@ -408,3 +389,2 @@

this._eventOutput.bindThis(this);
//overrides on/removeListener/pipe/unpipe methods
EventHandler.setOutputHandler(this, this._eventOutput);

@@ -422,2 +402,3 @@ }

};
Particle.prototype.removeListener = function removeListener() {

@@ -427,2 +408,3 @@ _createEventOutput.call(this);

};
Particle.prototype.pipe = function pipe() {

@@ -432,2 +414,3 @@ _createEventOutput.call(this);

};
Particle.prototype.unpipe = function unpipe() {

@@ -434,0 +417,0 @@ _createEventOutput.call(this);

@@ -22,4 +22,4 @@ /* This Source Code Form is subject to the terms of the Mozilla Public

this.options = this.options || {};
this._energy = 0.0;
this._eventOutput = null;
this._eventOutput = new EventHandler();
EventHandler.setOutputHandler(this, this._eventOutput);
}

@@ -34,3 +34,3 @@

Constraint.prototype.setOptions = function setOptions(options) {
for (var key in options) this.options[key] = options[key];
this._eventOutput.emit('change', options);
};

@@ -52,40 +52,5 @@

Constraint.prototype.getEnergy = function getEnergy() {
return this._energy;
return 0.0;
};
/**
* Setter for energy
*
* @method setEnergy
* @param energy {Number}
*/
Constraint.prototype.setEnergy = function setEnergy(energy) {
this._energy = energy;
};
function _createEventOutput() {
this._eventOutput = new EventHandler();
this._eventOutput.bindThis(this);
EventHandler.setOutputHandler(this, this._eventOutput);
}
Constraint.prototype.on = function on() {
_createEventOutput.call(this);
return this.on.apply(this, arguments);
};
Constraint.prototype.addListener = function addListener() {
_createEventOutput.call(this);
return this.addListener.apply(this, arguments);
};
Constraint.prototype.pipe = function pipe() {
_createEventOutput.call(this);
return this.pipe.apply(this, arguments);
};
Constraint.prototype.removeListener = function removeListener() {
return this.removeListener.apply(this, arguments);
};
Constraint.prototype.unpipe = function unpipe() {
return this.unpipe.apply(this, arguments);
};
module.exports = Constraint;

@@ -31,2 +31,4 @@ /* This Source Code Form is subject to the terms of the Mozilla Public

function Snap(options) {
Constraint.call(this);
this.options = Object.create(this.constructor.DEFAULT_OPTIONS);

@@ -40,4 +42,2 @@ if (options) this.setOptions(options);

this.impulse2 = new Vector();
Constraint.call(this);
}

@@ -49,3 +49,3 @@

Snap.DEFAULT_OPTIONS = {
period : 300,
period : 300,
dampingRatio : 0.1,

@@ -58,6 +58,2 @@ length : 0,

function _calcEnergy(impulse, disp, dt) {
return Math.abs(impulse.dot(disp)/dt);
}
/**

@@ -78,25 +74,14 @@ * Basic options setter

if (options.period !== undefined) this.options.period = options.period;
Constraint.prototype.setOptions.call(this, options);
};
/**
* Set the anchor position
*
* @method setOptions
* @param {Array} v TODO
*/
Snap.prototype.setAnchor = function setAnchor(v) {
if (this.options.anchor !== undefined) this.options.anchor = new Vector();
this.options.anchor.set(v);
};
/**
* Calculates energy of spring
*
* @method getEnergy
* @param {Object} target TODO
* @param {Object} source TODO
* @param targets {Body} target physics body
* @param source {Body} source physics body
* @return energy {Number}
*/
Snap.prototype.getEnergy = function getEnergy(target, source) {
Snap.prototype.getEnergy = function getEnergy(targets, source) {
var options = this.options;

@@ -107,5 +92,9 @@ var restLength = options.length;

var dist = anchor.sub(target.position).norm() - restLength;
return 0.5 * strength * dist * dist;
var energy = 0.0;
for (var i = 0; i < targets.length; i++){
var target = targets[i];
var dist = anchor.sub(target.position).norm() - restLength;
energy += 0.5 * strength * dist * dist;
}
return energy;
};

@@ -122,3 +111,3 @@

Snap.prototype.applyConstraint = function applyConstraint(targets, source, dt) {
var options = this.options;
var options = this.options;
var pDiff = this.pDiff;

@@ -149,3 +138,3 @@ var vDiff = this.vDiff;

vDiff.set(v1.sub(v2));
effMass = 1/(w1 + w2);
effMass = 1 / (w1 + w2);
}

@@ -189,4 +178,2 @@ else {

}
this.setEnergy(_calcEnergy(impulse1, pDiff, dt));
}

@@ -193,0 +180,0 @@ };

@@ -22,4 +22,4 @@ /* This Source Code Form is subject to the terms of the Mozilla Public

this.force = new Vector(force);
this._energy = 0.0;
this._eventOutput = null;
this._eventOutput = new EventHandler();
EventHandler.setOutputHandler(this, this._eventOutput);
}

@@ -34,3 +34,3 @@

Force.prototype.setOptions = function setOptions(options) {
for (var key in options) this.options[key] = options[key];
this._eventOutput.emit('change', options);
};

@@ -55,40 +55,5 @@

Force.prototype.getEnergy = function getEnergy() {
return this._energy;
return 0.0;
};
/*
* Setter for a force's potential energy.
*
* @method setEnergy
* @param energy {Number}
*/
Force.prototype.setEnergy = function setEnergy(energy) {
this._energy = energy;
};
function _createEventOutput() {
this._eventOutput = new EventHandler();
this._eventOutput.bindThis(this);
EventHandler.setOutputHandler(this, this._eventOutput);
}
Force.prototype.on = function on() {
_createEventOutput.call(this);
return this.on.apply(this, arguments);
};
Force.prototype.addListener = function addListener() {
_createEventOutput.call(this);
return this.addListener.apply(this, arguments);
};
Force.prototype.pipe = function pipe() {
_createEventOutput.call(this);
return this.pipe.apply(this, arguments);
};
Force.prototype.removeListener = function removeListener() {
return this.removeListener.apply(this, arguments);
};
Force.prototype.unpipe = function unpipe() {
return this.unpipe.apply(this, arguments);
};
module.exports = Force;

@@ -10,3 +10,2 @@ /* This Source Code Form is subject to the terms of the Mozilla Public

//TODO: test options manager
var Force = require('./Force');

@@ -13,0 +12,0 @@ var Vector = require('../../math/Vector');

@@ -11,3 +11,5 @@ /* This Source Code Form is subject to the terms of the Mozilla Public

//TODO: test inheritance
var Force = require('./Force');
var Spring = require('./Spring');
var Quaternion = require('../../math/Quaternion');

@@ -35,2 +37,42 @@ /**

/** @const */
var pi = Math.PI;
function _calcStiffness() {
var options = this.options;
options.stiffness = Math.pow(2 * pi / options.period, 2);
}
function _calcDamping() {
var options = this.options;
options.damping = 4 * pi * options.dampingRatio / options.period;
}
function _init() {
_calcStiffness.call(this);
_calcDamping.call(this);
}
RotationalSpring.prototype.setOptions = function setOptions(options) {
// TODO fix no-console error
/* eslint no-console: 0 */
if (options.anchor !== undefined) {
if (options.anchor instanceof Quaternion) this.options.anchor = options.anchor;
if (options.anchor instanceof Array) this.options.anchor = new Quaternion(options.anchor);
}
if (options.period !== undefined){
this.options.period = options.period;
}
if (options.dampingRatio !== undefined) this.options.dampingRatio = options.dampingRatio;
if (options.length !== undefined) this.options.length = options.length;
if (options.forceFunction !== undefined) this.options.forceFunction = options.forceFunction;
if (options.maxLength !== undefined) this.options.maxLength = options.maxLength;
_init.call(this);
Force.prototype.setOptions.call(this, options);
};
/**

@@ -43,10 +85,12 @@ * Adds a torque force to a physics body's torque accumulator.

RotationalSpring.prototype.applyForce = function applyForce(targets) {
var force = this.force;
var options = this.options;
var disp = this.disp;
var force = this.force;
var options = this.options;
var disp = this.disp;
var stiffness = options.stiffness;
var damping = options.damping;
var restLength = options.length;
var anchor = options.anchor;
var stiffness = options.stiffness;
var damping = options.damping;
var restLength = options.length;
var anchor = options.anchor;
var forceFunction = options.forceFunction;
var maxLength = options.maxLength;

@@ -66,5 +110,5 @@ for (var i = 0; i < targets.length; i++) {

force.set(disp.normalize(stiffness * this.forceFunction(dist, this.options.lMax)));
force.set(disp.normalize(stiffness * forceFunction(dist, maxLength)));
if (damping) force.set(force.add(target.angularVelocity.mult(-damping)));
if (damping) force.add(target.angularVelocity.mult(-damping)).put(force);

@@ -79,5 +123,5 @@ target.applyTorque(force);

* @method getEnergy
* @param {Body} target The physics body attached to the spring
* @param [targets] target The physics body attached to the spring
*/
RotationalSpring.prototype.getEnergy = function getEnergy(target) {
RotationalSpring.prototype.getEnergy = function getEnergy(targets) {
var options = this.options;

@@ -88,6 +132,11 @@ var restLength = options.length;

var dist = anchor.sub(target.orientation).norm() - restLength;
return 0.5 * strength * dist * dist;
var energy = 0.0;
for (var i = 0; i < targets.length; i++) {
var target = targets[i];
var dist = anchor.sub(target.orientation).norm() - restLength;
energy += 0.5 * strength * dist * dist;
}
return energy;
};
module.exports = RotationalSpring;

@@ -10,2 +10,4 @@ /* This Source Code Form is subject to the terms of the Mozilla Public

/*global console */
var Force = require('./Force');

@@ -24,2 +26,4 @@ var Vector = require('../../math/Vector');

function Spring(options) {
Force.call(this);
this.options = Object.create(this.constructor.DEFAULT_OPTIONS);

@@ -32,3 +36,2 @@ if (options) this.setOptions(options);

_init.call(this);
Force.call(this);
}

@@ -39,3 +42,5 @@

/** @const */ var pi = Math.PI;
/** @const */
var pi = Math.PI;
var MIN_PERIOD = 150;

@@ -67,3 +72,3 @@ /**

* A Hookean spring force, linear in the displacement
* see: http://en.wikipedia.org/wiki/FENE
* see: http://en.wikipedia.org/wiki/Hooke's_law
* @attribute FENE

@@ -95,3 +100,3 @@ * @type Function

*/
period : 300,
period : 300,

@@ -144,6 +149,2 @@ /**

function _setForceFunction(fn) {
this.forceFunction = fn;
}
function _calcStiffness() {

@@ -159,8 +160,3 @@ var options = this.options;

function _calcEnergy(strength, dist) {
return 0.5 * strength * dist * dist;
}
function _init() {
_setForceFunction.call(this, this.options.forceFunction);
_calcStiffness.call(this);

@@ -174,11 +170,22 @@ _calcDamping.call(this);

* @method setOptions
* @param options {Objects}
* @param options {Object}
*/
Spring.prototype.setOptions = function setOptions(options) {
// TODO fix no-console error
/* eslint no-console: 0 */
if (options.anchor !== undefined) {
if (options.anchor.position instanceof Vector) this.options.anchor = options.anchor.position;
if (options.anchor instanceof Vector) this.options.anchor = options.anchor;
if (options.anchor instanceof Array) this.options.anchor = new Vector(options.anchor);
if (options.anchor instanceof Vector) this.options.anchor = options.anchor;
if (options.anchor instanceof Array) this.options.anchor = new Vector(options.anchor);
}
if (options.period !== undefined) this.options.period = options.period;
if (options.period !== undefined){
if (options.period < MIN_PERIOD) {
options.period = MIN_PERIOD;
console.warn('The period of a SpringTransition is capped at ' + MIN_PERIOD + ' ms. Use a SnapTransition for faster transitions');
}
this.options.period = options.period;
}
if (options.dampingRatio !== undefined) this.options.dampingRatio = options.dampingRatio;

@@ -190,2 +197,3 @@ if (options.length !== undefined) this.options.length = options.length;

_init.call(this);
Force.prototype.setOptions.call(this, options);
};

@@ -200,11 +208,12 @@

Spring.prototype.applyForce = function applyForce(targets, source) {
var force = this.force;
var disp = this.disp;
var options = this.options;
var force = this.force;
var disp = this.disp;
var options = this.options;
var stiffness = options.stiffness;
var damping = options.damping;
var restLength = options.length;
var lMax = options.maxLength;
var anchor = options.anchor || source.position;
var stiffness = options.stiffness;
var damping = options.damping;
var restLength = options.length;
var maxLength = options.maxLength;
var anchor = options.anchor || source.position;
var forceFunction = options.forceFunction;

@@ -226,3 +235,3 @@ for (var i = 0; i < targets.length; i++) {

disp.normalize(stiffness * this.forceFunction(dist, lMax))
disp.normalize(stiffness * forceFunction(dist, maxLength))
.put(force);

@@ -236,4 +245,2 @@

if (source) source.applyForce(force.mult(-1));
this.setEnergy(_calcEnergy(stiffness, dist));
}

@@ -246,26 +253,20 @@ };

* @method getEnergy
* @param target {Body} The physics body attached to the spring
* @return energy {Number}
* @param [targets] target The physics body attached to the spring
* @return {source} The potential energy of the spring
*/
Spring.prototype.getEnergy = function getEnergy(target) {
var options = this.options;
Spring.prototype.getEnergy = function getEnergy(targets, source) {
var options = this.options;
var restLength = options.length;
var anchor = options.anchor;
var anchor = (source) ? source.position : options.anchor;
var strength = options.stiffness;
var dist = anchor.sub(target.position).norm() - restLength;
return 0.5 * strength * dist * dist;
var energy = 0.0;
for (var i = 0; i < targets.length; i++){
var target = targets[i];
var dist = anchor.sub(target.position).norm() - restLength;
energy += 0.5 * strength * dist * dist;
}
return energy;
};
/**
* Sets the anchor to a new position
*
* @method setAnchor
* @param anchor {Array} New anchor of the spring
*/
Spring.prototype.setAnchor = function setAnchor(anchor) {
if (!this.options.anchor) this.options.anchor = new Vector();
this.options.anchor.set(anchor);
};
module.exports = Spring;

@@ -23,10 +23,9 @@ /* This Source Code Form is subject to the terms of the Mozilla Public

function VectorField(options) {
Force.call(this);
this.options = Object.create(VectorField.DEFAULT_OPTIONS);
if (options) this.setOptions(options);
_setFieldOptions.call(this, this.options.field);
Force.call(this);
//registers
this.evaluation = new Vector(0,0,0);
this.evaluation = new Vector();
}

@@ -54,3 +53,3 @@

CONSTANT : function(v, options) {
return v.set(options.direction);
options.direction.put(this.evaluation);
},

@@ -63,6 +62,6 @@

* @param v {Vector} Current position of physics body
* @return {Number} unscaled force
* @return {Vector} unscaled force
*/
LINEAR : function(v) {
return v;
v.put(this.evaluation);
},

@@ -75,22 +74,9 @@

* @param v {Vector} Current position of physics body
* @return {Number} unscaled force
* @return {Vector} unscaled force
*/
RADIAL : function(v) {
return v.set(v.mult(-1, v));
v.mult(-1).put(this.evaluation);
},
/**
* Spherical force
* @attribute SPHERE_ATTRACTOR
* @type Function
* @param v {Vector} Current position of physics body
* @param options {Object} An object with the radius of the sphere
* Pass a {radius : Number} into the VectorField options
* @return {Number} unscaled force
*/
SPHERE_ATTRACTOR : function(v, options) {
return v.set(v.mult((options.radius - v.norm()) / v.norm()));
},
/**
* Point attractor force, e.g., Hookean spring with an anchor

@@ -102,6 +88,6 @@ * @attribute POINT_ATTRACTOR

* Pass a {position : Vector} into the VectorField options
* @return {Number} unscaled force
* @return {Vector} unscaled force
*/
POINT_ATTRACTOR : function(v, options) {
return v.set(options.position.sub(v));
options.position.sub(v).put(this.evaluation);
}

@@ -123,5 +109,5 @@ };

* @type Number
* @default 1
* @default .01
*/
strength : 1,
strength : .01,

@@ -144,3 +130,7 @@ /**

VectorField.prototype.setOptions = function setOptions(options) {
for (var key in options) this.options[key] = options[key];
if (options.strength !== undefined) this.options.strength = options.strength;
if (options.field !== undefined) {
this.options.field = options.field;
_setFieldOptions.call(this, this.options.field);
}
};

@@ -154,21 +144,13 @@

if (!this.options.direction) this.options.direction = new Vector(0,1,0);
else if (this.options.direction instanceof Array) this.options.direction = new Vector(this.options.direction);
break;
case FIELDS.POINT_ATTRACTOR:
if (!this.options.position) this.options.position = new Vector(0,0,0);
else if (this.options.position instanceof Array) this.options.position = new Vector(this.options.position);
break;
case FIELDS.SPHERE_ATTRACTOR:
if (!this.options.radius) this.options.radius = 1;
break;
}
}
function _evaluate(v) {
var evaluation = this.evaluation;
var field = this.options.field;
evaluation.set(v);
return field(evaluation, this.options);
}
/**
* Adds the vectorfield's force to a physics body's force accumulator.
* Adds the VectorField's force to a physics body's force accumulator.
*

@@ -180,12 +162,42 @@ * @method applyForce

var force = this.force;
var strength = this.options.strength;
var field = this.options.field;
for (var i = 0; i < targets.length; i++) {
var particle = targets[i];
force.set(
_evaluate.call(this, particle.position)
.mult(particle.mass * this.options.strength)
);
particle.applyForce(force);
var target = targets[i];
field.call(this, target.position, this.options);
this.evaluation.mult(target.mass * strength).put(force);
target.applyForce(force);
}
};
VectorField.prototype.getEnergy = function getEnergy(targets) {
var field = this.options.field;
var FIELDS = VectorField.FIELDS;
var energy = 0;
var i;
var target;
switch (field) {
case FIELDS.CONSTANT:
energy = targets.length * this.options.direction.norm();
break;
case FIELDS.RADIAL:
for (i = 0; i < targets.length; i++){
target = targets[i];
energy += target.position.norm();
}
break;
case FIELDS.POINT_ATTRACTOR:
for (i = 0; i < targets.length; i++){
target = targets[i];
energy += target.position.sub(this.options.position).norm();
}
break;
}
energy *= this.options.strength;
return energy;
};
module.exports = VectorField;
module.exports = {
PhysicsEngine: require('./PhysicsEngine'),
bodies: require('./bodies'),
forces: require('./forces'),
constraints: require('./constraints'),
forces: require('./forces'),
integrators: require('./integrators')
};

@@ -10,4 +10,5 @@ /* This Source Code Form is subject to the terms of the Mozilla Public

var OptionsManager = require('../../core/OptionsManager');
/**

@@ -31,56 +32,5 @@ * Ordinary Differential Equation (ODE) Integrator.

*/
function SymplecticEuler(options) {
this.options = Object.create(SymplecticEuler.DEFAULT_OPTIONS);
this._optionsManager = new OptionsManager(this.options);
var SymplecticEuler = {};
if (options) this.setOptions(options);
}
/**
* @property SymplecticEuler.DEFAULT_OPTIONS
* @type Object
* @protected
* @static
*/
SymplecticEuler.DEFAULT_OPTIONS = {
/**
* The maximum velocity of a physics body
* Range : [0, Infinity]
* @attribute velocityCap
* @type Number
*/
velocityCap : undefined,
/**
* The maximum angular velocity of a physics body
* Range : [0, Infinity]
* @attribute angularVelocityCap
* @type Number
*/
angularVelocityCap : undefined
};
/*
* Setter for options
*
* @method setOptions
* @param {Object} options
*/
SymplecticEuler.prototype.setOptions = function setOptions(options) {
this._optionsManager.patch(options);
};
/*
* Getter for options
*
* @method getOptions
* @return {Object} options
*/
SymplecticEuler.prototype.getOptions = function getOptions() {
return this._optionsManager.value();
};
/*
* Updates the velocity of a physics body from its accumulated force.

@@ -93,3 +43,3 @@ * v <- v + dt * f / m

*/
SymplecticEuler.prototype.integrateVelocity = function integrateVelocity(body, dt) {
SymplecticEuler.integrateVelocity = function integrateVelocity(body, dt) {
var v = body.velocity;

@@ -113,7 +63,6 @@ var w = body.inverseMass;

*/
SymplecticEuler.prototype.integratePosition = function integratePosition(body, dt) {
SymplecticEuler.integratePosition = function integratePosition(body, dt) {
var p = body.position;
var v = body.velocity;
if (this.options.velocityCap) v.cap(this.options.velocityCap).put(v);
p.add(v.mult(dt)).put(p);

@@ -130,3 +79,3 @@ };

*/
SymplecticEuler.prototype.integrateAngularMomentum = function integrateAngularMomentum(body, dt) {
SymplecticEuler.integrateAngularMomentum = function integrateAngularMomentum(body, dt) {
var L = body.angularMomentum;

@@ -137,3 +86,2 @@ var t = body.torque;

if (this.options.angularVelocityCap) t.cap(this.options.angularVelocityCap).put(t);
L.add(t.mult(dt)).put(L);

@@ -151,3 +99,3 @@ t.clear();

*/
SymplecticEuler.prototype.integrateOrientation = function integrateOrientation(body, dt) {
SymplecticEuler.integrateOrientation = function integrateOrientation(body, dt) {
var q = body.orientation;

@@ -154,0 +102,0 @@ var w = body.angularVelocity;

@@ -11,7 +11,11 @@ /* This Source Code Form is subject to the terms of the Mozilla Public

/**
* The Physics Engine is responsible for mediating Bodies and their
* interaction with forces and constraints. The Physics Engine handles the
* logic of adding and removing bodies, updating their state of the over
* time.
* The Physics Engine is responsible for mediating bodies with their
* interaction with forces and constraints (agents). Specifically, it
* is responsible for:
*
* - adding and removing bodies
* - updating a body's state over time
* - attaching and detaching agents
* - sleeping upon equillibrium and waking upon excitation
*
* @class PhysicsEngine

@@ -27,5 +31,5 @@ * @constructor

this._bodies = []; //list of managed bodies
this._agents = {}; //hash of managed agents
this._forces = []; //list of IDs of agents that are forces
this._constraints = []; //list of IDs of agents that are constraints
this._agentData = {}; //hash of managed agent data
this._forces = []; //list of Ids of agents that are forces
this._constraints = []; //list of Ids of agents that are constraints

@@ -38,4 +42,6 @@ this._buffer = 0.0;

this._hasBodies = false;
this._eventHandler = null;
}
/** const */
var TIMESTEP = 17;

@@ -45,2 +51,11 @@ var MIN_TIME_STEP = 1000 / 120;

var now = Date.now;
// Catalogue of outputted events
var _events = {
start : 'start',
update : 'update',
end : 'end'
};
/**

@@ -62,13 +77,25 @@ * @property PhysicsEngine.DEFAULT_OPTIONS

/**
* The energy threshold before the Engine stops updating
* The energy threshold required for the Physics Engine to update
* @attribute sleepTolerance
* @type Number
*/
sleepTolerance : 1e-7
sleepTolerance : 1e-7,
/**
* The maximum velocity magnitude of a physics body
* Range : [0, Infinity]
* @attribute velocityCap
* @type Number
*/
velocityCap : undefined,
/**
* The maximum angular velocity magnitude of a physics body
* Range : [0, Infinity]
* @attribute angularVelocityCap
* @type Number
*/
angularVelocityCap : undefined
};
var now = (function() {
return Date.now;
})();
/**

@@ -86,3 +113,3 @@ * Options setter

* Method to add a physics body to the engine. Necessary to update the
* body over time.
* body over time.
*

@@ -100,2 +127,3 @@ * @method addBody

else this._particles.push(body);
body.on('start', this.wake.bind(this));
return body;

@@ -106,4 +134,6 @@ };

* Remove a body from the engine. Detaches body from all forces and
* constraints.
* constraints.
*
* TODO: Fix for in loop
*
* @method removeBody

@@ -116,3 +146,3 @@ * @param body {Body}

if (index > -1) {
for (var i = 0; i < Object.keys(this._agents).length; i++) this.detachFrom(i, body);
for (var agent in this._agentData) this.detachFrom(agent.id, body);
array.splice(index,1);

@@ -132,4 +162,7 @@ }

this._agents[this._currAgentId] = {
agent.on('change', this.wake.bind(this));
this._agentData[this._currAgentId] = {
agent : agent,
id : this._currAgentId,
targets : targets,

@@ -145,3 +178,3 @@ source : source

* Attaches a force or constraint to a Body. Returns an AgentId of the
* attached agent which can be used to detach the agent.
* attached agent which can be used to detach the agent.
*

@@ -155,2 +188,4 @@ * @method attach

PhysicsEngine.prototype.attach = function attach(agents, targets, source) {
this.wake();
if (agents instanceof Array) {

@@ -173,3 +208,3 @@ var agentIDs = [];

PhysicsEngine.prototype.attachTo = function attachTo(agentID, target) {
_getBoundAgent.call(this, agentID).targets.push(target);
_getAgentData.call(this, agentID).targets.push(target);
};

@@ -179,3 +214,3 @@

* Undoes PhysicsEngine.attach. Removes an agent and its associated
* effect on its affected Bodies.
* effect on its affected Bodies.
*

@@ -193,3 +228,3 @@ * @method detach

// detach agents array
delete this._agents[id];
delete this._agentData[id];
};

@@ -205,3 +240,3 @@

PhysicsEngine.prototype.detachFrom = function detachFrom(id, target) {
var boundAgent = _getBoundAgent.call(this, id);
var boundAgent = _getAgentData.call(this, id);
if (boundAgent.source === target) this.detach(id);

@@ -222,3 +257,3 @@ else {

PhysicsEngine.prototype.detachAll = function detachAll() {
this._agents = {};
this._agentData = {};
this._forces = [];

@@ -229,4 +264,4 @@ this._constraints = [];

function _getBoundAgent(id) {
return this._agents[id];
function _getAgentData(id) {
return this._agentData[id];
}

@@ -241,3 +276,3 @@

PhysicsEngine.prototype.getAgent = function getAgent(id) {
return _getBoundAgent.call(this, id).agent;
return _getAgentData.call(this, id).agent;
};

@@ -277,3 +312,3 @@

* Iterates over every Particle and applies a function whose first
* argument is the Particle
* argument is the Particle
*

@@ -292,3 +327,3 @@ * @method forEachParticle

* Iterates over every Body that isn't a Particle and applies
* a function whose first argument is the Body
* a function whose first argument is the Body
*

@@ -308,3 +343,3 @@ * @method forEachBody

* Iterates over every Body and applies a function whose first
* argument is the Body
* argument is the Body
*

@@ -321,3 +356,3 @@ * @method forEach

function _updateForce(index) {
var boundAgent = _getBoundAgent.call(this, this._forces[index]);
var boundAgent = _getAgentData.call(this, this._forces[index]);
boundAgent.agent.applyForce(boundAgent.targets, boundAgent.source);

@@ -332,3 +367,3 @@ }

function _updateConstraint(index, dt) {
var boundAgent = this._agents[this._constraints[index]];
var boundAgent = this._agentData[this._constraints[index]];
return boundAgent.agent.applyConstraint(boundAgent.targets, boundAgent.source, dt);

@@ -346,4 +381,6 @@ }

function _updateVelocities(particle, dt) {
particle.integrateVelocity(dt);
function _updateVelocities(body, dt) {
body.integrateVelocity(dt);
if (this.options.velocityCap)
body.velocity.cap(this.options.velocityCap).put(body.velocity);
}

@@ -354,2 +391,4 @@

body.updateAngularVelocity();
if (this.options.angularVelocityCap)
body.angularVelocity.cap(this.options.angularVelocityCap).put(body.angularVelocity);
}

@@ -361,5 +400,5 @@

function _updatePositions(particle, dt) {
particle.integratePosition(dt);
particle.emit('update', particle);
function _updatePositions(body, dt) {
body.integratePosition(dt);
body.emit(_events.update, body);
}

@@ -376,3 +415,3 @@

function _getEnergyParticles() {
function _getParticlesEnergy() {
var energy = 0.0;

@@ -383,3 +422,2 @@ var particleEnergy = 0.0;

energy += particleEnergy;
if (particleEnergy < particle.sleepTolerance) particle.sleep();
});

@@ -389,19 +427,24 @@ return energy;

function _getEnergyForces() {
function _getAgentsEnergy() {
var energy = 0;
for (var index = this._forces.length - 1; index > -1; index--)
energy += this._forces[index].getEnergy() || 0.0;
for (var id in this._agentData)
energy += this.getAgentEnergy(id);
return energy;
}
function _getEnergyConstraints() {
var energy = 0;
for (var index = this._constraints.length - 1; index > -1; index--)
energy += this._constraints[index].getEnergy() || 0.0;
return energy;
}
/**
* Calculates the potential energy of an agent, like a spring, by its Id
*
* @method getAgentEnergy
* @param agentId {Number} The attached agent Id
* @return energy {Number}
*/
PhysicsEngine.prototype.getAgentEnergy = function(agentId) {
var agentData = _getAgentData.call(this, agentId);
return agentData.agent.getEnergy(agentData.targets, agentData.source);
};
/**
* Calculates the kinetic energy of all Body objects and potential energy
* of all attached agents.
* of all attached agents.
*

@@ -413,3 +456,3 @@ * TODO: implement.

PhysicsEngine.prototype.getEnergy = function getEnergy() {
return _getEnergyParticles.call(this) + _getEnergyForces.call(this) + _getEnergyConstraints.call(this);
return _getParticlesEnergy.call(this) + _getAgentsEnergy.call(this);
};

@@ -419,3 +462,3 @@

* Updates all Body objects managed by the physics engine over the
* time duration since the last time step was called.
* time duration since the last time step was called.
*

@@ -425,6 +468,3 @@ * @method step

PhysicsEngine.prototype.step = function step() {
// if (this.getEnergy() < this.options.sleepTolerance) {
// this.sleep();
// return;
// };
if (this.isSleeping()) return;

@@ -450,5 +490,8 @@ //set current frame's time

// this._buffer = 0.0;
_integrate.call(this, TIMESTEP);
// this.emit('update', this);
this.emit(_events.update, this);
if (this.getEnergy() < this.options.sleepTolerance) this.sleep();
};

@@ -458,2 +501,3 @@

* Tells whether the Physics Engine is sleeping or awake.
*
* @method isSleeping

@@ -467,7 +511,22 @@ * @return {Boolean}

/**
* Stops the Physics Engine from updating. Emits an 'end' event.
* Tells whether the Physics Engine is sleeping or awake.
*
* @method isActive
* @return {Boolean}
*/
PhysicsEngine.prototype.isActive = function isSleeping() {
return !this._isSleeping;
};
/**
* Stops the Physics Engine update loop. Emits an 'end' event.
*
* @method sleep
*/
PhysicsEngine.prototype.sleep = function sleep() {
this.emit('end', this);
if (this._isSleeping) return;
this.forEach(function(body) {
body.sleep();
});
this.emit(_events.end, this);
this._isSleeping = true;

@@ -477,8 +536,10 @@ };

/**
* Starts the Physics Engine from updating. Emits an 'start' event.
* Restarts the Physics Engine update loop. Emits an 'start' event.
*
* @method wake
*/
PhysicsEngine.prototype.wake = function wake() {
if (!this._isSleeping) return;
this._prevTime = now();
this.emit('start', this);
this.emit(_events.start, this);
this._isSleeping = false;

@@ -485,0 +546,0 @@ };

@@ -44,31 +44,5 @@ Famo.us

Cloning this repository directly is primarily for those wishing to contribute to our codebase. Check out our [contributing instructions][contributing] to get involved. Since we use git submodules, all subfolders will be unpopulated unless you initialize and update your submodules. To clone from the command line, run
git clone git@github.com:Famous/famous.git path/to/folder
cd path/to/folder
git submodule update --init
Cloning this repository directly is primarily for those wishing to contribute to our codebase. Check out our [contributing instructions][contributing] to get involved.
Or clone with the `--recursive` flag for a convenient one-liner
git clone git@github.com:Famous/famous.git --recursive path/to/folder
Note: cloning only provides the Famo.us folder with all Famo.us code, but it does no application scaffolding. You will additionally need to create your own index.html, and include the `famous.css` file that is included in `famous/core`. Require.js is currently a hard dependency for using Famo.us.
## Famous.git Package
This package contains the submodules necessary to be productive in Famo.us. They are all hosted on [our github organization][famous-organization-github].
| Submodule | Description |
| --------- | ----------- |
| core.git | The low level componentry of Famo.us, plus the required famous.css stylesheet. |
| events.git | Events are used for communication between objects in Famous. |
| inputs.git | The inputs library is used to interpret user input to the device. |
| math.git | A simple math library used throughout the core. |
| modifiers.git | Implementations of the core/Modifier pattern which output transforms to the render tree. |
| physics.git | Core engine controlling animations via physical simulation. |
| surfaces.git | Surfaces extend core/Surface and encapsulate common HTML tags like `<img>` and `<canvas>`.|
| transitions.git | Transitions are used to create animation, usually by providing input to a Modifier. |
| utilities.git | Utilities hosts various helper classes and static methods. |
| views.git | Views are visually interactable components for use in applications. |
| widgets.git | Widgets are small visually interactable components for use in applications with their own styling. |
Note: cloning only provides the Famo.us folder with all Famo.us code, but it does no application scaffolding. You will additionally need to create your own index.html, and include the `famous.css` file that is included in `famous/core`. Require.js is currently a hard dependency to work off of the Famo.us head.

@@ -75,0 +49,0 @@ ## Documentation

module.exports = {
CanvasSurface: require('./CanvasSurface'),
ContainerSurface: require('./ContainerSurface'),
ImageSurface: require('./ImageSurface'),
FormContainerSurface: require('./FormContainerSurface'),
ImageSurface: require('./ImageSurface'),
InputSurface: require('./InputSurface'),

@@ -7,0 +7,0 @@ SubmitInputSurface: require('./SubmitInputSurface'),

@@ -26,3 +26,3 @@ /* This Source Code Form is subject to the terms of the Mozilla Public

* @param {Array} [options.properties] string dictionary of HTML attributes to set on target div
* @param {string} [options.content] inner (HTML) content of surface
* @param {String} [options.src] videoUrl URL
* @param {boolean} [options.autoplay] autoplay

@@ -56,4 +56,9 @@ */

VideoSurface.prototype.setOptions = function setOptions(options) {
for (var key in VideoSurface.DEFAULT_OPTIONS) {
if (options[key] !== undefined) this.options[key] = options[key];
if (options.size) this.setSize(options.size);
if (options.classes) this.setClasses(options.classes);
if (options.properties) this.setProperties(options.properties);
if (options.autoplay) this.options.autoplay = options.autoplay;
if (options.src) {
this._videoUrl = options.src;
this._contentDirty = true;
}

@@ -60,0 +65,0 @@ };

@@ -25,7 +25,13 @@ /* This Source Code Form is subject to the terms of the Mozilla Public

this._final = Transform.identity.slice();
this.translate = new Transitionable([0, 0, 0]);
this.rotate = new Transitionable([0, 0, 0]);
this.skew = new Transitionable([0, 0, 0]);
this.scale = new Transitionable([1, 1, 1]);
this._finalTranslate = [0, 0, 0];
this._finalRotate = [0, 0, 0];
this._finalSkew = [0, 0, 0];
this._finalScale = [1, 1, 1];
this.translate = new Transitionable(this._finalTranslate);
this.rotate = new Transitionable(this._finalRotate);
this.skew = new Transitionable(this._finalSkew);
this.scale = new Transitionable(this._finalScale);
if (transform) this.set(transform);

@@ -43,2 +49,11 @@ }

function _buildFinal() {
return Transform.build({
translate: this._finalTranslate,
rotate: this._finalRotate,
skew: this._finalSkew,
scale: this._finalScale
});
}
/**

@@ -56,7 +71,5 @@ * An optimized way of setting only the translation component of a Transform

TransitionableTransform.prototype.setTranslate = function setTranslate(translate, transition, callback) {
this._finalTranslate = translate;
this._final = _buildFinal.call(this);
this.translate.set(translate, transition, callback);
this._final = this._final.slice();
this._final[12] = translate[0];
this._final[13] = translate[1];
if (translate[2] !== undefined) this._final[14] = translate[2];
return this;

@@ -77,7 +90,5 @@ };

TransitionableTransform.prototype.setScale = function setScale(scale, transition, callback) {
this._finalScale = scale;
this._final = _buildFinal.call(this);
this.scale.set(scale, transition, callback);
this._final = this._final.slice();
this._final[0] = scale[0];
this._final[5] = scale[1];
if (scale[2] !== undefined) this._final[10] = scale[2];
return this;

@@ -98,10 +109,5 @@ };

TransitionableTransform.prototype.setRotate = function setRotate(eulerAngles, transition, callback) {
this._finalRotate = eulerAngles;
this._final = _buildFinal.call(this);
this.rotate.set(eulerAngles, transition, callback);
this._final = _build.call(this);
this._final = Transform.build({
translate: this.translate.get(),
rotate: eulerAngles,
scale: this.scale.get(),
skew: this.skew.get()
});
return this;

@@ -122,9 +128,5 @@ };

TransitionableTransform.prototype.setSkew = function setSkew(skewAngles, transition, callback) {
this._finalSkew = skewAngles;
this._final = _buildFinal.call(this);
this.skew.set(skewAngles, transition, callback);
this._final = Transform.build({
translate: this.translate.get(),
rotate: this.rotate.get(),
scale: this.scale.get(),
skew: skewAngles
});
return this;

@@ -146,5 +148,10 @@ };

TransitionableTransform.prototype.set = function set(transform, transition, callback) {
this._final = transform;
var components = Transform.interpret(transform);
this._finalTranslate = components.translate;
this._finalRotate = components.rotate;
this._finalSkew = components.skew;
this._finalScale = components.scale;
this._final = transform;
var _callback = callback ? Utility.after(4, callback) : null;

@@ -151,0 +158,0 @@ this.translate.set(components.translate, transition, _callback);

@@ -25,3 +25,3 @@ /* This Source Code Form is subject to the terms of the Mozilla Public

var getTime = (window.performance) ?
var getTime = (window.performance && window.performance.now) ?
function() {

@@ -28,0 +28,0 @@ return window.performance.now();

@@ -124,3 +124,3 @@ /* This Source Code Form is subject to the terms of the Mozilla Public

* outTransformFrom sets the accessor for the state of the transform used in transitioning out renderables.
* @method show
* @method outTransformFrom
* @param {Function|Transitionable} transform A function that returns a transform from outside closure, or a

@@ -133,3 +133,3 @@ * a transitionable that manages a full transform (a sixteen value array).

else if (transform && transform.get) this.outTransformMap = transform.get.bind(transform);
else throw new Error('inTransformFrom takes only function or getter object');
else throw new Error('outTransformFrom takes only function or getter object');
//TODO: tween transition

@@ -141,3 +141,3 @@ return this;

* outOpacityFrom sets the accessor for the state of the opacity used in transitioning out renderables.
* @method inOpacityFrom
* @method outOpacityFrom
* @param {Function|Transitionable} opacity A function that returns an opacity from outside closure, or a

@@ -150,3 +150,3 @@ * a transitionable that manages opacity (a number between zero and one).

else if (opacity && opacity.get) this.outOpacityMap = opacity.get.bind(opacity);
else throw new Error('inOpacityFrom takes only function or getter object');
else throw new Error('outOpacityFrom takes only function or getter object');
//TODO: tween opacity

@@ -158,3 +158,3 @@ return this;

* outOriginFrom sets the accessor for the state of the origin used in transitioning out renderables.
* @method inOriginFrom
* @method outOriginFrom
* @param {Function|Transitionable} origin A function that returns an origin from outside closure, or a

@@ -167,3 +167,3 @@ * a transitionable that manages origin (a two value array of numbers between zero and one).

else if (origin && origin.get) this.outOriginMap = origin.get.bind(origin);
else throw new Error('inOriginFrom takes only function or getter object');
else throw new Error('outOriginFrom takes only function or getter object');
//TODO: tween origin

@@ -170,0 +170,0 @@ return this;

@@ -38,5 +38,12 @@ /* This Source Code Form is subject to the terms of the Mozilla Public

EventHandler.setInputHandler(this, this.scrollview);
EventHandler.setOutputHandler(this, this.scrollview);
this.scrollview.subscribe(this.container);
this._eventInput = new EventHandler();
EventHandler.setInputHandler(this, this._eventInput);
this._eventInput.pipe(this.scrollview);
this._eventOutput = new EventHandler();
EventHandler.setOutputHandler(this, this._eventOutput);
this.container.pipe(this._eventOutput);
this.scrollview.pipe(this._eventOutput);
}

@@ -48,3 +55,3 @@

},
scrollview: {direction: Utility.Direction.X}
scrollview: {}
};

@@ -73,2 +80,12 @@

/**
* Returns the width and the height of the ScrollContainer instance.
*
* @method getSize
* @return {Array} A two value array of the ScrollContainer instance's current width and height (in that order).
*/
ScrollContainer.prototype.getSize = function getSize() {
return this.container.getSize.apply(this.container, arguments);
};
/**
* Generate a render spec from the contents of this component.

@@ -81,5 +98,5 @@ *

ScrollContainer.prototype.render = function render() {
return this.container.render.apply(this.container, arguments);
return this.container.render();
};
module.exports = ScrollContainer;

@@ -63,5 +63,7 @@ var Entity = require('../core/Entity');

var EDGE_TOLERANCE = 0; //slop for detecting passing the edge
function _sizeForDir(size) {
if (!size) size = this._contextSize;
var dimension = (this.options.direction === Utility.Direction.X) ? 0 : 1;
var dimension = this.options.direction;
return (size[dimension] === undefined) ? this._contextSize[dimension] : size[dimension];

@@ -78,7 +80,21 @@ }

function _getClipSize() {
if (this.options.clipSize) return this.options.clipSize;
else return _sizeForDir.call(this, this._contextSize);
if (this.options.clipSize !== undefined) return this.options.clipSize;
if (this._contextSize[this.options.direction] > this.getCumulativeSize()[this.options.direction]) {
return _sizeForDir.call(this, this.getCumulativeSize());
} else {
return _sizeForDir.call(this, this._contextSize);
}
}
/**
* Returns the cumulative size of the renderables in the view sequence
* @method getCumulativeSize
* @return {array} a two value array of the view sequence's cumulative size up to the index.
*/
Scroller.prototype.getCumulativeSize = function(index) {
if (index === undefined) index = this._node._.cumulativeSizes.length - 1;
return this._node._.getSize(index);
};
/**
* Patches the Scroller instance's options with the passed-in ones.

@@ -89,10 +105,9 @@ * @method setOptions

Scroller.prototype.setOptions = function setOptions(options) {
if (options.groupScroll !== this.options.groupScroll) {
if (options.groupScroll)
this.group.pipe(this._eventOutput);
else
this.group.unpipe(this._eventOutput);
}
this._optionsManager.setOptions(options);
if (this.options.groupScroll) {
this.group.pipe(this._eventOutput);
}
else {
this.group.unpipe(this._eventOutput);
}
};

@@ -226,20 +241,2 @@

function _normalizeState() {
var nodeSize = _sizeForDir.call(this, this._node.getSize());
var nextNode = this._node && this._node.getNext ? this._node.getNext() : null;
while (nextNode && this._position + this._positionOffset >= nodeSize) {
this._positionOffset -= nodeSize;
this._node = nextNode;
nodeSize = _sizeForDir.call(this, this._node.getSize());
nextNode = this._node && this._node.getNext ? this._node.getNext() : null;
}
var prevNode = this._node && this._node.getPrevious ? this._node.getPrevious() : null;
while (prevNode && this._position + this._positionOffset < 0) {
var prevNodeSize = _sizeForDir.call(this, prevNode.getSize());
this._positionOffset += prevNodeSize;
this._node = prevNode;
prevNode = this._node && this._node.getPrevious ? this._node.getPrevious() : null;
}
}
function _innerRender() {

@@ -250,4 +247,2 @@ var size = null;

this._onEdge = 0;
var offset = -this._positionOffset;

@@ -275,16 +270,24 @@ var clipSize = _getClipSize.call(this);

var edgeSize = (nodesSize !== undefined && nodesSize < clipSize) ? nodesSize : clipSize;
if (!currNode && offset - position <= edgeSize) {
this._onEdge = 1;
this._eventOutput.emit('edgeHit', {
position: offset - edgeSize
});
if (!currNode && offset - position < clipSize - EDGE_TOLERANCE) {
if (this._onEdge !== 1){
this._onEdge = 1;
this._eventOutput.emit('onEdge', {
position: offset - clipSize
});
}
}
else if (!this._node.getPrevious() && position <= 0) {
this._onEdge = -1;
this._eventOutput.emit('edgeHit', {
position: 0
});
else if (!this._node.getPrevious() && position < -EDGE_TOLERANCE) {
if (this._onEdge !== -1) {
this._onEdge = -1;
this._eventOutput.emit('onEdge', {
position: 0
});
}
}
else {
if (this._onEdge !== 0){
this._onEdge = 0;
this._eventOutput.emit('offEdge');
}
}

@@ -299,3 +302,3 @@ // backwards

while (currNode && ((offset - position) > -(_getClipSize.call(this) + this.options.margin))) {
while (currNode && ((offset - position) > -(clipSize + this.options.margin))) {
_output.call(this, currNode, offset, result);

@@ -309,3 +312,2 @@ currNode = currNode.getPrevious ? currNode.getPrevious() : null;

_normalizeState.call(this);
return result;

@@ -312,0 +314,0 @@ }

@@ -34,2 +34,9 @@ /* This Source Code Form is subject to the terms of the Mozilla Public

/** @enum */
var EdgeStates = {
TOP: -1,
NONE: 0,
BOTTOM: 1
};
/**

@@ -69,7 +76,19 @@ * Scrollview will lay out a collection of renderables sequentially in the specified direction, and will

function Scrollview(options) {
// patch options with defaults
this.options = Object.create(Scrollview.DEFAULT_OPTIONS);
this._optionsManager = new OptionsManager(this.options);
this._node = null;
// create sub-components
this._scroller = new Scroller(this.options);
this.sync = new GenericSync(
['scroll', 'touch'],
{
direction : this.options.direction,
scale : this.options.syncScale,
rails: this.options.rails,
preventDefault: this.options.preventDefault
}
);
this._physicsEngine = new PhysicsEngine();

@@ -79,9 +98,34 @@ this._particle = new Particle();

this.spring = new Spring({anchor: [0, 0, 0]});
this.spring = new Spring({
anchor: [0, 0, 0],
period: this.options.edgePeriod,
dampingRatio: this.options.edgeDamp
});
this.drag = new Drag({
forceFunction: Drag.FORCE_FUNCTIONS.QUADRATIC,
strength: this.options.drag
});
this.friction = new Drag({
forceFunction: Drag.FORCE_FUNCTIONS.LINEAR,
strength: this.options.friction
});
this.drag = new Drag({forceFunction: Drag.FORCE_FUNCTIONS.QUADRATIC});
this.friction = new Drag({forceFunction: Drag.FORCE_FUNCTIONS.LINEAR});
// state
this._node = null;
this._touchCount = 0;
this._springState = SpringStates.NONE;
this._onEdge = EdgeStates.NONE;
this._pageSpringPosition = 0;
this._edgeSpringPosition = 0;
this._touchVelocity = 0;
this._earlyEnd = false;
this._needsPaginationCheck = false;
this._displacement = 0;
this._totalShift = 0;
this._cachedIndex = 0;
this.sync = new GenericSync(['scroll', 'touch'], {direction : this.options.direction});
// subcomponent logic
this._scroller.positionFrom(this.getPosition.bind(this));
// eventing
this._eventInput = new EventHandler();

@@ -96,17 +140,6 @@ this._eventOutput = new EventHandler();

this._touchCount = 0;
this._springState = SpringStates.NONE;
this._onEdge = 0; // -1 for top, 1 for bottom
this._pageSpringPosition = 0;
this._edgeSpringPosition = 0;
this._touchVelocity = undefined;
this._earlyEnd = false;
this._needsPaginationCheck = false;
_bindEvents.call(this);
this._scroller = new Scroller();
this._scroller.positionFrom(this.getPosition.bind(this));
this.setOptions(options);
_bindEvents.call(this);
// override default options with passed-in custom options
if (options) this.setOptions(options);
}

@@ -117,5 +150,5 @@

rails: true,
friction: 0.001,
friction: 0.005,
drag: 0.0001,
edgeGrip: 0.5,
edgeGrip: 0.2,
edgePeriod: 300,

@@ -129,4 +162,5 @@ edgeDamp: 1,

pageSwitchSpeed: 0.5,
speedLimit: 10,
groupScroll: false
speedLimit: 5,
groupScroll: false,
syncScale: 1
};

@@ -139,2 +173,3 @@

_detachAgents.call(this);
this.setVelocity(0);

@@ -149,4 +184,4 @@ this._touchVelocity = 0;

if (this._onEdge && event.slip) {
if ((velocity < 0 && this._onEdge < 0) || (velocity > 0 && this._onEdge > 0)) {
if (this._onEdge !== EdgeStates.NONE && event.slip) {
if ((velocity < 0 && this._onEdge === EdgeStates.TOP) || (velocity > 0 && this._onEdge === EdgeStates.BOTTOM)) {
if (!this._earlyEnd) {

@@ -164,4 +199,18 @@ _handleEnd.call(this, event);

if (event.slip) this.setVelocity(velocity);
else this.setPosition(this.getPosition() + delta);
if (event.slip) {
var speedLimit = this.options.speedLimit;
if (velocity < -speedLimit) velocity = -speedLimit;
else if (velocity > speedLimit) velocity = speedLimit;
this.setVelocity(velocity);
var deltaLimit = speedLimit * 16;
if (delta > deltaLimit) delta = deltaLimit;
else if (delta < -deltaLimit) delta = -deltaLimit;
}
this.setPosition(this.getPosition() + delta);
this._displacement += delta;
if (this._springState === SpringStates.NONE) _normalizeState.call(this);
}

@@ -173,3 +222,3 @@

_detachAgents.call(this);
if (this._onEdge) _setSpring.call(this, this._edgeSpringPosition, SpringStates.EDGE);
if (this._onEdge !== EdgeStates.NONE) _setSpring.call(this, this._edgeSpringPosition, SpringStates.EDGE);
_attachAgents.call(this);

@@ -182,3 +231,3 @@ var velocity = -event.velocity;

this.setVelocity(velocity);
this._touchVelocity = undefined;
this._touchVelocity = 0;
this._needsPaginationCheck = true;

@@ -194,5 +243,27 @@ }

this._scroller.on('edgeHit', function(data) {
this._eventInput.on('resize', function() {
this._node._.calculateSize();
}.bind(this));
this._scroller.on('onEdge', function(data) {
this._edgeSpringPosition = data.position;
_handleEdge.call(this, this._scroller.onEdge());
this._eventOutput.emit('onEdge');
}.bind(this));
this._scroller.on('offEdge', function() {
this.sync.setOptions({scale: this.options.syncScale});
this._onEdge = this._scroller.onEdge();
this._eventOutput.emit('offEdge');
}.bind(this));
this._particle.on('update', function(particle) {
if (this._springState === SpringStates.NONE) _normalizeState.call(this);
this._displacement = particle.position.x - this._totalShift;
}.bind(this));
this._particle.on('end', function() {
if (!this.options.paginated || (this.options.paginated && this._springState !== SpringStates.NONE))
this._eventOutput.emit('settle');
}.bind(this));
}

@@ -212,28 +283,22 @@

var direction = this.options.direction;
var nodeSize = (node.getSize() || this._scroller.getSize())[direction];
if (!nodeSize) nodeSize = this._scroller.getSize()[direction];
return nodeSize;
var nodeSize = node.getSize();
return (!nodeSize) ? this._scroller.getSize()[direction] : nodeSize[direction];
}
function _handleEdge(edgeDetected) {
if (!this._onEdge && edgeDetected) {
this.sync.setOptions({scale: this.options.edgeGrip});
if (!this._touchCount && this._springState !== SpringStates.EDGE) {
_setSpring.call(this, this._edgeSpringPosition, SpringStates.EDGE);
}
function _handleEdge(edge) {
this.sync.setOptions({scale: this.options.edgeGrip});
this._onEdge = edge;
if (!this._touchCount && this._springState !== SpringStates.EDGE) {
_setSpring.call(this, this._edgeSpringPosition, SpringStates.EDGE);
}
else if (this._onEdge && !edgeDetected) {
this.sync.setOptions({scale: 1});
if (this._springState && Math.abs(this.getVelocity()) < 0.001) {
// reset agents, detaching the spring
_detachAgents.call(this);
_attachAgents.call(this);
}
if (this._springState && Math.abs(this.getVelocity()) < 0.001) {
// reset agents, detaching the spring
_detachAgents.call(this);
_attachAgents.call(this);
}
this._onEdge = edgeDetected;
}
function _handlePagination() {
if (!this._needsPaginationCheck) return;
if (this._touchCount) return;

@@ -251,8 +316,16 @@ if (this._springState === SpringStates.EDGE) return;

var positionNext = position > 0.5 * nodeSize;
var positionPrev = position < 0.5 * nodeSize;
var velocityNext = velocity > 0;
var velocityPrev = velocity < 0;
if ((positionNext && !velocitySwitch) || (velocitySwitch && velocityNext)) this.goToNextPage();
this._needsPaginationCheck = false;
if ((positionNext && !velocitySwitch) || (velocitySwitch && velocityNext)) {
this.goToNextPage();
}
else if (velocitySwitch && velocityPrev) {
this.goToPreviousPage();
}
else _setSpring.call(this, 0, SpringStates.PAGE);
this._needsPaginationCheck = false;
}

@@ -289,9 +362,12 @@

function _normalizeState() {
var offset = 0;
var position = this.getPosition();
position += (position < 0 ? -0.5 : 0.5) >> 0;
var nodeSize = _nodeSizeForDirection.call(this, this._node);
var nextNode = this._node.getNext();
while (position > nodeSize + TOLERANCE && nextNode) {
_shiftOrigin.call(this, -nodeSize);
position -= nodeSize;
while (offset + position >= nodeSize && nextNode) {
offset -= nodeSize;
this._scroller.sequenceFrom(nextNode);

@@ -306,10 +382,25 @@ this._node = nextNode;

while (position < -TOLERANCE && previousNode) {
while (offset + position <= 0 && previousNode) {
previousNodeSize = _nodeSizeForDirection.call(this, previousNode);
this._scroller.sequenceFrom(previousNode);
this._node = previousNode;
_shiftOrigin.call(this, previousNodeSize);
position += previousNodeSize;
offset += previousNodeSize;
previousNode = this._node.getPrevious();
}
if (offset) _shiftOrigin.call(this, offset);
if (this._node) {
if (this._node.index !== this._cachedIndex) {
if (this.getPosition() < 0.5 * nodeSize) {
this._cachedIndex = this._node.index;
this._eventOutput.emit('pageChange', {direction: -1, index: this._cachedIndex});
}
} else {
if (this.getPosition() > 0.5 * nodeSize) {
this._cachedIndex = this._node.index + 1;
this._eventOutput.emit('pageChange', {direction: 1, index: this._cachedIndex});
}
}
}
}

@@ -321,2 +412,4 @@

this.setPosition(this.getPosition() + amount);
this._totalShift += amount;
if (this._springState === SpringStates.EDGE) {

@@ -330,2 +423,78 @@ this.spring.setOptions({anchor: [this._edgeSpringPosition, 0, 0]});

/**
* Returns the index of the first visible renderable
*
* @method getCurrentIndex
* @return {Number} The current index of the ViewSequence
*/
Scrollview.prototype.getCurrentIndex = function getCurrentIndex() {
return this._node.index;
};
/**
* goToPreviousPage paginates your Scrollview instance backwards by one item.
*
* @method goToPreviousPage
* @return {ViewSequence} The previous node.
*/
Scrollview.prototype.goToPreviousPage = function goToPreviousPage() {
if (!this._node || this._onEdge === EdgeStates.TOP) return null;
// if moving back to the current node
if (this.getPosition() > 1 && this._springState === SpringStates.NONE) {
_setSpring.call(this, 0, SpringStates.PAGE);
return this._node;
}
// if moving to the previous node
var previousNode = this._node.getPrevious();
if (previousNode) {
var previousNodeSize = _nodeSizeForDirection.call(this, previousNode);
this._scroller.sequenceFrom(previousNode);
this._node = previousNode;
_shiftOrigin.call(this, previousNodeSize);
_setSpring.call(this, 0, SpringStates.PAGE);
}
return previousNode;
};
/**
* goToNextPage paginates your Scrollview instance forwards by one item.
*
* @method goToNextPage
* @return {ViewSequence} The next node.
*/
Scrollview.prototype.goToNextPage = function goToNextPage() {
if (!this._node || this._onEdge === EdgeStates.BOTTOM) return null;
var nextNode = this._node.getNext();
if (nextNode) {
var currentNodeSize = _nodeSizeForDirection.call(this, this._node);
this._scroller.sequenceFrom(nextNode);
this._node = nextNode;
_shiftOrigin.call(this, -currentNodeSize);
_setSpring.call(this, 0, SpringStates.PAGE);
}
return nextNode;
};
/**
* Paginates the Scrollview to an absolute page index.
*
* @method goToPage
*/
Scrollview.prototype.goToPage = function goToPage(index) {
var currentIndex = this.getCurrentIndex();
var i;
if (currentIndex > index) {
for (i = 0; i < currentIndex - index; i++)
this.goToPreviousPage();
}
if (currentIndex < index) {
for (i = 0; i < index - currentIndex; i++)
this.goToNextPage();
}
};
Scrollview.prototype.outputFrom = function outputFrom() {

@@ -338,2 +507,4 @@ return this._scroller.outputFrom.apply(this._scroller, arguments);

* (generally the node currently at the top).
*
* @deprecated
* @method getPosition

@@ -350,3 +521,28 @@ * @param {number} [node] If specified, returns the position of the node at that index in the

/**
* Sets position of the physics particle that controls Scrollview instance's "position"
* Returns the absolute position associated with the Scrollview instance
*
* @method getAbsolutePosition
* @return {number} The position of the Scrollview's current Node,
* in pixels translated.
*/
Scrollview.prototype.getAbsolutePosition = function getAbsolutePosition() {
return this._scroller.getCumulativeSize(this.getCurrentIndex())[this.options.direction] + this.getPosition();
};
/**
* Returns the offset associated with the Scrollview instance's current node
* (generally the node currently at the top).
*
* @method getOffset
* @param {number} [node] If specified, returns the position of the node at that index in the
* Scrollview instance's currently managed collection.
* @return {number} The position of either the specified node, or the Scrollview's current Node,
* in pixels translated.
*/
Scrollview.prototype.getOffset = Scrollview.prototype.getPosition;
/**
* Sets the position of the physics particle that controls Scrollview instance's "position"
*
* @deprecated
* @method setPosition

@@ -360,3 +556,12 @@ * @param {number} x The amount of pixels you want your scrollview to progress by.

/**
* Sets the offset of the physics particle that controls Scrollview instance's "position"
*
* @method setPosition
* @param {number} x The amount of pixels you want your scrollview to progress by.
*/
Scrollview.prototype.setOffset = Scrollview.prototype.setPosition;
/**
* Returns the Scrollview instance's velocity.
*
* @method getVelocity

@@ -373,2 +578,3 @@ * @return {Number} The velocity.

* the Scrollview instance will scroll at the passed-in velocity.
*
* @method setVelocity

@@ -383,2 +589,3 @@ * @param {number} v The magnitude of the velocity.

* Patches the Scrollview instance's options with the passed-in ones.
*
* @method setOptions

@@ -388,73 +595,42 @@ * @param {Options} options An object of configurable options for the Scrollview instance.

Scrollview.prototype.setOptions = function setOptions(options) {
if (options) {
if (options.direction !== undefined) {
if (options.direction === 'x') options.direction = Utility.Direction.X;
else if (options.direction === 'y') options.direction = Utility.Direction.Y;
}
// preprocess custom options
if (options.direction !== undefined) {
if (options.direction === 'x') options.direction = Utility.Direction.X;
else if (options.direction === 'y') options.direction = Utility.Direction.Y;
}
this._scroller.setOptions(options);
this._optionsManager.setOptions(options);
if (options.groupScroll !== this.options.groupScroll) {
if (options.groupScroll)
this.subscribe(this._scroller);
else
this.unsubscribe(this._scroller);
}
this._scroller.setOptions(this.options);
if (this.options.groupScroll)
this._scroller.pipe(this._eventInput);
else
this._scroller.unpipe(this._eventInput);
// patch custom options
this._optionsManager.setOptions(options);
this.drag.setOptions({strength: this.options.drag});
this.friction.setOptions({strength: this.options.friction});
// propagate options to sub-components
this.spring.setOptions({
period: this.options.edgePeriod,
dampingRatio: this.options.edgeDamp
});
// scroller sub-component
this._scroller.setOptions(options);
this.sync.setOptions({
rails: this.options.rails,
direction: (this.options.direction === Utility.Direction.X) ? GenericSync.DIRECTION_X : GenericSync.DIRECTION_Y
});
};
/**
* goToPreviousPage paginates your Scrollview instance backwards by one item.
* @method goToPreviousPage
* @return {ViewSequence} The previous node.
*/
Scrollview.prototype.goToPreviousPage = function goToPreviousPage() {
if (!this._node) return null;
var previousNode = this._node.getPrevious();
if (previousNode) {
var currentPosition = this.getPosition();
var previousNodeSize = _nodeSizeForDirection.call(this, previousNode);
this._scroller.sequenceFrom(previousNode);
this._node = previousNode;
var previousSpringPosition = (currentPosition < TOLERANCE) ? -previousNodeSize : 0;
_setSpring.call(this, previousSpringPosition, SpringStates.PAGE);
_shiftOrigin.call(this, previousNodeSize);
// physics sub-components
if (options.drag !== undefined) this.drag.setOptions({strength: this.options.drag});
if (options.friction !== undefined) this.friction.setOptions({strength: this.options.friction});
if (options.edgePeriod !== undefined || options.edgeDamp !== undefined) {
this.spring.setOptions({
period: this.options.edgePeriod,
dampingRatio: this.options.edgeDamp
});
}
this._eventOutput.emit('pageChange', {direction: -1});
return previousNode;
};
/**
* goToNextPage paginates your Scrollview instance forwards by one item.
* @method goToNextPage
* @return {ViewSequence} The next node.
*/
Scrollview.prototype.goToNextPage = function goToNextPage() {
if (!this._node) return null;
var nextNode = this._node.getNext();
if (nextNode) {
var currentPosition = this.getPosition();
var currentNodeSize = _nodeSizeForDirection.call(this, this._node);
var nextNodeSize = _nodeSizeForDirection.call(this, nextNode);
this._scroller.sequenceFrom(nextNode);
this._node = nextNode;
var nextSpringPosition = (currentPosition > currentNodeSize - TOLERANCE) ? currentNodeSize + nextNodeSize : currentNodeSize;
_setSpring.call(this, nextSpringPosition, SpringStates.PAGE);
_shiftOrigin.call(this, -currentNodeSize);
// sync sub-component
if (options.rails || options.direction !== undefined || options.syncScale !== undefined || options.preventDefault) {
this.sync.setOptions({
rails: this.options.rails,
direction: (this.options.direction === Utility.Direction.X) ? GenericSync.DIRECTION_X : GenericSync.DIRECTION_Y,
scale: this.options.syncScale,
preventDefault: this.options.preventDefault
});
}
this._eventOutput.emit('pageChange', {direction: 1});
return nextNode;
};

@@ -472,3 +648,3 @@

Scrollview.prototype.sequenceFrom = function sequenceFrom(node) {
if (node instanceof Array) node = new ViewSequence({array: node});
if (node instanceof Array) node = new ViewSequence({array: node, trackSize: true});
this._node = node;

@@ -496,8 +672,4 @@ return this._scroller.sequenceFrom(node);

Scrollview.prototype.render = function render() {
if (!this._node) return null;
if (this.options.paginated && this._needsPaginationCheck) _handlePagination.call(this);
_normalizeState.call(this);
_handleEdge.call(this, this._scroller.onEdge());
if (this.options.paginated) _handlePagination.call(this);
return this._scroller.render();

@@ -504,0 +676,0 @@ };

@@ -24,5 +24,2 @@ /* This Source Code Form is subject to the terms of the Mozilla Public

* to just use integers as well.
* @param {Array.Number} [options.defaultItemSize=[50, 50]] In the case where a renderable layed out
* under SequentialLayout's control doesen't have a getSize method, SequentialLayout will assign it
* this default size. (Commonly a case with Views).
*/

@@ -37,8 +34,2 @@ function SequentialLayout(options) {

this._itemsCache = [];
this._outputCache = {
size: null,
target: this._itemsCache
};
if (options) this.setOptions(options);

@@ -48,5 +39,3 @@ }

SequentialLayout.DEFAULT_OPTIONS = {
direction: Utility.Direction.Y,
itemSpacing: 0,
defaultItemSize: [50, 50]
direction: Utility.Direction.Y
};

@@ -120,39 +109,35 @@

SequentialLayout.prototype.render = function render() {
var length = 0;
var girth = 0;
var length = 0;
var secondaryDirection = this.options.direction ^ 1;
var currentNode = this._items;
var item = null;
var itemSize = [];
var output = {};
var result = [];
var i = 0;
var lengthDim = (this.options.direction === Utility.Direction.X) ? 0 : 1;
var girthDim = (this.options.direction === Utility.Direction.X) ? 1 : 0;
this._size = [0, 0];
var currentNode = this._items;
var result = this._itemsCache;
var i = 0;
while (currentNode) {
var item = currentNode.get();
item = currentNode.get();
if (!item) break;
var itemSize;
if (item && item.getSize) itemSize = item.getSize();
if (!itemSize) itemSize = this.options.defaultItemSize;
if (itemSize[girthDim] !== true) girth = Math.max(girth, itemSize[girthDim]);
if (item.getSize) itemSize = item.getSize();
var output = this._outputFunction.call(this, item, length, i);
result[i] = output;
output = this._outputFunction.call(this, item, length, i++);
result.push(output);
if (itemSize[lengthDim] && (itemSize[lengthDim] !== true)) length += itemSize[lengthDim] + this.options.itemSpacing;
if (itemSize) {
if (itemSize[this.options.direction]) length += itemSize[this.options.direction];
if (itemSize[secondaryDirection] > this._size[secondaryDirection]) this._size[secondaryDirection] = itemSize[secondaryDirection];
}
currentNode = currentNode.getNext();
i++;
}
this._itemsCache.splice(i);
if (!girth) girth = undefined;
this._size[this.options.direction] = length;
if (!this._size) this._size = [0, 0];
this._size[lengthDim] = length - this.options.itemSpacing; // account for last itemSpacing
this._size[girthDim] = girth;
this._outputCache.size = this.getSize();
return this._outputCache;
return result;
};
module.exports = SequentialLayout;

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc