Example #1
0
    function App(options) {
        // extend from view
        View.apply(this, arguments);

        // create the layout
        this.layout = new HeaderFooterLayout();

        // create the header
        this.header = new TitleBar(this.options.header);

        // create the navigation bar
        this.navigation = new NavigationBar(this.options.navigation);

        // create the content area
        this.contentArea = new EdgeSwapper(this.options.content);

        // link endpoints of layout to widgets
        this.layout.id['header'].link(this.header);
        this.layout.id['footer'].link(Utility.transformInFront).link(this.navigation);
        this.layout.id['content'].link(Utility.transformBehind).link(this.contentArea);
        
        // assign received events to content area
        this.eventInput.pipe(this.contentArea);

        // navigation events are app events
        EventHandler.setOutputHandler(this, this.navigation)
        this.eventInput = new EventHandler();
        EventHandler.setInputHandler(this, this.eventInput);
        this.eventOutput = new EventHandler();
        EventHandler.setOutputHandler(this, this.eventOutput);

        // declare the render nodes
        this._currentSection = undefined;
        this._sections = {};
        this._sectionTitles = {};

        // Initialize sections if they were passed at instantiation time
        this.options.sections && this.initSections(this.options.sections);

        // respond to the the selection of a different section
        this.navigation.on('select', function(data) {
            this.eventOutput.emit('triggerBackToNoneEditing');
            $('body').removeClass('editing');
            this._currentSection = data.id;
            this.header.show(this._sectionTitles[data.id]);
            this.contentArea.show(this._sections[data.id].get());
//            if (!this.header._surfaces[data.id].eventHandled) this.onHeaderClick(data);
        }.bind(this));

        // assign the layout to this view
        this._link(this.layout);
    }
Example #2
0
    function TwoFingerSync(targetSync,options) {
        this.targetGet = targetSync;

        this.options = {
            scale: 1
        };

        if (options) {
            this.setOptions(options);
        } else {
            this.setOptions(this.options);
        }

        this.input = new FEH();
        this.output = new FEH();

        FEH.setInputHandler(this, this.input);
        FEH.setOutputHandler(this, this.output);

        this.touchAId = undefined;
        this.posA = undefined;
        this.timestampA = undefined;
        this.touchBId = undefined;
        this.posB = undefined;
        this.timestampB = undefined;

        this.input.on('touchstart', this.handleStart.bind(this));
        this.input.on('touchmove', this.handleMove.bind(this));
        this.input.on('touchend', this.handleEnd.bind(this));
        this.input.on('touchcancel', this.handleEnd.bind(this));
    };
Example #3
0
    function CardsApp(options) {
        this.options = Object.create(CardsApp.DEFAULT_OPTIONS);
        if(options) this.setOptions(options);

        // create the layout
        this.layout = new HeaderFooterLayout({
            headerSize: this.options.headerSize,
            footerSize: this.options.footerSize
        });

        // create the header
        this.header = new (this.options.headerWidget)({
            size: [undefined, this.options.headerSize],
            inTransition: this.options.headerFeel.inTransition,
            outTransition: this.options.headerFeel.outTransition
        });

        // create the navigation bar
        this.navigation = new (this.options.navigationWidget)({
            size: [undefined, this.options.footerSize],
            feel: this.options.navigationFeel 
        });

        // create the content area
        this.contentArea = new (this.options.contentWidget)({
            inTransition: this.options.contentFeel.inTransition,
            outTransition: this.options.contentFeel.outTransition,
            overlap: this.options.contentFeel.overlap              
        });

        // link endpoints of layout to widgets
        this.layout.id['header'].link(this.header);
        this.layout.id['footer'].link(this.navigation);
        this.layout.id['content'].link(Util.transformBehind).link(this.contentArea);
        
        // assign received events to content area
        this.eventInput = new EventHandler();
        EventHandler.setInputHandler(this, this.eventInput);
        this.eventInput.pipe(this.contentArea);

        // navigation events are app events
        EventHandler.setOutputHandler(this, this.navigation);

        // declare the render nodes
        this._currScene = undefined;
        this.id = [];

        // setup all the scenes (load tweets, insert into view widgets, etc)
        _prepareScenes.call(this);

        // respond to the the selection of a different section
        this.navigation.on('select', function(data) {
            this._currScene = data.id;
            this.header.show(this.options.scenes[data.id].title);
            this.contentArea.show(this.id[data.id]);
        }.bind(this));

        // start on first section
        this.select(0);
    };
Example #4
0
    function MouseSync(targetGet, options) {
        this.targetGet = targetGet;

        this.options =  {
            direction: undefined,
            rails: false,
            scale: 1,
            stallTime: 50
        };

        if (options) {
            this.setOptions(options);
        } else {
            this.setOptions(this.options);
        }

        this.input = new FEH();
        this.output = new FEH();

        FEH.setInputHandler(this, this.input);
        FEH.setOutputHandler(this, this.output);

        this._prevCoord = undefined;
        this._prevTime = undefined;
        this._prevVel = undefined;
        this.input.on('mousedown', _handleStart.bind(this));
        this.input.on('mousemove', _handleMove.bind(this));
        this.input.on('mouseup', _handleEnd.bind(this));
        this.input.on('mouseleave', _handleEnd.bind(this));
    }
Example #5
0
    function TouchSync(targetSync,options) {
        this.targetGet = targetSync;

        this.output = new FEH();
        this.touchTracker = new FTT();

        this.options = {
            direction: undefined,
            rails: false,
            scale: 1
        };

        if (options) {
            this.setOptions(options);
        } else {
            this.setOptions(this.options);
        }

        FEH.setOutputHandler(this, this.output);
        FEH.setInputHandler(this, this.touchTracker);

        this.touchTracker.on('trackstart', _handleStart.bind(this));
        this.touchTracker.on('trackmove', _handleMove.bind(this));
        this.touchTracker.on('trackend', _handleEnd.bind(this));
    }
Example #6
0
    function CameraView(options) {
        View.call(this);
        this.model = options.model;

        // Set up event handlers
        this.eventInput = new EventHandler();
        EventHandler.setInputHandler(this, this.eventInput);
        this.eventOutput = new EventHandler();
        EventHandler.setOutputHandler(this, this.eventOutput);

        this.localVideoSurface = new Surface({
            content: '<div class="camera local-video blur off"><video muted="true" autoplay poster="content/images/transparent.png"></video></div>'
        });
        this.remoteVideoSurface = new Surface({
            properties: {
                zIndex: -3
            },
            content: '<div class="camera remote-video"><video autoplay poster="content/images/transparent.png"></video></div>'
        });
        this.localVideoSurface.pipe(this.eventOutput);
        this.remoteVideoSurface.pipe(this.eventOutput);

        this.transform = new Mod({
            origin: [0.9, 0.1]
        });
        this._add(new Mod({
            transform: FM.translate(0,0,-5)
        })).link(this.remoteVideoSurface);
        this._add(this.transform).link(this.localVideoSurface);
        this.turnOff();
    }
