/* <copyright>
This file contains proprietary software owned by Motorola Mobility, Inc.<br/>
No rights, expressed or implied, whatsoever to this software are provided by Motorola Mobility, Inc. hereunder.<br/>
(c) Copyright 2011 Motorola Mobility, Inc. All Rights Reserved.
</copyright> */
var Montage = require("montage").Montage,
Component = require("ui/component").Component,
FlowBezierSpline = require("ui/flow-bezier-spline").FlowBezierSpline;
var Flow = exports.Flow = Montage.create(Component, {
_repetition: {
serializable: true,
value: null
},
_translateComposer: {
serializable: true,
value: null
},
_splinePaths: {
enumerable: false,
value: null
},
splinePaths: {
enumerable: false,
get: function () {
if (!this._splinePaths) {
this._splinePaths = [];
}
return this._splinePaths;
},
set: function (value) {
this._splinePaths = value;
}
},
appendPath: {
value: function (path) {
var splinePath = Object.create(FlowBezierSpline).init(),
pathKnots = path.knots,
length = path.knots.length,
knots = [],
nextHandlers = [],
previousHandlers = [],
densities = [],
i, j;
splinePath.parameters = {};
for (i in path.units) {
splinePath.parameters[i] = {
data: [],
units: path.units[i]
};
}
for (i = 0; i < length; i++) {
knots[i] = pathKnots[i].knotPosition;
previousHandlers[i] = pathKnots[i].previousHandlerPosition;
nextHandlers[i] = pathKnots[i].nextHandlerPosition;
densities[i] = pathKnots[i].previousDensity; // TODO: implement previous/next density
for (j in path.units) {
splinePath.parameters[j].data.push(pathKnots[i][j]);
}
}
splinePath.knots = knots;
splinePath.previousHandlers = previousHandlers;
splinePath.nextHandlers = nextHandlers;
splinePath.densities = densities;
splinePath._computeDensitySummation();
this.splinePaths.push(splinePath);
if (!path.hasOwnProperty("headOffset")) {
path.headOffset = 0;
}
if (!path.hasOwnProperty("tailOffset")) {
path.tailOffset = 0;
}
this._paths.push(path);
this._updateLength();
}
},
_paths: {
enumerable: false,
value: null
},
paths: { // TODO: listen for changes?
serializable: true,
get: function () {
return this._paths;
},
set: function (value) {
var length = value.length,
i;
if (length) {
if (!this._paths) {
this._paths = [];
} else {
this._paths.wipe();
this._splinePaths.wipe();
}
for (i = 0; i < length; i++) {
this.appendPath(value[i]);
}
}
}
},
_cameraPosition: {
enumerable: false,
value: [0, 0, 800]
},
_cameraTargetPoint: {
enumerable: false,
value: [0, 0, 0]
},
_cameraFov: {
enumerable: false,
value: 50
},
// TODO: Implement camera roll
_cameraRoll: {
enumerable: false,
value: 0
},
cameraPosition: {
serializable: true,
get: function () {
return this._cameraPosition;
},
set: function (value) {
this._cameraPosition = value;
this._isCameraUpdated = true;
this.needsDraw = true;
}
},
cameraTargetPoint: {
serializable: true,
get: function () {
return this._cameraTargetPoint;
},
set: function (value) {
this._cameraTargetPoint = value;
this._isCameraUpdated = true;
this.needsDraw = true;
}
},
cameraFov: {
serializable: true,
get: function () {
return this._cameraFov;
},
set: function (value) {
this._cameraFov = value;
this._isCameraUpdated = true;
this.needsDraw = true;
}
},
cameraRoll: {
serializable: true,
get: function () {
return this._cameraRoll;
},
set: function (value) {
this._cameraRoll = value;
this._isCameraUpdated = true;
this.needsDraw = true;
}
},
_stride: {
enumerable: false,
value: 0
},
stride: {
serializable: true,
get: function () {
return this._stride;
},
set: function (value) {
this._stride = value;
if (this._translateComposer) {
this._translateComposer.translateStrideX = value * 300;
}
}
},
_scrollingTransitionDurationMiliseconds: {
enumerable: false,
value: 500
},
_scrollingTransitionDuration: {
enumerable: false,
value: "500ms"
},
scrollingTransitionDuration: { // TODO: think about using the Date Converter
serializable: true,
get: function () {
return this._scrollingTransitionDuration;
},
set: function (duration) {
var durationString = duration + "",
length = durationString.length,
value;
if ((length >= 2) && (durationString[length - 1] === "s")) {
if ((length >= 3) && (durationString[length - 2] === "m")) {
value = durationString.substr(0, length - 2) - 0;
} else {
value = durationString.substr(0, length - 1) * 1000;
}
} else {
value = durationString - 0;
durationString += "ms";
}
if (!isNaN(value) && (this._scrollingTransitionDurationMiliseconds !== value)) {
this._scrollingTransitionDurationMiliseconds = value;
this._scrollingTransitionDuration = durationString;
}
}
},
_scrollingTransitionTimingFunctionBezier: {
enumerable: false,
value: [.25, .1, .25, 1]
},
_scrollingTransitionTimingFunction: {
enumerable: false,
value: "ease"
},
hasSelectedIndexScrolling: {
serializable: true,
value: false
},
selectedIndexScrollingOffset: {
serializable: true,
value: 0
},
_handleSelectedIndexesChange: {
enumerable: false,
value: function (event) {
if (this.hasSelectedIndexScrolling && event.plus) {
this.startScrollingIndexToOffset(event.plus[0], this.selectedIndexScrollingOffset);
}
}
},
_timingFunctions: {
enumerable: false,
value: {
"ease": [.25, .1, .25, 1],
"linear": [0, 0, 1, 1],
"ease-in": [.42, 0, 1, 1],
"ease-out": [0, 0, .58, 1],
"ease-in-out": [.42, 0, .58, 1]
}
},
scrollingTransitionTimingFunction: {
serializable: true,
get: function () {
return this._scrollingTransitionTimingFunction;
},
set: function (timingFunction) {
var string = timingFunction + "",
bezier,
i;
if (this._timingFunctions.hasOwnProperty(string)) {
this._scrollingTransitionTimingFunction = string;
this._scrollingTransitionTimingFunctionBezier = this._timingFunctions[string];
} else {
if ((string.substr(0, 13) === "cubic-bezier(") && (string.substr(string.length - 1, 1) === ")")) {
bezier = string.substr(13, string.length - 14).split(",");
if (bezier.length === 4) {
for (i = 0; i < 4; i++) {
bezier[i] -= 0;
if (isNaN(bezier[i])) {
return;
}
}
if (bezier[0] < 0) {
bezier[0] = 0;
} else {
if (bezier[0] > 1) {
bezier[0] = 1;
}
}
if (bezier[2] < 0) {
bezier[2] = 0;
} else {
if (bezier[2] > 1) {
bezier[2] = 1;
}
}
// TODO: check it is not the same bezier
this._scrollingTransitionTimingFunction = "cubic-bezier(" + bezier + ")";
this._scrollingTransitionTimingFunctionBezier = bezier;
}
}
}
}
},
_computeCssCubicBezierValue: {
enumerable: false,
value: function (x, bezier) {
var t = .5,
step = .25,
t2,
k,
i;
for (i = 0; i < 20; i++) { // TODO: optimize with Newton's method or similar
t2 = t * t;
k = 1 - t;
if ((3 * (k * k * t * bezier[0] + k * t2 * bezier[2]) + t2 * t) > x) {
t -= step;
} else {
t += step;
}
step *= .5;
}
t2 = t * t;
k = 1 - t;
return 3 * (k * k * t * bezier[1] + k * t2 * bezier[3]) + t2 * t;
}
},
_isTransitioningScroll: {
enumerable: false,
value: false
},
stopScrolling: {
value: function () {
|