Example #7
0
    /**
     * @constructor
     */
    function RenderArbiter(cull) {
        this.nodes = {};
        this.faders = {};
        this.mode = -1;
        this.cull = cull;

        this.outputEvents = new EventHandler();
        EventHandler.setOutputHandler(this, this.outputEvents);
    };
Example #8
0
    function Scrollview(options) {
        this.options = {
            direction: Utility.Direction.Y,
            rails: !0,
            defaultItemSize: [100, 100],
            itemSpacing: 0,
            clipSize: void 0,
            margin: void 0,
            friction: .001,
            drag: 1e-4,
            edgeGrip: .5,
            edgePeriod: 300,
            edgeDamp: 1,
            paginated: !1,
            pagePeriod: 500,
            pageDamp: .8,
            pageStopSpeed: 1 / 0,
            pageSwitchSpeed: 1,
            speedLimit: 10
        };

        this.node = null;
        this.physicsEngine = new PhysicsEngine;
        this.particle = new Particle;
        this.physicsEngine.addBody(this.particle);
        this.spring = new Spring({anchor: [0, 0, 0]});
        this.drag = new Drag({forceFunction: Drag.FORCE_FUNCTIONS.QUADRATIC});
        this.friction = new Drag({forceFunction: Drag.FORCE_FUNCTIONS.LINEAR});
        this.sync = new GenericSync(function () {
            return -this.getPosition()
        }.bind(this), {
            direction: this.options.direction == Utility.Direction.X ? GenericSync.DIRECTION_X : GenericSync.DIRECTION_Y
        });
        this.eventInput = new EventHandler;
        this.eventOutput = new EventHandler;
        this.sync.pipe(this.eventInput);
        this.sync.pipe(this.eventOutput);
        EventHandler.setOutputHandler(this, this.eventOutput);
        this._outputFunction = void 0;
        this._masterOutputFunction = void 0;
        this.setOutputFunction();
        this.touchCount = 0;
        this._springAttached = !1;
        this._onEdge = 0;
        this._springPosition = 0;
        this._touchVelocity = void 0;
        this._earlyEnd = !1;
        this._masterOffset = 0;
        this._lastFrameNode = void 0;
        options ? this.setOptions(options) : this.setOptions({});
        a.call(this);
        this.group = new Group;
        this.group.link({render: S.bind(this)});
        this._entityId = Entity.register(this);
        this._contextSize = [window.innerWidth, window.innerHeight];
        this._offsets = {};
    }
Example #9
0
    function TitleNav(options) {
        this.options = Object.create(TitleNav.DEFAULT_OPTIONS);
        this.lightbox = new LightBox();
        this._surfaces = {};
        if(options) this.setOptions(options);

        this.eventInput = new EventHandler();
        EventHandler.setInputHandler(this, this.eventInput);
        this.eventOutput = new EventHandler();
        EventHandler.setOutputHandler(this, this.eventOutput);
    };
Example #10
0
    function AddFavoriteView(options) {
        HeaderFooterLayout.call(this);

        var upDownTransform = new UpDownTransform;

        if(options.inTransform === undefined) this.options.inTransform = upDownTransform.options.inTransform;
        if(options.outTransform === undefined) this.options.outTransform = upDownTransform.options.outTransform;
        if(options.inTransition === undefined) this.options.inTransition = upDownTransform.options.inTransition;
        if(options.outTransition === undefined) this.options.outTransition = upDownTransform.options.outTransition;
        if(options.inOpacity === undefined) this.options.inOpacity = upDownTransform.options.inOpacity;
        if(options.outOpacity === undefined) this.options.outOpacity = upDownTransform.options.outOpacity;

        this.model = options.model;

        // Set up event handlers
        this.eventInput = new EventHandler();
        EventHandler.setInputHandler(this, this.eventInput);
        this.eventOutput = new EventHandler();
        EventHandler.setOutputHandler(this, this.eventOutput);

        this.header = new Surface({
            classes: ['header'],
            size: [undefined, 50],
            properties: {
            },
            content: '<button class="left close-button cancel-favorite">Cancel</button><div>Add to Favor</div><button class="right close-button done-favorite">Done</button>'
        });
        this.content = new Surface({
            classes: ['surface', 'add-favorite-view'],
            size: [undefined, undefined],
            properties: {
                backgroundColor: 'transparent'
            }
        });

        this.id.header.link(this.header);
        this.id.content.link(this.content);

        this.content.on('click', function() {

        }.bind(this));

        this.template();

        this.content.pipe(this.eventOutput);
        this.header.pipe(this.eventOutput);

        this.header.on('click', function(e){
            if (target.hasClass("close-button")) this.eventOutput.emit('showApp');
        }.bind(this));

    }
Example #11
0
    function NavBar(options) {
        this.options = Object.create(NavBar.DEFAULT_OPTIONS);

        this.layout = new GridLayout();
        this.buttons = [];
        this._buttonIds = {};

        if(options) this.setOptions(options);

        this.eventOutput = new EventHandler();
        EventHandler.setOutputHandler(this, this.eventOutput);

        this.layout.sequenceFrom(this.buttons);
    };
Example #12
0
    function FeedItem(options) {
        this.options = Object.create(FeedItem.DEFAULT_OPTIONS);

        this.surface = new Surface({
            size: this.options.size,
            classes: this.options.classes
        });
        if(options) this.setOptions(options);

        this.eventInput = new EventHandler();
        this.eventOutput = new EventHandler();
        EventHandler.setInputHandler(this, this.eventInput);
        EventHandler.setOutputHandler(this, this.eventOutput);
        this.surface.pipe(this.eventInput);
    };
Example #13
0
    function ScrollContainer(options) {
        this.options = Object.create(ScrollContainer.DEFAULT_OPTIONS);

        this.surface = new ContainerSurface(this.options.look);
        this.scrollview = new Scrollview(this.options.feel);

        if(options) this.setOptions(options);

        this.surface.link(this.scrollview);

        EventHandler.setInputHandler(this, this.surface);
        EventHandler.setOutputHandler(this, this.surface);

        this.pipe(this.scrollview);
    };
Example #14
0
    /** @constructor */
    function Slider(options)
    {
        this.options = {
            size: [200, 60],
            indicatorSize: [200, 30],
            labelSize: [200, 30],
            range: [0, 1],
            precision: 2,
            defaultValue: 0,
            label: '',
            fillColor: 'rgba(170, 170, 170, 1)'
        }

        if(options) this.setOptions(options);
        this.value = this.options.defaultValue;
   
        this.indicator = new FamousCanvasSurface({
            size: this.options.indicatorSize
        });
        this.indicator.addClass('slider-back');
        
        this.label = new FamousSurface({
            size: this.options.labelSize, 
            content: this.options.label, 
            classes: ['slider-label']
        });
        this.label.setProperties({ 'pointer-events': 'none' });

        this.eventOutput = new FEH();
        this.eventInput = new FEH();
        FEH.setInputHandler(this, this.eventInput);
        FEH.setOutputHandler(this, this.eventOutput);

        this.sync = new GenericSync(this.get.bind(this), { 
            scale: (this.options.range[1] - this.options.range[0])/this.options.indicatorSize[0],
            direction: GenericSync.DIRECTION_X
        });

        this.eventInput.on('update', function(data) {
            this.set(data.p); 
        }.bind(this));

        this.indicator.pipe(this.sync).pipe(this.eventInput);

        this._drawPos = 0;
        _updateLabel.call(this);
    }
Example #15
0
    /** @constructor */
    function Collision(opts){

        this.opts = {
            restitution : .5
        };

        if (opts) this.setOpts(opts);

        this.eventOutput = new EventHandler();
        EventHandler.setOutputHandler(this, this.eventOutput);

        //registers
        this.n      = new Vector();
        this.vRel   = new Vector();
        this.I      = new Vector();
        this.disp   = new Vector();

    };
Example #16
0
define(function(require, exports, module) {
        var Engine = require('famous/Engine');
        var Lightbox = require('famous-views/Lightbox');
        var EventHandler = require('famous/EventHandler');
        var OptionsManager = require('famous/OptionsManager');

        var context;

        var Modal = {
                lightbox: new Lightbox(),
                eventOutput: new EventHandler(),
                eventInput: new EventHandler(),
        };

        EventHandler.setOutputHandler(Modal, Modal.eventOutput);
        EventHandler.setInputHandler(Modal, Modal.eventInput);

        Modal.setOptions = function(options) {
                this.lightbox.setOptions(options);
        };

        Modal.getOptions = function() {
                return this.lightbox.getOptions();
        };

        Modal.show = function(target, transition) {
                if (!context) {
                        context = Engine.createContext();
                        context.srcNode.object = this.lightbox;
                }
                this.lightbox.show(target, transition, function() {
                        this.eventInput.emit('Modal displaying');
                }.bind(this));
        };

        Modal.hide = function(transition) {
                this.lightbox.hide(transition, function() {
                        this.eventOutput.emit('Modal hidden');
                }.bind(this));
        };


        module.exports = Modal;
});
Example #17
0
    /** @constructor */
    function Wall(opts){
        this.opts = {
            restitution : 0.7,
            k : 0,
            n : new Vector(),
            d : 0,
            onContact : Wall.ON_CONTACT.REFLECT
        };

        if (opts) this.setOpts(opts);

        //registers
        this.diff     = new Vector();
        this.impulse  = new Vector();
        this.slop     = -1;

        this.eventHandler = new EventHandler();
        EventHandler.setOutputHandler(this, this.eventHandler);
    };
Example #18
0
    /** @constructor */
    function CollisionJacobian(opts){
        this.opts = {
            k : 0.5,
            restitution : 0.5
        };

        if (opts) this.setOpts(opts);

        this.eventOutput = new EventHandler();
        EventHandler.setOutputHandler(this, this.eventOutput);

        //registers
        this.n        = new Vector();
        this.pDiff    = new Vector();
        this.vDiff    = new Vector();
        this.impulse1 = new Vector();
        this.impulse2 = new Vector();
        this.slop     = 0;
    };
Example #19
0
    function App(options) {
        // extend from view
        View.apply(this, arguments);

        // create the layout
        this.layout = new HeaderFooterLayout();

        // create the header
        this.header = new TitleBar(this.options.header);

        // create the navigation bar
        this.navigation = new NavigationBar(this.options.navigation);

        // create the content area
        this.contentArea = new EdgeSwapper(this.options.content);

        // link endpoints of layout to widgets
        this.layout.id['header'].link(this.header);
        this.layout.id['footer'].link(Utility.transformInFront).link(this.navigation);
        this.layout.id['content'].link(Utility.transformBehind).link(this.contentArea);
        
        // assign received events to content area
        this.eventInput.pipe(this.contentArea);

        // navigation events are app events
        EventHandler.setOutputHandler(this, this.navigation);

        // declare the render nodes
        this._currentSection = undefined;
        this._sections = {};
        this._sectionTitles = {};

        // respond to the the selection of a different section
        this.navigation.on('select', function(data) {
            this._currentSection = data.id;
            this.header.show(this._sectionTitles[data.id]);
            this.contentArea.show(this._sections[data.id].get());
        }.bind(this));

        // assign the layout to this view
        this._link(this.layout);
    };
    function ImportContactView(options){
        HeaderFooterLayout.call(this);
        this.collection = options.collection;

        // Set up event handlers
        this.eventInput = new EventHandler();
        EventHandler.setInputHandler(this, this.eventInput);
        this.eventOutput = new EventHandler();
        EventHandler.setOutputHandler(this, this.eventOutput);

        this.header = new Surface({
            content: '<button class="left back-button">Back</button><div>' + options.title + ' Contacts</div>',
            classes: ['header'],
            size: [undefined, 50],
            properties: {
            }
        });
        this.content = new SocialView({
            collection: this.collection
        });

        this.id.header.link(this.header);
        this.id.content.link(this.content);

        this.header.pipe(this.eventOutput);
        this.content.pipe(this.eventOutput);

        this.header.on('click', function(e) {
            var target = $(e.target);
            if (target.hasClass(".edit-button")) {
                this.submitForm();
            }
        }.bind(this));

        this.header.on('click', function(e){
            if ($(e.target).hasClass('back-button'))
                this.eventOutput.emit('goBack');
        }.bind(this));

        this.header.pipe(this.eventOutput);

    }
Example #21
0
define(function(require, exports, module) {
    var Engine = require('famous/Engine');
    var LightBox = require('famous-views/LightBox');
    var EventHandler = require('famous/EventHandler');

    var context;
    var eventOutput = new EventHandler();

    var Modal = {
        lightBox: new LightBox()
    };

    EventHandler.setOutputHandler(Modal, eventOutput);

    Modal.setOptions = function(options) {
        this.lightBox.setOptions(options);
    };

    Modal.getOptions = function() {
        return this.lightBox.getOptions();
    };

    Modal.show = function(target, transition) {
        if(!context) {
            context = Engine.createContext();
            context.link(this.lightBox);
        }
        this.lightBox.show(target, transition, function() {
            eventOutput.emit('show');
        }.bind(this));
    };

    Modal.hide = function(transition) {
        this.lightBox.hide(transition, function() {
            eventOutput.emit('hide');
        }.bind(this));
    };

    module.exports = Modal;
});
    function IncomingCallView(options) {
        View.call(this);
        this.collection = options.collection;

        // Set up event handlers
        this.eventInput = new EventHandler();
        EventHandler.setInputHandler(this, this.eventInput);
        this.eventOutput = new EventHandler();
        EventHandler.setOutputHandler(this, this.eventOutput);

        this.headerLightBox = new LightBox({
            inTransition:false,
            outTransition:false,
            showOrigin: [0.5, 0.1]
        });

        this.footerLightBox = new LightBox({
            inTransform: Matrix.translate(0, 900, 0),
            inTransition: {duration: duration, curve: Easing.inQuadNorm()},
            inOpacity: 0,
            inOrigin: [0.5, 0.5],
            outTransform: Matrix.translate(0, 900, 0),
            outOpacity: 0,
            outOrigin: [0.5, 0.5],
            outTransition: {duration:duration, curve: Easing.outQuadNorm()},
            showTransform: Matrix.identity,
            showOpacity: 1,
            showOrigin: [0.5, 0.9]
        });

        this.header = new Surface({
            classes:['outgoing-call-view'],
            size: [undefined, 300],
            _origin:[0.5,-0.5],
            properties: {
                backgroundColor: 'transparent'
            }
        });

        var declineButton = Templates.button({
            classes:["decline-button", "big-button"],
            checked:true,
            content:'Decline',
            size:[160,70]
        })
        var answerButton = Templates.button({
            classes:["answer-button", "big-button"],
            checked:true,
            content:'Answer',
            size:[160,70]
        })

        this.footer = new Surface({
            classes: ['incoming-call-view-buttons'],
            size: [undefined, 80],
            properties: {
                backgroundColor: 'transparent'
            },
            content: '<div class="box">' + declineButton + answerButton + '</div>'
        });

        this._add(this.headerLightBox);
        this._add(this.footerLightBox);

        _.bindAll(this, 'template');
        this.collection.bind('add', this.template);

        this.ringtone = new SoundPlayer([
            'content/audio/ringtone.mp3'
        ]);

        this.footer.on('click', function(e) {
            var target = $(e.target);
            if (target.hasClass("decline-button")) {
                this.stop();
            }
            else if (target.hasClass("answer-button")) {
                this.accept();
            }
        }.bind(this));

        this.eventInput.on('incomingCall', function() {
//            console.log("incomingCall");
        });
        this.eventInput.on('incomingCallAnswerClick', function() {
            this.accept();
        }.bind(this));
    }
Example #23
0
    function AlertView(message, okHidden) {
        View.call(this);
        // Set up event handlers
        this.eventInput = new EventHandler();
        EventHandler.setInputHandler(this, this.eventInput);
        this.eventOutput = new EventHandler();
        EventHandler.setOutputHandler(this, this.eventOutput);

        this.options = {
            inTransform: Matrix.identity,
//            inOpacity: 1,
//            inOrigin: [0.5, 0.5],
            outTransform: Matrix.identity,
//            outOpacity: 1,
//            outOrigin: [0.5, 0.5],
            showTransform: Matrix.identity,
//            showOpacity: 1,
//            showOrigin: [0.5, 0.5],
            inTransition: {duration: 100},
            outTransition: {duration: 100},
            overlap: true
        };


        this.bigSurface = new Surface({
            size: [undefined, undefined],
            properties:{
                background: "rgba(0,0,0,0.5)",
                zIndex: 1000
            }
        });
        this.alertSurface = new Surface({
            classes:['alert'],
            size: [340, 220],
            properties:{
                borderRadius: "10px",
                background: "rgba(59, 59, 59, 0.90)",
                color: 'rgba(245, 236, 236,1)',
//                textAlign: "center",
                zIndex:1001
            }
        });

        this.alertLightBox = new LightBox({
            inTransform: Matrix.identity,
            inOpacity: 0.1,
            inOrigin: [0.5, 0.45],
            outTransform: Matrix.scale(0.001,0.001,0.001),
            outOpacity: 1,
            outOrigin: [0.5, 0.45],
            showTransform: Matrix.identity,
            showOpacity: 1,
            showOrigin: [0.5, 0.45],
            inTransition: {duration: 200, curve: Easing.inQuadNorm()},
            outTransition: {duration: 100, curve: Easing.outQuintNorm()},
        });

        this.setAlertMessage(message, okHidden);

        this._add(this.bigSurface);
        this._add(this.alertLightBox);

        this.alertLightBox.show(this.alertSurface);
    }
Example #24
0
    /**
     * @class Lays out the sequenced renderables sequentially and makes them scrollable.
     * @description Items outside the viewport are automatically culled.
     * @name Scrollview
     * @constructor
     * @example 
     *   var myScrollview = new Scrollview({
     *       itemSpacing: 20
     *   });
     * 
     *   var mySequence = new ViewSequence();
     *   for(var i = 0; i < 50; i++) {
     *       surfaces.push(new Surface({content: 'Item ' + i}));
     *   }
     *   myScrollview.sequenceFrom(surfaces); // link items into scrollview
     *
     *   Engine.pipe(myScrollview); // let events on root window control the scrollview
     *   myContext.link(myScrollview); // link scrollview into myContext
     */
    function Scrollview(options) {
        this.options = {
            direction: Utility.Direction.Y,
            rails: true,
            itemSpacing: 0,
            clipSize: undefined,
            margin: undefined,
            friction: 0.001,
            drag: 0.0001,
            edgeGrip: 0.5,
            edgePeriod: 300,
            edgeDamp: 1,
            paginated: false,
            pagePeriod: 500,
            pageDamp: 0.8,
            pageStopSpeed: Infinity,
            pageSwitchSpeed: 1,
            speedLimit: 10
        };

        this.node = null;

        this.physicsEngine = new PhysicsEngine();
        this.particle = new Particle();
        this.physicsEngine.addBody(this.particle);

        this.spring = new Spring({anchor: [0, 0, 0]});

        this.drag = new Drag({forceFunction: Drag.FORCE_FUNCTIONS.QUADRATIC});
        this.friction = new Drag({forceFunction: Drag.FORCE_FUNCTIONS.LINEAR});

        this.sync = new GenericSync((function() {
            return -this.getPosition();
        }).bind(this), {direction: (this.options.direction == Utility.Direction.X) ? GenericSync.DIRECTION_X : GenericSync.DIRECTION_Y});
        
        this.eventInput = new EventHandler();
        this.eventOutput = new EventHandler();

        this.rawInput = new EventHandler();
        this.rawInput.pipe(this.sync);
        this.sync.pipe(this.eventInput);
        this.sync.pipe(this.eventOutput);
        this.rawInput.pipe(this.eventInput);

        EventHandler.setInputHandler(this, this.rawInput);
        EventHandler.setOutputHandler(this, this.eventOutput);

        this._outputFunction = undefined;
        this._masterOutputFunction = undefined;
        this.setOutputFunction(); // use default

        this.touchCount = 0;
        this._springAttached = false;
        this._onEdge = 0; // -1 for top, 1 for bottom
        this._springPosition = 0;
        this._touchVelocity = undefined;
        this._earlyEnd = false;

        this._masterOffset = 0; // minimize writes
        this._lastFrameNode = undefined;
        
        if(options) this.setOptions(options);
        else this.setOptions({});

        _bindEvents.call(this);

        this.group = new Group();
        this.group.link({render: _innerRender.bind(this)});

        this._entityId = Entity.register(this);
        this._contextSize = [window.innerWidth, window.innerHeight];

        this._offsets = {};
    }
Example #25
0
    /**
     * @constructor
     */
    function Scrollview(options) {
        this.options = {
            direction: Utility.Direction.Y,
            rails: true,
            defaultItemSize: [100, 100],
            itemSpacing: 0,
            clipSize: undefined,
            margin: undefined,
            drag: 0.001,
            friction: 0.00005,
            edgeGrip: 0.5,
            edgeFirmness: 0.0001,
            edgeDamp: 1,
            paginated: false,
            pageFirmness: 0.0002,
            pageDamp: 0.8,
            pageStopSpeed: Infinity,
            pageSwitchSpeed: 1,
            speedLimit: 10
        };

        this.energyHelper = new EnergyHelper(0);
        this.sync = new GenericSync((function() {
            return -this.getPos();
        }).bind(this), {direction: (this.options.direction == Utility.Direction.X) ? GenericSync.DIRECTION_X : GenericSync.DIRECTION_Y});
        
        this.eventInput = new EventHandler();
        this.eventOutput = new EventHandler();
        this.sync.pipe(this.eventInput);
        this.sync.pipe(this.eventOutput);

        EventHandler.setOutputHandler(this, this.eventOutput);

        this._outputFunction = undefined;
        this._masterOutputFunction = undefined;
        this.setOutputFunction(); // use default

        this.touchCount = 0;
        this.springAttached = false;
        this.currSpring = undefined;
        this._onEdge = 0; // -1 for top, 1 for bottom
        this.edgeSpringPos = undefined;
        this._touchVel = undefined;
        this._earlyEnd = false;

        // will be defined in setOptions
        this.drag = undefined;
        this.friction = undefined;
        this.edgeSpring = undefined;
        this.endSpring = undefined;

        this._masterOffset = 0; // minimize writes
        this._lastFrameNode = undefined;
        
        if(options) this.setOptions(options);
        else this.setOptions({});

        _bindEvents.call(this);

        this.group = new Group();
        this.group.link({render: _innerRender.bind(this)});

        this._entityId = Entity.register(this);
        this._contextSize = [window.innerWidth, window.innerHeight];
    }
Example #26
0
    function MainController() {
        // Set up event handlers
        this.eventInput = new EventHandler();
        EventHandler.setInputHandler(this, this.eventInput);
        this.eventOutput = new EventHandler();
        EventHandler.setOutputHandler(this, this.eventOutput);

        this.loadUser(function(data) {
            if (data.chatroom) {
                this.chatroom = data.chatroom;
                data.objectId = 'unknown';
                data.firstname = data.chatroom.calleeFirstName;
                data.lastname = data.chatroom.calleeLastName;
                data.username = data.chatroom.calleeName;
            }
            // Set up models and collections
            this.appSettings = new Settings({
                id: data.objectId
            });
            this.appSettings.fetch();
            this.appSettings.save({
                cid: data.objectId,
                email: data.email || "",
                firstname: data.firstname || data.username || "",
                lastname: data.lastname || "",
                username: data.username || ""
            });

            this.appSettings.me = data;
            this.appSettings = this.appSettings;

            this.contactCollection = new ContactCollection([], {
                firebase: this.appSettings.get('userDatabaseUrl') + this.appSettings.get('cid')+'/contacts'
            });
            this.recentCalls = new CallCollection();
            this.curCall = new Call();

            // Set up views
            var favoritesSection = new FavoritesSectionView({
                collection: this.contactCollection
            });
            var recentsSection = new RecentsSectionView({
                collection: this.recentCalls
            });
            var contactsSection = new ContactsSectionView({
                collection: this.contactCollection
            });
            var settingsSection = new SettingsSectionView({
                model: this.appSettings
            });
            favoritesSection.pipe(this.eventOutput);
            this.eventInput.pipe(favoritesSection);
            recentsSection.pipe(this.eventOutput);
            this.eventInput.pipe(recentsSection);
            contactsSection.pipe(this.eventOutput);
            settingsSection.pipe(this.eventOutput);

            // Config and initialize app
            config.sections = [
                favoritesSection,
                recentsSection,
                contactsSection,
                settingsSection
            ];

            // create the App from the template
            var myApp = new App(config);
            var myLightbox = new LightBox({overlap:true});
            var alertLightbox = new LightBox({overlap:true});
            var addContactView = new AddContactView({collection: this.contactCollection});

            myApp.pipe(this.eventOutput);
            addContactView.pipe(this.eventOutput);
            var cameraView = new CameraView({});

            // create a display context and hook in the App
            var mainDisplay = FamousEngine.createContext();
            mainDisplay.add(cameraView);
            mainDisplay.add(myLightbox);
            mainDisplay.add(alertLightbox);
            myLightbox.show(myApp);
            FamousEngine.pipe(myApp);

            // start on the main section
            myApp.select(myApp.options.sections[2].title);

            var outgoingCallView = new OutgoingCallView({collection: this.recentCalls});
            var incomingCallView = new IncomingCallView({collection: this.recentCalls});
            var connectedCallView = new ConnectedCallView({collection: this.recentCalls});
            outgoingCallView.pipe(this.eventOutput);
            incomingCallView.pipe(this.eventOutput);
            connectedCallView.pipe(this.eventOutput);
            this.pipe(connectedCallView.eventInput);

            // events handling
            this.eventOutput.on('callEnd', onCallEnd);
            this.eventOutput.on('incomingCall', onIncomingCall);
            this.eventOutput.on('outgoingCall', onOutgoingCall);
            this.eventOutput.on('connectedCall', onConnectedCall);
            this.eventOutput.on('outGoingCallAccept', onOutGoingCallAccept);
            this.eventOutput.on('editContact', onEditContact);
            this.eventOutput.on('showApp', onShowApp);
            this.eventOutput.on('chatOn', onChatOn);
            this.eventOutput.on('chatOff', onChatOff);
            this.eventOutput.on('loadRecent', onLoadRecent);
            this.eventOutput.on('clearRecent', onClearRecent);
            this.eventOutput.on('deleteRecent', onDeleteRecent);
            this.eventOutput.on('deleteFavorite', onDeleteFavorite);
            this.eventOutput.on('onEngineClick', onEngineClick);
            this.eventOutput.on('closeAlert', onCloseAlert);
            this.eventOutput.on('editContactDone', onEditContactDone);
            this.eventOutput.on('addContactDone', onAddContactDone);
            this.eventOutput.on('triggerBackToNoneEditing',onTriggerBackToNoneEditing.bind(this));

            function onDeleteFavorite (model) {
                model.toggleFavorite();
            }

            function onDeleteRecent (model) {
                model.destroy();
            }

            function onEditContactDone (formContact){
//            this.contactCollection.add(formContact);
//            this.contactCollection.trigger('sync');
            }

            function onAddContactDone (formContact){
//                this.contactCollection.add(formContact);
//                this.contactCollection.trigger('sync');
            }

            function onLoadRecent (e){
                recentsSection.setMissOnly(e.target.outerText);
                recentsSection.loadContacts();
            }

            function onClearRecent (e){
                recentsSection.clearContact();
                recentsSection.loadContacts();
            }

            function onShowApp(eventData) {
                var callback;
                if (eventData instanceof Function) {
                    callback = eventData;
                }
                $('.camera').addClass('blur');
                myLightbox.show(myApp, true, callback);
            }

            function onOutGoingCallAccept() {
                outgoingCallView.accept();
            }

            function onConnectedCall(eventData) {
                var callback;
                if (eventData instanceof Function) {
                    callback = eventData;
                }
                connectedCallView.start(this.appSettings);
                myLightbox.show(connectedCallView, true, callback);
                this.eventOutput.emit('chatOn');
                if (!this.localStream){
                    alert("Please allow camera/microphone access for Beepe");
                }
            }

            function onOutgoingCall(eventData) {
                outgoingCallView.start(eventData, this.appSettings);
                myLightbox.show(outgoingCallView, true);
            }

            function onIncomingCall(eventData) {
                if (this.appSettings.get('notification')) {
                    var myNotification = new Notify('Incoming Call From', {
                        icon: 'famous-time/content/ios_icon_x144.png',
                        body: eventData.get('firstname') + ' ' + eventData.get('lastname'),
                        notifyShow: onShowNotification.bind(this),
                        notifyClose: onCloseNotification.bind(this),
                        notifyClick: onClickNotification.bind(this)
                    });
                    function onShowNotification() {
                    }
                    function onCloseNotification() {
                        parent.focus();
                    }
                    function onClickNotification() {
                        parent.focus();
                    }
                    myNotification.show();
                }

                var curView = myLightbox.nodes[0].get();
                if (curView instanceof IncomingCallView || curView instanceof ConnectedCallView)
                    return;
                if (curView instanceof OutgoingCallView) {
                    outgoingCallView.accept();
                    this.eventOutput.emit('incomingCallAnswer', eventData);
                }
                else {
                    incomingCallView.start(eventData);
                    myLightbox.show(incomingCallView, true);
                }
            }

            function onCallEnd(eventData) {

                this.eventOutput.emit('chatOff');
                // ligntbox shown object stop
                var curView = myLightbox.nodes[0].object;
                if (curView instanceof IncomingCallView || curView instanceof ConnectedCallView) {
                    curView.stop();
                }
                if (this.chatroom) {
                    var url = '/login?r=' + this.chatroom.objectId;
                    if (this.chatroom.callerName) {
                        url += '&fn=' + this.chatroom.callerName;
                    }
                    window.location = url;
                }
            }

            function onEditContact(eventData) {
                if (eventData instanceof Contact || eventData instanceof Call) addContactView.setContact(eventData);
                else addContactView.setContact(undefined);
                addContactView.renderContact();
                myLightbox.show(addContactView, true);
            }

            function onChatOn() {
                cameraView.turnOn();
            }

            function onChatOff() {
                cameraView.turnOff();
            }

            FamousEngine.on('click', onEngineClick.bind(this));
            function onEngineClick(e) {
                switch (e.target.id)
                {
                    case 'clear-button':
                        this.eventOutput.emit('clearRecent');
                        break;
                    case 'add-contact':
                        this.eventOutput.emit('editContact');
                        break;
                    case 'recent-edit-contact':
                        $('body').toggleClass('editing');
                        this.eventInput.emit('toggleAllRecent');
                        break;
                    case 'favorite-edit-contact':
                        $('body').toggleClass('editing');
                        this.eventInput.emit('toggleAllFavorite');
                        break;
                    case 'contact-edit-contact':
                        $('body').toggleClass('editing');
                        break;
                    case 'recent-toggle':
                        this.eventOutput.emit('loadRecent', e);
                        break;
                    case 'close-alert':
                        this.eventOutput.emit('closeAlert');
                }
            }

            function onTriggerBackToNoneEditing(e) {
                this.eventInput.emit('backToNoneEditing');
            }

            function onAlert(word, okHidden){
                var alertView = new AlertView(word, okHidden);
                alertLightbox.show(alertView,true);
            }

            function onCloseAlert(){
                alertLightbox.hide();
            }

            window.alert = onAlert;
            if (this.chatroom) alert('Please allow Beepe to use your camera/microphone for phone calls.', true);

            // fastclick hack
            $('body').on('click', 'input', function(e) {
                $(e.target).focus();
            });

            this.init();


              window.colabeo = this;
//            window.myLightbox = myLightbox;
//        colabeo.recentsSection = recentsSection;
//        colabeo.contactsSection = contactsSection;
                colabeo.favoritesSection = favoritesSection;
//        colabeo.cameraView = cameraView;
//            colabeo.addContactView = addContactView;
//            colabeo.connectedCallView = connectedCallView;
//        colabeo.app = myApp;
//        colabeo.engine = FamousEngine;
//        colabeo.social = {};


        }.bind(this));
    }
Example #27
0
    function AddContactView(options) {
        View.call(this);
        window.addContactView = this;
        this.formObject = {};
        this.social = {};
        this.headerFooterLayout = new HeaderFooterLayout({
            headerSize: 50,
            footerSize: 0
        });
        var upDownTransform = new UpDownTransform;

        if(options.inTransform === undefined) this.options.inTransform = upDownTransform.options.inTransform;
        if(options.outTransform === undefined) this.options.outTransform = upDownTransform.options.outTransform;
        if(options.inTransition === undefined) this.options.inTransition = upDownTransform.options.inTransition;
        if(options.outTransition === undefined) this.options.outTransition = upDownTransform.options.outTransition;
        if(options.inOpacity === undefined) this.options.inOpacity = upDownTransform.options.inOpacity;
        if(options.outOpacity === undefined) this.options.outOpacity = upDownTransform.options.outOpacity;
        this.options.showOrigin = [0,0];
        this.options.inOrigin = [0,0];
        this.options.outOrigin = [0,0];

        this.model = options.model;

        // Set up event handlers
        this.eventInput = new EventHandler();
        EventHandler.setInputHandler(this, this.eventInput);
        this.eventOutput = new EventHandler();
        EventHandler.setOutputHandler(this, this.eventOutput);

        this.header = new Surface({
            classes: ['header'],
            size: [undefined, 50],
            properties: {
            }
        });
        this.content = new Surface({
            classes: ['add-contact-view'],
            size: [undefined, undefined],
            properties: {
                'padding': '20px',
                backgroundColor: 'transparent'
            }
        });

        this.headerFooterLayout.id.header.link(this.header);
        this.headerFooterLayout.id.content.link(this.content);

        var edgeSwapper = new EdgeSwapper();

        this._link (edgeSwapper);
        edgeSwapper.show(this.headerFooterLayout);

        this.content.pipe(this.eventOutput);
        this.header.pipe(this.eventOutput);

        this.renderContact();

        this.header.on('click', function(e) {
            var target = $(e.target);
            if (target.hasClass("done-contact")) {
                this.submitForm();
                $('body').removeClass('editing');
                this.eventOutput.emit('triggerBackToNoneEditing');
                this.eventOutput.emit('showApp');
            } else if (target.hasClass("close-button")){
                this.eventOutput.emit('showApp');
            }
        }.bind(this));

        this.collection = options.collection;

        this.content.on('click', function(e){
            var target = $(e.target);
            if (target.hasClass('import-contact')){
                var source = target[0].id;
                if (!this.social[source]) {
                    this.social[source] = new SocialContactCollection();
                    this.social[source].url = '/contact/'+source;
                    this.social[source].fetch({
                        success : onDataHandler.bind(this),
                        error: onErrorHandler.bind(this)
                    });
                } else {
                    onDataHandler.bind(this)();
                }
                function onDataHandler() {
                    if (_.isArray(this.social[source].models)) {
                        //TODO: pull collections from server
                        var newSocialView = new ImportContactView({
                            title: _(source).capitalize(),
                            collection: this.social[source]});
                        newSocialView.pipe(this.eventOutput);
                        edgeSwapper.show(newSocialView, true);
                    }
                }
                function onErrorHandler() {
                    this.eventOutput.emit('onSocialLink', source);
                    delete this.social[source];
//                    alert("Go to Settings and link before adding " + _(source).capitalize() + " contact.");
                }

            } else if (target.hasClass('remove-button')){
                var source = target[0].id;
                if (source)
                    delete this.formObject[source];
                this.renderContact();
            }
        }.bind(this));

//        this.eventOutput.on('importSource', onImportSource);
        this.eventOutput.on('goBack', onGoBack);

        function onImportSource(eventData){
            if (!eventData || !eventData.attributes) return;
            this.getFormObject();
            if (eventData.attributes.provider) {
                this.formObject[eventData.attributes.provider] = eventData.attributes;
            } else {
                this.formObject = _.extend(this.formObject, eventData.attributes);
            }
            this.formObject.firstname = this.formObject.firstname?this.formObject.firstname:eventData.attributes.firstname;
            this.formObject.lastname = this.formObject.lastname?this.formObject.lastname:eventData.attributes.lastname;
            this.formObject.email = this.formObject.email?this.formObject.email:eventData.attributes.email;
            this.renderContact();
        }

        function onGoBack(eventData){
            edgeSwapper.show(this.headerFooterLayout, true, function() {
                onImportSource.bind(this)(eventData);
            }.bind(this));
        }
    }
Example #28
0
    Playlist.prototype.importCards = function() {
        //Set up event handlers
        this.eventInput = new EventHandler();
        EventHandler.setInputHandler(this, this.eventInput);  // binds certain methods of event handler to module so can do things like module.pipe and module.on outside of the module.  Pipe() is how you send things.  
        this.eventOutput = new EventHandler();
        EventHandler.setOutputHandler(this, this.eventOutput);  // if want surface to react while outside module, do this.eventOutput.on('event', callback)

        var spacing = 50;   //spacing between particles on grid
        var N = this.collection.models.length;   //number of particles.   is all in collection
        this.particleRadius = 1;

        //force strengths
        var rodStiffness    = 0.7;
        var gravityStrength = 0.006;  // if higher than zero, unanchor bottom row
        var dragStrength    = 0.005;

        //grid parameters
        this.Nrows = 5; // Math.floor(Math.sqrt(N)) to make more dynamic
        this.Ncols = 5; // fixed number of columns to fit screen

        var width = (this.Ncols-1) * spacing;
        var height = (this.Nrows-1) * spacing;

        var marginX = -width/2;
        var marginY = -height/2;

        //creates particle grid
        var grid = [[]];
        for (var row = 0; row < this.Nrows; row++){
            
            grid[row] = [];
            var y = marginY + spacing * row;
            
            for (var col = 0; col < this.Ncols; col++){
                
                var x = marginX + spacing * col;
                var p = [x,y,0];

                var particle = PE.createBody({  // particle not being shown; add surface for content
                    m : 2,
                    shape : PE.BODIES.CIRCLE,
                    r : 30,
                    classes: ['imageParticles'],
                    p : p
                });

                var particleSurface = new Surface({
                    size : [20, 20],
                    content: '<img class="savedImage" src="' + this.collection.models[row*this.Ncols + col+1].get('imageUrl') + '"< />',
                    classes: ['savedImage']
                });

                surfaceArray.push(particleSurface);
                particle.add(particleSurface);

                // this.physicsTracker = new PhysicsTracker(particle);
                // particleSurface.pipe(this.physicsTracker);

                grid[row][col] = particle;
            };
        };

        //creates additional surface to reduce load lag
        var particleSurface = new Surface({
                    size : [20, 20],
                    content: '<img class="savedImage" src="' + this.collection.models[this.Nrows*this.Ncols+1].get('imageUrl') + '"< />',
                    classes: ['savedImage']
                });
        surfaceArray.push(particleSurface);

        //current constraint being used
        var rod = new Rod({
            length : spacing,
            stiffness : rodStiffness
        });

        //apply constraint to grid
        var particleRight, particleDown, particleCenter;
        for (var row = 0; row < this.Nrows; row++){
            for (var col = 0; col < this.Ncols; col++){   
                particleCenter = grid[row][col];
                
                if (row < this.Nrows-1) {
                    particleDown  = grid[row+1][col];
                    PE.attach(rod,  particleDown, particleCenter);
                };

                if (col < this.Ncols-1) {
                    particleRight = grid[row][col+1];
                    PE.attach(rod, particleRight, particleCenter);
                };
            };
        };

        //anchor top particles by setting their immunity to true
        for (var col = 0; col < this.Ncols; col++) {
            grid[0][col].setImmunity(Particle.IMMUNITIES.ALL);
        };

        this.gravity = new VectorField({
            field : VectorField.FIELDS.CONSTANT,
            strength : gravityStrength
        });

        this.drag = new Drag({strength : dragStrength});
        this.walls = new Walls({restitution : 0});

        PE.attach([this.gravity, this.drag, this.walls]);

        var physicsNode = new RenderNode();
        physicsNode.link(new Modifier({
            origin : [.49,0],
            transform : FM.translate(-10, 220, 4)
        }))

        physicsNode.link(PE);
        this.containerSurface.add(physicsNode);
        particleSurface.pipe(this.eventOutput);
    };
Example #29
0
 function _createEventOutput() {
     this.eventOutput = new EventHandler();
     this.eventOutput.bindThis(this);
     EventHandler.setOutputHandler(this, this.eventOutput);
 };
Example #30
0
    /**
     * @name SelectionBall
     * @constructor
     * To be deleted.
     */
    function SelectionBall(items, options) {
        this.options = {
            radius: undefined,
            zoomDistance: 0,
            spinDrag: 0.001,
            spinFriction: 1e-6,
            spinTightness: 0.0001,
            spinDamp: 0.8,
            recenterTightness: 0.001,
            recenterDamp: 5,
            zoomTransition: {duration: 1000, curve: 'easeInOut'},
            tileSize: [500, 500]
        };

        if(options) this.setOptions(options);

        if(!this.options.radius) {
            var tileArea = this.options.tileSize[0] * this.options.tileSize[1];
            var totalArea = items.length * tileArea;
            this.options.radius = Math.sqrt(totalArea / (Math.PI * 4));
        }

        this.zoom = new Transitionable(2*this.options.radius);
        this.shaper = new Shaper();

        this.scrollH = new EnergyHelper(0, 0, 0.01/this.options.radius);
        this.scrollV = new EnergyHelper(0, 0, 0.01/this.options.radius);
        var dragAgent = EnergyHelper.drag(this.options.spinDrag);
        var frictionAgent = EnergyHelper.friction(this.options.spinFriction);
        var recenterAgent = EnergyHelper.spring(0, this.options.recenterTightness, this.options.recenterDamp);

        this.eventInput = new EventHandler();
        this.eventOutput = new EventHandler();

        EventHandler.setInputHandler(this, this.eventInput);
        EventHandler.setOutputHandler(this, this.eventOutput);

        this.sync = new GenericSync((function() {
            return [this.scrollH.getPos(), this.scrollV.getPos()];
        }).bind(this), {
            scale: Math.PI/this.options.radius
        });
        this.sync.pipe(this.eventInput);

        this.eventInput.pipe(function(type, data) {
            if(type != 'start' && type != 'update' && type != 'end') {
                this.sync.emit(type, data); 
            }
        }.bind(this));

        this.eventInput.on('start', (function(data) {
            this.scrollH.setAgents([]);
            this.scrollH.setVelo(0);
            this.scrollV.setAgents([]);
            this.scrollV.setVelo(0);
        }).bind(this));
        this.eventInput.on('update', (function(data) {
            this.scrollH.setPos(data.p[0]);
            
            var vPos = data.p[1];
            if(vPos < -0.2*Math.PI) vPos = Math.min(-0.2*Math.PI, this.scrollV.getPos());
            else if(vPos > 0.2*Math.PI) vPos = Math.max(0.2*Math.PI, this.scrollV.getPos());
            this.scrollV.setPos(vPos);
        }).bind(this));
        this.eventInput.on('end', (function(data) {
            this.scrollH.setVelo(data.v[0]);
            this.scrollH.setAgents([dragAgent, frictionAgent]);
            this.scrollV.setVelo(data.v[1]);
            this.scrollV.setAgents([dragAgent, frictionAgent, recenterAgent]);
        }).bind(this));

        var sphereAngles = _generateSphereAngles(items.length, this.options.radius, this.options.tileSize);
        var sphereShape = _sphereAnglesToShape(sphereAngles, this.options.radius);

        for(var i = 0; i < items.length; i++) {
            this.shaper.side(i).from(items[i]);
            items[i].on('click', (function(i) {
                var spinTarget = -sphereAngles[i][1];
                var spinStart = this.scrollH.getPos() % (2*Math.PI);
                if(spinStart - spinTarget > Math.PI) this.scrollH.setPos(spinStart - 2*Math.PI);
                if(spinStart - spinTarget < -Math.PI) this.scrollH.setPos(spinStart + 2*Math.PI);
                var spinAgent = EnergyHelper.spring(spinTarget, this.options.spinTightness, this.options.spinDamp);
                this.scrollH.setAgents([spinAgent]);

                var tiltTarget = sphereAngles[i][0];
                var tiltAgent = EnergyHelper.spring(tiltTarget, this.options.spinTightness, this.options.spinDamp);
                this.scrollV.setAgents([tiltAgent]);

                this.zoom.set(this.options.radius + this.options.zoomDistance, this.options.zoomTransition, this.eventOutput.emit.bind(this.eventOutput, 'select', {id: i}));
            }).bind(this, i));
        }
        this.shaper.setShapeAll(sphereShape);
    };