# HG changeset patch # User Sean Halle # Date 1417984680 28800 # Node ID a8e5e71adcf3bb811f0402e5db4b9b77ec69911c # Parent cc10d99e3f83f734356610fa4bcf930d84b91c69 Maintenance.. been a while.. lots of stuff diff -r cc10d99e3f83 -r a8e5e71adcf3 1__Development/0__Code_Dev/ExecutionEngine/POP_runtime__w_TestApp__ML_lib__proj/RUNME.sh --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/1__Development/0__Code_Dev/ExecutionEngine/POP_runtime__w_TestApp__ML_lib__proj/RUNME.sh Sun Dec 07 12:38:00 2014 -0800 @@ -0,0 +1,6 @@ +#!/bin/bash + +export PATH=$PATH:./dist/bin +export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:./PR__lib + +./dist/bin/dku__test_app diff -r cc10d99e3f83 -r a8e5e71adcf3 1__Development/0__Code_Dev/ExecutionEngine/POP_runtime__w_TestApp__ML_lib__proj/__Checklist_for_project.txt --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/1__Development/0__Code_Dev/ExecutionEngine/POP_runtime__w_TestApp__ML_lib__proj/__Checklist_for_project.txt Sun Dec 07 12:38:00 2014 -0800 @@ -0,0 +1,66 @@ + +This file is used as a helper just before creating a .zip and posting it to the OpenSourceResearchInstitute.org (OSRI) website as a downloadable project. + +Details to check: (mark them off as go) + +(Before creating .zip and uploading) +Check: +-] README is up to date +-] README that specializes to circumstances of this project is up to date +-] This file is up to date + +-] All repositories are: +-] committed locally, to capture local changes +-] pulled and merged, to get updates from other projects +-] pushed, to publish changes from this project +- -] PR__lib +- -] PR__include +- -] language implementation +- -] Application +- - -] Input and output directories +- -] top level project repository + +(After creating .zip, publishing on OSRI site, and switching over to a guest VM that has different paths and different numbers of cores.. perhaps diff machine) + +Check: +-] .zip of target final version is created +-] .zip is uploaded to OSRI site +-] Are in a guest VM +-] download .zip from OSRI site +-] unzip it + +Check: +-] make works from command line (in guest VM) +- -] C_Libraries +- -] proto-runtime as application +- -] proto-runtime as library, normal +- - -] the .so has "normal" naming +- - -] The .so is automatically moved to PR__lib directory + +- -] proto-runtime as library, debug mode +- - -] the .so has "debug" naming +- - -] The .so is automatically moved to PR__lib directory + +- -] language impl as application +- -] language impl as library, normal +- - -] the .so has "normal" naming +- - -] The .so is automatically moved to PR__lib directory + +- -] language impl as library, debug mode +- - -] it links to the debug version of proto-runtime +- - -] The .so is automatically moved to PR__lib directory + +- -] application, normal +- - -] the executable has "normal" naming +- - -] the executable is automatically moved to the dist/bin directory + +- -] application, debug mode +- - -] it links to debug version of language +- - -] it links to debug version of proto-runtime +- - -] the executable has "debug" naming +- - -] the executable is automatically moved to the dist/bin directory + +Check: +-] The RUNME.sh runs and gives correct results +-] The RUNME_debug.sh runs and gives correct results + diff -r cc10d99e3f83 -r a8e5e71adcf3 1__Development/0__Code_Dev/ExecutionEngine/POP_runtime__w_TestApp__ML_lib__proj/application__POP_Test_App/.hgeol --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/1__Development/0__Code_Dev/ExecutionEngine/POP_runtime__w_TestApp__ML_lib__proj/application__POP_Test_App/.hgeol Sun Dec 07 12:38:00 2014 -0800 @@ -0,0 +1,14 @@ + +[patterns] +**.py = native +**.txt = native +**.c = native +**.h = native +**.cpp = native +**.java = native +**.class = bin +**.jar = bin +**.sh = native +**.pl = native +**.jpg = bin +**.gif = bin diff -r cc10d99e3f83 -r a8e5e71adcf3 1__Development/0__Code_Dev/ExecutionEngine/POP_runtime__w_TestApp__ML_lib__proj/application__POP_Test_App/.hgignore --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/1__Development/0__Code_Dev/ExecutionEngine/POP_runtime__w_TestApp__ML_lib__proj/application__POP_Test_App/.hgignore Sun Dec 07 12:38:00 2014 -0800 @@ -0,0 +1,12 @@ +nbproject +Makefile +build +dist +src/Default +src/.settings +src/.cproject +src/.project +.dep.inc +glob:.cproject +glob:.project +glob:Debug diff -r cc10d99e3f83 -r a8e5e71adcf3 1__Development/0__Code_Dev/ExecutionEngine/POP_runtime__w_TestApp__ML_lib__proj/application__POP_Test_App/14_Nv_22___TestApp.odg Binary file 1__Development/0__Code_Dev/ExecutionEngine/POP_runtime__w_TestApp__ML_lib__proj/application__POP_Test_App/14_Nv_22___TestApp.odg has changed diff -r cc10d99e3f83 -r a8e5e71adcf3 1__Development/0__Code_Dev/ExecutionEngine/POP_runtime__w_TestApp__ML_lib__proj/application__POP_Test_App/App_Design_Notes.txt --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/1__Development/0__Code_Dev/ExecutionEngine/POP_runtime__w_TestApp__ML_lib__proj/application__POP_Test_App/App_Design_Notes.txt Sun Dec 07 12:38:00 2014 -0800 @@ -0,0 +1,44 @@ + +This test app is a wrapper that just creates the data structures of a POP +execution graph. + +A node contains a fn pointer to the C code of a primitive POP operation. + +The primitive operations are inside the POP library. + +A node also contains an array of input ports and an array of output ports. + +Lastly, a node has a pre-pended set of data used by the runtime system, for + tracking where it is within the process of spanning the graph while + going upstream to fill empty inputs. + +======================= +The graph built by this code performs a summation, of X*X, from +1 to 10 + +The original code is the summation sign, which is defined as a from-into + where the into is the "..." primitive, and the body is "X*X", with + the iteration substituted into the two X variable positions. + +This means that the "..." node has a sub-graph of the "X*X" that it + provides inputs to. For first shot, just make both "X" positions be input + ports. So, one output from the "..." goes to two inputs in the "X*X" node. + +In the first version of the POP execution engine, it looks like the "..." + is implemented such that it calls a separate "execute this subgraph" + function on the body. That body could, in turn, contain more "..." + primitives, and those in turn call "execute this subgraph" on their bodies. + +What this means for this "compiled" execution graph is that the body of a + "..." primitive must be a distinct sub-graph that has no connections that + manage to wrap around and relate to or affect or act as ancestors to the + input to the "..." primitive. + +Here, we will build a graph whose root node is a hierarchy node. It takes + + the primitive "*", and the + return value from that is the return value of the sub-graph that the "..." + primitive executed. + + + diff -r cc10d99e3f83 -r a8e5e71adcf3 1__Development/0__Code_Dev/ExecutionEngine/POP_runtime__w_TestApp__ML_lib__proj/application__POP_Test_App/POP__Test_App/POP__Test_App.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/1__Development/0__Code_Dev/ExecutionEngine/POP_runtime__w_TestApp__ML_lib__proj/application__POP_Test_App/POP__Test_App/POP__Test_App.h Sun Dec 07 12:38:00 2014 -0800 @@ -0,0 +1,44 @@ +/* + * Copyright Oct 24, 2009 OpenSourceResearchInstitute.org + * Licensed under GNU General Public License version 2 + */ + +#ifndef _POP_TEST_APP_H_ +#define _POP_TEST_APP_H_ + +#include + +#include "../PR_defs__turn_on_and_off.h" +#include +#include + +//=============================== Defines ============================== + +//============================== Structures ============================== + +typedef struct + { + int32 *data; + } +SeedParams; + +typedef struct + { + int32 start; + int32 end; + int32 *data; + } +TaskParams; + +//============================= Processor Functions ========================= +void test_app_seed_Fn( void *data, SlaveVP *animatingSlv ); //seed VP function +void task_birthFn( void *_params, SlaveVP *animVP ); + + +//================================ Entry Point ============================== +void +POP__Test_App( ); + +//================================ Global Vars ============================== + +#endif /*_SSR_MATRIX_MULT_H_*/ diff -r cc10d99e3f83 -r a8e5e71adcf3 1__Development/0__Code_Dev/ExecutionEngine/POP_runtime__w_TestApp__ML_lib__proj/application__POP_Test_App/POP__Test_App/SeedVP.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/1__Development/0__Code_Dev/ExecutionEngine/POP_runtime__w_TestApp__ML_lib__proj/application__POP_Test_App/POP__Test_App/SeedVP.c Sun Dec 07 12:38:00 2014 -0800 @@ -0,0 +1,70 @@ +/* + * Copyright 2014 OpenSourceResearchInstitute.org + * Licensed under GNU General Public License version 2 + * + * Author: seanhalle@yahoo.com + * + */ + +#include +#include +#include "POP__Test_App.h" + + +/* +This code makes an execution graph. It creates the node data structs and + then connects them. + +The graph built by this code performs a summation, of X*X, from +1 to 10 + +The original source is the summation sign, which is defined as a from-into + where the into is the "..." primitive, and the body becomes "X*X", with + the iteration substituted into the two X variable positions. + +This means that the "..." node has a sub-graph of the "X*X" that it + provides inputs to. For first shot, just make both "X" positions be input + ports. So, one output port from the "..." goes to two input ports in the + "X*X" node. + */ +void +test_app_seed_Fn( void *_params, SlaveVP *seedVP ) + { + SeedParams *seedParams = (SeedParams *)_params; //used to comm with main() + + POP__start( seedVP ); //starts the PR_POP langlet + //can start additional languages here, and then freely mix "constructs" + // from them + + rootNode = createExeGraph(); + + POP__execute_graph( rootNode, params, seedVP ); + + //POP__wait_for_all_children_to_end( animSlv ); //bug prone -- children must do same + POP__wait_for_all_POP_created_work_to_end( seedVP ); + + seedParams->data = data; //sends results back to main() + + POP__shutdown( seedVP ); //Shuts down POP within the process + + //This ends the last live entity capable of work, in a process + // that has no external input ports.. hence, no activity can take place + // past that point.. PR detects that, and then automatically ends the + // process. + PR__end_seedVP( seedVP ); + } + +/* +Have a "..." node, with a sub-graph of "X*X" that it + provides inputs to. For first shot, just make both "X" positions be input + ports. So, one output port from the "..." goes to two input ports in the + "X*X" node. + */ +POPExeNode * +createExeGraph() { + + elipsisNode = PR__malloc( sizeof( POPExeNode ) + 3 * sizeof( POPInPort) + + 1 * sizeof( POPOutPort ) ); + elipsisBodyNode = PR__malloc( sizeof( POPExeNode ) + + 2 * sizeof( POPInPort) + 1 * sizeof( POPOutPort ) ); +} \ No newline at end of file diff -r cc10d99e3f83 -r a8e5e71adcf3 1__Development/0__Code_Dev/ExecutionEngine/POP_runtime__w_TestApp__ML_lib__proj/application__POP_Test_App/POP__Test_App/Task.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/1__Development/0__Code_Dev/ExecutionEngine/POP_runtime__w_TestApp__ML_lib__proj/application__POP_Test_App/POP__Test_App/Task.c Sun Dec 07 12:38:00 2014 -0800 @@ -0,0 +1,29 @@ +/* + * Copyright 2009 OpenSourceResearchInstitute.org + * Licensed under GNU General Public License version 2 + * + * Author: seanhalle@yahoo.com + * + */ + + +#include +#include +#include "POP__Test_App.h" + +int +square( int x ) + { return x*x; + } + +void task_birthFn( void *_params, SlaveVP *animVP ) + { int32 i; + TaskParams *params = (TaskParams *)_params; + int32 *data = params->data; + DEBUG__printf(TRUE, "Task %d", params->start); + for( i=params->start; i < params->end; ++i ) + { data[i] = square(i); + } + POP__end_task( animVP ); + } + diff -r cc10d99e3f83 -r a8e5e71adcf3 1__Development/0__Code_Dev/ExecutionEngine/POP_runtime__w_TestApp__ML_lib__proj/application__POP_Test_App/PR_defs__turn_on_and_off.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/1__Development/0__Code_Dev/ExecutionEngine/POP_runtime__w_TestApp__ML_lib__proj/application__POP_Test_App/PR_defs__turn_on_and_off.h Sun Dec 07 12:38:00 2014 -0800 @@ -0,0 +1,90 @@ +/* + * Copyright 2009 OpenSourceResearchInstitute.org + * Licensed under GNU General Public License version 2 + * + * Author: seanhalle@yahoo.com + * + */ + +#ifndef _PR_DEFS_TURN_ON_AND_OFF_H +#define _PR_DEFS_TURN_ON_AND_OFF_H +#define _GNU_SOURCE + + +#define MODE__MULTI_LANG + +//====================== Turn Debug things on and off ===================== +/*When DEBUG__TURN_ON_SEQUENTIAL_MODE is defined, PR does sequential exe in the main thread + * It still does co-routines and all the mechanisms are the same, it just + * has only a single thread and animates Slvs one at a time + */ +//#define DEBUG__TURN_ON_SEQUENTIAL_MODE + //check for sequential mode and redefine num cores to be 1 so that lang + // code doesn't have to do special #ifdef for sequential mode +#ifdef DEBUG__TURN_ON_SEQUENTIAL_MODE + #ifdef NUM_CORES + #undef NUM_CORES + #define NUM_CORES 1 + #endif +#endif + +/*turns on the probe-instrumentation in the application -- when not + * defined, the calls to the probe functions turn into comments + */ +#define DEBUG__TURN_ON_DEBUG_PRINT + +/*These defines turn types of bug messages on and off + */ +#define dbgAppFlow TRUE /* Top level flow of application code -- general*/ +#define dbgProbes FALSE /* for issues inside probes themselves*/ +#define dbgMaster FALSE /* obsolete*/ +#define dbgRqstHdlr TRUE /* in request handler code*/ +#define dbgSS FALSE /* in request handler code*/ +#define dbgInfra FALSE /* in request handler code*/ + +//#define DEBUG__TURN_ON_ERROR_MSGS + +//================== Turn Probe Things on and off ==================== +/*Probes are used in the application as a cheap, convenient, and fast way + * to collect statistics. Define this to enable them, else the probe + * statements in the application code all turn into empty whitespace + * in the pre-processor + */ +//#define PROBES__TURN_ON_STATS_PROBES + +/*When PROBES__TURN_ON_STATS_PROBES is defined, turn on one of these to choose + * what kind of measurement the probes store + */ +//#define PROBES__USE_TSC_PROBES +#define PROBES__USE_TIME_OF_DAY_PROBES +//#define PROBES__USE_PERF_CTR_PROBES + + +//============== Turn Internal Measurement Things on and off =============== + +//#define MEAS__TURN_ON_SUSP_MEAS +//#define MEAS__TURN_ON_MASTER_MEAS +//#define MEAS__TURN_ON_MASTER_LOCK_MEAS +//#define MEAS__TURN_ON_MALLOC_MEAS +//#define MEAS__TURN_ON_PLUGIN_MEAS +//#define MEAS__TURN_ON_SYSTEM_MEAS + /*turn on/off subtraction of create measurements from plugin meas*/ +//#define MEAS__TURN_ON_EXCLUDE_CREATION_TIME + + +//#define HOLISTIC__TURN_ON_PERF_COUNTERS +//#define HOLISTIC__TURN_ON_OBSERVE_UCC +//#define HOLISTIC__TURN_ON_DETECT_CONSTRAINT_GRAPH + +//=================== Turn on or off system options ======================= +// +/*Defining SYS__TURN_ON_WORK_STEALING causes the core controller behavior + * to change. When it detects too many back-to-back masters, then it + * searches the other core controllers, looking for work it can steal from + * them. + */ +//#define SYS__TURN_ON_WORK_STEALING + +//=========================================================================== +#endif /* */ + diff -r cc10d99e3f83 -r a8e5e71adcf3 1__Development/0__Code_Dev/ExecutionEngine/POP_runtime__w_TestApp__ML_lib__proj/application__POP_Test_App/__brch__POP_Dev --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/1__Development/0__Code_Dev/ExecutionEngine/POP_runtime__w_TestApp__ML_lib__proj/application__POP_Test_App/__brch__POP_Dev Sun Dec 07 12:38:00 2014 -0800 @@ -0,0 +1,1 @@ +Applications normally have only the default branch -- they shouldn't be affected by any choices in VMS or language.. diff -r cc10d99e3f83 -r a8e5e71adcf3 1__Development/0__Code_Dev/ExecutionEngine/POP_runtime__w_TestApp__ML_lib__proj/application__POP_Test_App/main.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/1__Development/0__Code_Dev/ExecutionEngine/POP_runtime__w_TestApp__ML_lib__proj/application__POP_Test_App/main.c Sun Dec 07 12:38:00 2014 -0800 @@ -0,0 +1,50 @@ +/* + * Copyright 2012 OpenSourceResearchInstitute.org + * Licensed under GNU General Public License version 2 + * + * author seanhalle@yahoo.com + */ + +#include +#include + +#include "POP__Test_App/POP__Test_App.h" +#include //declares PR__create_process + + +/*This demonstrates the use of the proto-runtime system. It allows multiple + * languages to be mixed within a single sub-program. It also allows multiple + * sub-programs to be started, where each uses its own set of languages. The + * running sub-programs can then communicate with each other. + * + */ +int main( int argc, char **argv ) + { PRProcess *testProcess1, *testProcess2; + + DEBUG__printf(TRUE, "arguments: %s | %s", argv[0], argv[1] ); + + //A proto-runtime based language sits on top of the proto-runtime. So, + // first start the proto-runtime system, then create processes (which + // start languages inside themselves) + PR__start(); + + //Now that PR is started, create processes. + //Each process creates a seedVP and starts it running -- that then starts + // the languages used inside the process.. + //To get results from a process, it gets complicated.. simple soln is + // just use PR's malloc and free, in the main thread, between PR__start + // and PR__shutdown + //The call returns a process struct (which has access to the seedVP) + int32 *result = PR__malloc( 2 * sizeof(int32) ); + testProcess1 = PR__create_process( &test_app_seed_Fn, result ); + + PR__wait_for_process_to_end( testProcess1 ); + printf("\n\nresults: %d, %d\n\n", result[0], result[1] ); + + PR__free(result); + + PR__wait_for_all_activity_to_end(); //equivalent of detecting shutdown + PR__shutdown(); + + exit(0); //cleans up + } diff -r cc10d99e3f83 -r a8e5e71adcf3 1__Development/0__Code_Dev/Javascript_approach/.idea/workspace.xml --- a/1__Development/0__Code_Dev/Javascript_approach/.idea/workspace.xml Sat Aug 09 03:34:26 2014 -0700 +++ b/1__Development/0__Code_Dev/Javascript_approach/.idea/workspace.xml Sun Dec 07 12:38:00 2014 -0800 @@ -2,11 +2,12 @@ - - - + + + + @@ -29,14 +30,14 @@ - + - - + + @@ -45,36 +46,9 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + @@ -82,8 +56,8 @@ - - + + @@ -92,65 +66,32 @@ - - + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + - + - - + + - - + - + - - + + @@ -159,8 +100,8 @@ - - + + @@ -169,8 +110,8 @@ - - + + @@ -193,31 +134,42 @@ - - + + + + + + + + + + + + + + - - + - + - - + + @@ -247,14 +199,14 @@ @@ -351,14 +303,6 @@ - - - - diff -r cc10d99e3f83 -r a8e5e71adcf3 1__Development/0__Code_Dev/Javascript_approach/9__misc/click_handler_error/famousEventBug.html --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/1__Development/0__Code_Dev/Javascript_approach/9__misc/click_handler_error/famousEventBug.html Sun Dec 07 12:38:00 2014 -0800 @@ -0,0 +1,30 @@ + + + + famo.us App + + + + + + + + + + + + + + + + + + diff -r cc10d99e3f83 -r a8e5e71adcf3 1__Development/0__Code_Dev/Javascript_approach/9__misc/click_handler_error/famous_event_bug.js --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/1__Development/0__Code_Dev/Javascript_approach/9__misc/click_handler_error/famous_event_bug.js Sun Dec 07 12:38:00 2014 -0800 @@ -0,0 +1,280 @@ + + +define(function(require, exports, module) { + var Engine = require("famous/core/Engine"); + var Surface = require("famous/core/Surface"); + var Modifier = require("famous/core/Modifier"); + var Transform = require('famous/core/Transform'); + var StateModifier = require('famous/modifiers/StateModifier'); + var ContainerSurface = require("famous/surfaces/ContainerSurface"); + var Scrollview = require("famous/views/Scrollview"); + + var mainContext = Engine.createContext(); + + var msgEl = document.createElement("div"); + msgEl.id = "msgEl"; + document.body.appendChild(msgEl); //only need to append once then reuse + + function clickHandler(e) { + var msg = "event: " + e.type + " target: " + e.origin.id; + msgEl.innerHTML = msg; + console.log(msg); + } + function keydownHdlr(e) { + var msg = "event: " + e.type + ' keyCode=' + keyval(e.keyCode); + msgEl.innerHTML = msg; + console.log(msg); + } + + +//=========================== + document.addEventListener("keydown",keydownHdlr,false); +// document.addEventListener("keypress",keypress,false); +// document.addEventListener("keyup",keyup,false); +// document.addEventListener("textInput",textinput,false); + + + +//=========================== + var el1 = document.createElement("div"); + document.body.appendChild(el1); //only need to append once then reuse + + //now set the SVG text string -- from this point down can be repeated + // for multiple strings without removing or re-adding the element, nor + // fiddling with the DOM + var text1_1_1_SVG = ' svg text for event '; + //note the id is inside the text element! Also the fill and stroke are + // null so nothing paints + el1.innerHTML = text1_1_1_SVG; + + //get the element -- this seems to be what triggers the bounding box calc + var test = document.getElementById("svgText1"); //use ID of the text elem +// test.addEventListener("keydown",keydown,false); + + //get the box, take the values out of it, and display them + var rect = test.getBoundingClientRect(); + var str = ""; + for (i in rect) { //a trick for getting all the attributes of the object + str += i + " = " + rect[i] + " "; + } + console.log("svgText1: " + str); + + el1.addEventListener("mouseover", + function(e) { +// msgEl.innerHTML = "mouse enter: " + e.charcode; + console.log("svg text mouse enter: "+e.type + " target: "+e)}); + + el1.addEventListener("mouseout", + function(e) { + console.log("svg text mouse out: "+e.type + " target: "+e); +// msgEl.innerHTML = "key down: " + e.charcode; + }); +// el1.addEventListener("click", +// function(e) { +// console.log("key press: "+e.type + " target: "+e); +// msgEl.innerHTML = "key press: " + e.charcode; +// }); + +//=========================== + +/* + var NS="http://www.w3.org/2000/svg"; + var svgEl = document.createElementNS(NS,"svg"); + document.body.appendChild( svgEl ); + var rect=function(h,w,fill){ + var NS="http://www.w3.org/2000/svg"; + var SVGObj= document.createElementNS(NS,"rect"); + SVGObj.width.baseVal.value=w; + SVGObj.height.baseVal.value=h; + SVGObj.setAttribute("height",h); + SVGObj.style.fill=fill; + return SVGObj; + } + var r= rect(100,100,"blue"); + svgEl.appendChild(r); +*/ + + var el4 = document.createElement("script"); + var overHdlr = function(e) { + var msg = "mouse over ele3: " + e.type + " target: " + e.currentTarget.viewBox.ID; + console.log(msg); + msgEl.innerHTML = msg; + } + var boxSVG = ' '; + var el3 = document.createElement("div"); + el3.viewBox = { + ID: 10 + } + el3.innerHTML = boxSVG; + +/* + el3.addEventListener("mouseover", + function(e) { + var msg = "mouse over ele3: "+e.type + " target: "+e.currentTarget.viewBox.ID; + console.log(msg); + msgEl.innerHTML = msg; + }); + + el3.addEventListener("mouseout", + function(e) { + var msg = "mouse left ele3: "+e.type + " target: "+e.currentTarget.viewBox.ID; +// console.log("svg text mouse out: "+e.type + " target: "+e); + msgEl.innerHTML = msg; + }); +*/ + document.body.appendChild(el3); + + var test = document.getElementById("svgBox1"); + test.addEventListener("mouseover", + function(e) { + var msg = "mouse enter svg box: "+e.type + " target: "+ e.viewBox; + console.log(msg); + msgEl.innerHTML = msg; + }); + test.addEventListener("mouseout", + function(e) { + var msg = "mouse exit svg box: "+e.type + " target: "+e; + console.log(msg); + msgEl.innerHTML = msg; + }); + + var mySurface = new Surface({ + size: [true, true], + content: boxSVG, + properties: { + color: 'white', + lineHeight: '200%', + textAlign: 'center', + fontSize: '36px', + cursor: 'pointer' + } + }); + var mySurface2 = new Surface({ + size: [true, true], + content: boxSVG, + properties: { + color: 'white', + lineHeight: '200%', + textAlign: 'center', + fontSize: '36px', + cursor: 'pointer' + } + }); + var sigmaSVG = ' '; + + var sigmaSurf = new Surface({ + size: [100, 100], + content: sigmaSVG, + properties: { + color: 'black', + lineHeight: '200%', + textAlign: 'center', + fontSize: '36px', + cursor: 'pointer' + } + }); + + mySurface.on('mouseover', clickHandler); + mySurface.on('mouseout', clickHandler); + sigmaSurf.on('mouseover', clickHandler); + sigmaSurf.on('mouseout', clickHandler); + mySurface2.on('mouseover', clickHandler); + mySurface2.on('mouseout', clickHandler); + + var moveModifier1 = new StateModifier({ + transform: Transform.translate(250, 100, 0) + }); + var moveModifier2 = new StateModifier({ + transform: Transform.translate(350, 150, 0) + }); + var rotateModifier = new StateModifier({ + transform: Transform.rotateZ(Math.PI/4) + }); + +//the origin is the point inside the child, relative to the child's +// internal axes, at which the child will be pinned inside its parent. +//The align is the point inside the parent, relative to the parent's axes, +// at which the origins of children will be pinned. +//The origin is also the point about which rotations are performed + var moveRelativeModifier = new StateModifier({ + size: [20, 20], + align: [0.5,0], + origin: [0.5,0] + }); + var moveRelativeModifier2 = new StateModifier({ + size: [20, 20], + align: [0.5,0], + origin: [0.5,0] + }); + + var moveModifier2 = new StateModifier({ + transform: Transform.translate(350, 150, 0) + }); + + var scaleMod = new StateModifier({ + transform: Transform.scale(0.5, 0.5, 1) + }); + + +//can make a tree inside the context -- so, can have a transform applied +// to multiple children.. do so by making a var that holds the transform +// node, then add to that variable multiple times. +//Note, though that a given surface object will only render once! Have to +// clone it if want multiple versions to be drawn. +//Same goes for modifiers -- cannot put same modifier object at multiple +// places within tree -- it will only render children of ONE of those places! + var node = mainContext.add(rotateModifier); + node.add(moveModifier2).add(moveRelativeModifier).add(mySurface); + node.add(moveModifier1).add(scaleMod).add(mySurface2); + mainContext.add(moveRelativeModifier2).add(sigmaSurf); + + //========== copy-pasted scrollview example stuff below this ========== + var container = new ContainerSurface( + { + size: [400, 400], + properties: + { + overflow: 'hidden' + } + }); + + var surfaces = []; + //create a thing that is able to transition between surfaces.. the + // surface that transitions in is the new one that is seeable on screen. + var scrollview = new Scrollview(); + + //create the renderable surfaces, each is capable of being seeable on screen + var temp; + /* + for (var i = 0; i < 5; i++) { + temp = new Surface({ + size: [undefined, 50], + content: 'I am surface: ' + (i + 1), + classes: ['red-bg'], + properties: { + textAlign: 'center', + lineHeight: '50px' + } + }); + temp.on('click', clickHandler); + + //put the surface into the scrollview management element + temp.pipe(scrollview); + //put the surface into an array of surfaces, for bookkeeping + surfaces.push(temp); + } + */ + + //The scrollview is now loaded up with all the surfaces, so tell it how + // want it to transition between the different surfaces + scrollview.sequenceFrom(surfaces); + + //add the scrollview to the container.. the container defines size and + // some other properties.. + container.add(scrollview); + + //make the container viewable, and hence the scrollview, hence whatever + // surface is loaded as the top in the scrollview + mainContext.add(new Modifier({origin: [.5, .5]})).add(container); + +}); diff -r cc10d99e3f83 -r a8e5e71adcf3 1__Development/0__Code_Dev/Javascript_approach/9__misc/click_handler_error/print_key_press.js --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/1__Development/0__Code_Dev/Javascript_approach/9__misc/click_handler_error/print_key_press.js Sun Dec 07 12:38:00 2014 -0800 @@ -0,0 +1,128 @@ + + + +define( function(require, exports, module) { + +var lines= 0; +var maxlines= 24; +var savedKeyMsg = ""; + +function showmesg(t) +{ + var old= savedKeyMsg; + if (lines >= maxlines) + { + var i= old.indexOf('\n'); + if (i >= 0) + old= old.substr(i+1); + } + else + lines++; + + savedKeyMsg= old + t + '\n'; +// el2.innerHTML = savedKeyMsg; + console.log(savedKeyMsg); +} + +function keyval(n) +{ + if (n == null) return 'undefined'; + var s= pad(3,n); + if (n >= 32 && n < 127) s+= ' (' + String.fromCharCode(n) + ')'; + while (s.length < 9) s+= ' '; + return s; +} + +function keymesg(w,e) +{ + var row= 0; + var head= [w, ' ']; + if (true) + { + showmesg(head[row] + + ' keyCode=' + keyval(e.keyCode) + + ' which=' + keyval(e.which) + + ' charCode=' + keyval(e.charCode)); + row= 1; + } + if (true) + { + showmesg(head[row] + + ' shiftKey='+pad(5,e.shiftKey) + + ' ctrlKey='+pad(5,e.ctrlKey) + + ' altKey='+pad(5,e.altKey) + + ' metaKey='+pad(5,e.metaKey)); + row= 1; + } + if (true) + { + showmesg(head[row] + + ' key='+e.key + + ' char='+e.char + + ' location='+e.location + + ' repeat='+e.repeat); + row= 1; + } + if (true) + { + showmesg(head[row] + + ' keyIdentifier='+ pad(8,e.keyIdentifier)+ + ' keyLocation='+e.keyLocation); + row= 1; + } + if (row == 0) + showmesg(head[row]); +} + +function pad(n,s) +{ + s+= ''; + while (s.length < n) s+= ' '; + return s; +} + +function suppressdefault(e,flag) +{ + if (flag) + { + if (e.preventDefault) e.preventDefault(); + if (e.stopPropagation) e.stopPropagation(); + } + return !flag; +} + +function keydown(e) +{ + if (!e) e= event; + keymesg('keydown ',e); + return suppressdefault(e,false); +} + +function keyup(e) +{ + if (!e) e= event; + keymesg('keyup ',e); + return suppressdefault(e,false); +} + +function keypress(e) +{ + if (!e) e= event; + keymesg('keypress',e); + return suppressdefault(e,false); +} + +function textinput(e) +{ + if (!e) e= event; + //showmesg('textInput data=' + e.data); + showmesg('textInput data='+e.data); + return suppressdefault(e,false); +} + +return { + showmesg: showmesg, + keydown: keydown, + keyup: keyup +} +}); \ No newline at end of file diff -r cc10d99e3f83 -r a8e5e71adcf3 1__Development/0__Code_Dev/Javascript_approach/APACHE_LICENSE-2.0.html --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/1__Development/0__Code_Dev/Javascript_approach/APACHE_LICENSE-2.0.html Sun Dec 07 12:38:00 2014 -0800 @@ -0,0 +1,444 @@ + + + + Apache License, Version 2.0 + + + + + + + + + + + + + + + + + +
+ + +
+

Apache License

Version 2.0, January 2004

+http://www.apache.org/licenses/

+

TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION

+

1. Definitions.

+

"License" shall mean the terms and conditions for use, reproduction, and +distribution as defined by Sections 1 through 9 of this document.

+

"Licensor" shall mean the copyright owner or entity authorized by the +copyright owner that is granting the License.

+

"Legal Entity" shall mean the union of the acting entity and all other +entities that control, are controlled by, or are under common control with +that entity. For the purposes of this definition, "control" means (i) the +power, direct or indirect, to cause the direction or management of such +entity, whether by contract or otherwise, or (ii) ownership of fifty +percent (50%) or more of the outstanding shares, or (iii) beneficial +ownership of such entity.

+

"You" (or "Your") shall mean an individual or Legal Entity exercising +permissions granted by this License.

+

"Source" form shall mean the preferred form for making modifications, +including but not limited to software source code, documentation source, +and configuration files.

+

"Object" form shall mean any form resulting from mechanical transformation +or translation of a Source form, including but not limited to compiled +object code, generated documentation, and conversions to other media types.

+

"Work" shall mean the work of authorship, whether in Source or Object form, +made available under the License, as indicated by a copyright notice that +is included in or attached to the work (an example is provided in the +Appendix below).

+

"Derivative Works" shall mean any work, whether in Source or Object form, +that is based on (or derived from) the Work and for which the editorial +revisions, annotations, elaborations, or other modifications represent, as +a whole, an original work of authorship. For the purposes of this License, +Derivative Works shall not include works that remain separable from, or +merely link (or bind by name) to the interfaces of, the Work and Derivative +Works thereof.

+

"Contribution" shall mean any work of authorship, including the original +version of the Work and any modifications or additions to that Work or +Derivative Works thereof, that is intentionally submitted to Licensor for +inclusion in the Work by the copyright owner or by an individual or Legal +Entity authorized to submit on behalf of the copyright owner. For the +purposes of this definition, "submitted" means any form of electronic, +verbal, or written communication sent to the Licensor or its +representatives, including but not limited to communication on electronic +mailing lists, source code control systems, and issue tracking systems that +are managed by, or on behalf of, the Licensor for the purpose of discussing +and improving the Work, but excluding communication that is conspicuously +marked or otherwise designated in writing by the copyright owner as "Not a +Contribution."

+

"Contributor" shall mean Licensor and any individual or Legal Entity on +behalf of whom a Contribution has been received by Licensor and +subsequently incorporated within the Work.

+

2. Grant of Copyright License. Subject to the +terms and conditions of this License, each Contributor hereby grants to You +a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable +copyright license to reproduce, prepare Derivative Works of, publicly +display, publicly perform, sublicense, and distribute the Work and such +Derivative Works in Source or Object form.

+

3. Grant of Patent License. Subject to the terms +and conditions of this License, each Contributor hereby grants to You a +perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable +(except as stated in this section) patent license to make, have made, use, +offer to sell, sell, import, and otherwise transfer the Work, where such +license applies only to those patent claims licensable by such Contributor +that are necessarily infringed by their Contribution(s) alone or by +combination of their Contribution(s) with the Work to which such +Contribution(s) was submitted. If You institute patent litigation against +any entity (including a cross-claim or counterclaim in a lawsuit) alleging +that the Work or a Contribution incorporated within the Work constitutes +direct or contributory patent infringement, then any patent licenses +granted to You under this License for that Work shall terminate as of the +date such litigation is filed.

+

4. Redistribution. You may reproduce and +distribute copies of the Work or Derivative Works thereof in any medium, +with or without modifications, and in Source or Object form, provided that +You meet the following conditions:

+
    +
  1. You must give any other recipients of the Work or Derivative Works a +copy of this License; and
  2. + +
  3. You must cause any modified files to carry prominent notices stating +that You changed the files; and
  4. + +
  5. You must retain, in the Source form of any Derivative Works that You +distribute, all copyright, patent, trademark, and attribution notices from +the Source form of the Work, excluding those notices that do not pertain to +any part of the Derivative Works; and
  6. + +
  7. If the Work includes a "NOTICE" text file as part of its distribution, +then any Derivative Works that You distribute must include a readable copy +of the attribution notices contained within such NOTICE file, excluding +those notices that do not pertain to any part of the Derivative Works, in +at least one of the following places: within a NOTICE text file distributed +as part of the Derivative Works; within the Source form or documentation, +if provided along with the Derivative Works; or, within a display generated +by the Derivative Works, if and wherever such third-party notices normally +appear. The contents of the NOTICE file are for informational purposes only +and do not modify the License. You may add Your own attribution notices +within Derivative Works that You distribute, alongside or as an addendum to +the NOTICE text from the Work, provided that such additional attribution +notices cannot be construed as modifying the License. +
    +
    +You may add Your own copyright statement to Your modifications and may +provide additional or different license terms and conditions for use, +reproduction, or distribution of Your modifications, or for any such +Derivative Works as a whole, provided Your use, reproduction, and +distribution of the Work otherwise complies with the conditions stated in +this License. +
  8. + +
+ +

5. Submission of Contributions. Unless You +explicitly state otherwise, any Contribution intentionally submitted for +inclusion in the Work by You to the Licensor shall be under the terms and +conditions of this License, without any additional terms or conditions. +Notwithstanding the above, nothing herein shall supersede or modify the +terms of any separate license agreement you may have executed with Licensor +regarding such Contributions.

+

6. Trademarks. This License does not grant +permission to use the trade names, trademarks, service marks, or product +names of the Licensor, except as required for reasonable and customary use +in describing the origin of the Work and reproducing the content of the +NOTICE file.

+

7. Disclaimer of Warranty. Unless required by +applicable law or agreed to in writing, Licensor provides the Work (and +each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT +WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, +without limitation, any warranties or conditions of TITLE, +NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You +are solely responsible for determining the appropriateness of using or +redistributing the Work and assume any risks associated with Your exercise +of permissions under this License.

+

8. Limitation of Liability. In no event and +under no legal theory, whether in tort (including negligence), contract, or +otherwise, unless required by applicable law (such as deliberate and +grossly negligent acts) or agreed to in writing, shall any Contributor be +liable to You for damages, including any direct, indirect, special, +incidental, or consequential damages of any character arising as a result +of this License or out of the use or inability to use the Work (including +but not limited to damages for loss of goodwill, work stoppage, computer +failure or malfunction, or any and all other commercial damages or losses), +even if such Contributor has been advised of the possibility of such +damages.

+

9. Accepting Warranty or Additional Liability. +While redistributing the Work or Derivative Works thereof, You may choose +to offer, and charge a fee for, acceptance of support, warranty, indemnity, +or other liability obligations and/or rights consistent with this License. +However, in accepting such obligations, You may act only on Your own behalf +and on Your sole responsibility, not on behalf of any other Contributor, +and only if You agree to indemnify, defend, and hold each Contributor +harmless for any liability incurred by, or claims asserted against, such +Contributor by reason of your accepting any such warranty or additional +liability.

+

END OF TERMS AND CONDITIONS

+

APPENDIX: How to apply the Apache License to your work

+

To apply the Apache License to your work, attach the following boilerplate +notice, with the fields enclosed by brackets "[]" replaced with your own +identifying information. (Don't include the brackets!) The text should be +enclosed in the appropriate comment syntax for the file format. We also +recommend that a file or class name and description of purpose be included +on the same "printed page" as the copyright notice for easier +identification within third-party archives.

+
Copyright [yyyy] [name of copyright owner]
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+
+
+ + + + diff -r cc10d99e3f83 -r a8e5e71adcf3 1__Development/0__Code_Dev/Javascript_approach/DESIGN_NOTES__14_Jn_22.txt --- a/1__Development/0__Code_Dev/Javascript_approach/DESIGN_NOTES__14_Jn_22.txt Sat Aug 09 03:34:26 2014 -0700 +++ b/1__Development/0__Code_Dev/Javascript_approach/DESIGN_NOTES__14_Jn_22.txt Sun Dec 07 12:38:00 2014 -0800 @@ -206,42 +206,231 @@ -] when all reachable neighbors of elem done, restore position saved before visiting elem. If none, then are done. == -Now, have view boxes attached to the elements (there is a tree of viewboxes for each element, which includes boxes for the ports and any visual cues caused by properties or derived from properties) +Now, have view boxes attached to the elements (there is a tree of viewboxes for each element, which includes boxes for the ports ((which only provide scaling and translation of the sub-graph that appears inside the port)) and any visual cues caused by properties or derived from properties) disconnect the ones for this elem from the ones for other elems.. so a given box can only be reached from exactly one elem! -Soooo.. what need is to have two separate kinds of hierarchy.. there is hierarchy for a single element node, which includes all of the things that are visualized for that element, including boxes for empty ports, and indicators of the boundary around what should be drawn inside the POSITION of a given port. Call that an element-set. +Soooo.. what need is to have two separate kinds of hierarchy.. there is hierarchy for a single element node, which includes all of the things that are visualized for that element, including boxes for empty ports, and indicators of the boundary around what should be drawn inside the POSITION of a given port. Call that an view-set. -Then there is hierarchy between different element-sets.. for example, which other element goes inside a given port's boundary box.. this is what applies parental shift and scale transforms. +Then there is hierarchy between different view-sets.. for example, which other element goes inside a given port's boundary box.. this is what applies parental shift and scale transforms. So there are some cases here.. element inside port of another element, and element that is a linked element of another. Also case of ordered children of a common parent. - For example, in the Gabe Transform rule, there is a big blue arrow drawn between the query pattern sub-graph and the resultant pattern sub-graph.. the tail goes to the parent's first child, the tip to the second child, and the two children are arranged side-by-side inside of the bounding box of the parent.. where the parent has no shape, just a positioning of children rule and the blue arrow between children + For example, in the Gabe Transform rule, the top level element is a hierarchy element. It has a big blue arrow drawn between the query pattern sub-graph and the resultant pattern sub-graph.. the tail goes to the parent's first child, the tip to the second child, and the two children are arranged side-by-side inside of the bounding box of the parent.. where the parent has no shape to represent it directly, but rather a positioning of children rule and the blue arrow between children. + Hence, that top level element has, as it's view set, a view box that has the blue arrow as its shape, and has two transforms, one to be applied to each child that puts the child in place and scales it. -So, it is up to the parent to decide position of each child hierarchy.. has to know the contents of the child hierarchies in order to calc the size of bounding box.. but, will deal with sizing later.. rely upon user interaction to get the sizing right.. do sizing as graph grows, one bit at a time.. for now, the parent has a translation and scale to apply to the child, while the child has its own declared size.. so, that is element-set to element-set +So, it is up to the parent to decide position of each child hierarchy.. has to know the contents of the child hierarchies in order to calc the size of bounding box.. but, will deal with sizing later.. rely upon user interaction to get the sizing right.. do sizing as graph grows, one bit at a time.. for now, the parent has a translation and scale to apply to the child, while the child has its own declared size.. so, that is view-set to view-set -So, each element set has rules about how to arrange things inside the set.. and another set of rules about how to arrange children or neighbor sets! +So, each view-set has rules about how to arrange things inside the set.. and another set of rules about how to arrange children or neighbor sets! So, the visualizer is the thing that knows the rules and calculates placement and size (scale).. this results in artefacts: links between boxes and links between sets, and info on translate and scale! so within a set there is no scaling. -between sets, either can state itself as reference for the pair, and then state a translation and scaling for the other. It is an error for two directly linked to both state themselves the reference for the other. However, a given set act as both a reference and a recipient, across different sets that are paired to it. +between sets, either of them can state itself as reference for the pair, and then state a translation and scaling for the other. It is an error for two directly linked to both state themselves the reference for the other. However, a given set can act in one case as a reference and in another as a recipient, across different sets that are paired to it. -So, it is the link from one element set to another where the reference designation lies along with the translation and scaling of the recipient +So, it is the link from one view-set to another where the reference designation lies, along with the translation and scaling of the recipient Hmmmmmm.. means that a link between two viewbox-sets is a full object rather than just a pointer! -Hmmmmmm.. want to specialize to the point that encode this distinction about element set versus simple viewbox? What about making it a view-set box.. leaving out any notion of element? Then it just says that view boxes can be grouped into sets that are treated as a single whole, as far as translation and scaling are concerned.. +Hmmmmmm.. want to specialize to the point that encode this distinction about view-set versus simple viewbox? What about making it a view-set box.. leaving out any notion of element? Then it just says that view boxes can be grouped into sets that are treated as a single whole, as far as translation and scaling are concerned.. Then, it is the visualizer that recognizes what gets put together as a view-set, and calculates the translations and scalings that one view-set imposes on another view-set.. Take an example: Summation symbol.. the body is a separate view-set, but the summation view-set determines the scaling and position of the body set. + There needs to be some connection, from the transform that places the child, to the root view box of that child. The child has its own root element, and that element has its own view set. So, that view set should be attached as the contents of the child-position in the parent -- the root view box of the view set should be attached to the end of the chain of child's transforms in the parent. + Do this connection inside the link object that links two view-sets. The link states which is the parent, and it states a translation and scaling to be applied to the child view set. The translation and scaling is relative to the parent's origin (which can, in turn be a child for some other view set, such that it was translated and scaled, and so on..) + ==================== Implementation: -] create a view-set object -] two kinds of links in the view hierarchy.. - -] the view set acts as root/head to its contained viewboxes, which form a tree. -- -] the view set has array of objects that act as links to other view sets. The link objects are shared by both view-sets, and back-link to the view sets. The link objects form the glue.. a view-set determines the relative positions and sizes of other view sets via the link objects. each view set knows only about the link objects it is connected to, - +- -] the view set has array of objects that act as links to other view sets. The link objects are shared by both view-sets, and back-link to the view sets. +Hence, a view-set determines the relative positions and sizes of other view sets via the link objects. each view set knows only about the link objects it is connected to. +-] view set link object has two pointers in it, one to the parent view-set and one to the child view-set. A link object contains an offset and a scale, that are relative to the parent view-set's root viewbox, and are applied to the child view-set's whole view tree. + + +//============================================================== +//== +//== Menu, Commands, Interaction -- assigning responsibilities +//== +//============================================================== + +-] Something has to generate the contents of a menu -- that is specific to the commands that are valid, and relies upon a context. + +-] Something has to receive the gesture that triggers display of the menu and then draw the menu, and populate it with a handler or handlers for the items in the menu, so that a custom function runs for a particular item chosen + + +-] Q: what about shipping event handler together with view boxes? And maybe shipping a menu function? So individual boxes set the fill of the menu, while menu function does plumbing.. the Display expects a menu function that it can call to get menu contents.. Q: make key-based handling standard across different kinds of holders? It seems src specific.. +Maaaybe not.. any contents viewer will need to interact with the user.. the visualizer is specifically for human visual representation. So a human will interact. Sooooo, a menu system will be needed no matter what.. sooooo, the menu contents are provided by the holder, and rendered in menu format by the Display.. + + +//============================================================== +//== +//== Commander -- turning gesture into command +//== +//============================================================== + + +Example: +-] Previously a gesture caused the start of the mode for typing text into a field, say for entering the name of a variable +-] The gesture handler receives a new gesture event +- -] the gesture handler looks up the current "mode", within state shareable among the event handlers. +- -] The code then branches to where it extracts the value of the key pressed, from the event object. +- -] When the mode started, a "collector" object was created that collects the key strokes -- when done, the user will give a gesture that causes the collection to be treated as a unit that is placed into a command that then goes to the modifier. +- -] the collector object also has a link to the syntax graph object that is related to the text being typed in (cases: 1. an existing object is being modified, so that is the object linked to in the collector object; 2. a new element will be inserted, so the insertion point is linked to in the collector object; 3. ?). +- -] Idea: the related object is found as follows: 1. the event contains the Famous surface that the event happened on, get that. 2. the surface contains a back link to the view box it corresponds to, get that. 3. (one possibility) climb the view box tree until reach the view set, get that. (second possibility) the view box has a back link to the syntax-graph node it corresponds to, plus the name of the field within that node object 4. the view set back links to the syntax element, get that OR have the back link directly from the view box. Now have the syntax element related to the gesture, OR the syntax node object related to the gesture. +- - -] Not exactly clear how linking from view boxes back to graph nodes works best.. might link individual view boxes back to, say, property nodes or port nodes if that proves to make things easier. +- -] The gesture-handler extracts any needed info from the event object, such as which key was pressed, and adds that to the collector-object. +- -] The gesture-handler invokes the commander, passing along the gesture information and the syntax node related to it. + +Thinking that things like moving edit-point (aka insertion point) and popping up the menu and navigation through the menus are all done by holder-specific event handlers. The holder sends handlers to the Display, for example, packaged with the view boxes. Those perform things that don't directly modify the syntax graph. Only once enough gestures have been captured that a full sentence specifying a modification of the graph is ready, then does a command get packaged up and sent to the modifier. + +So, the commander is the collection of event handlers that are attached to the view boxes! + +There will be common functions, so the view box handlers will be decorations that pass along to the core commander functionality. + +Soooo.. how to decide which options are available in the menu? They will depend upon the point in the graph where the edit point lies, or upon what has been selected, or upon which view box has received the event, and upon the current mode.. for example, can be laying down a connection between elements, or can be putting something into a port-box, or inserting a new element at a point in the graph. + +Hmmm, thinking to make it easy, for now, all new elements are simply put down, with no connections, then wire it up. Later, will add checks, that look at the types of ports and give a visual indication, direct from event handler, when two ports that are being wired are incompatible.. likewise, when displaying ports as boxes and subgraphs have an implied bounding box around them that is the output port of that subgraph, it won't let a subgraph be inserted into a port if the subgraph's output is incompatible. These checks will all come from the holder, in the form of handlers given to the Display. Might need to have some kind of round trip thing.. where event handlers send a command to the Modifier, which performs the check and sends a response back.. what's allowed will depend upon the details inside the graph.. + +But for now, just want the functionality of being able to build a graph! Architect the code to be compatible with adding checks, probably inside the event handler, so that menus get populated according to the syntax graph details, and attempts to modify the graph are denied during the attempt, based upon details of the graph.. hmmm, guess that means need something inside the holder in addition to the modifier.. need an action checker, or referee, or rule judge, whatever call it.. kinda like referee, decides which actions are within the rules.. yeah, so make event handlers such that they can send attempted action to the referee, which is back in the holder, and get a response, then either allow the action or disallow with a message sent back by the referee. + +Good. I like that.. + +So here's where we're at: +-] Generic Display defined event handler +- -] It knows or figures out which view box (in a manner that depends upon the technology used to paint) +- -] from the view box gets the holder-specific event handler attached to the box. +- -] it calls the holder specific event handler in the view box +-] The view box's event handler is specific to the kind of visual thing -- a variable name, or an element shape, or a port box. +-] the view box's event handler figures out the action, based upon the type of event and the contents (IE, click vs drag vs keydown + particular key combo) +-] For certain kinds of actions, the view-box handler can make a call to the src holder's referee to see if the action is allowed +-] For menu actions, the view-box handler can make a call to the src holders referee to ask for valid contents to place into the menu +- -] the context of the event is sent to the referee or is available to the referee, such as which graph node is under the cursor, or which mode was previously chosen, or what nodes are currently selected. +-] The menu painting is implemented by the Display. The contents and the handler triggered by each is supplied by the referee, and is relayed by the view box handler that receives the start-menu event, or relayed by the menu-handler that receives the select-this-in-menu (a keydown or a click) event. + +Yes. That covers populating the menu, based upon what is under the mouse and which key is pressed, and it covers checking the validity of attempted actions, and it covers advancing through the menu, and it covers making some parts be fixed things of the Display, while others are custom things of the src holder. Yes, all covered :-) + +So, the outcome of the view box event handler is either a modification of context (such as zoom, pan, selected portions of graph, change edit mode), or it is a command indicating a change to the syntax graph (such as wire two ports together, or add new element, delete element or wiring, add property, and so on) +-] A command indicates a particular node or nodes in the syntax graph to be modified, and the modification to be made. Or else indicates the addition of a new node or nodes, such as addition of a new element of a particular command type. +- -] Most of the information in the command is taken from or generated by the code sent by the referee, which was the code of the menu handler, which was sent as the contents of a requested menu. IE, user has a menu up, hits the key for a particular choice in the menu, that key is associated to a particular handler function that was sent by the referee, that handler function knows how to populate a command for creating a new Summation element. + +-] The command is then sent to the Modifier, by the view box event handler or by the menu event handler. +-] the modifier modifies the syntax graph objects that are indicated in the command. +-] The modifier notifies the visualizer about the nodes that have changed. +-] The visualizer modifies the view sets of the affected elements, +-] The visualizer then sends a notice to the display regarding the view set changes. +- -] Not clear on this part just yet.. does the visualizer send notice of which were deleted, which had contents changed, and which added? Or does it just send the boundaries of a sub-graph that should be painted? In order to send boundaries, those boundaries will have to be in-sync with pan and zoom, which are handled.. where? Directly in the event handler, all inside the display? Or, do pan and zoom make it back into the view set graph? They modify the "do not cross" markers inside view set links! Hence, the modifier must be the one to change those, hence pan and zoom generate commands. Sooooo.. it seems just fine to have the visualizer just cause the entire current visualized sub-graph be redrawn.. it just tells the Display to redraw! As simple as that. It should, for example, be sure to block off any view sets that will be too small to be visualized, maybe adding a "too small" marker in the view-links, letting the Display choose an appropriate symbol, such as a small box or something.. + +-] Okay, looking like modifier updates the do-not-cross markers in the view-set graph and modifies which element is the root of the view. The visualizer makes changes to the view boxes that correspond to the changed graph nodes. Then the visualizer tells display to redraw the whole visible sub-graph, starting from the root! + +Done. That will all work. + +Last thing is just calculating the curves that connect elements! Haven't gotten to this yet.. in the graph form, have the arrows going between nodes.. in the Hamiltonian Path form, will have arrows that represent scopes triggering processor creation.. these arrows are not one-to-one with things in the view graphs! Rather, they are implied by one node having a pointer to another node -- the existence of that pointer causes an arrow to be drawn from node that holds the pointer to the node pointed to. + +Have to calculate the positions on the shapes where the arrow originates and where it ends. + +have to add something to the view set that equates to the arrows, which has the data for the end points and the data for the control points that determine the arrow shape. + +Let's see.. can have arrows inside a single element's view set.. in this graph view, each of the property boxes is visible and they are linked via arrows to the element node and the port nodes. + +Hmmmm.. have to work this out next, as the next step in visualizing a graph.. + +Now, just need the stupid event handling to work like it's supposed to! +- - thinking abandon Famous. Just post elements directly to the DOM. Means have to calculate the shifts and scales myself.. see if can lift code from Famous for that.. All I need is the thing where build a tree of parents that have shift and scale in the link to children, and accumulate the shift + scale of ancestors. Once the shift + scale chain has been applied, just add the result as a shape with the given size and position directly to the root of the DOM. + +The problem may be that famous doesn't play well with SVG things, so have to attach the event handlers directly in the SVG string, which means have to post the generic Display handler in the HTML of the seed page, so that it can be named in the string that is inserted as "innerHTML" in the elements. See whether can add a back pointer to an element and retrieve that from the event object, inside the generic handler.. + +//============================================================== +//== +//== Visualizer -- generating view set graph +//== +//============================================================== + +So, the way seeing view sets and view boxes and custom syntax shapes work is this: + +-] in syntax graph, a property node states a visualization ID +-] that ID is looked up by the visualizer.. retrieves code that takes the graph element, crawls it looking for the visual properties it needs, then constructs the view set and view boxes and links those to the appropriate other view sets. +- -] The code for that ID can do anything it wants as the way it generates the view-set. For starters, for, say, Summation, will have a fixed SVG shape that the code knows, and will have fixed locations around it for the input and output ports, and will have a fixed size for each of those ports. +- -] The input ports (and drawn output ports) each have their own bounding box. Likewise, every view set has a total bounding box for the entire set. The input port is part of the parent view set, so it has a translation and a scaling that is applied to the child view set. The translation equals the position of the port (it is positioned relative to the same origin as the syntax shape). The scale is calculated by taking the ration of the port width / contained-view-set-width and the port-height / contain-view-set-height and then choosing the smaller of the two. When that is applied to the contained view set, then it will all fit within the port bounding box. +- -] Can insert view sets that are not attached to any element. For example, an entire sub-graph, conisting of, say, 8 elements is inserted as the body of a summation. Make a view set as the parent of that entire sub-graph. The view sets of the elements are placed relative to this graph-wide view-set's origin. + +Thusly, to make the visualizer code, only have to get an SVG string for the shape, doesn't matter what size it is! It has a fixed size. Then make the input port and drawn output port boxes of a size that looks reasonable compared to the shape. And give them fixed positions relative to the shape's position. There you go. Done. That now visualizes with appropriate sizes relative to all the rest, due to the thing where take ratio of bounding boxes as the scaling factor. + + +//============================================================== +//== +//== Code discovery system -- reuse! +//== +//============================================================== +I'm sitting here writing all this front end stuff, and for sure someone else has written stuff very similar that I should be able to repurpose! Yet web searches just don't catch it. The current process for finding code out there that we can use doesn't work very well! + +-] People throw up their code, but don't talk about the patterns within it.. they put a vew paragraphs about the outside, using it as a whole, but that's it.. and no words about the interfaces, nor the modules inside, nor the mechanics/plumbing.. +- -> A visual approach may help to quickly see the boundaries.. if the editor tool has a visual feature to highlight portions of code that are bound together due to names or shared variables, that will help to see boundaries quickly, so then can see the pieces.. then don't need words about the code, the picture shows quickly. +- -> However.. still need to search for these internal pieces! Improve this by allowing other people to annotate and markup the code base.. the system of pulling other code in by reference, and then adding mods over the top should help here.. when pull in code, can add local annotations, and the system sees the pieces that have been extracted.. the system also sees the naming, so when do a search, can just talk about what looking for, and the names use in search may match to names used in variables and functions and comments.. both original and those added over the top of references. + +-] Going through someone else's code to figure out whether it will work for your purpose is painful. Don't want to invest too much effort on something that will prove unusable. +- -> address by making it faster to evaluate other's code.. visual approach, features that show the stickyness between bits of code (for example, if find one thing that does part of what want, can enable a tool that shows all the code that gets pulled along with it, due to names or variables -- getting away from names as wiring should help this, and the explicit scopes talk about below may help as well) + +-] boundaries within code are not clear.. what are the functional pieces? The ways some people split their code up is beyond bizarre, and inverted ass backwards. Discovering where the handles are that can grab and cleanly extract a piece takes a LOT of effort, have to learn large parts of the code. +- -> visual code may help here.. people see the shape of what they produce.. and can visually detect boundaries, given effective visualization (maybe 3D) + +-] code is not cleanly separable. Can't just grab a piece -- there are global vars and contextual vars that go with it, and it becomes like sticky spaghetti, grab just one strand, and it clings to another, then another, then whole big chunks have to be pulled out together! +- -> need language to encourage contained pieces that fit together.. explicit scope containers might help here.. no global variables! Still are shared vars, but the code shows clearly variables that are shared, and shows what things get those variables. +- -> This will help make viable a tool that visualizes all the strands that have to be pulled in together +- -> Also, the type-driven execution (inversion of control stuff) sounds like it will help as well. Although, this is a layer above basic POP, done via syntax extensions. + += =] The challenge is to make POP gracefully support a variety of execution models -- just said a type driven model, want to allow ordering choices on the data. Type driven has no ordering of datums relative to each other, any type that matches gets gobbled into any transform that accepts. Want other orderings such as in-order (dataflow), or guard based (codetime), or something like annotations that state allowed pairings of datums (IE, door fits in particular frame, or a type of frame, separate the two, do things to them separately, then annotation says how to pair a particular door that has finished to a frame that is also finished). Or even annotations that state order of functions (imperative style) or order of data flowing through transforms (stream based) or order of applying transforms to data (the data doesn't have to stay in order relative to other data, just the transforms have to be applied in a particular ancestry-of-data.. IE, track history of data, each transform is an edge, each node is a result of a particular path through transforms, has a particular pattern ((type)) for data.. so state something about allowed ancestry graph shapes). Even control as data (compute some data which then acts as control for ordering of other computations.. is in INRIA notes somewhere, 2008 or so) +- -> Note that some of the execution models will support discovery and reuse better than others! Allow the menagerie, but build the reuse system in whatever way works best for reuse! It will inevitably end up biasing towards particular execution models, which will encourage code that gets written in that model, and encourage extensions on top of that(those) particular execution model(s). + += =] so, what is implied in basic POP approach, for supporting, say, imperative style, where the programmer explicitly states the scheduling of transforms on datums (IE, the application code tracks datums and commands particular transforms on particular datums) + + +- -> Seeing licensing being built in to system, as giving permission to view and reference.. anything with an open source license is automatically made available to the search system, which indexes across all POP instances, and caches so that if the original source instance goes down then the cached code is still available. Code is identified by name, not by location within a particular instance. The caching is peer to peer, so there is no central anything.. the indexes migrate around and update as circumstances permit. May have name server infrastructure, so have fixed "locations" that a new POP instance will connect to, in order to tie into the POP system. Those are the "bootstrap" servers, that act as entry points. + + +======================================================================== += += += +======================================================================== +Thinking about interfacing the javascript parts with the POP executable.. + +There's a Display piece and visualizer piece + +There are Holders, which have visualizers.. and then there are processors, which may want to vizualize something.. and then there are name-spaces.. which are chosen to be defined as part of a processor.. + +So there's the case when have a running program.. which is a collection of live processors.. + +And have case when have a worksheet.. which is a visualization of a collection of live processors plus views generated by Holders.. + +And have case when seeing worm-holes out to other name-spaces (POP processor instances).. + +And have case when viewing and browsing and searching.. will have other POP instances to interact with, they present visualizations that come through the worm-hole onto your Display. + +Sooooo.. javascript is the Display implementation right now.. and it is the srcHolder, its Visualizer, Commander, and Modifier.. but the executable will be a C data-structure (graph) that builds itself out and a C based runtime that crawls the graph, generating inputs and firing off operations. + +So, what's the interface between the C exe-graph and the javascript Display, and how do those relate to the CTOS persistent processors, the interconnection/enclosure of those processors, and the Visualization of the processors and their interconnection? How does a Display relate to a worksheet and how does a worksheet relate to the mix of srcHolders and live processors underneath it that are visualized upon the worksheet surface? + +-] So, I'm seeing for a worksheet that it Covers the entire Display, with perhaps a couple icons that can be expanded up in the corners.. So, can bring up views of available worksheets, and can bring up Service processors, such as for finding other POP instances that have relevant stuff to your interest, and so on.. + +-] I would say that POP instances advertise.. any that offer a worm-hole advertise what it will connected you to.. the equivalent of Google becomes a peer-to-peer system built in to the fabric.. when you do a search for things of interest, it is these advertisements are part of that.. and seeing POP instances that act as discovery clearing houses, maybe.. not sure how that's all going to evolve best.. but some sort of system of POP instances making stuff available via advertised worm-holes that can be discovered.. every pop instance has a Discovery Service processor, which in turn has available some inter-POP instance mechanism for going out and finding these advertised worm-holes.. I guess the two work together.. and the inter-pop service is a virtual thing that runs in all the machines that are part of POP instances, as a peer-to-peer mechanism. + +-] In any case, have a worksheet -- that is a visualization of a collection of live processors and Holder visualizations.. so, thinking each live processor can have its own Visualizer.. +- -] Holder processors have Visualizers that paint the data inside them and have a Commander that provides a means for interactively exploring that data via a Display. srcHolders add a Modifier for interactive editing of the data inside the Holder. +- -] other kinds of processors may also have their own Visualizer, which may connect to a Display. Or, they may connect to their enclosing processor's Visualizer, or even the Visualizer of a worm-hole connected processor. +- -] There is a CTOS/POP standard for one processor to discover the existence of another processor, and then to request connection to its visualizer. +- -] There is also a CTOS/POP standard for discovering what kind of processor and asking about the Visualizer present within it. +- -] It is up to the individual processors to ensure that the requesting visualizer knows how to set datums that the receiving understands. There is no standard for what a Visualizer has inside of it, neither commands (other than detection commands and the connect command and the accept command) + +In the case of games.. need very high speed access to the painting hardware.. so that comes in the form of a Display.. so thinking might have different kinds of Display Interface Language.. for example, make Direct X displays, and OpenGL displays, where the Visualizer talks to the Display directly via DirectX or OpenGL calls. And then provide a wrapper around such Displays, so have the ViewGraph interface are defining right now for the srcHolder to make the MVDM loop. + +(BTW, thinking about quality of stuff writing here, and envisioning big projects that may have been designed and were beautiful in many ways but died because they had too high a barrier between where are at the time of inception versus that end point.. obviously all this POP stuff and the physics-as-only-fields stuff with the computation model stuff are prime candidates for such a thing! Seeing in inner eye a wasteland of half-finished art works, ambitious and beautiful, lying rusting and rotting away.. the end-goal was fantastic and the structure was worked out to arrive there, but the journey required too much change from adoptors, and too much effort to get to something usable.. chances are clearly high that this will all end up like that, the thought occurs to me.. Euoaaaa.. NO! Dammit. Mmmmm, working for my pleasure, not really any particular end-point outcome in the world. Just enjoying working out these ideas and giving them some form of life in code, as exercise while learning skills I can trade for money (javascript, Python, Raphael, requirejs, jquery, mongodb.. need to work in mongodb!) ) + +(BTW, what about writing the compiler in Python, called from the Bottle server, can start it now, as learning vehicle for Python.. and when have persistent processors, what about saving them into mongodb.. or better, saving all the source into mongo, to make it searchable.. start the discovery service that way.. add meta data about each source graph, just talking about it, and break that down via text mining, and turn it into an index for matching requests for code.. eventually add a recommendation system to track people's characteristics and match them with relevant code from others. In fact, can add mongo now, finishing up that pymongo thing, and put in the ) + +===================================== +basically, the only thing inside javascript is the source graph and the srcHolder. So the rest of the processors can be written.. what? Inside C? Have the Display interface.. hmmm.. what about making a javascript escape, and sending JSON through it.. could be sending to local host back and forth like I do with persisting the source graph. \ No newline at end of file diff -r cc10d99e3f83 -r a8e5e71adcf3 1__Development/0__Code_Dev/Javascript_approach/MVDM_implementation/POPDisplay.html --- a/1__Development/0__Code_Dev/Javascript_approach/MVDM_implementation/POPDisplay.html Sat Aug 09 03:34:26 2014 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,48 +0,0 @@ - - - - - POP Display - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff -r cc10d99e3f83 -r a8e5e71adcf3 1__Development/0__Code_Dev/Javascript_approach/MVDM_implementation/app/GabePatternSrcHolder.js --- a/1__Development/0__Code_Dev/Javascript_approach/MVDM_implementation/app/GabePatternSrcHolder.js Sat Aug 09 03:34:26 2014 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,30 +0,0 @@ - - -//Make a SrcHolder object -define( function( require, exports, module ) { - -//bookkeeping, setup -var visualizer = require('./POPSyntaxGraphVisualizer'); -var commander = require('./POPSyntaxGraphCommander'); -var modifier = require('./POPSyntaxGraphModifier'); -var syntaxGraph = require('./buildGabePatternSyntaxGraph'); - -var persistence = require('./persistence'); - -//persistence.clearPersistentGraph(); -//persistence.persistTheGraph( syntaxGraph ); -//console.log("\npersisting graph done!\n") - -//wait until all the writes complete before retrieving! -syntaxGraph = persistence.retrieveTheGraph(); -console.log("\nretrieving graph done!\n") - -return{ - visualizer: visualizer, - commander: commander, - modifier: modifier, - syntaxGraph: syntaxGraph -}; -}); - - diff -r cc10d99e3f83 -r a8e5e71adcf3 1__Development/0__Code_Dev/Javascript_approach/MVDM_implementation/app/POPApp.js --- a/1__Development/0__Code_Dev/Javascript_approach/MVDM_implementation/app/POPApp.js Sat Aug 09 03:34:26 2014 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,48 +0,0 @@ - -//This is testing scaffolding.. -define(function(require, exports, module) { - - //get the Display object, which contains a function for passing a view - // hierarchy, which the Display then paints onto the screen - var POPDisplay = require('./POPDisplay'); - - //cause the source holder object to be made, which will in turn - // cause a graph of syntax objects to be built inside of it - // and also cause a visualizer object to be built inside of it - var srcHolder = require('./GabePatternSrcHolder'); - - //back-link the visualizer, commander, and modifier - //Note: can have multiple triplets, one for each kind of visualization - // for example, these are for seeing graph form.. later will add a triple - // for seeing the custom syntax form - srcHolder.visualizer.setSrcHolder( srcHolder ); - srcHolder.commander.setSrcHolder( srcHolder ); - srcHolder.modifier.setSrcHolder( srcHolder ); - - //connect the pieces together - //Not sure yet what final form this will take.. for now.. - srcHolder.visualizer.connectToDisplay( POPDisplay ); - POPDisplay.connectToCommander( srcHolder.commander ); - srcHolder.commander.connectToModifier( srcHolder.modifier ); - srcHolder.modifier.connectToSyntaxGraph( srcHolder.syntaxGraph ); - srcHolder.modifier.connectToVisualizer( srcHolder.visualizer ); - - //run test on the modifier, which in turn sends a sub-graph to the - // visualizer, which in turn sends the view hierarchy attached to the - // graph to the Display, which converts the hierarchy into Famous - // render tree, which causes it to paint. - srcHolder.modifier.runTest( ); - - //Once the system is complete, the view will be initialized to whatever - // the last view was before suspend. When first built, the srcHolder - // will be empty, so the view will have a null viewSubGraph. - //As the MVDM loop gathers gestures, it will build up the syntax graph, - // and during the process update the viewSubGraph. - //Each gesture that modifies a portion of the graph that is currently - // within the view will cause a change in the viewSubGraph.. - //Thinking perhaps just have markers inside the normal graph that delimit - // the boundaries of the view sub-graph. Implies that the view can only - // include connected portions of the graph.. may be overly restrictive.. - // might have case where filter the kinds of things that are visible, - // which will collect disconnected pieces from the main graph. -}); diff -r cc10d99e3f83 -r a8e5e71adcf3 1__Development/0__Code_Dev/Javascript_approach/MVDM_implementation/app/POPDisplay.js --- a/1__Development/0__Code_Dev/Javascript_approach/MVDM_implementation/app/POPDisplay.js Sat Aug 09 03:34:26 2014 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,180 +0,0 @@ - - -//Make a Display object, and a number of functions that operate on it. -// One of the functions accepts an array of visual element objects as -// input, and turns those visual elements into a famous render tree. -//The famous context, and the surfaces, and so on exist inside the Display -// object. - -//This uses require.js to create a module. This module has the name of the -// file (POPDisplay). Inside the define, a number of data structures and -// functions are created, then returned at the end. The returned things are -// what can be accessed by external functions that load this module, via -// themselves using the require("POPDisplay") call -define(function(require, exports, module) { -//Create the famous infrastructure, which is used for rendering on screen -var Engine = require("famous/core/Engine"); -var Surface = require("famous/core/Surface"); -var Modifier = require("famous/core/Modifier"); -var Transform = require('famous/core/Transform'); -var StateModifier = require('famous/modifiers/StateModifier'); -var ContainerSurface = require("famous/surfaces/ContainerSurface"); -var EventHandler = require('famous/core/EventHandler'); - -var commander = {}; //set by POPApp via a function (defined below) - -//make the context, which controls rendering to the screen -// once add something to this context, that add makes the thing visibly -// have effect. -//Note, these are available to the render function via the closure -// mechanism -var mainContext = Engine.createContext(); - -var handleGesture = function( event ) { - //not sure this is the right form, but provide a handler for - // gestures made by the programmer/user - //This will make an object that pairs the gesture to the view - // element that is represented by the surface(s) involved in - // the gesture. - //It will then send the object to the command generator, which - // is part of the source holder - console.log("handleGesture"); -} - -//acceptRootViewSet is the main trigger.. it causes the Display to build -// a render tree out of the incoming view set. -//BUG: need a way to limit the view sets that this crawls to, other wise it -// will just find all the other view sets via the view set links and render -// the entire graph! -function acceptRootViewSet (rootViewSet) { - //Here, convert each view hierarchy element into an equivalent - // famous render tree node -return; - //during testing, log some known positions within the hierarchy - console.log("POPDisplay: root view set: " + rootViewSet.ID); - - //==================================== - //== Build the Render tree - //==================================== - //the root view set is a container, placed at the user-view origin - var rootContainer = new ContainerSurface({ - //For now, fixed root size.. later, will set according to window - // being displayed within.. - size: [rootViewSet.width, rootViewSet.height], - properties: { - overflow: 'hidden' - } - }); - mainContext.add(rootContainer); - - //If a viewBox in the hierarchy has children, then make a famous - // container that corresponds to it. - //The children will be offset relative to - // the container's origin, and all will be transformed as a unit. - // The viewBox may also have a shape, in which case a surface with the - // shape, but no transform, is added to the container. - //While traversing the hierarchy, keep two queues of upcoming "parents" - // one for parent containers, the other for the viewBoxs that correspond - // to those containers. The container queue controls the loop "end" - // condition.. - //Each time find a viewBox that has children, push that viewBox into a queue - // and push the viewBox's newly made container into a queue - //When done with all current children, grab the oldest parent from the - // queues. - // - //So, set up for these loops.. - var viewBox = {}; var newSurface = {}; var newSurfMod = {}; - var newContainer = {}; var newContMod = {}; - var i = 0; var numChildren = 0; -//rewrite display to handle view sets! - var nextGenParents = []; var parentContainer = {}; var viewBoxChildren = []; - nextGenParents.push( {viewBox: rootViewSet, container: rootContainer}); - //loop, getting oldest parent pair in queue each time - while( (parentPair = nextGenParents.shift()) != undefined ) { - parentContainer = parentPair.container; - viewBoxChildren = parentPair.viewBox.children; - numChildren = viewBoxChildren.length; - console.log("numChildren: " + numChildren); - - for( i=0; i < numChildren; i++) { - viewBox = viewBoxChildren[i]; - console.log("viewBoxID: " + viewBox.ID); - //check whether viewBox has children -- if so, create a - // container so that all children transform together, and - // have same origin - if(viewBox.children.length != 0) { - newContainer = new ContainerSurface({ - size: [viewBox.width, viewBox.height], - properties: { - overflow: 'hidden' - } - }); - newContMod = new StateModifier({ - transform: Transform.translate(viewBox.xOffset, viewBox.yOffset, 0) - }); - //add child container and its transform to parent container - parentContainer.add( newContMod ).add( newContainer ); - //now check whether the viewBox has a shape to render - if(viewBox.shape != null) { - newSurface = new Surface({ - size: [viewBox.width, viewBox.height], - content: viewBox.shape - }); - //no transform.. using transform applied to container - newContainer.add( newSurface ); - } - //now add to list of parents in next outer-loop - nextGenParents.push( {viewBox: viewBox, container: newContainer} ); - } - //Does viewBox have a shape to render? - if(viewBox.shape != null) { - newSurface = new Surface({ - size: [viewBox.width, viewBox.height], - content: viewBox.shape - }); - //for this case, need a transform for the x and y offsets - newSurfMod = new StateModifier({ - transform: Transform.translate(viewBox.xOffset, viewBox.yOffset, 0) - }); - parentContainer.add( newSurfMod ).add( newSurface ); - } - } - //finished all children of this viewBox.. loop to get new parent - } -} - -function init() { - console.log("init"); - return; - // var POPStuffToDraw = - var mySurface = new Surface({ - size: [100, 100], - content: '', - properties: { - color: 'white', - lineHeight: '200%', - textAlign: 'center', - fontSize: '36px', - cursor: 'pointer' - } - }); - var stateModifier = new StateModifier({ - transform: Transform.translate(250, 100, 0) - }); - mainContext.add(stateModifier).add(mySurface); -} - -function connectToCommander( commanderIn ) { - commander = commanderIn; - console.log("display connect to commander"); -} - -return{ - init: init, - connectToCommander: connectToCommander, - handleGesture: handleGesture, - acceptRootViewSet: acceptRootViewSet -}; -}); - - diff -r cc10d99e3f83 -r a8e5e71adcf3 1__Development/0__Code_Dev/Javascript_approach/MVDM_implementation/app/POPGraphClasses.js --- a/1__Development/0__Code_Dev/Javascript_approach/MVDM_implementation/app/POPGraphClasses.js Sat Aug 09 03:34:26 2014 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,167 +0,0 @@ - - -define( function(require, exports, module) { - -//Using inheritance via prototype, to keep a running hash of objects -// indexed by their ID -- ID is auto generated as the objects are created -function ObjColl(){ - //start at 1 because 0 is interpreted same a null and other special ways - currID = 1; //private, will create one ObjColl and use as prototype - objColl = []; - this.getNextID = function( obj ) { - objColl[currID] = obj; //objColl and currID are in the closure! - return currID++; - }; - this.getByID = function( ID ) { - return objColl[ID]; - } - this.insertByID = function( obj ){ - objColl[obj.ID] = obj; //objColl is in the closure! - } -} -var theObjColl = new ObjColl(); - -//need all the classes to have common ObjColl instance, but each has -// different constructor! So, each needs its own prototype instance, so -// need to create an empty object to act as the prototype instance, so can -// add the constructor to that instance -function ConstructorBuffer(){ -} - -//create a "class" of graph elements.. make an elem via the "new" call.. -function GraphElem() { - this.type = 'GraphElem', - this.ID = this.getNextID(this); //this.getNextID promotes to prototype - this.properties = []; - this.portsIn = []; - this.portsOut = []; - this.linkedElems = []; - this.viewSet = undefined; -}; -var graphElemProto = new ConstructorBuffer(); -graphElemProto.__proto__ = theObjColl; -GraphElem.prototype = graphElemProto; -GraphElem.prototype.constructor = GraphElem; - -function ViewSet() { - this.type = 'ViewSet', - this.ID = this.getNextID(this); //this.getNextID promotes to prototype - this.syntaxElem = {}; //back link to the corresponding syntax graph element - this.rootViewBox = []; - this.viewSetLinks = []; -} -var viewSetProto = new ConstructorBuffer(); -viewSetProto.__proto__ = theObjColl; -ViewSet.prototype = viewSetProto; -ViewSet.prototype.constructor = ViewSet; - -function ViewSetLink() { - this.type = 'ViewSetLink', - this.ID = this.getNextID(this); //this.getNextID promotes to prototype - this.referenceViewSet = {}; - this.subordinateViewSet = {}; - this.xOffset = 0; - this.yOffset = 0; - this.scale = 1.0; -} -var viewSetLinkProto = new ConstructorBuffer(); -viewSetLinkProto.__proto__ = theObjColl; -ViewSetLink.prototype = viewSetLinkProto; -ViewSetLink.prototype.constructor = ViewSetLink; - -//the constructor for a ViewBox object -function ViewBox() { - this.type = 'ViewBox', - this.ID = this.getNextID(this); //this.getNextID promotes to prototype - this.shape = undefined; - this.width = 0; //size of bounding box (before scaling) - this.height = 0; - this.xOffset = 0; //offset moves self and all descendants rel to parent - this.yOffset = 0; - this.scale = 1.0; //scale applies to self and all descendants - this.parent = undefined; //allows traversing upward through hierarchy - this.children = []; //these are children view bounding boxes - this.handlers = []; //array of objects -> { typeOfEvent, Fn } -} -var viewBoxProto = new ConstructorBuffer(); -viewBoxProto.__proto__ = theObjColl; -ViewBox.prototype = viewBoxProto; -ViewBox.prototype.constructor = ViewBox; -ViewBox.prototype.WithParams = function(shape, width, height, xOffset, yOffset, scale) { - this.shape = shape; - this.width = width; //size of bounding box (before scaling) - this.height = height; - this.xOffset = xOffset; //offset moves self and all descendants rel to parent - this.yOffset = yOffset; - this.scale = scale; //scale applies to self and all descendants - return this; //so object returns from "constructor" call.. -} - -function GraphProperty() { - this.type = 'GraphProperty', - this.ID = this.getNextID(this); //this.getNextID promotes to prototype - this.propertyName = ""; - this.propertyValue = ""; - this.subProperties = []; -} -var graphPropertyProto = new ConstructorBuffer(); -graphPropertyProto.__proto__ = theObjColl; -GraphProperty.prototype = graphPropertyProto; -GraphProperty.prototype.constructor = GraphProperty; -GraphProperty.prototype.WithParams = function(propertyName, propertyValue) { - this.propertyName = propertyName; - this.propertyValue = propertyValue; - return this; -} - -function GraphPort() { - this.type = 'GraphPort', - this.ID = this.getNextID(this); //this.getNextID promotes to prototype - this.element = {}; - this.properties = []; - this.pairedPorts = []; -} -var graphPortProto = new ConstructorBuffer(); -graphPortProto.__proto__ = theObjColl; -GraphPort.prototype = graphPortProto; -GraphPort.prototype.constructor = GraphPort; -GraphPort.prototype.WithElem = function(elem) { - this.element = elem; - return this; -} - - -function stdKeyHdlr(e) { - console.log("key event: " + e.type + " on: " + e.target.ID); -} - -function stdClickHdlr(e) { - console.log("click event: " + e.type + " on: " + e.target.ID); -} - -function stdDragHdlr(e) { - console.log("drag event: " + e.type + " on: " + e.target.ID); -} - - -return { - theObjColl: theObjColl, - ObjColl: ObjColl, //the class that theObjColl is instance of - GraphElem: GraphElem, - graphElemProto: graphElemProto, - ViewSet: ViewSet, - viewSetProto: viewSetProto, - ViewSetLink: ViewSetLink, - viewSetLinkProto: viewSetLinkProto, - ViewBox: ViewBox, - viewBoxProto: viewBoxProto, - GraphProperty: GraphProperty, - graphPropertyProto: graphPropertyProto, - GraphPort: GraphPort, - graphPortProto: graphPortProto, - stdKeyHdlr: stdKeyHdlr, - stdClickHdlr: stdClickHdlr, - stdDragHdlr: stdDragHdlr -}; -}); - diff -r cc10d99e3f83 -r a8e5e71adcf3 1__Development/0__Code_Dev/Javascript_approach/MVDM_implementation/app/POPSyntaxGraphCommander.js --- a/1__Development/0__Code_Dev/Javascript_approach/MVDM_implementation/app/POPSyntaxGraphCommander.js Sat Aug 09 03:34:26 2014 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,35 +0,0 @@ - - -//Make a Modifier object, consisting of the modifier functions in a closure. -//The Modifier is given commands from the Commander, and executes them, which -// modifies the syntax graph inside the holder. The mods trigger update of -// the sub-graph to visualize. The visualizer is told of the changes -define(function(require, exports, module) { -//Create the famous infrastructure, which is used for rendering on screen - -var srcHolder = {}; -var modifier = {}; - -function init() { - //access Visualizer values here, as a closure - console.log("init Commander"); -} - -function setSrcHolder( srcHolderIn ) { - srcHolder = srcHolderIn; -} - -function connectToModifier( modifierIn ) { - //access Visualizer values here, as a closure - modifier = modifierIn; - console.log("connect commander to modifier"); -} - -return{ - init: init, - setSrcHolder: setSrcHolder, - connectToModifier: connectToModifier -}; -}); - - diff -r cc10d99e3f83 -r a8e5e71adcf3 1__Development/0__Code_Dev/Javascript_approach/MVDM_implementation/app/POPSyntaxGraphModifier.js --- a/1__Development/0__Code_Dev/Javascript_approach/MVDM_implementation/app/POPSyntaxGraphModifier.js Sat Aug 09 03:34:26 2014 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,53 +0,0 @@ - - -//Make a Commander object, consisting of the command functions. -//The Commander is given gestures detected by the Display, and turns them -// into commands and passes those along to the Modifier -define(function(require, exports, module) { -//Create the famous infrastructure, which is used for rendering on screen - -var srcHolder = {}; -var syntaxGraphRoot = {}; -var visualizer = {}; - -var viewSubGraph = {}; - -function init() { - //access Visualizer values here, as a closure - console.log("init modifier"); -} - -function setSrcHolder( srcHolderIn ) { - srcHolder = srcHolderIn; -} - -function connectToSyntaxGraph( syntaxGraphRootIn ) { - //access values here, as a closure - syntaxGraphRoot = syntaxGraphRootIn; - console.log("connect modifier to Syntax Graph"); -} -function connectToVisualizer( visualizerIn ) { - //access values here, as a closure - visualizer = visualizerIn; - console.log("connect modifier to Visualizer"); -} - -function runTest( ){ - -//Trigger the visualizer to build a view hierarchy and pass that -// to the Display object, which in turn triggers the Display to build -// a famous render tree corresponding to the view hierarchy, which paints -// the syntax graph representation into the browser -visualizer.setViewSubGraph( syntaxGraphRoot.rootElem ); -} - -return{ - init: init, - setSrcHolder: setSrcHolder, - connectToSyntaxGraph: connectToSyntaxGraph, - connectToVisualizer: connectToVisualizer, - runTest: runTest -}; -}); - - diff -r cc10d99e3f83 -r a8e5e71adcf3 1__Development/0__Code_Dev/Javascript_approach/MVDM_implementation/app/POPSyntaxGraphVisualizer.js --- a/1__Development/0__Code_Dev/Javascript_approach/MVDM_implementation/app/POPSyntaxGraphVisualizer.js Sat Aug 09 03:34:26 2014 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,237 +0,0 @@ - - -//Make a Visualizer object, and a number of functions that operate on it. -// One of the functions accepts -define(function(require, exports, module) { -var srcHolder = {}; -var DisplayToSendTo = {}; - -var rootViewSet = {}; - -//var renderer = require('./renderPOPSyntaxGraph'); - - -function init() { - //access Visualizer values here, as a closure - console.log("init visualizer"); -} - -function setSrcHolder( srcHolderIn ) { - srcHolder = srcHolderIn; - rootViewSet = srcHolder.syntaxGraph.rootViewSet; -} - -function connectToDisplay( POPDisplay ) { - //access Visualizer values here, as a closure - DisplayToSendTo = POPDisplay; - console.log("connectToDisplay"); -} - - -//Calling this function triggers a series of events: -//1) it generates a view hierarchy that represents the syntax graph -//2) it sends that view hierarchy to the Display -//3) the Display creates an internal representation of the hierarchy -//4) the Display paints that internal representation to some device -function visualizeNewSubGraph( newSubGraphRootElem ) { - //access Visualizer values here, as a closure - console.log("visualizeNewSubGraph"); - - //Once developed, this is where the visualizer will calculate the - // positions and scales inside the view set links, and will fill in any - // newly needed view boxes. For example when a new elem is added, then - // the visualizer has to create the view tree for it. - //When get to adding that functionality, may turn out that need to have - // side band comm between modifier and visualizer.. for example, when a - // "drag elem" command happens, then the only mod is a change to the view - // graph.. so have the modifier talk to the visualizer directly, passing - // along the change to the view. - - //for now, just set the view root to be the view set attached to the elem - //Note: this is NOT the right behavior.. the root view set is often the - // view set that is above the root element.. if the root elem's view - // set is subordinate to any, then the one it is subordinate to should - // be the root view set (I think.. have to see in practice). - rootViewSet = newSubGraphRootElem.viewSet; - - console.log("Visualizer -- new root view set ID: " + rootViewSet.ID ); - - //for now, just send reference to the viewHierarchy -- make this - // sane later (not sure whether will do a "class" and create - // instance via new operator, or what..) - DisplayToSendTo.acceptRootViewSet( rootViewSet ); - - return; -//=================================== - //for first pass, just build the view hierarchy by hand - - //A view hierarchy consists of bounding boxes arranged in a - // a hierarchy. Inside each bounding box is either more bounding - // boxes or a paintable thing, or both. - //For now, paintable things are all SVG, even text is SVG text - - //In this test, just construct the hierarchy for the two boxes - // that already did the by-hand SVG for, with the bezier connecting - // them.. for now, just make the data structs and populate with - // info gotten from the by-hand rendering - //Later, will calculate all the box sizes and positions relative to - // parents, starting from the syntax graph - var gottenElem = renderer.getRootBox; - rootViewSet.rootBox = { - ID: gottenElem.ID, - type: 'container', - width: gottenElem.width, - height: gottenElem.height, - parent: null, - children: [] - } //note, left out parent-relative position and shape! - var currParent = rootViewSet.rootBox; - var children = currParent.children; - //first child is the syntactic element box - var gottenElem = renderer.getElemBox; - children[0] = { - ID: gottenElem.ID, - type: 'shape', - width: gottenElem.width, //match the SVG shapes inside - height: gottenElem.height, - xOffset: gottenElem.x, - yOffset: gottenElem.y, - shape: gottenElem.shape, - parent: currParent, - children: [] - } - //second child is the properties box attached to the first box - gottenElem = renderer.getPropertiesBox; - children[1] = { - ID: gottenElem.ID, - type: 'shape', - width: gottenElem.width, //match the SVG shapes inside - height: gottenElem.height, - xOffset: gottenElem.x, - yOffset: gottenElem.y, - shape: gottenElem.shape, - parent: currParent, - children: [] - } - console.log("box2: " + children[1].shape); - //third child is the bezier curve connecting the boxes - gottenElem = renderer.getBezier; - children[2] = { - ID: gottenElem.ID, - type: 'shape', - width: gottenElem.width, - height: gottenElem.height, - xOffset: gottenElem.x, - yOffset: gottenElem.y, - shape: gottenElem.shape, - parent: currParent, - children: null - } - - //now add the text to the elem box - currParent = children[0]; - children = currParent.children; //set to children of elem box - gottenElem = renderer.getText1_1_1; - children[0] = { - ID: gottenElem.ID, - type: 'shape', - width: gottenElem.width, - height: gottenElem.height, - xOffset: gottenElem.x, - yOffset: gottenElem.y, - shape: gottenElem.shape, - parent: currParent, - children: null - } - gottenElem = renderer.getText1_1_2; - children[1] = { - ID: gottenElem.ID, - type: 'shape', - width: gottenElem.width, - height: gottenElem.height, - xOffset: gottenElem.x, - yOffset: gottenElem.y, - shape: gottenElem.shape, - parent: currParent, - children: null - } - gottenElem = renderer.getText1_1_3; - children[2] = { - ID: gottenElem.ID, - type: 'shape', - width: gottenElem.width, - height: gottenElem.height, - xOffset: gottenElem.x, - yOffset: gottenElem.y, - shape: gottenElem.shape, - parent: currParent, - children: null - } - gottenElem = renderer.getText1_1_4; - children[3] = { - ID: gottenElem.ID, - type: 'shape', - width: gottenElem.width, - height: gottenElem.height, - xOffset: gottenElem.x, - yOffset: gottenElem.y, - shape: gottenElem.shape, - parent: currParent, - children: null - } - - //now add the text to the properties box - currParent = rootViewSet.rootBox.children[1]; - children = currParent.children; - gottenElem = renderer.getText1_2_1; - children[0] = { - ID: gottenElem.ID, - type: 'shape', - width: gottenElem.width, - height: gottenElem.height, - xOffset: gottenElem.x, - yOffset: gottenElem.y, - shape: gottenElem.shape, - parent: currParent, - children: null - } - gottenElem = renderer.getText1_2_2; - children[1] = { - ID: gottenElem.ID, - type: 'shape', - width: gottenElem.width, - height: gottenElem.height, - xOffset: gottenElem.x, - yOffset: gottenElem.y, - shape: gottenElem.shape, - parent: currParent, - children: null - } - gottenElem = renderer.getText1_2_3; - children[2] = { - ID: gottenElem.ID, - type: 'shape', - width: gottenElem.width, - height: gottenElem.height, - xOffset: gottenElem.x, - yOffset: gottenElem.y, - shape: gottenElem.shape, - parent: currParent, - children: null - } - console.log("Visualizer: " + rootViewSet.children[0].children[2].shape + " y: " + rootViewSet.children[0].children[2].yOffset); - //for now, just send reference to the rootViewSet -- make this - // sane later (not sure whether will do a "class" and create - // instance via new operator, or what.. - DisplayToSendTo.acceptRootViewSet( rootViewSet ); -} - -return{ - init: init, - setSrcHolder: setSrcHolder, - connectToDisplay: connectToDisplay, - setViewSubGraph: visualizeNewSubGraph -}; -}); - - diff -r cc10d99e3f83 -r a8e5e71adcf3 1__Development/0__Code_Dev/Javascript_approach/MVDM_implementation/app/persistence.js --- a/1__Development/0__Code_Dev/Javascript_approach/MVDM_implementation/app/persistence.js Sat Aug 09 03:34:26 2014 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,646 +0,0 @@ - -define( function(require, exports, module) { - -//Get the class objects that define behavior for each of the structures that -// appears in a POP syntax graph.. will use these as read in JSON of a graph -// and parse it into objects of these classes! -var graphClasses = require("./POPGraphClasses"); - - -//=========================== -//== Learning stuff -- playing with local file system things.. -//=========================== - -//note: only Chrome supports the file api ! -// start Chrome with flag "--allow-file-access-from-files" to enable the API - - -//put a file selector button onto the screen and register an event handler -// that fires after one or a group of files is chosen - var outputEl = document.body.appendChild(document.createElement("output")); - outputEl.id = "fileListOutput"; - - var inputEl = document.createElement("div"); - document.body.appendChild(inputEl); - var innerHTMLStr = ''; - inputEl.innerHTML = innerHTMLStr; - - var gottenElem = document.getElementById("fileChooserElem"); - gottenElem.addEventListener('change', handleFileSelect, false); - - //The event handler - function handleFileSelect(evt) { - var files = evt.target.files; // FileList object - - console.log("got event! "); - - // files is a FileList of File objects. List some properties. - var output = []; - for (var i = 0, f; f = files[i]; i++) { - output.push ( - '
  • ' + f.name + ' (' + (f.type || "n/a") + ') - ' + - f.size + ' bytes, last modified: ' + - (f.lastModifiedDate ? f.lastModifiedDate.toLocaleDateString() : "n/a") + - '
  • '); - var reader = new FileReader(); - - //The file API is asynchronous, so before do a read, register - // a callback that runs when the read completes. - // It's a Closure, which encloses the file info as theFile. - //The closure runs now, which makes a function invocation body - // that includes the parameter, and this run makes a new function - // spec which is returned as the callback! That new function spec - // has the invocation of the closure attached to it, so it still - // has the closure parameter (theFile) available when it is called - // back later. - reader.onload = (function(theFile) { - return function(e) { - console.log("file: " + theFile.name + " content: " + e.target.result); - }; - })(f); //here, invoke the closure function, passing it the file - - // trigger the onload -- reads in the image file as a data URL. - console.log("file contents: " + reader.readAsText(f) ); - } - document.getElementById('fileListOutput').innerHTML = '
      ' + output.join('') + '
    '; - console.log("files: " + output.join("")); - } - -//this is a call-back that runs at the conclusion of initializing the file system - function onInitFs(fs) { - console.log('\n\n!!!Opened file system: ' + fs.name +"\n\n"); - } - - -//note, in order to get persistent file system access to work, had to start -// chrome with the flag "--allow-file-access-from-files" and added -// "--allow-file-access" just for good measure -//Test that file system access works via the Filer.js demo in the packages- -// libraries-tools directory -- click on index and see if red "error" shows up - navigator.webkitPersistentStorage.requestQuota ( - 1024*1024*280, - function(grantedBytes) { - document.getElementById('fileListOutput').innerHTML = 'request quota callback: ' + grantedBytes; - window.webkitRequestFileSystem(window.PERSISTENT, grantedBytes, onInitFs, errorHandler); - }, - errorHandler - ) - - - function errorHandler(e) { - var msg = ''; - - switch (e.code) { - case FileError.QUOTA_EXCEEDED_ERR: - msg = 'QUOTA_EXCEEDED_ERR'; - break; - case FileError.NOT_FOUND_ERR: - msg = 'NOT_FOUND_ERR'; - break; - case FileError.SECURITY_ERR: - msg = 'SECURITY_ERR'; - break; - case FileError.INVALID_MODIFICATION_ERR: - msg = 'INVALID_MODIFICATION_ERR'; - break; - case FileError.INVALID_STATE_ERR: - msg = 'INVALID_STATE_ERR'; - break; - default: - msg = 'Unknown Error'; - break; - }; - - console.log('Error: ' + msg); - } - - -//================================================== -//== -//================================================== - -//The src holder has to serialize the syntax graph out to persistent -// storage, and bring it back in, converting back to javascript objects -//JSON can stringify and then parse back, but it can't handle circuits -// in the graph, so have to write code that crawls the graph and -// individually stringifies each element -//So, the steps: -//-] crawl only the elements. -//-] An element has properties, ports, and linked elements attached.. -//- -] properties are fine as-is, the stringify will handle them -//- -] ports have pointers back to the element, so those must be replaced -// with the element's ID before stringify -//- -] linked elements can potentially link back around in a -// circle, so replace those links with IDs before stringify -// -//-] start at root, get the first element. -//-] For a given element: -//- -] check whether marked as already visited if yes, return, else -// continue -//- -] mark the element as having been visited -//- -] visit each port (save this position before visiting!), and -// for a given port: -//- - -] follow each pairedPort link, and process element linked to the -// paired port -//- - -] when come back, replace pairedPort pointer with ID of the -// pointed-to port -//- -] for each element in the array of linked elements: -//- - -] visit and process the element linked to (save position first) -//- - -] when come back, replace the pointer with ID of the linked elem -//- -] when all the elment's ports and linked elems have been visited, -// return to the position were in just before visiting this element -//-] when no where to return to, then done! - function persistTheGraph( theGraphRoot ) { - var shadowGraphRoot = {}; - - //save out the top level object that has the handles to the view hierarchy root - // and the root element. Also persist the view hierarchy root because it doesn't - // fit cleanly to try to reach it from the root element.. by persisting it here, - // can then do a single recursive call and only pass the next syntax element to - // clean up. Any view stuff will be reached from that element - var rootElem = theGraphAnchor.rootElem; //save 'cause pointers about to be replaced - persistAnchorAndViewSetRoot(theGraphAnchor, shadowGraphRoot); - visitNextElemAndPersistIt(rootElem); -// endPersisting(); //tell web server that persist protocol ended - - //now, restore all the pointers, replacing the IDs with pointer to object - restoreAnchorAndViewSetRoot(theGraphAnchor, shadowGraphRoot); - visitNextElemAndRestoreIt(rootElem); - } - - function persistAnchorAndViewSetRoot(theGraphRoot, shadowGraphRoot) { - //save the top level root object and the top view set, which is above - // the view set of the root element - //Replace pointer to root elem with its ID and cut off pointers - // inside the root view set link, so JSON stringify only gets the root - // view set and its one view set link object - shadowGraphRoot.rootElem = theGraphAnchor.rootElem; - theGraphAnchor.rootElem = theGraphAnchor.rootElem.ID; - - //remove the back link from the view set link back to the root view set - shadowGraphRoot.backLinkToRootViewSet = theGraphAnchor.rootViewSet.viewSetLinks[0].referenceViewSet; - theGraphAnchor.rootViewSet.viewSetLinks[0].referenceViewSet = - theGraphAnchor.rootViewSet.viewSetLinks[0].referenceViewSet.ID; - - //cut off the view set link, that points to the view set of the root element - shadowGraphRoot.linkToRootElemsViewSet = - theGraphAnchor.rootViewSet.viewSetLinks[0].subordinateViewSet; - theGraphAnchor.rootViewSet.viewSetLinks[0].subordinateViewSet = - theGraphAnchor.rootViewSet.viewSetLinks[0].subordinateViewSet.ID; - - //Now, ready to go, stringify away! - var stringOfGraphRoot = JSON.stringify(theGraphAnchor, null, '\t'); -// console.log("JSON of graphRoot: " + stringOfGraphRoot ); - persistString(stringOfGraphRoot) - } - -//Contract: have already verified that this elem has not been visited before calling - function visitNextElemAndPersistIt(elem) { - //mark the element as having been visited - elem.isAlreadyVisited = true; - - //cut the back link going from the view set to the elem node - if ((elem.viewSet || {}).syntaxElem) { - elem.viewSet.syntaxElem = elem.viewSet.syntaxElem.ID; - } - - //visit each port - var elemToVisit = {}; - var i = 0; - var j = 0; - var inPort = {}; - var ports = elem.portsIn; - var numPorts = ports.length; - var numPairedPorts = 0; - for (j = 0; j < numPorts; j++) { - inPort = ports[j]; - numPairedPorts = inPort.pairedPorts.length; - //follow each pairedPort link - for (i = 0; i < numPairedPorts; i++) { - //process element linked to the paired port - elemToVisit = inPort.pairedPorts[i].element; - if (!elemToVisit.isAlreadyVisited) { - visitNextElemAndPersistIt(elemToVisit); - } - //back from visit, replace pointer with ID of pointed to port - inPort.pairedPorts[i] = inPort.pairedPorts[i].ID; - } - //replace the element back-pointer in the port object - inPort.element = inPort.element.ID; - } - ports = elem.portsOut; - numPorts = ports.length; - var outPort = {}; - for (j = 0; j < numPorts; j++) { - outPort = ports[j]; - numPairedPorts = outPort.pairedPorts.length; - //follow each pairedPort link - for (i = 0; i < numPairedPorts; i++) { - //process element linked to the paired port - elemToVisit = outPort.pairedPorts[i].element; - if (!elemToVisit.isAlreadyVisited) { - visitNextElemAndPersistIt(elemToVisit); - } - //when come back, replace pointer with ID of pointed to port - outPort.pairedPorts[i] = outPort.pairedPorts[i].ID; - } - //replace the element back-pointer in the port object - outPort.element = outPort.element.ID; - } - var numLinkedElems = elem.linkedElems.length; - for (i = 0; i < numLinkedElems; i++) { - if (!(elem.linkedElems[i].isAlreadyVisited)) { - visitNextElemAndPersistIt(elem.linkedElems[i]); - } - //back from visit, replace pointer with ID of pointed to elem - elem.linkedElems[i] = elem.linkedElems[i].ID; - } - - //cut links to the view sets embedded within view set link objects - if ((elem.viewSet || {}).viewSetLinks) { - var viewSet = elem.viewSet; - var numLinked = viewSet.viewSetLinks.length; - var viewSetLink = {}; - for (i = 0; i < numLinked; i++) { - viewSetLink = viewSet.viewSetLinks[i]; - if (viewSetLink) { - viewSetLink.referenceViewSet = viewSetLink.referenceViewSet.ID; - viewSetLink.subordinateViewSet = viewSetLink.subordinateViewSet.ID; - } - } - } - //cut back-links to parent view boxes within view set tree - if ((elem.viewSet || {}).rootViewBox) { - walkViewTree(elem.viewSet.rootViewBox); - } - - //this elem, and all objects reachable from it are now safe to be - // stringified with JSON.. so do it! - var stringOfElemNode = JSON.stringify(elem, null, '\t'); -// console.log("JSON of elem: " + stringOfElemNode ); - persistString(stringOfElemNode); - } - -//walk the tree, replacing all parent pointers with ID -// dont bother keeping shadow copy, easily restored without copy - function walkViewTree(viewBox) { - if (viewBox.parent) viewBox.parent = viewBox.parent.ID; - if (viewBox.children.length > 0) { - var childBox = {}; - var numChildren = viewBox.children.length; - for (i = 0; i < numChildren; i++) { - childBox = viewBox.children[i]; - if (childBox) { - walkViewTree(childBox); - } - } - } -// console.log("done recursing viewBox: " + viewBox.ID) - } - - //===================================== -//Search the graph for places where pointer has been replaced by an ID, -// when find one, look up the object with that ID and replace the ID with pointer - function restoreAnchorAndViewSetRoot( theGraphAnchor ) { - var theObjColl = graphClasses.theObjColl; - - theGraphAnchor.rootElem = theObjColl.getByID(theGraphAnchor.rootElem); - - //restore the back link from the view set link - theGraphAnchor.rootViewSet.viewSetLinks[0].referenceViewSet = - theObjColl.getByID(theGraphAnchor.rootViewSet.viewSetLinks[0].referenceViewSet); - theGraphAnchor.rootViewSet.viewSetLinks[0].subordinateViewSet = - theObjColl.getByID(theGraphAnchor.rootViewSet.viewSetLinks[0].subordinateViewSet); - } - -//Contract: have already verified that this elem has not been visited before calling - function visitNextElemAndRestoreIt( elem ) { - //mark the element as having been visited - elem.isAlreadyVisited = false; //all start at true, making false marks as restored - - //restore the back link going from the view set to the elem node - if ((elem.viewSet || {}).syntaxElem) { //idiom makes safe when viewset undefined - elem.viewSet.syntaxElem = elem.getByID(elem.viewSet.syntaxElem); - } - - //restore each port - var elemToVisit = {}; - var i = 0; - var j = 0; - var inPort = {}; - var portsIn = elem.portsIn; - var numPorts = portsIn.length; - var numPairedPorts = 0; - //as go along, restore pointers by looking them up - for (j = 0; j < numPorts; j++) { - inPort = portsIn[j]; - - //restore the element back-pointer in the port object - inPort.element = inPort.getByID(inPort.element); - - //follow each pairedPort link - numPairedPorts = inPort.pairedPorts.length; - for (i = 0; i < numPairedPorts; i++) { - //process element linked to the paired port - //first, replace pointer to port - inPort.pairedPorts[i] = inPort.getByID(inPort.pairedPorts[i]); - elemToVisit = inPort.pairedPorts[i].element; - if (typeof elemToVisit == 'number') { - //means the element back-pointer inside the port on the other end - // is still the ID.. IE, that port and its element not restored yet - visitNextElemAndRestoreIt(outPort.getByID(elemToVisit)); - } - else if (elemToVisit.isAlreadyVisited) { //if still marked from before - //don't think this case will ever come up! if elem not restored, - // then the elem's port's back pointer will still be an ID and above - // if() will catch it.. - visitNextElemAndRestoreIt(elemToVisit); - } - } - } - var outPorts = elem.portsOut; - numPorts = outPorts.length; - var outPort = {}; - for (j = 0; j < numPorts; j++) { - outPort = outPorts[j]; - //restore back link from outPort to its element - outPort.element = outPort.getByID(outPort.element); - numPairedPorts = outPort.pairedPorts.length; - //visit each pairedPort link - for (i = 0; i < numPairedPorts; i++) { - //restore the pointer to the paired port - outPort.pairedPorts[i] = outPort.getByID(outPort.pairedPorts[i]); - //process element linked to the paired port - elemToVisit = outPort.pairedPorts[i].element; - if (typeof elemToVisit == 'number') { - //means the element back-pointer inside the port on the other end - // is still the ID.. IE, that port and its element not restored yet - visitNextElemAndRestoreIt(outPort.getByID(elemToVisit)); - } - else if (elemToVisit.isAlreadyVisited) { //if needs restoring - //don't think this case will ever come up! if not restored, - // then the elem back pointer will still be an ID and above - // if() will catch it.. - visitNextElemAndRestoreIt(elemToVisit); - } - } - } - var numLinkedElems = elem.linkedElems.length; - for (i = 0; i < numLinkedElems; i++) { - //restore linked elem first, then process that restored elem - elem.linkedElems[i] = elem.getByID(elem.linkedElems[i]); - if (elem.linkedElems[i].isAlreadyVisited) { - visitNextElemAndRestoreIt(elem.linkedElems[i]); - } - } - - //restore links to the view sets embedded within view set link objects - if ((elem.viewSet || {}).viewSetLinks) { - var viewSet = elem.viewSet; - var numLinked = viewSet.viewSetLinks.length; //array always exists - var viewSetLink = {}; - for (i = 0; i < numLinked; i++) { - viewSetLink = viewSet.viewSetLinks[i]; - if (viewSetLink) { - viewSetLink.referenceViewSet = elem.getByID(viewSetLink.referenceViewSet); - viewSetLink.subordinateViewSet = elem.getByID(viewSetLink.subordinateViewSet); - } - } - } - //restore back-links to parent view boxes within view set tree - if ((elem.viewSet || {}).rootViewBox) { //idiom that's safe when viewSet undefine - walkViewTreeAndRestore(elem.viewSet.rootViewBox); - } - } - -//walk the tree, restoring all IDs with parent and children pointers - function walkViewTreeAndRestore(viewBox) { - //replace ID that's in the parent field with looked up object pointer - if (viewBox.parent) viewBox.parent = viewBox.getByID(viewBox.parent); - if (viewBox.children.length > 0) { //all view boxes should have array! - var childBox = {}; - var numChildren = viewBox.children.length; - for (i = 0; i < numChildren; i++) { - viewBox.children[i] = viewBox.getByID(viewBox.children[i]); - childBox = viewBox.children[i]; - if (childBox) { - walkViewTree(childBox); - } - } - } -// console.log("done restoring viewBox: " + viewBox.ID) - } - -//================================== - - function clearPersistentGraph() { - //bottle server - var theUrl = "http://localhost:8080/cleargraph"; - var xmlHttp = new XMLHttpRequest(); - xmlHttp.open("GET", theUrl, false); - console.log("about to send clear graph command"); - xmlHttp.send(null); - console.log("done clearing: " + xmlHttp.responseText); - } - - function persistString(stringToWrite) { - //bottle server - //convert newline to %N, tab to %T, backslash to %H and forward slash to %S - // then convert back in server before storing to file - stringToWrite = stringToWrite.replace(/[\t]/g, '%T'); - stringToWrite = stringToWrite.replace(/[\n]/g, '%N'); - stringToWrite = stringToWrite.replace(/[\\]/g, '%H'); - stringToWrite = stringToWrite.replace(/[/]/g, '%S'); - var theUrl = "http://localhost:8080/save1elem/" + stringToWrite; - - console.log("theURL: " + theUrl); - - var xmlHttp = null; - xmlHttp = new XMLHttpRequest(); - xmlHttp.open("GET", theUrl, false); //true means send asynchronously - xmlHttp.onload = function (e) { - if (xmlHttp.readyState === 4) { - if (xmlHttp.status === 200) { - console.log("response to the write: " + xmlHttp.responseText); - } else { - console.error(xmlHttp.statusText); - } - } - }; - xmlHttp.onerror = function (e) { - console.error(xmlHttp.statusText); - }; - xmlHttp.send(null); - } - - function endPersisting() { - //bottle server - var theUrl = "http://localhost:8080/endsavinggraph"; - var xmlHttp = new XMLHttpRequest(); - xmlHttp.open("GET", theUrl, false);//do synchronously - xmlHttp.send(null); - console.log("end persisting: " + xmlHttp.responseText); - } - - -//============================================================= -//== -//== Retrieve SyntaxGraph from server -//== -//============================================================= - - function retrieveTheGraph() { - var theUrl = "http://localhost:8080/retrievegraph"; - var xmlHttp = new XMLHttpRequest(); - xmlHttp.open("GET", theUrl, false); //do synchronously - xmlHttp.send(null); - var theJSONString = xmlHttp.responseText; - - //starting a new graph, so the set of objects in the obj coll not - // objects from this new graph -- reset the object collection - // then fill it back up again as parse the objects in.. - graphClasses.theObjColl = new graphClasses.ObjColl(); //make empty one - - console.log( "Retrieved: " + theJSONString ); - - //split the string into separate JSON object-strings - var objJSONArray = theJSONString.split(/separator\n/); - - //remove the last, empty string - var temp = objJSONArray.pop(); - if( temp !== "" ) objJSONArray.push(temp); //if not empty, put it back - - //now parse each string, turning it into objects, and registering them - for( var i = 0; i < objJSONArray.length; i++ ) { - JSON.parse(objJSONArray[i], restoreParsedObj); - } - //one of the parsed JSON strings was the graph anchor obj, which - // was placed into theObjColl during JSON parsing. Grab it - // then call restore, which will walk the graph, find the places - // where a pointer should be, grab the ID sitting there, and use - // that to get the obj and replace the ID with pointer to the object - theGraphAnchor = graphClasses.theObjColl.graphAnchor; - restoreAnchorAndViewSetRoot( theGraphAnchor ); - visitNextElemAndRestoreIt( theGraphAnchor.rootElem ); - return theGraphAnchor; - } - - //This registers each object that has an ID and restores any that have - // a type to their correct class, and it restores handler functions - function restoreParsedObj(k,v) { - if(v.rootElem) { //This is the graph anchor (AKA head)! - graphClasses.theObjColl.graphAnchor = v; - } - if(v.ID) { //ID is a valid field when v is a full object, to be registered - console.log("inserting: " + k + " | ID: " + v.ID); - graphClasses.theObjColl.insertByID( v ); //have a struct worthy of registering - } - if( v.type ) {//add the appropriate __proto__ obj - switch( v.type ) { - case "GraphElem": v.__proto__ = graphClasses.graphElemProto; - break; - case "ViewSet": v.__proto__ = graphClasses.viewSetProto; - break; - case "ViewSetLink": v.__proto__ = graphClasses.viewSetLinkProto; - break; - case "ViewBox": v.__proto__ = graphClasses.viewBoxProto; - break; - case "GraphProperty": v.__proto__ = graphClasses.graphPropertyProto; - break; - case "GraphPort": v.__proto__ = graphClasses.graphPortProto; - break; - } - } - switch(k) { - case "handlers": //view box's array of handler fns - var hdlrPair; //v is an array of objects, each w/type and fn - for( var i = 0; i < v.length; i++) { - hdlrPair = v[i]; - switch (hdlrPair.type) { - case "key": - hdlrPair.fn = graphClasses.stdKeyHdlr; - break; - case "click": - hdlrPair.fn = graphClasses.stdClickHdlr; - break; - case "drag": - hdlrPair.fn = graphClasses.stdDragHdlr; - break; - } - } - - //console.log("key: " + k + " | ret value: " + v + " add .toJSON before stringify!"); - break; - case "isAlreadyVisited": - return true; //restore relies on this being true - break; - } - return v; - } - -// //for this top group, if value is number then it's the ID of obj to get -// case "rootElem": -// case "referenceViewSet": -// case "subordinateViewSet": -// case "element": -// case "syntaxElem": -// case "parent": -// if( typeof v === 'number' ) { -// var theObj = graphClasses.theObjColl.getByID(v); -// var retValue = theObj ? theObj : v; //means need two passes! -// console.log("key: " + k + " | ID: " + v + " | ret value: " + retValue); -// return retValue; -// } -// break; -// //for these two, value is an array of IDs -// case "pairedPorts": -// case "linkedElems": -// for( var i = 0; i < v.length; i++) { -// var val = v[i]; -// if( typeof val === 'number' ) { -// var theObj = graphClasses.theObjColl.getByID(val); -// var retValue = theObj ? theObj : val; //means need two passes! -// console.log("array -- key: " + k + " | ID: " + v[i] + " | ret value: " + i + ": " + retValue); -// v[i] = retValue; -// } -// } -// return v; -// break; - -//================================ - function startRetrieve() { - var theUrl = "http://localhost:8080/startretrievinggraph"; - var xmlHttp = new XMLHttpRequest(); - xmlHttp.open("GET", theUrl, false); - xmlHttp.send(null); - console.log("started retrieve: " + xmlHttp.responseText); - } - - function retrieveNextPersistedString() { - var theUrl = "http://localhost:8080/get1elem"; - var xmlHttp = null; - - xmlHttp = new XMLHttpRequest(); - xmlHttp.open("GET", theUrl, false); - xmlHttp.send(null); - console.log("retrieved string: " + xmlHttp.responseText); - } - - function endRetrieve() { - var theUrl = "http://localhost:8080/endretrievinggraph"; - var xmlHttp = new XMLHttpRequest(); - xmlHttp.open("GET", theUrl, false); - xmlHttp.send(null); - console.log("end retrieve: " + xmlHttp.responseText); - } - -//================================= - - -return { - persistString: persistString, - clearPersistentGraph: clearPersistentGraph, - persistTheGraph: persistTheGraph, - retrieveTheGraph: retrieveTheGraph -}; -}); diff -r cc10d99e3f83 -r a8e5e71adcf3 1__Development/0__Code_Dev/Javascript_approach/MVDM_implementation/app/renderPOPSyntaxGraph.js --- a/1__Development/0__Code_Dev/Javascript_approach/MVDM_implementation/app/renderPOPSyntaxGraph.js Sat Aug 09 03:34:26 2014 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,462 +0,0 @@ - - -define(function(require, exports, module) { - var Engine = require("famous/core/Engine"); - var Surface = require("famous/core/Surface"); - var Modifier = require("famous/core/Modifier"); - var Transform = require('famous/core/Transform'); - var StateModifier = require('famous/modifiers/StateModifier'); - var ContainerSurface = require("famous/surfaces/ContainerSurface"); - var EventHandler = require('famous/core/EventHandler'); - - var mainContext = Engine.createContext(); - - var boxSVG = []; - boxSVG[1] = ''; - - -//Draw a simple syntax graph, with a box of the correct color for each -// node, and curvy links with arrows going from text inside one node to -// text inside another node. -//Approach taken: -//Generate the SVG from calculations -- hold strings in an array, and -// build up an SVG string by adding string piece, then variable value then -// another string piece, and so on. -//Make each box a surface holding an SVG -//Sizing of the box happens inside the SVG string -//Positioning the box happens via a modifier - -//Make one container surface to hold each element node together with its -// properties and ports -//Make a separate surface for each SVG element -- one for each box, one for -// each text in a box, one for each curvy connector arrow between boxes or -// between texts. -//For each surface, make a modifier that positions the box relative to the -// container surface's origin -//At the end, make transforms to move the entire container around - - //elem1 is the root element from the Gabe Pattern syntax graph - // here, make the visual elements that reproduce what see in the .pdf - var elem1Container = new ContainerSurface({ - size: [600, 600], //size it big for now, trim to contents later - properties: { - overflow: 'hidden' - } - }); - var retRootBox = { - ID: "retRootBox", - width: elem1Container.size[0], - height: elem1Container.size[1], - shape: null - } - - -//== -// 1:width 2:height 3:x 4:y 5:rx 6:ry 7:width 8:height 9:fill 10:stroke -// 11:stroke-width 12:opacity - var box1_1w = 66; var box1_1h = 86; var box1_1pad = 2; - var boxSVGFromParts1_1 = boxSVG[1] + (box1_1w + box1_1pad) + boxSVG[2] + (box1_1h + box1_1pad) + boxSVG[3] + '1' + boxSVG[4] + '1' + boxSVG[5] + '20' + boxSVG[6] + '20' + boxSVG[7] + box1_1w + boxSVG[8] + box1_1h + boxSVG[9] + 'none' + boxSVG[10] + 'red' + boxSVG[11] + '2' + boxSVG[12] + '1' + boxSVG[13]; - -//== elem1 box 1 --> box1_1 - var box1_1 = new Surface({ - size: [true, true], - content: boxSVGFromParts1_1 - }); - var box1_1x = 0; - var box1_1y = 2; - var boxMod1_1_1 = new StateModifier({ - transform: Transform.translate(box1_1x, box1_1y, 0) - }); - - var retElemBox = { - ID: "retElemBox", - x: box1_1x, - y: box1_1y, - width: box1_1w + box1_1pad, //outside of SVG BBox NOT shape in box - height: box1_1h + box1_1pad, - shape: boxSVGFromParts1_1 - } - - //Below, calculate a bezier curve that is anchored at the end of such - // text, so need the bounding box of a text element.. to do so, must - // first render the text! That appears to be the only way to calculate - // the bounding box.. there doesn't seem to be any other means to predict - // it. - //So, the famous infrastructure is a bit messed up when it comes to this - // instead, will directly manipulate the DOM, by placing the text as - // an SVG element with fill and stroke set to none so it is not - // visible. Then use the DOM call to get the bounding box. - //Unfortunately, there doesn't appear to be any clean way! - - //Do this part once, the creating a DOM element and adding it to document - var el1 = document.createElement("div"); - document.body.appendChild(el1); //only need to append once then reuse - -//== elem1 box 1 text 1 --> text1_1_1 - var text1_1_1 = new Surface({ - size: [true, true], - content: "properties", - properties: { - color: 'black', - textAlign: 'left', - fontSize: '11px', - cursor: 'hand' - } - }); - - //now set the SVG text string -- from this point down can be repeated - // for multiple strings without removing or re-adding the element, nor - // fiddling with the DOM - var text1_1_1_SVG = ' ' + text1_1_1.content + ' '; - //note that id is inside the text element! Also the fill and stroke are - // null so that nothing paints - el1.innerHTML = text1_1_1_SVG; - - //get the element -- this seems to be what triggers the bounding box calc - var gottenElem = document.getElementById("svgText"); //use ID of the text elem - - //get the box, take the values out of it, and display them - var rect = gottenElem.getBoundingClientRect(); - console.log("svgText width: " + rect.width + " right: " + rect.right); - - var retText1_1_1 = { - ID: "retText1_1_1", - width: rect.width, - height: rect.height, - shape: text1_1_1_SVG - } - - var text1_1_2 = new Surface({ - size: [true, true], - content: "portsIn", - properties: { - cursor: 'pointer' - } - }); - //repeat for the next text surface - var text1_1_2_SVG = ' ' + text1_1_2.content + ' '; - el1.innerHTML = text1_1_2_SVG; - var gottenElem = document.getElementById("svgText"); - var rect = gottenElem.getBoundingClientRect(); - console.log("svgText: " + gottenElem.textContent + " width: " + rect.width + " right: " + rect.right); - - var retText1_1_2 = { - ID: "retText1_1_2", - width: rect.width, - height: rect.height, - shape: text1_1_2_SVG - } - - var text1_1_3 = new Surface({ - size: [true, true], - content: "portsOut", - properties: { - color: 'black', - textAlign: 'left', - fontSize: '11px', - cursor: 'pointer' - } - }); - //repeat for the next text surface - var text1_1_3_SVG = ' ' + text1_1_3.content + ' '; - el1.innerHTML = text1_1_3_SVG; - var gottenElem = document.getElementById("svgText"); - var rect = gottenElem.getBoundingClientRect(); - console.log("svgText: " + gottenElem.textContent + " width: " + rect.width + " right: " + rect.right); - - var retText1_1_3 = { - ID: "retText1_1_3", - width: rect.width, - height: rect.height, - shape: text1_1_3_SVG - } - - var text1_1_4 = new Surface({ - size: [true, true], - content: "subElems", - properties: { - color: 'black', - textAlign: 'left', - fontSize: '11px', - cursor: 'pointer' - } - }); - //repeat for the next text surface - var text1_1_4_SVG = ' ' + text1_1_4.content + ' '; - el1.innerHTML = text1_1_4_SVG; - var gottenElem = document.getElementById("svgText"); - var rect = gottenElem.getBoundingClientRect(); - console.log("svgText: " + gottenElem.textContent + " width: " + rect.width + " right: " + rect.right); - - var retText1_1_4 = { - ID: "retText1_1_4", - width: rect.width, - height: rect.height, - shape: text1_1_4_SVG - } - - -//== elem 1 box 1 text 1 mod 1 -> textMod1_1_1_1 - var text1_1_1x = 8; - var text1_1_1y = 8; - var textMod1_1_1_1 = new StateModifier({ - transform: Transform.translate(text1_1_1x, text1_1_1y, 0) - }); - retText1_1_1.x = 8; retText1_1_1.y = 8; //subtract box x & y - var textMod1_1_2_1 = new StateModifier({ - transform: Transform.translate(8, 25, 0) - }); - retText1_1_2.x = 8; retText1_1_2.y = 23; //subtract box x & y - var textMod1_1_3_1 = new StateModifier({ - transform: Transform.translate(8, 42, 0) - }); - retText1_1_3.x = 8; retText1_1_3.y = 40; //subtract box x & y - var textMod1_1_4_1 = new StateModifier({ - transform: Transform.translate(8, 59, 0) - }); - retText1_1_4.x = 8; retText1_1_4.y = 57; //subtract box x & y -//== - elem1Container.add(boxMod1_1_1).add(box1_1); - elem1Container.add(textMod1_1_1_1).add(text1_1_1); - elem1Container.add(textMod1_1_2_1).add(text1_1_2); - elem1Container.add(textMod1_1_3_1).add(text1_1_3); - elem1Container.add(textMod1_1_4_1).add(text1_1_4); - -//== elem 1 box 2 --> box1_2 -// 1:width 2:height 3:x 4:y 5:rx 6:ry 7:width 8:height 9:fill 10:stroke -// 11:stroke-width 12:opacity - var box1_2w = 183; var box1_2h = 69; var box1_2pad = 2; - var boxSVGFromParts1_2 = boxSVG[1] + (box1_2w + box1_2pad) + boxSVG[2] + (box1_2h + box1_2pad) + boxSVG[3] + '1' + boxSVG[4] + '1' + boxSVG[5] + '20' + boxSVG[6] + '20' + boxSVG[7] + box1_2w + boxSVG[8] + box1_2h + boxSVG[9] + 'none' + boxSVG[10] + 'green' + boxSVG[11] + '2' + boxSVG[12] + '1' + boxSVG[13]; - - var box1_2 = new Surface({ - size: [true, true], - content: boxSVGFromParts1_2 - }); - var box1_2x = 100; - var box1_2y = 2; - var boxMod1_2_1 = new StateModifier({ - transform: Transform.translate(box1_2x, box1_2y, 0) - }); - var retPropertiesBox = { - ID: "retPropertiesBox", - x: box1_2x, - y: box1_2y, - width: box1_2w + box1_2pad, //think should be 2*pad! - height: box1_2h + box1_2pad, - shape: boxSVGFromParts1_2 - } - -//== elem 1 box 2 text 1 --> text1_2_1 - var text1_2_1 = new Surface({ - size: [true, true], - content: "propertyName: TypeOfElement", - properties: { - color: 'black', - textAlign: 'left', - fontSize: '11px', - cursor: 'pointer' - } - }); - //repeat for the next text surface - var text1_2_1_SVG = ' ' + text1_2_1.content + ' '; - el1.innerHTML = text1_2_1_SVG; - var gottenElem = document.getElementById("svgText"); - var rect = gottenElem.getBoundingClientRect(); - console.log("svgText: " + gottenElem.textContent + " width: " + rect.width + " right: " + rect.right); - var retText1_2_1 = { - ID: "retText1_2_1", - width: rect.width, - height: rect.height, - shape: text1_2_1_SVG - } - - - var text1_2_2 = new Surface({ - size: [true, true], - content: "propertyValue: GabeTransformRule", - properties: { - color: 'black', - textAlign: 'left', - fontSize: '11px', - cursor: 'pointer' - } - }); - //repeat for the next text surface - var text1_2_2_SVG = ' ' + text1_2_2.content + ' '; - el1.innerHTML = text1_2_2_SVG; -// document.body.appendChild(el1); - var gottenElem = document.getElementById("svgText"); - var rect = gottenElem.getBoundingClientRect(); - console.log("svgText: " + gottenElem.textContent + " width: " + rect.width + " right: " + rect.right); - var retText1_2_2 = { - ID: "retText1_2_2", - width: rect.width, - height: rect.height, - shape: text1_2_2_SVG - } - - //repeat for the next text surface - var text1_2_3_SVG = ' ' + 'subProperties' + ' '; - el1.innerHTML = text1_2_3_SVG; -// document.body.appendChild(el1); - var gottenElem = document.getElementById("svgText"); -// gottenElem.parentNode.replaceChild(el1, el1); - - var rect = gottenElem.getBoundingClientRect(); - console.log("svgText: " + gottenElem.textContent + " width: " + rect.width + " right: " + rect.right); - var retText1_2_3 = { - ID: "retText1_2_3", - width: rect.width, - height: rect.height, - shape: text1_2_3_SVG - } - var text1_2_3 = new Surface({ - size: [rect.width, rect.height], - content: text1_2_3_SVG - }); - -//== - var textMod1_2_1_1 = new StateModifier({ - transform: Transform.translate(108, 8, 0) - }); - retText1_2_1.x = 8; retText1_2_1.y = 6; //subtract box x & y - var textMod1_2_2_1 = new StateModifier({ - transform: Transform.translate(108, 25, 0) - }); - retText1_2_2.x = 8; retText1_2_2.y = 23; //subtract box x & y - var textMod1_2_3_1 = new StateModifier({ - transform: Transform.translate(108, 42, 0) - }); - retText1_2_3.x = 8; retText1_2_3.y = 40; //subtract box x & y -//== - elem1Container.add(boxMod1_2_1).add(box1_2); - elem1Container.add(textMod1_2_1_1).add(text1_2_1); - elem1Container.add(textMod1_2_2_1).add(text1_2_2); - elem1Container.add(textMod1_2_3_1).add(text1_2_3); - -//Now, add bezier curve, in SVG.. -//One end point is the end of "properties" text surface inside the elem box -//Other end point is the middle of side of properties box - var bezSVG = []; - bezSVG[1] = ''; - - //now calculate the end points of the curve -- they connect to the - // right edge of the "properties" text in the left box, and to the - // middle of the left side of the right box - var bezPoints = [{},{}]; - var bezOrigin = { - x: box1_1x + retText1_1_1.width + retText1_1_1.x, - y: text1_1_1y + retText1_1_1.height/2 + 3 - } - bezPoints[0].x = 0; - bezPoints[0].y = 0; - bezPoints[1].x = box1_2x - bezOrigin.x; - bezPoints[1].y = box1_2y + (box1_2h+box1_2pad)/2 - bezOrigin.y; - - var controlPoints = []; - controlPoints[0] = {x:bezPoints[1].x, y:bezPoints[0].y}; - controlPoints[1] = {x:bezPoints[0].x, y:bezPoints[1].y}; - - - // 1:width 2:height 3:st x 4:st y 5:c1 x 6:c1 y 7:c2 x 8:c2 y 9: end x - // 10: end y 11:fill 12:stroke 13:stroke-width 14:opacity - var bezWidth = (bezPoints[1].x - bezPoints[0].x + 4); //add 2x stroke - var bezHeight = (bezPoints[1].y - bezPoints[0].y + 4); //add 2x stroke - console.log("bez width: " + bezWidth + " and height: " + bezHeight); - var bezSVG1 = ""; - bezSVG1 += bezSVG[1] + bezWidth; - bezSVG1 += bezSVG[2] + bezHeight; - bezSVG1 += bezSVG[3] + (bezPoints[0].x + 2); //move by stroke width - bezSVG1 += bezSVG[4] + (bezPoints[0].y + 2); //move by stroke width - bezSVG1 += bezSVG[5] + controlPoints[0].x; - bezSVG1 += bezSVG[6] + controlPoints[0].y; - bezSVG1 += bezSVG[7] + controlPoints[1].x; - bezSVG1 += bezSVG[8] + controlPoints[1].y; - bezSVG1 += bezSVG[9] + bezPoints[1].x; - bezSVG1 += bezSVG[10] + bezPoints[1].y; - bezSVG1 += bezSVG[11] + 'none' + bezSVG[12] + 'black' + bezSVG[13] + '2' + bezSVG[14] + '1' + bezSVG[15]; - - var bez1_1 = new Surface({ - size: [true, true], - content: bezSVG1 - }); - var bezMod = new StateModifier({ - transform: Transform.translate(bezOrigin.x, bezOrigin.y, 0) - }); - - elem1Container.add(bezMod).add(bez1_1); - - var retBezier = { - ID: "bezier", - x: bezOrigin.x, - y: bezOrigin.y, - width: bezWidth, - height: bezHeight, - shape: bezSVG1 - } - -//for some reason, the way use el1 above makes the DOM stop rendering -// So, in order to get these other elements to render, first remove -// the element that have been using to calc bounding box sizes.. -var elToRemove = document.getElementById("svgText"); -elToRemove.parentNode.parentNode.removeChild(elToRemove.parentNode); - -//okay, now new DOM elements will render -var el2 = document.createElement("span") -var displayStr = bezSVG1.replace(/"); -//document.body.appendChild(el2); -console.log("bez svg: " + bezSVG1); - -//== elem 1 Modifer 1 --> contMod1_1 - var contMod1_1 = new StateModifier({ - transform: Transform.translate(50, 50, 0) - }); - var contMod1_2 = new StateModifier({ - transform: Transform.scale(1, 1) - }); -//== - - //cause this all to be painted, by adding to the main context -// mainContext.add(contMod1_1).add(contMod1_2).add(elem1Container); - - return { - getRootBox: retRootBox, - getElemBox: retElemBox, - getText1_1_1: retText1_1_1, - getText1_1_2: retText1_1_2, - getText1_1_3: retText1_1_3, - getText1_1_4: retText1_1_4, - getPropertiesBox: retPropertiesBox, - getText1_2_1: retText1_2_1, - getText1_2_2: retText1_2_2, - getText1_2_3: retText1_2_3, - getBezier: retBezier - } -}); diff -r cc10d99e3f83 -r a8e5e71adcf3 1__Development/0__Code_Dev/Javascript_approach/MVDM_implementation/lib/classList.js --- a/1__Development/0__Code_Dev/Javascript_approach/MVDM_implementation/lib/classList.js Sat Aug 09 03:34:26 2014 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,138 +0,0 @@ - -/* - * classList.js: Cross-browser full element.classList implementation. - * 2011-06-15 - * - * By Eli Grey, http://eligrey.com - * Public Domain. - * NO WARRANTY EXPRESSED OR IMPLIED. USE AT YOUR OWN RISK. - */ - -/*global self, document, DOMException */ - -/*! @source http://purl.eligrey.com/github/classList.js/blob/master/classList.js*/ - -if (typeof document !== "undefined" && !("classList" in document.createElement("a"))) { - -(function (view) { - -"use strict"; - -var - classListProp = "classList" - , protoProp = "prototype" - , elemCtrProto = (view.HTMLElement || view.Element)[protoProp] - , objCtr = Object - , strTrim = String[protoProp].trim || function () { - return this.replace(/^\s+|\s+$/g, ""); - } - , arrIndexOf = Array[protoProp].indexOf || function (item) { - var - i = 0 - , len = this.length - ; - for (; i < len; i++) { - if (i in this && this[i] === item) { - return i; - } - } - return -1; - } - // Vendors: please allow content code to instantiate DOMExceptions - , DOMEx = function (type, message) { - this.name = type; - this.code = DOMException[type]; - this.message = message; - } - , checkTokenAndGetIndex = function (classList, token) { - if (token === "") { - throw new DOMEx( - "SYNTAX_ERR" - , "An invalid or illegal string was specified" - ); - } - if (/\s/.test(token)) { - throw new DOMEx( - "INVALID_CHARACTER_ERR" - , "String contains an invalid character" - ); - } - return arrIndexOf.call(classList, token); - } - , ClassList = function (elem) { - var - trimmedClasses = strTrim.call(elem.className) - , classes = trimmedClasses ? trimmedClasses.split(/\s+/) : [] - , i = 0 - , len = classes.length - ; - for (; i < len; i++) { - this.push(classes[i]); - } - this._updateClassName = function () { - elem.className = this.toString(); - }; - } - , classListProto = ClassList[protoProp] = [] - , classListGetter = function () { - return new ClassList(this); - } -; -// Most DOMException implementations don't allow calling DOMException's toString() -// on non-DOMExceptions. Error's toString() is sufficient here. -DOMEx[protoProp] = Error[protoProp]; -classListProto.item = function (i) { - return this[i] || null; -}; -classListProto.contains = function (token) { - token += ""; - return checkTokenAndGetIndex(this, token) !== -1; -}; -classListProto.add = function (token) { - token += ""; - if (checkTokenAndGetIndex(this, token) === -1) { - this.push(token); - this._updateClassName(); - } -}; -classListProto.remove = function (token) { - token += ""; - var index = checkTokenAndGetIndex(this, token); - if (index !== -1) { - this.splice(index, 1); - this._updateClassName(); - } -}; -classListProto.toggle = function (token) { - token += ""; - if (checkTokenAndGetIndex(this, token) === -1) { - this.add(token); - } else { - this.remove(token); - } -}; -classListProto.toString = function () { - return this.join(" "); -}; - -if (objCtr.defineProperty) { - var classListPropDesc = { - get: classListGetter - , enumerable: true - , configurable: true - }; - try { - objCtr.defineProperty(elemCtrProto, classListProp, classListPropDesc); - } catch (ex) { // IE 8 doesn't support enumerable:true - if (ex.number === -0x7FF5EC54) { - classListPropDesc.enumerable = false; - objCtr.defineProperty(elemCtrProto, classListProp, classListPropDesc); - } - } -} else if (objCtr[protoProp].__defineGetter__) { - elemCtrProto.__defineGetter__(classListProp, classListGetter); -} - -}(self)); - -} diff -r cc10d99e3f83 -r a8e5e71adcf3 1__Development/0__Code_Dev/Javascript_approach/MVDM_implementation/lib/famous.css --- a/1__Development/0__Code_Dev/Javascript_approach/MVDM_implementation/lib/famous.css Sat Aug 09 03:34:26 2014 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,77 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. - * - * Owner: mark@famo.us - * @license MPL 2.0 - * @copyright Famous Industries, Inc. 2014 - */ - - -html { - width: 100%; - height: 100%; - margin: 0px; - padding: 0px; - overflow: hidden; - -webkit-transform-style: preserve-3d; - transform-style: preserve-3d; -} - -body { - position: absolute; - width: 100%; - height: 100%; - margin: 0px; - padding: 0px; - -webkit-transform-style: preserve-3d; - transform-style: preserve-3d; - -webkit-font-smoothing: antialiased; - -webkit-tap-highlight-color: transparent; - -webkit-perspective: 0; - perspective: none; - overflow: hidden; -} - -.famous-container, .famous-group { - position: absolute; - top: 0px; - left: 0px; - bottom: 0px; - right: 0px; - overflow: visible; - -webkit-transform-style: preserve-3d; - transform-style: preserve-3d; - -webkit-backface-visibility: visible; - backface-visibility: visible; - pointer-events: none; -} - -.famous-group { - width: 0px; - height: 0px; - margin: 0px; - padding: 0px; - -webkit-transform-style: preserve-3d; - transform-style: preserve-3d; -} - -.famous-surface { - position: absolute; - -webkit-transform-origin: center center; - transform-origin: center center; - -webkit-backface-visibility: hidden; - backface-visibility: hidden; - -webkit-transform-style: flat; - transform-style: preserve-3d; /* performance */ - -webkit-box-sizing: border-box; - -moz-box-sizing: border-box; - -webkit-tap-highlight-color: transparent; - pointer-events: auto; -} - -.famous-container-group { - position: relative; - width: 100%; - height: 100%; -} diff -r cc10d99e3f83 -r a8e5e71adcf3 1__Development/0__Code_Dev/Javascript_approach/MVDM_implementation/lib/famous.js --- a/1__Development/0__Code_Dev/Javascript_approach/MVDM_implementation/lib/famous.js Sat Aug 09 03:34:26 2014 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,17609 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. - * - * Owner: mark@famo.us - * @license MPL 2.0 - * @copyright Famous Industries, Inc. 2014 - */ - -define('famous/core/Entity',['require','exports','module'],function(require, exports, module) { - /** - * A singleton that maintains a global registry of Surfaces. - * Private. - * - * @private - * @static - * @class Entity - */ - - var entities = []; - - /** - * Get entity from global index. - * - * @private - * @method get - * @param {Number} id entity reigstration id - * @return {Surface} entity in the global index - */ - function get(id) { - return entities[id]; - } - - /** - * Overwrite entity in the global index - * - * @private - * @method set - * @param {Number} id entity reigstration id - * @return {Surface} entity to add to the global index - */ - function set(id, entity) { - entities[id] = entity; - } - - /** - * Add entity to global index - * - * @private - * @method register - * @param {Surface} entity to add to global index - * @return {Number} new id - */ - function register(entity) { - var id = entities.length; - set(id, entity); - return id; - } - - /** - * Remove entity from global index - * - * @private - * @method unregister - * @param {Number} id entity reigstration id - */ - function unregister(id) { - set(id, null); - } - - module.exports = { - register: register, - unregister: unregister, - get: get, - set: set - }; -}); - -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. - * - * Owner: mark@famo.us - * @license MPL 2.0 - * @copyright Famous Industries, Inc. 2014 - */ - -define('famous/core/Transform',['require','exports','module'],function(require, exports, module) { - - /** - * A high-performance static matrix math library used to calculate - * affine transforms on surfaces and other renderables. - * Famo.us uses 4x4 matrices corresponding directly to - * WebKit matrices (column-major order). - * - * The internal "type" of a Matrix is a 16-long float array in - * row-major order, with: - * elements [0],[1],[2],[4],[5],[6],[8],[9],[10] forming the 3x3 - * transformation matrix; - * elements [12], [13], [14] corresponding to the t_x, t_y, t_z - * translation; - * elements [3], [7], [11] set to 0; - * element [15] set to 1. - * All methods are static. - * - * @static - * - * @class Transform - */ - var Transform = {}; - - // WARNING: these matrices correspond to WebKit matrices, which are - // transposed from their math counterparts - Transform.precision = 1e-6; - Transform.identity = [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1]; - - /** - * Multiply two or more Transform matrix types to return a Transform matrix. - * - * @method multiply4x4 - * @static - * @param {Transform} a left Transform - * @param {Transform} b right Transform - * @return {Transform} - */ - Transform.multiply4x4 = function multiply4x4(a, b) { - return [ - a[0] * b[0] + a[4] * b[1] + a[8] * b[2] + a[12] * b[3], - a[1] * b[0] + a[5] * b[1] + a[9] * b[2] + a[13] * b[3], - a[2] * b[0] + a[6] * b[1] + a[10] * b[2] + a[14] * b[3], - a[3] * b[0] + a[7] * b[1] + a[11] * b[2] + a[15] * b[3], - a[0] * b[4] + a[4] * b[5] + a[8] * b[6] + a[12] * b[7], - a[1] * b[4] + a[5] * b[5] + a[9] * b[6] + a[13] * b[7], - a[2] * b[4] + a[6] * b[5] + a[10] * b[6] + a[14] * b[7], - a[3] * b[4] + a[7] * b[5] + a[11] * b[6] + a[15] * b[7], - a[0] * b[8] + a[4] * b[9] + a[8] * b[10] + a[12] * b[11], - a[1] * b[8] + a[5] * b[9] + a[9] * b[10] + a[13] * b[11], - a[2] * b[8] + a[6] * b[9] + a[10] * b[10] + a[14] * b[11], - a[3] * b[8] + a[7] * b[9] + a[11] * b[10] + a[15] * b[11], - a[0] * b[12] + a[4] * b[13] + a[8] * b[14] + a[12] * b[15], - a[1] * b[12] + a[5] * b[13] + a[9] * b[14] + a[13] * b[15], - a[2] * b[12] + a[6] * b[13] + a[10] * b[14] + a[14] * b[15], - a[3] * b[12] + a[7] * b[13] + a[11] * b[14] + a[15] * b[15] - ]; - }; - - /** - * Fast-multiply two or more Transform matrix types to return a - * Matrix, assuming bottom row on each is [0 0 0 1]. - * - * @method multiply - * @static - * @param {Transform} a left Transform - * @param {Transform} b right Transform - * @return {Transform} - */ - Transform.multiply = function multiply(a, b) { - return [ - a[0] * b[0] + a[4] * b[1] + a[8] * b[2], - a[1] * b[0] + a[5] * b[1] + a[9] * b[2], - a[2] * b[0] + a[6] * b[1] + a[10] * b[2], - 0, - a[0] * b[4] + a[4] * b[5] + a[8] * b[6], - a[1] * b[4] + a[5] * b[5] + a[9] * b[6], - a[2] * b[4] + a[6] * b[5] + a[10] * b[6], - 0, - a[0] * b[8] + a[4] * b[9] + a[8] * b[10], - a[1] * b[8] + a[5] * b[9] + a[9] * b[10], - a[2] * b[8] + a[6] * b[9] + a[10] * b[10], - 0, - a[0] * b[12] + a[4] * b[13] + a[8] * b[14] + a[12], - a[1] * b[12] + a[5] * b[13] + a[9] * b[14] + a[13], - a[2] * b[12] + a[6] * b[13] + a[10] * b[14] + a[14], - 1 - ]; - }; - - /** - * Return a Transform translated by additional amounts in each - * dimension. This is equivalent to the result of - * - * Transform.multiply(Matrix.translate(t[0], t[1], t[2]), m). - * - * @method thenMove - * @static - * @param {Transform} m a Transform - * @param {Array.Number} t floats delta vector of length 2 or 3 - * @return {Transform} - */ - Transform.thenMove = function thenMove(m, t) { - if (!t[2]) t[2] = 0; - return [m[0], m[1], m[2], 0, m[4], m[5], m[6], 0, m[8], m[9], m[10], 0, m[12] + t[0], m[13] + t[1], m[14] + t[2], 1]; - }; - - /** - * Return a Transform atrix which represents the result of a transform matrix - * applied after a move. This is faster than the equivalent multiply. - * This is equivalent to the result of: - * - * Transform.multiply(m, Transform.translate(t[0], t[1], t[2])). - * - * @method moveThen - * @static - * @param {Array.Number} v vector representing initial movement - * @param {Transform} m matrix to apply afterwards - * @return {Transform} the resulting matrix - */ - Transform.moveThen = function moveThen(v, m) { - if (!v[2]) v[2] = 0; - var t0 = v[0] * m[0] + v[1] * m[4] + v[2] * m[8]; - var t1 = v[0] * m[1] + v[1] * m[5] + v[2] * m[9]; - var t2 = v[0] * m[2] + v[1] * m[6] + v[2] * m[10]; - return Transform.thenMove(m, [t0, t1, t2]); - }; - - /** - * Return a Transform which represents a translation by specified - * amounts in each dimension. - * - * @method translate - * @static - * @param {Number} x x translation - * @param {Number} y y translation - * @param {Number} z z translation - * @return {Transform} - */ - Transform.translate = function translate(x, y, z) { - if (z === undefined) z = 0; - return [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, x, y, z, 1]; - }; - - /** - * Return a Transform scaled by a vector in each - * dimension. This is a more performant equivalent to the result of - * - * Transform.multiply(Transform.scale(s[0], s[1], s[2]), m). - * - * @method thenScale - * @static - * @param {Transform} m a matrix - * @param {Array.Number} s delta vector (array of floats && - * array.length == 3) - * @return {Transform} - */ - Transform.thenScale = function thenScale(m, s) { - return [ - s[0] * m[0], s[1] * m[1], s[2] * m[2], 0, - s[0] * m[4], s[1] * m[5], s[2] * m[6], 0, - s[0] * m[8], s[1] * m[9], s[2] * m[10], 0, - s[0] * m[12], s[1] * m[13], s[2] * m[14], 1 - ]; - }; - - /** - * Return a Transform which represents a scale by specified amounts - * in each dimension. - * - * @method scale - * @static - * @param {Number} x x scale factor - * @param {Number} y y scale factor - * @param {Number} z z scale factor - * @return {Transform} - */ - Transform.scale = function scale(x, y, z) { - if (z === undefined) z = 1; - return [x, 0, 0, 0, 0, y, 0, 0, 0, 0, z, 0, 0, 0, 0, 1]; - }; - - /** - * Return a Transform which represents a clockwise - * rotation around the x axis. - * - * @method rotateX - * @static - * @param {Number} theta radians - * @return {Transform} - */ - Transform.rotateX = function rotateX(theta) { - var cosTheta = Math.cos(theta); - var sinTheta = Math.sin(theta); - return [1, 0, 0, 0, 0, cosTheta, sinTheta, 0, 0, -sinTheta, cosTheta, 0, 0, 0, 0, 1]; - }; - - /** - * Return a Transform which represents a clockwise - * rotation around the y axis. - * - * @method rotateY - * @static - * @param {Number} theta radians - * @return {Transform} - */ - Transform.rotateY = function rotateY(theta) { - var cosTheta = Math.cos(theta); - var sinTheta = Math.sin(theta); - return [cosTheta, 0, -sinTheta, 0, 0, 1, 0, 0, sinTheta, 0, cosTheta, 0, 0, 0, 0, 1]; - }; - - /** - * Return a Transform which represents a clockwise - * rotation around the z axis. - * - * @method rotateZ - * @static - * @param {Number} theta radians - * @return {Transform} - */ - Transform.rotateZ = function rotateZ(theta) { - var cosTheta = Math.cos(theta); - var sinTheta = Math.sin(theta); - return [cosTheta, sinTheta, 0, 0, -sinTheta, cosTheta, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1]; - }; - - /** - * Return a Transform which represents composed clockwise - * rotations along each of the axes. Equivalent to the result of - * Matrix.multiply(rotateX(phi), rotateY(theta), rotateZ(psi)). - * - * @method rotate - * @static - * @param {Number} phi radians to rotate about the positive x axis - * @param {Number} theta radians to rotate about the positive y axis - * @param {Number} psi radians to rotate about the positive z axis - * @return {Transform} - */ - Transform.rotate = function rotate(phi, theta, psi) { - var cosPhi = Math.cos(phi); - var sinPhi = Math.sin(phi); - var cosTheta = Math.cos(theta); - var sinTheta = Math.sin(theta); - var cosPsi = Math.cos(psi); - var sinPsi = Math.sin(psi); - var result = [ - cosTheta * cosPsi, - cosPhi * sinPsi + sinPhi * sinTheta * cosPsi, - sinPhi * sinPsi - cosPhi * sinTheta * cosPsi, - 0, - -cosTheta * sinPsi, - cosPhi * cosPsi - sinPhi * sinTheta * sinPsi, - sinPhi * cosPsi + cosPhi * sinTheta * sinPsi, - 0, - sinTheta, - -sinPhi * cosTheta, - cosPhi * cosTheta, - 0, - 0, 0, 0, 1 - ]; - return result; - }; - - /** - * Return a Transform which represents an axis-angle rotation - * - * @method rotateAxis - * @static - * @param {Array.Number} v unit vector representing the axis to rotate about - * @param {Number} theta radians to rotate clockwise about the axis - * @return {Transform} - */ - Transform.rotateAxis = function rotateAxis(v, theta) { - var sinTheta = Math.sin(theta); - var cosTheta = Math.cos(theta); - var verTheta = 1 - cosTheta; // versine of theta - - var xxV = v[0] * v[0] * verTheta; - var xyV = v[0] * v[1] * verTheta; - var xzV = v[0] * v[2] * verTheta; - var yyV = v[1] * v[1] * verTheta; - var yzV = v[1] * v[2] * verTheta; - var zzV = v[2] * v[2] * verTheta; - var xs = v[0] * sinTheta; - var ys = v[1] * sinTheta; - var zs = v[2] * sinTheta; - - var result = [ - xxV + cosTheta, xyV + zs, xzV - ys, 0, - xyV - zs, yyV + cosTheta, yzV + xs, 0, - xzV + ys, yzV - xs, zzV + cosTheta, 0, - 0, 0, 0, 1 - ]; - return result; - }; - - /** - * Return a Transform which represents a transform matrix applied about - * a separate origin point. - * - * @method aboutOrigin - * @static - * @param {Array.Number} v origin point to apply matrix - * @param {Transform} m matrix to apply - * @return {Transform} - */ - Transform.aboutOrigin = function aboutOrigin(v, m) { - var t0 = v[0] - (v[0] * m[0] + v[1] * m[4] + v[2] * m[8]); - var t1 = v[1] - (v[0] * m[1] + v[1] * m[5] + v[2] * m[9]); - var t2 = v[2] - (v[0] * m[2] + v[1] * m[6] + v[2] * m[10]); - return Transform.thenMove(m, [t0, t1, t2]); - }; - - /** - * Return a Transform representation of a skew transformation - * - * @method skew - * @static - * @param {Number} phi scale factor skew in the x axis - * @param {Number} theta scale factor skew in the y axis - * @param {Number} psi scale factor skew in the z axis - * @return {Transform} - */ - Transform.skew = function skew(phi, theta, psi) { - return [1, 0, 0, 0, Math.tan(psi), 1, 0, 0, Math.tan(theta), Math.tan(phi), 1, 0, 0, 0, 0, 1]; - }; - - /** - * Return a Transform representation of a skew in the x-direction - * - * @method skewX - * @static - * @param {Number} angle the angle between the top and left sides - * @return {Transform} - */ - Transform.skewX = function skewX(angle) { - return [1, 0, 0, 0, Math.tan(angle), 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1]; - }; - - /** - * Return a Transform representation of a skew in the y-direction - * - * @method skewY - * @static - * @param {Number} angle the angle between the top and right sides - * @return {Transform} - */ - Transform.skewY = function skewY(angle) { - return [1, Math.tan(angle), 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1]; - }; - - /** - * Returns a perspective Transform matrix - * - * @method perspective - * @static - * @param {Number} focusZ z position of focal point - * @return {Transform} - */ - Transform.perspective = function perspective(focusZ) { - return [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, -1 / focusZ, 0, 0, 0, 1]; - }; - - /** - * Return translation vector component of given Transform - * - * @method getTranslate - * @static - * @param {Transform} m Transform - * @return {Array.Number} the translation vector [t_x, t_y, t_z] - */ - Transform.getTranslate = function getTranslate(m) { - return [m[12], m[13], m[14]]; - }; - - /** - * Return inverse affine transform for given Transform. - * Note: This assumes m[3] = m[7] = m[11] = 0, and m[15] = 1. - * Will provide incorrect results if not invertible or preconditions not met. - * - * @method inverse - * @static - * @param {Transform} m Transform - * @return {Transform} - */ - Transform.inverse = function inverse(m) { - // only need to consider 3x3 section for affine - var c0 = m[5] * m[10] - m[6] * m[9]; - var c1 = m[4] * m[10] - m[6] * m[8]; - var c2 = m[4] * m[9] - m[5] * m[8]; - var c4 = m[1] * m[10] - m[2] * m[9]; - var c5 = m[0] * m[10] - m[2] * m[8]; - var c6 = m[0] * m[9] - m[1] * m[8]; - var c8 = m[1] * m[6] - m[2] * m[5]; - var c9 = m[0] * m[6] - m[2] * m[4]; - var c10 = m[0] * m[5] - m[1] * m[4]; - var detM = m[0] * c0 - m[1] * c1 + m[2] * c2; - var invD = 1 / detM; - var result = [ - invD * c0, -invD * c4, invD * c8, 0, - -invD * c1, invD * c5, -invD * c9, 0, - invD * c2, -invD * c6, invD * c10, 0, - 0, 0, 0, 1 - ]; - result[12] = -m[12] * result[0] - m[13] * result[4] - m[14] * result[8]; - result[13] = -m[12] * result[1] - m[13] * result[5] - m[14] * result[9]; - result[14] = -m[12] * result[2] - m[13] * result[6] - m[14] * result[10]; - return result; - }; - - /** - * Returns the transpose of a 4x4 matrix - * - * @method transpose - * @static - * @param {Transform} m matrix - * @return {Transform} the resulting transposed matrix - */ - Transform.transpose = function transpose(m) { - return [m[0], m[4], m[8], m[12], m[1], m[5], m[9], m[13], m[2], m[6], m[10], m[14], m[3], m[7], m[11], m[15]]; - }; - - function _normSquared(v) { - return (v.length === 2) ? v[0] * v[0] + v[1] * v[1] : v[0] * v[0] + v[1] * v[1] + v[2] * v[2]; - } - function _norm(v) { - return Math.sqrt(_normSquared(v)); - } - function _sign(n) { - return (n < 0) ? -1 : 1; - } - - /** - * Decompose Transform into separate .translate, .rotate, .scale, - * and .skew components. - * - * @method interpret - * @static - * @param {Transform} M transform matrix - * @return {Object} matrix spec object with component matrices .translate, - * .rotate, .scale, .skew - */ - Transform.interpret = function interpret(M) { - - // QR decomposition via Householder reflections - //FIRST ITERATION - - //default Q1 to the identity matrix; - var x = [M[0], M[1], M[2]]; // first column vector - var sgn = _sign(x[0]); // sign of first component of x (for stability) - var xNorm = _norm(x); // norm of first column vector - var v = [x[0] + sgn * xNorm, x[1], x[2]]; // v = x + sign(x[0])|x|e1 - var mult = 2 / _normSquared(v); // mult = 2/v'v - - //bail out if our Matrix is singular - if (mult >= Infinity) { - return {translate: Transform.getTranslate(M), rotate: [0, 0, 0], scale: [0, 0, 0], skew: [0, 0, 0]}; - } - - //evaluate Q1 = I - 2vv'/v'v - var Q1 = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1]; - - //diagonals - Q1[0] = 1 - mult * v[0] * v[0]; // 0,0 entry - Q1[5] = 1 - mult * v[1] * v[1]; // 1,1 entry - Q1[10] = 1 - mult * v[2] * v[2]; // 2,2 entry - - //upper diagonal - Q1[1] = -mult * v[0] * v[1]; // 0,1 entry - Q1[2] = -mult * v[0] * v[2]; // 0,2 entry - Q1[6] = -mult * v[1] * v[2]; // 1,2 entry - - //lower diagonal - Q1[4] = Q1[1]; // 1,0 entry - Q1[8] = Q1[2]; // 2,0 entry - Q1[9] = Q1[6]; // 2,1 entry - - //reduce first column of M - var MQ1 = Transform.multiply(Q1, M); - - //SECOND ITERATION on (1,1) minor - var x2 = [MQ1[5], MQ1[6]]; - var sgn2 = _sign(x2[0]); // sign of first component of x (for stability) - var x2Norm = _norm(x2); // norm of first column vector - var v2 = [x2[0] + sgn2 * x2Norm, x2[1]]; // v = x + sign(x[0])|x|e1 - var mult2 = 2 / _normSquared(v2); // mult = 2/v'v - - //evaluate Q2 = I - 2vv'/v'v - var Q2 = [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1]; - - //diagonal - Q2[5] = 1 - mult2 * v2[0] * v2[0]; // 1,1 entry - Q2[10] = 1 - mult2 * v2[1] * v2[1]; // 2,2 entry - - //off diagonals - Q2[6] = -mult2 * v2[0] * v2[1]; // 2,1 entry - Q2[9] = Q2[6]; // 1,2 entry - - //calc QR decomposition. Q = Q1*Q2, R = Q'*M - var Q = Transform.multiply(Q2, Q1); //note: really Q transpose - var R = Transform.multiply(Q, M); - - //remove negative scaling - var remover = Transform.scale(R[0] < 0 ? -1 : 1, R[5] < 0 ? -1 : 1, R[10] < 0 ? -1 : 1); - R = Transform.multiply(R, remover); - Q = Transform.multiply(remover, Q); - - //decompose into rotate/scale/skew matrices - var result = {}; - result.translate = Transform.getTranslate(M); - result.rotate = [Math.atan2(-Q[6], Q[10]), Math.asin(Q[2]), Math.atan2(-Q[1], Q[0])]; - if (!result.rotate[0]) { - result.rotate[0] = 0; - result.rotate[2] = Math.atan2(Q[4], Q[5]); - } - result.scale = [R[0], R[5], R[10]]; - result.skew = [Math.atan2(R[9], result.scale[2]), Math.atan2(R[8], result.scale[2]), Math.atan2(R[4], result.scale[0])]; - - //double rotation workaround - if (Math.abs(result.rotate[0]) + Math.abs(result.rotate[2]) > 1.5 * Math.PI) { - result.rotate[1] = Math.PI - result.rotate[1]; - if (result.rotate[1] > Math.PI) result.rotate[1] -= 2 * Math.PI; - if (result.rotate[1] < -Math.PI) result.rotate[1] += 2 * Math.PI; - if (result.rotate[0] < 0) result.rotate[0] += Math.PI; - else result.rotate[0] -= Math.PI; - if (result.rotate[2] < 0) result.rotate[2] += Math.PI; - else result.rotate[2] -= Math.PI; - } - - return result; - }; - - /** - * Weighted average between two matrices by averaging their - * translation, rotation, scale, skew components. - * f(M1,M2,t) = (1 - t) * M1 + t * M2 - * - * @method average - * @static - * @param {Transform} M1 f(M1,M2,0) = M1 - * @param {Transform} M2 f(M1,M2,1) = M2 - * @param {Number} t - * @return {Transform} - */ - Transform.average = function average(M1, M2, t) { - t = (t === undefined) ? 0.5 : t; - var specM1 = Transform.interpret(M1); - var specM2 = Transform.interpret(M2); - - var specAvg = { - translate: [0, 0, 0], - rotate: [0, 0, 0], - scale: [0, 0, 0], - skew: [0, 0, 0] - }; - - for (var i = 0; i < 3; i++) { - specAvg.translate[i] = (1 - t) * specM1.translate[i] + t * specM2.translate[i]; - specAvg.rotate[i] = (1 - t) * specM1.rotate[i] + t * specM2.rotate[i]; - specAvg.scale[i] = (1 - t) * specM1.scale[i] + t * specM2.scale[i]; - specAvg.skew[i] = (1 - t) * specM1.skew[i] + t * specM2.skew[i]; - } - return Transform.build(specAvg); - }; - - /** - * Compose .translate, .rotate, .scale, .skew components into - * Transform matrix - * - * @method build - * @static - * @param {matrixSpec} spec object with component matrices .translate, - * .rotate, .scale, .skew - * @return {Transform} composed transform - */ - Transform.build = function build(spec) { - var scaleMatrix = Transform.scale(spec.scale[0], spec.scale[1], spec.scale[2]); - var skewMatrix = Transform.skew(spec.skew[0], spec.skew[1], spec.skew[2]); - var rotateMatrix = Transform.rotate(spec.rotate[0], spec.rotate[1], spec.rotate[2]); - return Transform.thenMove(Transform.multiply(Transform.multiply(rotateMatrix, skewMatrix), scaleMatrix), spec.translate); - }; - - /** - * Determine if two Transforms are component-wise equal - * Warning: breaks on perspective Transforms - * - * @method equals - * @static - * @param {Transform} a matrix - * @param {Transform} b matrix - * @return {boolean} - */ - Transform.equals = function equals(a, b) { - return !Transform.notEquals(a, b); - }; - - /** - * Determine if two Transforms are component-wise unequal - * Warning: breaks on perspective Transforms - * - * @method notEquals - * @static - * @param {Transform} a matrix - * @param {Transform} b matrix - * @return {boolean} - */ - Transform.notEquals = function notEquals(a, b) { - if (a === b) return false; - - // shortci - return !(a && b) || - a[12] !== b[12] || a[13] !== b[13] || a[14] !== b[14] || - a[0] !== b[0] || a[1] !== b[1] || a[2] !== b[2] || - a[4] !== b[4] || a[5] !== b[5] || a[6] !== b[6] || - a[8] !== b[8] || a[9] !== b[9] || a[10] !== b[10]; - }; - - /** - * Constrain angle-trio components to range of [-pi, pi). - * - * @method normalizeRotation - * @static - * @param {Array.Number} rotation phi, theta, psi (array of floats - * && array.length == 3) - * @return {Array.Number} new phi, theta, psi triplet - * (array of floats && array.length == 3) - */ - Transform.normalizeRotation = function normalizeRotation(rotation) { - var result = rotation.slice(0); - if (result[0] === Math.PI * 0.5 || result[0] === -Math.PI * 0.5) { - result[0] = -result[0]; - result[1] = Math.PI - result[1]; - result[2] -= Math.PI; - } - if (result[0] > Math.PI * 0.5) { - result[0] = result[0] - Math.PI; - result[1] = Math.PI - result[1]; - result[2] -= Math.PI; - } - if (result[0] < -Math.PI * 0.5) { - result[0] = result[0] + Math.PI; - result[1] = -Math.PI - result[1]; - result[2] -= Math.PI; - } - while (result[1] < -Math.PI) result[1] += 2 * Math.PI; - while (result[1] >= Math.PI) result[1] -= 2 * Math.PI; - while (result[2] < -Math.PI) result[2] += 2 * Math.PI; - while (result[2] >= Math.PI) result[2] -= 2 * Math.PI; - return result; - }; - - /** - * (Property) Array defining a translation forward in z by 1 - * - * @property {array} inFront - * @static - * @final - */ - Transform.inFront = [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 1e-3, 1]; - - /** - * (Property) Array defining a translation backwards in z by 1 - * - * @property {array} behind - * @static - * @final - */ - Transform.behind = [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, -1e-3, 1]; - - module.exports = Transform; -}); - - -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. - * - * Owner: mark@famo.us - * @license MPL 2.0 - * @copyright Famous Industries, Inc. 2014 - */ - -define('famous/core/SpecParser',['require','exports','module','./Transform'],function(require, exports, module) { - var Transform = require('./Transform'); - - /** - * - * This object translates the rendering instructions ("render specs") - * that renderable components generate into document update - * instructions ("update specs"). Private. - * - * @private - * @class SpecParser - * @constructor - */ - function SpecParser() { - this.result = {}; - } - SpecParser._instance = new SpecParser(); - - /** - * Convert a render spec coming from the context's render chain to an - * update spec for the update chain. This is the only major entry point - * for a consumer of this class. - * - * @method parse - * @static - * @private - * - * @param {renderSpec} spec input render spec - * @param {Object} context context to do the parse in - * @return {Object} the resulting update spec (if no callback - * specified, else none) - */ - SpecParser.parse = function parse(spec, context) { - return SpecParser._instance.parse(spec, context); - }; - - /** - * Convert a renderSpec coming from the context's render chain to an update - * spec for the update chain. This is the only major entrypoint for a - * consumer of this class. - * - * @method parse - * - * @private - * @param {renderSpec} spec input render spec - * @param {Context} context - * @return {updateSpec} the resulting update spec - */ - SpecParser.prototype.parse = function parse(spec, context) { - this.reset(); - this._parseSpec(spec, context, Transform.identity); - return this.result; - }; - - /** - * Prepare SpecParser for re-use (or first use) by setting internal state - * to blank. - * - * @private - * @method reset - */ - SpecParser.prototype.reset = function reset() { - this.result = {}; - }; - - // Multiply matrix M by vector v - function _vecInContext(v, m) { - return [ - v[0] * m[0] + v[1] * m[4] + v[2] * m[8], - v[0] * m[1] + v[1] * m[5] + v[2] * m[9], - v[0] * m[2] + v[1] * m[6] + v[2] * m[10] - ]; - } - - var _originZeroZero = [0, 0]; - - // From the provided renderSpec tree, recursively compose opacities, - // origins, transforms, and sizes corresponding to each surface id from - // the provided renderSpec tree structure. On completion, those - // properties of 'this' object should be ready to use to build an - // updateSpec. - SpecParser.prototype._parseSpec = function _parseSpec(spec, parentContext, sizeContext) { - var id; - var target; - var transform; - var opacity; - var origin; - var align; - var size; - - if (typeof spec === 'number') { - id = spec; - transform = parentContext.transform; - align = parentContext.align || parentContext.origin; - if (parentContext.size && align && (align[0] || align[1])) { - var alignAdjust = [align[0] * parentContext.size[0], align[1] * parentContext.size[1], 0]; - transform = Transform.thenMove(transform, _vecInContext(alignAdjust, sizeContext)); - } - this.result[id] = { - transform: transform, - opacity: parentContext.opacity, - origin: parentContext.origin || _originZeroZero, - align: parentContext.align || parentContext.origin || _originZeroZero, - size: parentContext.size - }; - } - else if (!spec) { // placed here so 0 will be cached earlier - return; - } - else if (spec instanceof Array) { - for (var i = 0; i < spec.length; i++) { - this._parseSpec(spec[i], parentContext, sizeContext); - } - } - else { - target = spec.target; - transform = parentContext.transform; - opacity = parentContext.opacity; - origin = parentContext.origin; - align = parentContext.align; - size = parentContext.size; - var nextSizeContext = sizeContext; - - if (spec.opacity !== undefined) opacity = parentContext.opacity * spec.opacity; - if (spec.transform) transform = Transform.multiply(parentContext.transform, spec.transform); - if (spec.origin) { - origin = spec.origin; - nextSizeContext = parentContext.transform; - } - 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 (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; - origin = null; - align = null; - } - - this._parseSpec(target, { - transform: transform, - opacity: opacity, - origin: origin, - align: align, - size: size - }, nextSizeContext); - } - }; - - module.exports = SpecParser; -}); - -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. - * - * Owner: mark@famo.us - * @license MPL 2.0 - * @copyright Famous Industries, Inc. 2014 - */ - -define('famous/core/RenderNode',['require','exports','module','./Entity','./SpecParser'],function(require, exports, module) { - var Entity = require('./Entity'); - var SpecParser = require('./SpecParser'); - - /** - * A wrapper for inserting a renderable component (like a Modifer or - * Surface) into the render tree. - * - * @class RenderNode - * @constructor - * - * @param {Object} object Target renderable component - */ - function RenderNode(object) { - this._object = null; - this._child = null; - this._hasMultipleChildren = false; - this._isRenderable = false; - this._isModifier = false; - - this._resultCache = {}; - this._prevResults = {}; - - this._childResult = null; - - if (object) this.set(object); - } - - /** - * Append a renderable to the list of this node's children. - * This produces a new RenderNode in the tree. - * Note: Does not double-wrap if child is a RenderNode already. - * - * @method add - * @param {Object} child renderable object - * @return {RenderNode} new render node wrapping child - */ - RenderNode.prototype.add = function add(child) { - var childNode = (child instanceof RenderNode) ? child : new RenderNode(child); - if (this._child instanceof Array) this._child.push(childNode); - else if (this._child) { - this._child = [this._child, childNode]; - this._hasMultipleChildren = true; - this._childResult = []; // to be used later - } - else this._child = childNode; - - return childNode; - }; - - /** - * Return the single wrapped object. Returns null if this node has multiple child nodes. - * - * @method get - * - * @return {Ojbect} contained renderable object - */ - RenderNode.prototype.get = function get() { - return this._object || (this._hasMultipleChildren ? null : (this._child ? this._child.get() : null)); - }; - - /** - * Overwrite the list of children to contain the single provided object - * - * @method set - * @param {Object} child renderable object - * @return {RenderNode} this render node, or child if it is a RenderNode - */ - RenderNode.prototype.set = function set(child) { - this._childResult = null; - this._hasMultipleChildren = false; - this._isRenderable = child.render ? true : false; - this._isModifier = child.modify ? true : false; - this._object = child; - this._child = null; - if (child instanceof RenderNode) return child; - else return this; - }; - - /** - * Get render size of contained object. - * - * @method getSize - * @return {Array.Number} size of this or size of single child. - */ - RenderNode.prototype.getSize = function getSize() { - var result = null; - var target = this.get(); - if (target && target.getSize) result = target.getSize(); - if (!result && this._child && this._child.getSize) result = this._child.getSize(); - return result; - }; - - // apply results of rendering this subtree to the document - function _applyCommit(spec, context, cacheStorage) { - var result = SpecParser.parse(spec, context); - var keys = Object.keys(result); - for (var i = 0; i < keys.length; i++) { - var id = keys[i]; - var childNode = Entity.get(id); - var commitParams = result[id]; - commitParams.allocator = context.allocator; - var commitResult = childNode.commit(commitParams); - if (commitResult) _applyCommit(commitResult, context, cacheStorage); - else cacheStorage[id] = commitParams; - } - } - - /** - * Commit the content change from this node to the document. - * - * @private - * @method commit - * @param {Context} context render context - */ - RenderNode.prototype.commit = function commit(context) { - // free up some divs from the last loop - var prevKeys = Object.keys(this._prevResults); - for (var i = 0; i < prevKeys.length; i++) { - var id = prevKeys[i]; - if (this._resultCache[id] === undefined) { - var object = Entity.get(id); - if (object.cleanup) object.cleanup(context.allocator); - } - } - - this._prevResults = this._resultCache; - this._resultCache = {}; - _applyCommit(this.render(), context, this._resultCache); - }; - - /** - * Generate a render spec from the contents of the wrapped component. - * - * @private - * @method render - * - * @return {Object} render specification for the component subtree - * only under this node. - */ - RenderNode.prototype.render = function render() { - if (this._isRenderable) return this._object.render(); - - var result = null; - if (this._hasMultipleChildren) { - result = this._childResult; - var children = this._child; - for (var i = 0; i < children.length; i++) { - result[i] = children[i].render(); - } - } - else if (this._child) result = this._child.render(); - - return this._isModifier ? this._object.modify(result) : result; - }; - - module.exports = RenderNode; -}); - -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. - * - * Owner: mark@famo.us - * @license MPL 2.0 - * @copyright Famous Industries, Inc. 2014 - */ - -define('famous/core/EventEmitter',['require','exports','module'],function(require, exports, module) { - /** - * EventEmitter represents a channel for events. - * - * @class EventEmitter - * @constructor - */ - function EventEmitter() { - this.listeners = {}; - this._owner = this; - } - - /** - * Trigger an event, sending to all downstream handlers - * listening for provided 'type' key. - * - * @method emit - * - * @param {string} type event type key (for example, 'click') - * @param {Object} event event data - * @return {EventHandler} this - */ - EventEmitter.prototype.emit = function emit(type, event) { - var handlers = this.listeners[type]; - if (handlers) { - for (var i = 0; i < handlers.length; i++) { - handlers[i].call(this._owner, event); - } - } - return this; - }; - - /** - * Bind a callback function to an event type handled by this object. - * - * @method "on" - * - * @param {string} type event type key (for example, 'click') - * @param {function(string, Object)} handler callback - * @return {EventHandler} this - */ - EventEmitter.prototype.on = function on(type, handler) { - if (!(type in this.listeners)) this.listeners[type] = []; - var index = this.listeners[type].indexOf(handler); - if (index < 0) this.listeners[type].push(handler); - return this; - }; - - /** - * Alias for "on". - * @method addListener - */ - EventEmitter.prototype.addListener = EventEmitter.prototype.on; - - /** - * Unbind an event by type and handler. - * This undoes the work of "on". - * - * @method removeListener - * - * @param {string} type event type key (for example, 'click') - * @param {function} handler function object to remove - * @return {EventEmitter} this - */ - EventEmitter.prototype.removeListener = function removeListener(type, handler) { - var index = this.listeners[type].indexOf(handler); - if (index >= 0) this.listeners[type].splice(index, 1); - return this; - }; - - /** - * Call event handlers with this set to owner. - * - * @method bindThis - * - * @param {Object} owner object this EventEmitter belongs to - */ - EventEmitter.prototype.bindThis = function bindThis(owner) { - this._owner = owner; - }; - - module.exports = EventEmitter; -}); - -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. - * - * Owner: mark@famo.us - * @license MPL 2.0 - * @copyright Famous Industries, Inc. 2014 - */ - -define('famous/core/EventHandler',['require','exports','module','./EventEmitter'],function(require, exports, module) { - var EventEmitter = require('./EventEmitter'); - - /** - * EventHandler forwards received events to a set of provided callback functions. - * It allows events to be captured, processed, and optionally piped through to other event handlers. - * - * @class EventHandler - * @extends EventEmitter - * @constructor - */ - function EventHandler() { - EventEmitter.apply(this, arguments); - - this.downstream = []; // downstream event handlers - this.downstreamFn = []; // downstream functions - - this.upstream = []; // upstream event handlers - this.upstreamListeners = {}; // upstream listeners - } - EventHandler.prototype = Object.create(EventEmitter.prototype); - EventHandler.prototype.constructor = EventHandler; - - /** - * Assign an event handler to receive an object's input events. - * - * @method setInputHandler - * @static - * - * @param {Object} object object to mix trigger, subscribe, and unsubscribe functions into - * @param {EventHandler} handler assigned event handler - */ - EventHandler.setInputHandler = function setInputHandler(object, handler) { - object.trigger = handler.trigger.bind(handler); - if (handler.subscribe && handler.unsubscribe) { - object.subscribe = handler.subscribe.bind(handler); - object.unsubscribe = handler.unsubscribe.bind(handler); - } - }; - - /** - * Assign an event handler to receive an object's output events. - * - * @method setOutputHandler - * @static - * - * @param {Object} object object to mix pipe, unpipe, on, addListener, and removeListener functions into - * @param {EventHandler} handler assigned event handler - */ - EventHandler.setOutputHandler = function setOutputHandler(object, handler) { - if (handler instanceof EventHandler) handler.bindThis(object); - object.pipe = handler.pipe.bind(handler); - object.unpipe = handler.unpipe.bind(handler); - object.on = handler.on.bind(handler); - object.addListener = object.on; - object.removeListener = handler.removeListener.bind(handler); - }; - - /** - * Trigger an event, sending to all downstream handlers - * listening for provided 'type' key. - * - * @method emit - * - * @param {string} type event type key (for example, 'click') - * @param {Object} event event data - * @return {EventHandler} this - */ - EventHandler.prototype.emit = function emit(type, event) { - EventEmitter.prototype.emit.apply(this, arguments); - var i = 0; - for (i = 0; i < this.downstream.length; i++) { - if (this.downstream[i].trigger) this.downstream[i].trigger(type, event); - } - for (i = 0; i < this.downstreamFn.length; i++) { - this.downstreamFn[i](type, event); - } - return this; - }; - - /** - * Alias for emit - * @method addListener - */ - EventHandler.prototype.trigger = EventHandler.prototype.emit; - - /** - * Add event handler object to set of downstream handlers. - * - * @method pipe - * - * @param {EventHandler} target event handler target object - * @return {EventHandler} passed event handler - */ - EventHandler.prototype.pipe = function pipe(target) { - if (target.subscribe instanceof Function) return target.subscribe(this); - - var downstreamCtx = (target instanceof Function) ? this.downstreamFn : this.downstream; - var index = downstreamCtx.indexOf(target); - if (index < 0) downstreamCtx.push(target); - - if (target instanceof Function) target('pipe', null); - else if (target.trigger) target.trigger('pipe', null); - - return target; - }; - - /** - * Remove handler object from set of downstream handlers. - * Undoes work of "pipe". - * - * @method unpipe - * - * @param {EventHandler} target target handler object - * @return {EventHandler} provided target - */ - EventHandler.prototype.unpipe = function unpipe(target) { - if (target.unsubscribe instanceof Function) return target.unsubscribe(this); - - var downstreamCtx = (target instanceof Function) ? this.downstreamFn : this.downstream; - var index = downstreamCtx.indexOf(target); - if (index >= 0) { - downstreamCtx.splice(index, 1); - if (target instanceof Function) target('unpipe', null); - else if (target.trigger) target.trigger('unpipe', null); - return target; - } - else return false; - }; - - /** - * Bind a callback function to an event type handled by this object. - * - * @method "on" - * - * @param {string} type event type key (for example, 'click') - * @param {function(string, Object)} handler callback - * @return {EventHandler} this - */ - EventHandler.prototype.on = function on(type, handler) { - EventEmitter.prototype.on.apply(this, arguments); - if (!(type in this.upstreamListeners)) { - var upstreamListener = this.trigger.bind(this, type); - this.upstreamListeners[type] = upstreamListener; - for (var i = 0; i < this.upstream.length; i++) { - this.upstream[i].on(type, upstreamListener); - } - } - return this; - }; - - /** - * Alias for "on" - * @method addListener - */ - EventHandler.prototype.addListener = EventHandler.prototype.on; - - /** - * Listen for events from an upstream event handler. - * - * @method subscribe - * - * @param {EventEmitter} source source emitter object - * @return {EventHandler} this - */ - EventHandler.prototype.subscribe = function subscribe(source) { - var index = this.upstream.indexOf(source); - if (index < 0) { - this.upstream.push(source); - for (var type in this.upstreamListeners) { - source.on(type, this.upstreamListeners[type]); - } - } - return this; - }; - - /** - * Stop listening to events from an upstream event handler. - * - * @method unsubscribe - * - * @param {EventEmitter} source source emitter object - * @return {EventHandler} this - */ - EventHandler.prototype.unsubscribe = function unsubscribe(source) { - var index = this.upstream.indexOf(source); - if (index >= 0) { - this.upstream.splice(index, 1); - for (var type in this.upstreamListeners) { - source.removeListener(type, this.upstreamListeners[type]); - } - } - return this; - }; - - module.exports = EventHandler; -}); - -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. - * - * Owner: mark@famo.us - * @license MPL 2.0 - * @copyright Famous Industries, Inc. 2014 - */ - -define('famous/core/ElementAllocator',['require','exports','module'],function(require, exports, module) { - - /** - * Internal helper object to Context that handles the process of - * creating and allocating DOM elements within a managed div. - * Private. - * - * @class ElementAllocator - * @constructor - * @private - * @param {Node} container document element in which Famo.us content will be inserted - */ - function ElementAllocator(container) { - if (!container) container = document.createDocumentFragment(); - this.container = container; - this.detachedNodes = {}; - this.nodeCount = 0; - } - - /** - * Move the document elements from their original container to a new one. - * - * @private - * @method migrate - * - * @param {Node} container document element to which Famo.us content will be migrated - */ - ElementAllocator.prototype.migrate = function migrate(container) { - var oldContainer = this.container; - if (container === oldContainer) return; - - if (oldContainer instanceof DocumentFragment) { - container.appendChild(oldContainer); - } - else { - while (oldContainer.hasChildNodes()) { - container.appendChild(oldContainer.removeChild(oldContainer.firstChild)); - } - } - - this.container = container; - }; - - /** - * Allocate an element of specified type from the pool. - * - * @private - * @method allocate - * - * @param {string} type type of element, e.g. 'div' - * @return {Node} allocated document element - */ - ElementAllocator.prototype.allocate = function allocate(type) { - type = type.toLowerCase(); - if (!(type in this.detachedNodes)) this.detachedNodes[type] = []; - var nodeStore = this.detachedNodes[type]; - var result; - if (nodeStore.length > 0) { - result = nodeStore.pop(); - } - else { - result = document.createElement(type); - this.container.appendChild(result); - } - this.nodeCount++; - return result; - }; - - /** - * De-allocate an element of specified type to the pool. - * - * @private - * @method deallocate - * - * @param {Node} element document element to deallocate - */ - ElementAllocator.prototype.deallocate = function deallocate(element) { - var nodeType = element.nodeName.toLowerCase(); - var nodeStore = this.detachedNodes[nodeType]; - nodeStore.push(element); - this.nodeCount--; - }; - - /** - * Get count of total allocated nodes in the document. - * - * @private - * @method getNodeCount - * - * @return {Number} total node count - */ - ElementAllocator.prototype.getNodeCount = function getNodeCount() { - return this.nodeCount; - }; - - module.exports = ElementAllocator; -}); - -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. - * - * Owner: mark@famo.us - * @license MPL 2.0 - * @copyright Famous Industries, Inc. 2014 - */ - -define('famous/utilities/Utility',['require','exports','module'],function(require, exports, module) { - /** - * This namespace holds standalone functionality. - * Currently includes name mapping for transition curves, - * name mapping for origin pairs, and the after() function. - * - * @class Utility - * @static - */ - var Utility = {}; - - /** - * Table of direction array positions - * - * @property {object} Direction - * @final - */ - Utility.Direction = { - X: 0, - Y: 1, - Z: 2 - }; - - /** - * Return wrapper around callback function. Once the wrapper is called N - * times, invoke the callback function. Arguments and scope preserved. - * - * @method after - * - * @param {number} count number of calls before callback function invoked - * @param {Function} callback wrapped callback function - * - * @return {function} wrapped callback with coundown feature - */ - Utility.after = function after(count, callback) { - var counter = count; - return function() { - counter--; - if (counter === 0) callback.apply(this, arguments); - }; - }; - - /** - * Load a URL and return its contents in a callback - * - * @method loadURL - * - * @param {string} url URL of object - * @param {function} callback callback to dispatch with content - */ - Utility.loadURL = function loadURL(url, callback) { - var xhr = new XMLHttpRequest(); - xhr.onreadystatechange = function onreadystatechange() { - if (this.readyState === 4) { - if (callback) callback(this.responseText); - } - }; - xhr.open('GET', url); - xhr.send(); - }; - - /** - * Create a document fragment from a string of HTML - * - * @method createDocumentFragmentFromHTML - * - * @param {string} html HTML to convert to DocumentFragment - * - * @return {DocumentFragment} DocumentFragment representing input HTML - */ - Utility.createDocumentFragmentFromHTML = function createDocumentFragmentFromHTML(html) { - var element = document.createElement('div'); - element.innerHTML = html; - var result = document.createDocumentFragment(); - while (element.hasChildNodes()) result.appendChild(element.firstChild); - return result; - }; - - module.exports = Utility; -}); - -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. - * - * Owner: david@famo.us - * @license MPL 2.0 - * @copyright Famous Industries, Inc. 2014 - */ - -define('famous/transitions/MultipleTransition',['require','exports','module','famous/utilities/Utility'],function(require, exports, module) { - var Utility = require('famous/utilities/Utility'); - - /** - * Transition meta-method to support transitioning multiple - * values with scalar-only methods. - * - * - * @class MultipleTransition - * @constructor - * - * @param {Object} method Transionable class to multiplex - */ - function MultipleTransition(method) { - this.method = method; - this._instances = []; - this.state = []; - } - - MultipleTransition.SUPPORTS_MULTIPLE = true; - - /** - * Get the state of each transition. - * - * @method get - * - * @return state {Number|Array} state array - */ - MultipleTransition.prototype.get = function get() { - for (var i = 0; i < this._instances.length; i++) { - this.state[i] = this._instances[i].get(); - } - return this.state; - }; - - /** - * Set the end states with a shared transition, with optional callback. - * - * @method set - * - * @param {Number|Array} endState Final State. Use a multi-element argument for multiple transitions. - * @param {Object} transition Transition definition, shared among all instances - * @param {Function} callback called when all endStates have been reached. - */ - MultipleTransition.prototype.set = function set(endState, transition, callback) { - var _allCallback = Utility.after(endState.length, callback); - for (var i = 0; i < endState.length; i++) { - if (!this._instances[i]) this._instances[i] = new (this.method)(); - this._instances[i].set(endState[i], transition, _allCallback); - } - }; - - /** - * Reset all transitions to start state. - * - * @method reset - * - * @param {Number|Array} startState Start state - */ - MultipleTransition.prototype.reset = function reset(startState) { - for (var i = 0; i < startState.length; i++) { - if (!this._instances[i]) this._instances[i] = new (this.method)(); - this._instances[i].reset(startState[i]); - } - }; - - module.exports = MultipleTransition; -}); - -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. - * - * Owner: david@famo.us - * @license MPL 2.0 - * @copyright Famous Industries, Inc. 2014 - */ - -define('famous/transitions/TweenTransition',['require','exports','module'],function(require, exports, module) { - - /** - * - * A state maintainer for a smooth transition between - * numerically-specified states. Example numeric states include floats or - * Transfornm objects. - * - * An initial state is set with the constructor or set(startValue). A - * corresponding end state and transition are set with set(endValue, - * transition). Subsequent calls to set(endValue, transition) begin at - * the last state. Calls to get(timestamp) provide the _interpolated state - * along the way. - * - * Note that there is no event loop here - calls to get() are the only way - * to find out state projected to the current (or provided) time and are - * the only way to trigger callbacks. Usually this kind of object would - * be part of the render() path of a visible component. - * - * @class TweenTransition - * @constructor - * - * @param {Object} options TODO - * beginning state - */ - function TweenTransition(options) { - this.options = Object.create(TweenTransition.DEFAULT_OPTIONS); - if (options) this.setOptions(options); - - this._startTime = 0; - this._startValue = 0; - this._updateTime = 0; - this._endValue = 0; - this._curve = undefined; - this._duration = 0; - this._active = false; - this._callback = undefined; - this.state = 0; - this.velocity = undefined; - } - - /** - * Transition curves mapping independent variable t from domain [0,1] to a - * range within [0,1]. Includes functions 'linear', 'easeIn', 'easeOut', - * 'easeInOut', 'easeOutBounce', 'spring'. - * - * @property {object} Curve - * @final - */ - TweenTransition.Curves = { - linear: function(t) { - return t; - }, - easeIn: function(t) { - return t*t; - }, - easeOut: function(t) { - return t*(2-t); - }, - easeInOut: function(t) { - if (t <= 0.5) return 2*t*t; - else return -2*t*t + 4*t - 1; - }, - easeOutBounce: function(t) { - return t*(3 - 2*t); - }, - spring: function(t) { - return (1 - t) * Math.sin(6 * Math.PI * t) + t; - } - }; - - TweenTransition.SUPPORTS_MULTIPLE = true; - TweenTransition.DEFAULT_OPTIONS = { - curve: TweenTransition.Curves.linear, - duration: 500, - speed: 0 /* considered only if positive */ - }; - - var registeredCurves = {}; - - /** - * Add "unit" curve to internal dictionary of registered curves. - * - * @method registerCurve - * - * @static - * - * @param {string} curveName dictionary key - * @param {unitCurve} curve function of one numeric variable mapping [0,1] - * to range inside [0,1] - * @return {boolean} false if key is taken, else true - */ - TweenTransition.registerCurve = function registerCurve(curveName, curve) { - if (!registeredCurves[curveName]) { - registeredCurves[curveName] = curve; - return true; - } - else { - return false; - } - }; - - /** - * Remove object with key "curveName" from internal dictionary of registered - * curves. - * - * @method unregisterCurve - * - * @static - * - * @param {string} curveName dictionary key - * @return {boolean} false if key has no dictionary value - */ - TweenTransition.unregisterCurve = function unregisterCurve(curveName) { - if (registeredCurves[curveName]) { - delete registeredCurves[curveName]; - return true; - } - else { - return false; - } - }; - - /** - * Retrieve function with key "curveName" from internal dictionary of - * registered curves. Default curves are defined in the - * TweenTransition.Curves array, where the values represent - * unitCurve functions. - * - * @method getCurve - * - * @static - * - * @param {string} curveName dictionary key - * @return {unitCurve} curve function of one numeric variable mapping [0,1] - * to range inside [0,1] - */ - TweenTransition.getCurve = function getCurve(curveName) { - var curve = registeredCurves[curveName]; - if (curve !== undefined) return curve; - else throw new Error('curve not registered'); - }; - - /** - * Retrieve all available curves. - * - * @method getCurves - * - * @static - * - * @return {object} curve functions of one numeric variable mapping [0,1] - * to range inside [0,1] - */ - TweenTransition.getCurves = function getCurves() { - return registeredCurves; - }; - - // Interpolate: If a linear function f(0) = a, f(1) = b, then return f(t) - function _interpolate(a, b, t) { - return ((1 - t) * a) + (t * b); - } - - function _clone(obj) { - if (obj instanceof Object) { - if (obj instanceof Array) return obj.slice(0); - else return Object.create(obj); - } - else return obj; - } - - // Fill in missing properties in "transition" with those in defaultTransition, and - // convert internal named curve to function object, returning as new - // object. - function _normalize(transition, defaultTransition) { - var result = {curve: defaultTransition.curve}; - if (defaultTransition.duration) result.duration = defaultTransition.duration; - if (defaultTransition.speed) result.speed = defaultTransition.speed; - if (transition instanceof Object) { - if (transition.duration !== undefined) result.duration = transition.duration; - if (transition.curve) result.curve = transition.curve; - if (transition.speed) result.speed = transition.speed; - } - if (typeof result.curve === 'string') result.curve = TweenTransition.getCurve(result.curve); - return result; - } - - /** - * Set internal options, overriding any default options. - * - * @method setOptions - * - * - * @param {Object} options options object - * @param {Object} [options.curve] function mapping [0,1] to [0,1] or identifier - * @param {Number} [options.duration] duration in ms - * @param {Number} [options.speed] speed in pixels per ms - */ - TweenTransition.prototype.setOptions = function setOptions(options) { - if (options.curve !== undefined) this.options.curve = options.curve; - if (options.duration !== undefined) this.options.duration = options.duration; - if (options.speed !== undefined) this.options.speed = options.speed; - }; - - /** - * Add transition to end state to the queue of pending transitions. Special - * Use: calling without a transition resets the object to that state with - * no pending actions - * - * @method set - * - * - * @param {number|FamousMatrix|Array.Number|Object.} endValue - * end state to which we _interpolate - * @param {transition=} 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 Zero-argument function to call on observed - * completion (t=1) - */ - TweenTransition.prototype.set = function set(endValue, transition, callback) { - if (!transition) { - this.reset(endValue); - if (callback) callback(); - return; - } - - this._startValue = _clone(this.get()); - transition = _normalize(transition, this.options); - if (transition.speed) { - var startValue = this._startValue; - if (startValue instanceof Object) { - var variance = 0; - for (var i in startValue) variance += (endValue[i] - startValue[i]) * (endValue[i] - startValue[i]); - transition.duration = Math.sqrt(variance) / transition.speed; - } - else { - transition.duration = Math.abs(endValue - startValue) / transition.speed; - } - } - - this._startTime = Date.now(); - this._endValue = _clone(endValue); - this._startVelocity = _clone(transition.velocity); - this._duration = transition.duration; - this._curve = transition.curve; - this._active = true; - this._callback = callback; - }; - - /** - * Cancel all transitions and reset to a stable state - * - * @method reset - * - * @param {number|Array.Number|Object.} startValue - * starting state - * @param {number} startVelocity - * starting velocity - */ - TweenTransition.prototype.reset = function reset(startValue, startVelocity) { - if (this._callback) { - var callback = this._callback; - this._callback = undefined; - callback(); - } - this.state = _clone(startValue); - this.velocity = _clone(startVelocity); - this._startTime = 0; - this._duration = 0; - this._updateTime = 0; - this._startValue = this.state; - this._startVelocity = this.velocity; - this._endValue = this.state; - this._active = false; - }; - - /** - * Get current velocity - * - * @method getVelocity - * - * @returns {Number} velocity - */ - TweenTransition.prototype.getVelocity = function getVelocity() { - return this.velocity; - }; - - /** - * Get interpolated state of current action at provided time. If the last - * action has completed, invoke its callback. - * - * @method get - * - * - * @param {number=} timestamp Evaluate the curve at a normalized version of this - * time. If omitted, use current time. (Unix epoch time) - * @return {number|Object.} beginning state - * _interpolated to this point in time. - */ - TweenTransition.prototype.get = function get(timestamp) { - this.update(timestamp); - return this.state; - }; - - function _calculateVelocity(current, start, curve, duration, t) { - var velocity; - var eps = 1e-7; - var speed = (curve(t) - curve(t - eps)) / eps; - if (current instanceof Array) { - velocity = []; - for (var i = 0; i < current.length; i++){ - if (typeof current[i] === 'number') - velocity[i] = speed * (current[i] - start[i]) / duration; - else - velocity[i] = 0; - } - - } - else velocity = speed * (current - start) / duration; - return velocity; - } - - function _calculateState(start, end, t) { - var state; - if (start instanceof Array) { - state = []; - for (var i = 0; i < start.length; i++) { - if (typeof start[i] === 'number') - state[i] = _interpolate(start[i], end[i], t); - else - state[i] = start[i]; - } - } - else state = _interpolate(start, end, t); - return state; - } - - /** - * Update internal state to the provided timestamp. This may invoke the last - * callback and begin a new action. - * - * @method update - * - * - * @param {number=} timestamp Evaluate the curve at a normalized version of this - * time. If omitted, use current time. (Unix epoch time) - */ - TweenTransition.prototype.update = function update(timestamp) { - if (!this._active) { - if (this._callback) { - var callback = this._callback; - this._callback = undefined; - callback(); - } - return; - } - - if (!timestamp) timestamp = Date.now(); - if (this._updateTime >= timestamp) return; - this._updateTime = timestamp; - - var timeSinceStart = timestamp - this._startTime; - if (timeSinceStart >= this._duration) { - this.state = this._endValue; - this.velocity = _calculateVelocity(this.state, this._startValue, this._curve, this._duration, 1); - this._active = false; - } - else if (timeSinceStart < 0) { - this.state = this._startValue; - this.velocity = this._startVelocity; - } - else { - var t = timeSinceStart / this._duration; - this.state = _calculateState(this._startValue, this._endValue, this._curve(t)); - this.velocity = _calculateVelocity(this.state, this._startValue, this._curve, this._duration, t); - } - }; - - /** - * Is there at least one action pending completion? - * - * @method isActive - * - * - * @return {boolean} - */ - TweenTransition.prototype.isActive = function isActive() { - return this._active; - }; - - /** - * Halt transition at current state and erase all pending actions. - * - * @method halt - * - */ - TweenTransition.prototype.halt = function halt() { - this.reset(this.get()); - }; - - // Register all the default curves - TweenTransition.registerCurve('linear', TweenTransition.Curves.linear); - TweenTransition.registerCurve('easeIn', TweenTransition.Curves.easeIn); - TweenTransition.registerCurve('easeOut', TweenTransition.Curves.easeOut); - TweenTransition.registerCurve('easeInOut', TweenTransition.Curves.easeInOut); - TweenTransition.registerCurve('easeOutBounce', TweenTransition.Curves.easeOutBounce); - TweenTransition.registerCurve('spring', TweenTransition.Curves.spring); - - TweenTransition.customCurve = function customCurve(v1, v2) { - v1 = v1 || 0; v2 = v2 || 0; - return function(t) { - return v1*t + (-2*v1 - v2 + 3)*t*t + (v1 + v2 - 2)*t*t*t; - }; - }; - - module.exports = TweenTransition; -}); - -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. - * - * Owner: david@famo.us - * @license MPL 2.0 - * @copyright Famous Industries, Inc. 2014 - */ - -define('famous/transitions/Transitionable',['require','exports','module','./MultipleTransition','./TweenTransition'],function(require, exports, module) { - var MultipleTransition = require('./MultipleTransition'); - var TweenTransition = require('./TweenTransition'); - - /** - * A state maintainer for a smooth transition between - * numerically-specified states. Example numeric states include floats or - * Transform objects. - * - * An initial state is set with the constructor or set(startState). A - * corresponding end state and transition are set with set(endState, - * transition). Subsequent calls to set(endState, transition) begin at - * the last state. Calls to get(timestamp) provide the interpolated state - * along the way. - * - * Note that there is no event loop here - calls to get() are the only way - * to find state projected to the current (or provided) time and are - * the only way to trigger callbacks. Usually this kind of object would - * be part of the render() path of a visible component. - * - * @class Transitionable - * @constructor - * @param {number|Array.Number|Object.} start - * beginning state - */ - function Transitionable(start) { - this.currentAction = null; - this.actionQueue = []; - this.callbackQueue = []; - - this.state = 0; - this.velocity = undefined; - this._callback = undefined; - this._engineInstance = null; - this._currentMethod = null; - - this.set(start); - } - - var transitionMethods = {}; - - Transitionable.registerMethod = function registerMethod(name, engineClass) { - if (!(name in transitionMethods)) { - transitionMethods[name] = engineClass; - return true; - } - else return false; - }; - - Transitionable.unregisterMethod = function unregisterMethod(name) { - if (name in transitionMethods) { - delete transitionMethods[name]; - return true; - } - else return false; - }; - - function _loadNext() { - if (this._callback) { - var callback = this._callback; - this._callback = undefined; - callback(); - } - if (this.actionQueue.length <= 0) { - this.set(this.get()); // no update required - return; - } - this.currentAction = this.actionQueue.shift(); - this._callback = this.callbackQueue.shift(); - - var method = null; - var endValue = this.currentAction[0]; - var transition = this.currentAction[1]; - if (transition instanceof Object && transition.method) { - method = transition.method; - if (typeof method === 'string') method = transitionMethods[method]; - } - else { - method = TweenTransition; - } - - if (this._currentMethod !== method) { - if (!(endValue instanceof Object) || method.SUPPORTS_MULTIPLE === true || endValue.length <= method.SUPPORTS_MULTIPLE) { - this._engineInstance = new method(); - } - else { - this._engineInstance = new MultipleTransition(method); - } - this._currentMethod = method; - } - - this._engineInstance.reset(this.state, this.velocity); - if (this.velocity !== undefined) transition.velocity = this.velocity; - this._engineInstance.set(endValue, transition, _loadNext.bind(this)); - } - - /** - * Add transition to end state to the queue of pending transitions. Special - * Use: calling without a transition resets the object to that state with - * no pending actions - * - * @method set - * - * @param {number|FamousMatrix|Array.Number|Object.} endState - * end state to which we interpolate - * @param {transition=} 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 Zero-argument function to call on observed - * completion (t=1) - */ - Transitionable.prototype.set = function set(endState, transition, callback) { - if (!transition) { - this.reset(endState); - if (callback) callback(); - return this; - } - - var action = [endState, transition]; - this.actionQueue.push(action); - this.callbackQueue.push(callback); - if (!this.currentAction) _loadNext.call(this); - return this; - }; - - /** - * Cancel all transitions and reset to a stable state - * - * @method reset - * - * @param {number|Array.Number|Object.} startState - * stable state to set to - */ - Transitionable.prototype.reset = function reset(startState, startVelocity) { - this._currentMethod = null; - this._engineInstance = null; - this._callback = undefined; - this.state = startState; - this.velocity = startVelocity; - this.currentAction = null; - this.actionQueue = []; - this.callbackQueue = []; - }; - - /** - * Add delay action to the pending action queue queue. - * - * @method delay - * - * @param {number} duration delay time (ms) - * @param {function} callback Zero-argument function to call on observed - * completion (t=1) - */ - Transitionable.prototype.delay = function delay(duration, callback) { - this.set(this.get(), {duration: duration, - curve: function() { - return 0; - }}, - callback - ); - }; - - /** - * Get interpolated state of current action at provided time. If the last - * action has completed, invoke its callback. - * - * @method get - * - * @param {number=} timestamp Evaluate the curve at a normalized version of this - * time. If omitted, use current time. (Unix epoch time) - * @return {number|Object.} beginning state - * interpolated to this point in time. - */ - Transitionable.prototype.get = function get(timestamp) { - if (this._engineInstance) { - if (this._engineInstance.getVelocity) - this.velocity = this._engineInstance.getVelocity(); - this.state = this._engineInstance.get(timestamp); - } - return this.state; - }; - - /** - * Is there at least one action pending completion? - * - * @method isActive - * - * @return {boolean} - */ - Transitionable.prototype.isActive = function isActive() { - return !!this.currentAction; - }; - - /** - * Halt transition at current state and erase all pending actions. - * - * @method halt - */ - Transitionable.prototype.halt = function halt() { - this.set(this.get()); - }; - - module.exports = Transitionable; -}); - -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. - * - * Owner: mark@famo.us - * @license MPL 2.0 - * @copyright Famous Industries, Inc. 2014 - */ - -define('famous/core/Context',['require','exports','module','./RenderNode','./EventHandler','./ElementAllocator','./Transform','famous/transitions/Transitionable'],function(require, exports, module) { - var RenderNode = require('./RenderNode'); - var EventHandler = require('./EventHandler'); - var ElementAllocator = require('./ElementAllocator'); - var Transform = require('./Transform'); - var Transitionable = require('famous/transitions/Transitionable'); - - var _originZeroZero = [0, 0]; - - function _getElementSize(element) { - return [element.clientWidth, element.clientHeight]; - } - - /** - * The top-level container for a Famous-renderable piece of the document. - * It is directly updated by the process-wide Engine object, and manages one - * render tree root, which can contain other renderables. - * - * @class Context - * @constructor - * @private - * @param {Node} container Element in which content will be inserted - */ - function Context(container) { - this.container = container; - this._allocator = new ElementAllocator(container); - - this._node = new RenderNode(); - this._eventOutput = new EventHandler(); - this._size = _getElementSize(this.container); - - this._perspectiveState = new Transitionable(0); - this._perspective = undefined; - - this._nodeContext = { - allocator: this._allocator, - transform: Transform.identity, - opacity: 1, - origin: _originZeroZero, - align: null, - size: this._size - }; - - this._eventOutput.on('resize', function() { - this.setSize(_getElementSize(this.container)); - }.bind(this)); - - } - - // Note: Unused - Context.prototype.getAllocator = function getAllocator() { - return this._allocator; - }; - - /** - * Add renderables to this Context's render tree. - * - * @method add - * - * @param {Object} obj renderable object - * @return {RenderNode} RenderNode wrapping this object, if not already a RenderNode - */ - Context.prototype.add = function add(obj) { - return this._node.add(obj); - }; - - /** - * Move this Context to another containing document element. - * - * @method migrate - * - * @param {Node} container Element to which content will be migrated - */ - Context.prototype.migrate = function migrate(container) { - if (container === this.container) return; - this.container = container; - this._allocator.migrate(container); - }; - - /** - * Gets viewport size for Context. - * - * @method getSize - * - * @return {Array.Number} viewport size as [width, height] - */ - Context.prototype.getSize = function getSize() { - return this._size; - }; - - /** - * Sets viewport size for Context. - * - * @method setSize - * - * @param {Array.Number} size [width, height]. If unspecified, use size of root document element. - */ - Context.prototype.setSize = function setSize(size) { - if (!size) size = _getElementSize(this.container); - this._size[0] = size[0]; - this._size[1] = size[1]; - }; - - /** - * Commit this Context's content changes to the document. - * - * @private - * @method update - * @param {Object} contextParameters engine commit specification - */ - Context.prototype.update = function update(contextParameters) { - if (contextParameters) { - if (contextParameters.transform) this._nodeContext.transform = contextParameters.transform; - if (contextParameters.opacity) this._nodeContext.opacity = contextParameters.opacity; - if (contextParameters.origin) this._nodeContext.origin = contextParameters.origin; - if (contextParameters.align) this._nodeContext.align = contextParameters.align; - if (contextParameters.size) this._nodeContext.size = contextParameters.size; - } - var perspective = this._perspectiveState.get(); - if (perspective !== this._perspective) { - this.container.style.perspective = perspective ? perspective.toFixed() + 'px' : ''; - this.container.style.webkitPerspective = perspective ? perspective.toFixed() : ''; - this._perspective = perspective; - } - - this._node.commit(this._nodeContext); - }; - - /** - * Get current perspective of this context in pixels. - * - * @method getPerspective - * @return {Number} depth perspective in pixels - */ - Context.prototype.getPerspective = function getPerspective() { - return this._perspectiveState.get(); - }; - - /** - * Set current perspective of this context in pixels. - * - * @method setPerspective - * @param {Number} perspective in pixels - * @param {Object} [transition] Transitionable object for applying the change - * @param {function(Object)} callback function called on completion of transition - */ - Context.prototype.setPerspective = function setPerspective(perspective, transition, callback) { - return this._perspectiveState.set(perspective, transition, callback); - }; - - /** - * Trigger an event, sending to all downstream handlers - * listening for provided 'type' key. - * - * @method emit - * - * @param {string} type event type key (for example, 'click') - * @param {Object} event event data - * @return {EventHandler} this - */ - Context.prototype.emit = function emit(type, event) { - return this._eventOutput.emit(type, event); - }; - - /** - * Bind a callback function to an event type handled by this object. - * - * @method "on" - * - * @param {string} type event type key (for example, 'click') - * @param {function(string, Object)} handler callback - * @return {EventHandler} this - */ - Context.prototype.on = function on(type, handler) { - return this._eventOutput.on(type, handler); - }; - - /** - * Unbind an event by type and handler. - * This undoes the work of "on". - * - * @method removeListener - * - * @param {string} type event type key (for example, 'click') - * @param {function} handler function object to remove - * @return {EventHandler} internal event handler object (for chaining) - */ - Context.prototype.removeListener = function removeListener(type, handler) { - return this._eventOutput.removeListener(type, handler); - }; - - /** - * Add event handler object to set of downstream handlers. - * - * @method pipe - * - * @param {EventHandler} target event handler target object - * @return {EventHandler} passed event handler - */ - Context.prototype.pipe = function pipe(target) { - return this._eventOutput.pipe(target); - }; - - /** - * Remove handler object from set of downstream handlers. - * Undoes work of "pipe". - * - * @method unpipe - * - * @param {EventHandler} target target handler object - * @return {EventHandler} provided target - */ - Context.prototype.unpipe = function unpipe(target) { - return this._eventOutput.unpipe(target); - }; - - module.exports = Context; -}); - -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. - * - * Owner: mark@famo.us - * @license MPL 2.0 - * @copyright Famous Industries, Inc. 2014 - */ - -define('famous/core/OptionsManager',['require','exports','module','./EventHandler'],function(require, exports, module) { - var EventHandler = require('./EventHandler'); - - /** - * A collection of methods for setting options which can be extended - * onto other classes. - * - * - * **** WARNING **** - * You can only pass through objects that will compile into valid JSON. - * - * Valid options: - * Strings, - * Arrays, - * Objects, - * Numbers, - * Nested Objects, - * Nested Arrays. - * - * This excludes: - * Document Fragments, - * Functions - * @class OptionsManager - * @constructor - * @param {Object} value options dictionary - */ - function OptionsManager(value) { - this._value = value; - this.eventOutput = null; - } - - /** - * Create options manager from source dictionary with arguments overriden by patch dictionary. - * - * @static - * @method OptionsManager.patch - * - * @param {Object} source source arguments - * @param {...Object} data argument additions and overwrites - * @return {Object} source object - */ - OptionsManager.patch = function patchObject(source, data) { - var manager = new OptionsManager(source); - for (var i = 1; i < arguments.length; i++) manager.patch(arguments[i]); - return source; - }; - - function _createEventOutput() { - this.eventOutput = new EventHandler(); - this.eventOutput.bindThis(this); - EventHandler.setOutputHandler(this, this.eventOutput); - } - - /** - * Create OptionsManager from source with arguments overriden by patches. - * Triggers 'change' event on this object's event handler if the state of - * the OptionsManager changes as a result. - * - * @method patch - * - * @param {...Object} arguments list of patch objects - * @return {OptionsManager} this - */ - OptionsManager.prototype.patch = function patch() { - var myState = this._value; - for (var i = 0; i < arguments.length; i++) { - var data = arguments[i]; - for (var k in data) { - if ((k in myState) && (data[k] && data[k].constructor === Object) && (myState[k] && myState[k].constructor === Object)) { - if (!myState.hasOwnProperty(k)) myState[k] = Object.create(myState[k]); - this.key(k).patch(data[k]); - if (this.eventOutput) this.eventOutput.emit('change', {id: k, value: this.key(k).value()}); - } - else this.set(k, data[k]); - } - } - return this; - }; - - /** - * Alias for patch - * - * @method setOptions - * - */ - OptionsManager.prototype.setOptions = OptionsManager.prototype.patch; - - /** - * Return OptionsManager based on sub-object retrieved by key - * - * @method key - * - * @param {string} identifier key - * @return {OptionsManager} new options manager with the value - */ - OptionsManager.prototype.key = function key(identifier) { - var result = new OptionsManager(this._value[identifier]); - if (!(result._value instanceof Object) || result._value instanceof Array) result._value = {}; - return result; - }; - - /** - * Look up value by key - * @method get - * - * @param {string} key key - * @return {Object} associated object - */ - OptionsManager.prototype.get = function get(key) { - return this._value[key]; - }; - - /** - * Alias for get - * @method getOptions - */ - OptionsManager.prototype.getOptions = OptionsManager.prototype.get; - - /** - * Set key to value. Outputs 'change' event if a value is overwritten. - * - * @method set - * - * @param {string} key key string - * @param {Object} value value object - * @return {OptionsManager} new options manager based on the value object - */ - OptionsManager.prototype.set = function set(key, value) { - var originalValue = this.get(key); - this._value[key] = value; - if (this.eventOutput && value !== originalValue) this.eventOutput.emit('change', {id: key, value: value}); - return this; - }; - - /** - * Return entire object contents of this OptionsManager. - * - * @method value - * - * @return {Object} current state of options - */ - OptionsManager.prototype.value = function value() { - return this._value; - }; - - /** - * Bind a callback function to an event type handled by this object. - * - * @method "on" - * - * @param {string} type event type key (for example, 'change') - * @param {function(string, Object)} handler callback - * @return {EventHandler} this - */ - OptionsManager.prototype.on = function on() { - _createEventOutput.call(this); - return this.on.apply(this, arguments); - }; - - /** - * Unbind an event by type and handler. - * This undoes the work of "on". - * - * @method removeListener - * - * @param {string} type event type key (for example, 'change') - * @param {function} handler function object to remove - * @return {EventHandler} internal event handler object (for chaining) - */ - OptionsManager.prototype.removeListener = function removeListener() { - _createEventOutput.call(this); - return this.removeListener.apply(this, arguments); - }; - - /** - * Add event handler object to set of downstream handlers. - * - * @method pipe - * - * @param {EventHandler} target event handler target object - * @return {EventHandler} passed event handler - */ - OptionsManager.prototype.pipe = function pipe() { - _createEventOutput.call(this); - return this.pipe.apply(this, arguments); - }; - - /** - * Remove handler object from set of downstream handlers. - * Undoes work of "pipe" - * - * @method unpipe - * - * @param {EventHandler} target target handler object - * @return {EventHandler} provided target - */ - OptionsManager.prototype.unpipe = function unpipe() { - _createEventOutput.call(this); - return this.unpipe.apply(this, arguments); - }; - - module.exports = OptionsManager; -}); - -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. - * - * Owner: mark@famo.us - * @license MPL 2.0 - * @copyright Famous Industries, Inc. 2014 - */ - -define('famous/core/Engine',['require','exports','module','./Context','./EventHandler','./OptionsManager'],function(require, exports, module) { - - /** - * The singleton object initiated upon process - * startup which manages all active Context instances, runs - * the render dispatch loop, and acts as a listener and dispatcher - * for events. All methods are therefore static. - * - * On static initialization, window.requestAnimationFrame is called with - * the event loop function. - * - * Note: Any window in which Engine runs will prevent default - * scrolling behavior on the 'touchmove' event. - * - * @static - * @class Engine - */ - var Context = require('./Context'); - var EventHandler = require('./EventHandler'); - var OptionsManager = require('./OptionsManager'); - - var Engine = {}; - - var contexts = []; - var nextTickQueue = []; - var deferQueue = []; - - var lastTime = Date.now(); - var frameTime; - var frameTimeLimit; - var loopEnabled = true; - var eventForwarders = {}; - var eventHandler = new EventHandler(); - - var options = { - containerType: 'div', - containerClass: 'famous-container', - fpsCap: undefined, - runLoop: true - }; - var optionsManager = new OptionsManager(options); - - /** @const */ - var MAX_DEFER_FRAME_TIME = 10; - - /** - * Inside requestAnimationFrame loop, step() is called, which: - * calculates current FPS (throttling loop if it is over limit set in setFPSCap), - * emits dataless 'prerender' event on start of loop, - * calls in order any one-shot functions registered by nextTick on last loop, - * calls Context.update on all Context objects registered, - * and emits dataless 'postrender' event on end of loop. - * - * @static - * @private - * @method step - */ - Engine.step = function step() { - var currentTime = Date.now(); - - // skip frame if we're over our framerate cap - if (frameTimeLimit && currentTime - lastTime < frameTimeLimit) return; - - var i = 0; - - frameTime = currentTime - lastTime; - lastTime = currentTime; - - eventHandler.emit('prerender'); - - // empty the queue - for (i = 0; i < nextTickQueue.length; i++) nextTickQueue[i].call(this); - nextTickQueue.splice(0); - - // limit total execution time for deferrable functions - while (deferQueue.length && (Date.now() - currentTime) < MAX_DEFER_FRAME_TIME) { - deferQueue.shift().call(this); - } - - for (i = 0; i < contexts.length; i++) contexts[i].update(); - - eventHandler.emit('postrender'); - }; - - // engage requestAnimationFrame - function loop() { - if (options.runLoop) { - Engine.step(); - requestAnimationFrame(loop); - } - else loopEnabled = false; - } - requestAnimationFrame(loop); - - // - // Upon main document window resize (unless on an "input" HTML element): - // scroll to the top left corner of the window, - // and for each managed Context: emit the 'resize' event and update its size. - // @param {Object=} event document event - // - function handleResize(event) { - for (var i = 0; i < contexts.length; i++) { - contexts[i].emit('resize'); - } - eventHandler.emit('resize'); - } - window.addEventListener('resize', handleResize, false); - handleResize(); - - // prevent scrolling via browser - window.addEventListener('touchmove', function(event) { - event.preventDefault(); - }, true); - - /** - * Add event handler object to set of downstream handlers. - * - * @method pipe - * - * @param {EventHandler} target event handler target object - * @return {EventHandler} passed event handler - */ - Engine.pipe = function pipe(target) { - if (target.subscribe instanceof Function) return target.subscribe(Engine); - else return eventHandler.pipe(target); - }; - - /** - * Remove handler object from set of downstream handlers. - * Undoes work of "pipe". - * - * @method unpipe - * - * @param {EventHandler} target target handler object - * @return {EventHandler} provided target - */ - Engine.unpipe = function unpipe(target) { - if (target.unsubscribe instanceof Function) return target.unsubscribe(Engine); - else return eventHandler.unpipe(target); - }; - - /** - * Bind a callback function to an event type handled by this object. - * - * @static - * @method "on" - * - * @param {string} type event type key (for example, 'click') - * @param {function(string, Object)} handler callback - * @return {EventHandler} this - */ - Engine.on = function on(type, handler) { - if (!(type in eventForwarders)) { - eventForwarders[type] = eventHandler.emit.bind(eventHandler, type); - if (document.body) { - document.body.addEventListener(type, eventForwarders[type]); - } - else { - Engine.nextTick(function(type, forwarder) { - document.body.addEventListener(type, forwarder); - }.bind(this, type, eventForwarders[type])); - } - } - return eventHandler.on(type, handler); - }; - - /** - * Trigger an event, sending to all downstream handlers - * listening for provided 'type' key. - * - * @method emit - * - * @param {string} type event type key (for example, 'click') - * @param {Object} event event data - * @return {EventHandler} this - */ - Engine.emit = function emit(type, event) { - return eventHandler.emit(type, event); - }; - - /** - * Unbind an event by type and handler. - * This undoes the work of "on". - * - * @static - * @method removeListener - * - * @param {string} type event type key (for example, 'click') - * @param {function} handler function object to remove - * @return {EventHandler} internal event handler object (for chaining) - */ - Engine.removeListener = function removeListener(type, handler) { - return eventHandler.removeListener(type, handler); - }; - - /** - * Return the current calculated frames per second of the Engine. - * - * @static - * @method getFPS - * - * @return {Number} calculated fps - */ - Engine.getFPS = function getFPS() { - return 1000 / frameTime; - }; - - /** - * Set the maximum fps at which the system should run. If internal render - * loop is called at a greater frequency than this FPSCap, Engine will - * throttle render and update until this rate is achieved. - * - * @static - * @method setFPSCap - * - * @param {Number} fps maximum frames per second - */ - Engine.setFPSCap = function setFPSCap(fps) { - frameTimeLimit = Math.floor(1000 / fps); - }; - - /** - * Return engine options. - * - * @static - * @method getOptions - * @param {string} key - * @return {Object} engine options - */ - Engine.getOptions = function getOptions() { - return optionsManager.getOptions.apply(optionsManager, arguments); - }; - - /** - * Set engine options - * - * @static - * @method setOptions - * - * @param {Object} [options] overrides of default options - * @param {Number} [options.fpsCap] maximum fps at which the system should run - * @param {boolean} [options.runLoop=true] whether the run loop should continue - * @param {string} [options.containerType="div"] type of container element. Defaults to 'div'. - * @param {string} [options.containerClass="famous-container"] type of container element. Defaults to 'famous-container'. - */ - Engine.setOptions = function setOptions(options) { - return optionsManager.setOptions.apply(optionsManager, arguments); - }; - - /** - * Creates a new Context for rendering and event handling with - * provided document element as top of each tree. This will be tracked by the - * process-wide Engine. - * - * @static - * @method createContext - * - * @param {Node} el will be top of Famo.us document element tree - * @return {Context} new Context within el - */ - Engine.createContext = function createContext(el) { - var needMountContainer = false; - if (!el) { - el = document.createElement(options.containerType); - el.classList.add(options.containerClass); - needMountContainer = true; - } - var context = new Context(el); - Engine.registerContext(context); - if (needMountContainer) { - Engine.nextTick(function(context, el) { - document.body.appendChild(el); - context.emit('resize'); - }.bind(this, context, el)); - } - return context; - }; - - /** - * Registers an existing context to be updated within the run loop. - * - * @static - * @method registerContext - * - * @param {Context} context Context to register - * @return {FamousContext} provided context - */ - Engine.registerContext = function registerContext(context) { - contexts.push(context); - return context; - }; - - /** - * Queue a function to be executed on the next tick of the - * Engine. - * - * @static - * @method nextTick - * - * @param {function(Object)} fn function accepting window object - */ - Engine.nextTick = function nextTick(fn) { - nextTickQueue.push(fn); - }; - - /** - * Queue a function to be executed sometime soon, at a time that is - * unlikely to affect frame rate. - * - * @static - * @method defer - * - * @param {Function} fn - */ - Engine.defer = function defer(fn) { - deferQueue.push(fn); - }; - - optionsManager.on('change', function(data) { - if (data.id === 'fpsCap') Engine.setFPSCap(data.value); - else if (data.id === 'runLoop') { - // kick off the loop only if it was stopped - if (!loopEnabled && data.value) { - loopEnabled = true; - requestAnimationFrame(loop); - } - } - }); - - module.exports = Engine; -}); - -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. - * - * Owner: mark@famo.us - * @license MPL 2.0 - * @copyright Famous Industries, Inc. 2014 - */ - -define('famous/core/Surface',['require','exports','module','./Entity','./EventHandler','./Transform'],function(require, exports, module) { - var Entity = require('./Entity'); - var EventHandler = require('./EventHandler'); - var Transform = require('./Transform'); - - var devicePixelRatio = window.devicePixelRatio || 1; - var usePrefix = document.createElement('div').style.webkitTransform !== undefined; - - /** - * A base class for viewable content and event - * targets inside a Famo.us application, containing a renderable document - * fragment. Like an HTML div, it can accept internal markup, - * properties, classes, and handle events. - * - * @class Surface - * @constructor - * - * @param {Object} [options] default option overrides - * @param {Array.Number} [options.size] [width, height] in pixels - * @param {Array.string} [options.classes] CSS classes to set on inner content - * @param {Array} [options.properties] string dictionary of HTML attributes to set on target div - * @param {string} [options.content] inner (HTML) content of surface - */ - function Surface(options) { - this.options = {}; - - this.properties = {}; - this.content = ''; - this.classList = []; - this.size = null; - - this._classesDirty = true; - this._stylesDirty = true; - this._sizeDirty = true; - this._contentDirty = true; - - this._dirtyClasses = []; - - this._matrix = null; - this._opacity = 1; - this._origin = null; - this._size = null; - - /** @ignore */ - this.eventForwarder = function eventForwarder(event) { - this.emit(event.type, event); - }.bind(this); - this.eventHandler = new EventHandler(); - this.eventHandler.bindThis(this); - - this.id = Entity.register(this); - - if (options) this.setOptions(options); - - this._currTarget = null; - } - Surface.prototype.elementType = 'div'; - Surface.prototype.elementClass = 'famous-surface'; - - /** - * Bind a callback function to an event type handled by this object. - * - * @method "on" - * - * @param {string} type event type key (for example, 'click') - * @param {function(string, Object)} fn handler callback - * @return {EventHandler} this - */ - Surface.prototype.on = function on(type, fn) { - if (this._currTarget) this._currTarget.addEventListener(type, this.eventForwarder); - this.eventHandler.on(type, fn); - }; - - /** - * Unbind an event by type and handler. - * This undoes the work of "on" - * - * @method removeListener - * @param {string} type event type key (for example, 'click') - * @param {function(string, Object)} fn handler - */ - Surface.prototype.removeListener = function removeListener(type, fn) { - this.eventHandler.removeListener(type, fn); - }; - - /** - * Trigger an event, sending to all downstream handlers - * listening for provided 'type' key. - * - * @method emit - * - * @param {string} type event type key (for example, 'click') - * @param {Object} [event] event data - * @return {EventHandler} this - */ - Surface.prototype.emit = function emit(type, event) { - if (event && !event.origin) event.origin = this; - var handled = this.eventHandler.emit(type, event); - if (handled && event && event.stopPropagation) event.stopPropagation(); - return handled; - }; - - /** - * Add event handler object to set of downstream handlers. - * - * @method pipe - * - * @param {EventHandler} target event handler target object - * @return {EventHandler} passed event handler - */ - Surface.prototype.pipe = function pipe(target) { - return this.eventHandler.pipe(target); - }; - - /** - * Remove handler object from set of downstream handlers. - * Undoes work of "pipe" - * - * @method unpipe - * - * @param {EventHandler} target target handler object - * @return {EventHandler} provided target - */ - Surface.prototype.unpipe = function unpipe(target) { - return this.eventHandler.unpipe(target); - }; - - /** - * Return spec for this surface. Note that for a base surface, this is - * simply an id. - * - * @method render - * @private - * @return {Object} render spec for this surface (spec id) - */ - Surface.prototype.render = function render() { - return this.id; - }; - - /** - * Set CSS-style properties on this Surface. Note that this will cause - * dirtying and thus re-rendering, even if values do not change. - * - * @method setProperties - * @param {Object} properties property dictionary of "key" => "value" - */ - Surface.prototype.setProperties = function setProperties(properties) { - for (var n in properties) { - this.properties[n] = properties[n]; - } - this._stylesDirty = true; - }; - - /** - * Get CSS-style properties on this Surface. - * - * @method getProperties - * - * @return {Object} Dictionary of this Surface's properties. - */ - Surface.prototype.getProperties = function getProperties() { - return this.properties; - }; - - /** - * Add CSS-style class to the list of classes on this Surface. Note - * this will map directly to the HTML property of the actual - * corresponding rendered
    . - * - * @method addClass - * @param {string} className name of class to add - */ - Surface.prototype.addClass = function addClass(className) { - if (this.classList.indexOf(className) < 0) { - this.classList.push(className); - this._classesDirty = true; - } - }; - - /** - * Remove CSS-style class from the list of classes on this Surface. - * Note this will map directly to the HTML property of the actual - * corresponding rendered
    . - * - * @method removeClass - * @param {string} className name of class to remove - */ - Surface.prototype.removeClass = function removeClass(className) { - var i = this.classList.indexOf(className); - if (i >= 0) { - this._dirtyClasses.push(this.classList.splice(i, 1)[0]); - this._classesDirty = true; - } - }; - - /** - * Reset class list to provided dictionary. - * @method setClasses - * @param {Array.string} classList - */ - Surface.prototype.setClasses = function setClasses(classList) { - var i = 0; - var removal = []; - for (i = 0; i < this.classList.length; i++) { - if (classList.indexOf(this.classList[i]) < 0) removal.push(this.classList[i]); - } - for (i = 0; i < removal.length; i++) this.removeClass(removal[i]); - // duplicates are already checked by addClass() - for (i = 0; i < classList.length; i++) this.addClass(classList[i]); - }; - - /** - * Get array of CSS-style classes attached to this div. - * - * @method getClasslist - * @return {Array.string} array of class names - */ - Surface.prototype.getClassList = function getClassList() { - return this.classList; - }; - - /** - * Set or overwrite inner (HTML) content of this surface. Note that this - * causes a re-rendering if the content has changed. - * - * @method setContent - * @param {string|Document Fragment} content HTML content - */ - Surface.prototype.setContent = function setContent(content) { - if (this.content !== content) { - this.content = content; - this._contentDirty = true; - } - }; - - /** - * Return inner (HTML) content of this surface. - * - * @method getContent - * - * @return {string} inner (HTML) content - */ - Surface.prototype.getContent = function getContent() { - return this.content; - }; - - /** - * Set options for this surface - * - * @method setOptions - * @param {Object} [options] overrides for default options. See constructor. - */ - Surface.prototype.setOptions = function setOptions(options) { - if (options.size) this.setSize(options.size); - if (options.classes) this.setClasses(options.classes); - if (options.properties) this.setProperties(options.properties); - if (options.content) this.setContent(options.content); - }; - - // Attach Famous event handling to document events emanating from target - // document element. This occurs just after deployment to the document. - // Calling this enables methods like #on and #pipe. - function _addEventListeners(target) { - for (var i in this.eventHandler.listeners) { - target.addEventListener(i, this.eventForwarder); - } - } - - // Detach Famous event handling from document events emanating from target - // document element. This occurs just before recall from the document. - function _removeEventListeners(target) { - for (var i in this.eventHandler.listeners) { - target.removeEventListener(i, this.eventForwarder); - } - } - - // Apply to document all changes from removeClass() since last setup(). - function _cleanupClasses(target) { - for (var i = 0; i < this._dirtyClasses.length; i++) target.classList.remove(this._dirtyClasses[i]); - this._dirtyClasses = []; - } - - // Apply values of all Famous-managed styles to the document element. - // These will be deployed to the document on call to #setup(). - function _applyStyles(target) { - for (var n in this.properties) { - target.style[n] = this.properties[n]; - } - } - - // Clear all Famous-managed styles from the document element. - // These will be deployed to the document on call to #setup(). - function _cleanupStyles(target) { - for (var n in this.properties) { - target.style[n] = ''; - } - } - - /** - * Return a Matrix's webkit css representation to be used with the - * CSS3 -webkit-transform style. - * Example: -webkit-transform: matrix3d(1,0,0,0,0,1,0,0,0,0,1,0,716,243,0,1) - * - * @method _formatCSSTransform - * @private - * @param {FamousMatrix} m matrix - * @return {string} matrix3d CSS style representation of the transform - */ - function _formatCSSTransform(m) { - m[12] = Math.round(m[12] * devicePixelRatio) / devicePixelRatio; - m[13] = Math.round(m[13] * devicePixelRatio) / devicePixelRatio; - - var result = 'matrix3d('; - for (var i = 0; i < 15; i++) { - result += (m[i] < 0.000001 && m[i] > -0.000001) ? '0,' : m[i] + ','; - } - result += m[15] + ')'; - return result; - } - - /** - * Directly apply given FamousMatrix to the document element as the - * appropriate webkit CSS style. - * - * @method setMatrix - * - * @static - * @private - * @param {Element} element document element - * @param {FamousMatrix} matrix - */ - - var _setMatrix; - if (navigator.userAgent.toLowerCase().indexOf('firefox') > -1) { - _setMatrix = function(element, matrix) { - element.style.zIndex = (matrix[14] * 1000000) | 0; // fix for Firefox z-buffer issues - element.style.transform = _formatCSSTransform(matrix); - }; - } - else if (usePrefix) { - _setMatrix = function(element, matrix) { - element.style.webkitTransform = _formatCSSTransform(matrix); - }; - } - else { - _setMatrix = function(element, matrix) { - element.style.transform = _formatCSSTransform(matrix); - }; - } - - // format origin as CSS percentage string - function _formatCSSOrigin(origin) { - return (100 * origin[0]) + '% ' + (100 * origin[1]) + '%'; - } - - // Directly apply given origin coordinates to the document element as the - // appropriate webkit CSS style. - var _setOrigin = usePrefix ? function(element, origin) { - element.style.webkitTransformOrigin = _formatCSSOrigin(origin); - } : function(element, origin) { - element.style.transformOrigin = _formatCSSOrigin(origin); - }; - - // Shrink given document element until it is effectively invisible. - var _setInvisible = usePrefix ? function(element) { - element.style.webkitTransform = 'scale3d(0.0001,0.0001,1)'; - element.style.opacity = 0; - } : function(element) { - element.style.transform = 'scale3d(0.0001,0.0001,1)'; - element.style.opacity = 0; - }; - - function _xyNotEquals(a, b) { - return (a && b) ? (a[0] !== b[0] || a[1] !== b[1]) : a !== b; - } - - /** - * One-time setup for an element to be ready for commits to document. - * - * @private - * @method setup - * - * @param {ElementAllocator} allocator document element pool for this context - */ - Surface.prototype.setup = function setup(allocator) { - var target = allocator.allocate(this.elementType); - if (this.elementClass) { - if (this.elementClass instanceof Array) { - for (var i = 0; i < this.elementClass.length; i++) { - target.classList.add(this.elementClass[i]); - } - } - else { - target.classList.add(this.elementClass); - } - } - target.style.display = ''; - _addEventListeners.call(this, target); - this._currTarget = target; - this._stylesDirty = true; - this._classesDirty = true; - this._sizeDirty = true; - this._contentDirty = true; - this._matrix = null; - this._opacity = undefined; - this._origin = null; - this._size = null; - }; - - /** - * Apply changes from this component to the corresponding document element. - * This includes changes to classes, styles, size, content, opacity, origin, - * and matrix transforms. - * - * @private - * @method commit - * @param {Context} context commit context - */ - Surface.prototype.commit = function commit(context) { - if (!this._currTarget) this.setup(context.allocator); - var target = this._currTarget; - - var matrix = context.transform; - var opacity = context.opacity; - var origin = context.origin; - var size = context.size; - - if (this._classesDirty) { - _cleanupClasses.call(this, target); - var classList = this.getClassList(); - for (var i = 0; i < classList.length; i++) target.classList.add(classList[i]); - this._classesDirty = false; - } - - if (this._stylesDirty) { - _applyStyles.call(this, target); - this._stylesDirty = false; - } - - if (this._contentDirty) { - this.deploy(target); - this.eventHandler.emit('deploy'); - this._contentDirty = false; - } - - if (this.size) { - var origSize = size; - size = [this.size[0], this.size[1]]; - if (size[0] === undefined && origSize[0]) size[0] = origSize[0]; - if (size[1] === undefined && origSize[1]) size[1] = origSize[1]; - } - - if (size[0] === true) size[0] = target.clientWidth; - if (size[1] === true) size[1] = target.clientHeight; - - if (_xyNotEquals(this._size, size)) { - if (!this._size) this._size = [0, 0]; - this._size[0] = size[0]; - this._size[1] = size[1]; - this._sizeDirty = true; - } - - if (!matrix && this._matrix) { - this._matrix = null; - this._opacity = 0; - _setInvisible(target); - return; - } - - if (this._opacity !== opacity) { - this._opacity = opacity; - target.style.opacity = (opacity >= 1) ? '0.999999' : opacity; - } - - if (_xyNotEquals(this._origin, origin) || Transform.notEquals(this._matrix, matrix) || this._sizeDirty) { - if (!matrix) matrix = Transform.identity; - this._matrix = matrix; - var aaMatrix = matrix; - if (origin) { - if (!this._origin) this._origin = [0, 0]; - this._origin[0] = origin[0]; - this._origin[1] = origin[1]; - aaMatrix = Transform.thenMove(matrix, [-this._size[0] * origin[0], -this._size[1] * origin[1], 0]); - _setOrigin(target, origin); - } - _setMatrix(target, aaMatrix); - } - - if (this._sizeDirty) { - if (this._size) { - target.style.width = (this.size && this.size[0] === true) ? '' : this._size[0] + 'px'; - target.style.height = (this.size && this.size[1] === true) ? '' : this._size[1] + 'px'; - } - this._sizeDirty = false; - } - }; - - /** - * Remove all Famous-relevant attributes from a document element. - * This is called by SurfaceManager's detach(). - * This is in some sense the reverse of .deploy(). - * - * @private - * @method cleanup - * @param {ElementAllocator} allocator - */ - Surface.prototype.cleanup = function cleanup(allocator) { - var i = 0; - var target = this._currTarget; - this.eventHandler.emit('recall'); - this.recall(target); - target.style.display = 'none'; - target.style.width = ''; - target.style.height = ''; - this._size = null; - _cleanupStyles.call(this, target); - var classList = this.getClassList(); - _cleanupClasses.call(this, target); - for (i = 0; i < classList.length; i++) target.classList.remove(classList[i]); - if (this.elementClass) { - if (this.elementClass instanceof Array) { - for (i = 0; i < this.elementClass.length; i++) { - target.classList.remove(this.elementClass[i]); - } - } - else { - target.classList.remove(this.elementClass); - } - } - _removeEventListeners.call(this, target); - this._currTarget = null; - allocator.deallocate(target); - _setInvisible(target); - }; - - /** - * Place the document element that this component manages into the document. - * - * @private - * @method deploy - * @param {Node} target document parent of this container - */ - Surface.prototype.deploy = function deploy(target) { - var content = this.getContent(); - if (content instanceof Node) { - while (target.hasChildNodes()) target.removeChild(target.firstChild); - target.appendChild(content); - } - else target.innerHTML = content; - }; - - /** - * Remove any contained document content associated with this surface - * from the actual document. - * - * @private - * @method recall - */ - Surface.prototype.recall = function recall(target) { - var df = document.createDocumentFragment(); - while (target.hasChildNodes()) df.appendChild(target.firstChild); - this.setContent(df); - }; - - /** - * Get the x and y dimensions of the surface. - * - * @method getSize - * @param {boolean} actual return computed size rather than provided - * @return {Array.Number} [x,y] size of surface - */ - Surface.prototype.getSize = function getSize(actual) { - return actual ? this._size : (this.size || this._size); - }; - - /** - * Set x and y dimensions of the surface. - * - * @method setSize - * @param {Array.Number} size as [width, height] - */ - Surface.prototype.setSize = function setSize(size) { - this.size = size ? [size[0], size[1]] : null; - this._sizeDirty = true; - }; - - module.exports = Surface; -}); - -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. - * - * Owner: mark@famo.us - * @license MPL 2.0 - * @copyright Famous Industries, Inc. 2014 - */ - -define('famous/core/Group',['require','exports','module','./Context','./Transform','./Surface'],function(require, exports, module) { - var Context = require('./Context'); - var Transform = require('./Transform'); - var Surface = require('./Surface'); - - /** - * A Context designed to contain surfaces and set properties - * to be applied to all of them at once. - * This is primarily used for specific performance improvements in the rendering engine. - * Private. - * - * @private - * @class Group - * @extends Surface - * @constructor - * @param {Object} [options] Surface options array (see Surface}) - */ - function Group(options) { - Surface.call(this, options); - this._shouldRecalculateSize = false; - this._container = document.createDocumentFragment(); - this.context = new Context(this._container); - this.setContent(this._container); - this._groupSize = [undefined, undefined]; - } - - /** @const */ - Group.SIZE_ZERO = [0, 0]; - - Group.prototype = Object.create(Surface.prototype); - Group.prototype.elementType = 'div'; - Group.prototype.elementClass = 'famous-group'; - - /** - * Add renderables to this component's render tree. - * - * @method add - * @private - * @param {Object} obj renderable object - * @return {RenderNode} Render wrapping provided object, if not already a RenderNode - */ - Group.prototype.add = function add() { - return this.context.add.apply(this.context, arguments); - }; - - /** - * Generate a render spec from the contents of this component. - * - * @private - * @method render - * @return {Number} Render spec for this component - */ - Group.prototype.render = function render() { - return Surface.prototype.render.call(this); - }; - - /** - * Place the document element this component manages into the document. - * - * @private - * @method deploy - * @param {Node} target document parent of this container - */ - Group.prototype.deploy = function deploy(target) { - this.context.migrate(target); - }; - - /** - * Remove this component and contained content from the document - * - * @private - * @method recall - * - * @param {Node} target node to which the component was deployed - */ - Group.prototype.recall = function recall(target) { - this._container = document.createDocumentFragment(); - this.context.migrate(this._container); - }; - - /** - * Apply changes from this component to the corresponding document element. - * - * @private - * @method commit - * - * @param {Object} context update spec passed in from above in the render tree. - */ - Group.prototype.commit = function commit(context) { - var transform = context.transform; - var origin = context.origin; - var opacity = context.opacity; - var size = context.size; - var result = Surface.prototype.commit.call(this, { - allocator: context.allocator, - transform: Transform.thenMove(transform, [-origin[0] * size[0], -origin[1] * size[1], 0]), - opacity: opacity, - origin: origin, - size: Group.SIZE_ZERO - }); - if (size[0] !== this._groupSize[0] || size[1] !== this._groupSize[1]) { - this._groupSize[0] = size[0]; - this._groupSize[1] = size[1]; - this.context.setSize(size); - } - this.context.update({ - transform: Transform.translate(-origin[0] * size[0], -origin[1] * size[1], 0), - origin: origin, - size: size - }); - return result; - }; - - module.exports = Group; -}); - -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. - * - * Owner: david@famo.us - * @license MPL 2.0 - * @copyright Famous Industries, Inc. 2014 - */ - -define('famous/transitions/TransitionableTransform',['require','exports','module','./Transitionable','famous/core/Transform','famous/utilities/Utility'],function(require, exports, module) { - var Transitionable = require('./Transitionable'); - var Transform = require('famous/core/Transform'); - var Utility = require('famous/utilities/Utility'); - - /** - * A class for transitioning the state of a Transform by transitioning - * its translate, scale, skew and rotate components independently. - * - * @class TransitionableTransform - * @constructor - * - * @param [transform=Transform.identity] {Transform} The initial transform state - */ - function TransitionableTransform(transform) { - 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]); - - if (transform) this.set(transform); - } - - function _build() { - return Transform.build({ - translate: this.translate.get(), - rotate: this.rotate.get(), - skew: this.skew.get(), - scale: this.scale.get() - }); - } - - /** - * An optimized way of setting only the translation component of a Transform - * - * @method setTranslate - * @chainable - * - * @param translate {Array} New translation state - * @param [transition] {Object} Transition definition - * @param [callback] {Function} Callback - * @return {TransitionableTransform} - */ - TransitionableTransform.prototype.setTranslate = function setTranslate(translate, transition, callback) { - 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; - }; - - /** - * An optimized way of setting only the scale component of a Transform - * - * @method setScale - * @chainable - * - * @param scale {Array} New scale state - * @param [transition] {Object} Transition definition - * @param [callback] {Function} Callback - * @return {TransitionableTransform} - */ - TransitionableTransform.prototype.setScale = function setScale(scale, transition, callback) { - 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; - }; - - /** - * An optimized way of setting only the rotational component of a Transform - * - * @method setRotate - * @chainable - * - * @param eulerAngles {Array} Euler angles for new rotation state - * @param [transition] {Object} Transition definition - * @param [callback] {Function} Callback - * @return {TransitionableTransform} - */ - TransitionableTransform.prototype.setRotate = function setRotate(eulerAngles, transition, callback) { - 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; - }; - - /** - * An optimized way of setting only the skew component of a Transform - * - * @method setSkew - * @chainable - * - * @param skewAngles {Array} New skew state - * @param [transition] {Object} Transition definition - * @param [callback] {Function} Callback - * @return {TransitionableTransform} - */ - TransitionableTransform.prototype.setSkew = function setSkew(skewAngles, transition, callback) { - 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; - }; - - /** - * Setter for a TransitionableTransform with optional parameters to transition - * between Transforms - * - * @method set - * @chainable - * - * @param transform {Array} New transform state - * @param [transition] {Object} Transition definition - * @param [callback] {Function} Callback - * @return {TransitionableTransform} - */ - TransitionableTransform.prototype.set = function set(transform, transition, callback) { - this._final = transform; - var components = Transform.interpret(transform); - - var _callback = callback ? Utility.after(4, callback) : null; - this.translate.set(components.translate, transition, _callback); - this.rotate.set(components.rotate, transition, _callback); - this.skew.set(components.skew, transition, _callback); - this.scale.set(components.scale, transition, _callback); - return this; - }; - - /** - * Sets the default transition to use for transitioning betwen Transform states - * - * @method setDefaultTransition - * - * @param transition {Object} Transition definition - */ - TransitionableTransform.prototype.setDefaultTransition = function setDefaultTransition(transition) { - this.translate.setDefault(transition); - this.rotate.setDefault(transition); - this.skew.setDefault(transition); - this.scale.setDefault(transition); - }; - - /** - * Getter. Returns the current state of the Transform - * - * @method get - * - * @return {Transform} - */ - TransitionableTransform.prototype.get = function get() { - if (this.isActive()) { - return _build.call(this); - } - else return this._final; - }; - - /** - * Get the destination state of the Transform - * - * @method getFinal - * - * @return Transform {Transform} - */ - TransitionableTransform.prototype.getFinal = function getFinal() { - return this._final; - }; - - /** - * Determine if the TransitionalTransform is currently transitioning - * - * @method isActive - * - * @return {Boolean} - */ - TransitionableTransform.prototype.isActive = function isActive() { - return this.translate.isActive() || this.rotate.isActive() || this.scale.isActive() || this.skew.isActive(); - }; - - /** - * Halts the transition - * - * @method halt - */ - TransitionableTransform.prototype.halt = function halt() { - this._final = this.get(); - this.translate.halt(); - this.rotate.halt(); - this.skew.halt(); - this.scale.halt(); - }; - - module.exports = TransitionableTransform; -}); - -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. - * - * Owner: mark@famo.us - * @license MPL 2.0 - * @copyright Famous Industries, Inc. 2014 - */ - -define('famous/core/Modifier',['require','exports','module','./Transform','famous/transitions/Transitionable','famous/transitions/TransitionableTransform'],function(require, exports, module) { - var Transform = require('./Transform'); - - /* TODO: remove these dependencies when deprecation complete */ - var Transitionable = require('famous/transitions/Transitionable'); - var TransitionableTransform = require('famous/transitions/TransitionableTransform'); - - /** - * - * A collection of visual changes to be - * applied to another renderable component. This collection includes a - * transform matrix, an opacity constant, a size, an origin specifier. - * Modifier objects can be added to any RenderNode or object - * capable of displaying renderables. The Modifier's children and descendants - * are transformed by the amounts specified in the Modifier's properties. - * - * @class Modifier - * @constructor - * @param {Object} [options] overrides of default options - * @param {Transform} [options.transform] affine transformation matrix - * @param {Number} [options.opacity] - * @param {Array.Number} [options.origin] origin adjustment - * @param {Array.Number} [options.size] size to apply to descendants - */ - function Modifier(options) { - this._transformGetter = null; - this._opacityGetter = null; - this._originGetter = null; - this._alignGetter = null; - this._sizeGetter = null; - - /* TODO: remove this when deprecation complete */ - this._legacyStates = {}; - - this._output = { - transform: Transform.identity, - opacity: 1, - origin: null, - align: null, - size: null, - target: null - }; - - if (options) { - if (options.transform) this.transformFrom(options.transform); - if (options.opacity !== undefined) this.opacityFrom(options.opacity); - if (options.origin) this.originFrom(options.origin); - if (options.align) this.alignFrom(options.align); - if (options.size) this.sizeFrom(options.size); - } - } - - /** - * Function, object, or static transform matrix which provides the transform. - * This is evaluated on every tick of the engine. - * - * @method transformFrom - * - * @param {Object} transform transform provider object - * @return {Modifier} this - */ - Modifier.prototype.transformFrom = function transformFrom(transform) { - if (transform instanceof Function) this._transformGetter = transform; - else if (transform instanceof Object && transform.get) this._transformGetter = transform.get.bind(transform); - else { - this._transformGetter = null; - this._output.transform = transform; - } - return this; - }; - - /** - * Set function, object, or number to provide opacity, in range [0,1]. - * - * @method opacityFrom - * - * @param {Object} opacity provider object - * @return {Modifier} this - */ - Modifier.prototype.opacityFrom = function opacityFrom(opacity) { - if (opacity instanceof Function) this._opacityGetter = opacity; - else if (opacity instanceof Object && opacity.get) this._opacityGetter = opacity.get.bind(opacity); - else { - this._opacityGetter = null; - this._output.opacity = opacity; - } - return this; - }; - - /** - * Set function, object, or numerical array to provide origin, as [x,y], - * where x and y are in the range [0,1]. - * - * @method originFrom - * - * @param {Object} origin provider object - * @return {Modifier} this - */ - Modifier.prototype.originFrom = function originFrom(origin) { - if (origin instanceof Function) this._originGetter = origin; - else if (origin instanceof Object && origin.get) this._originGetter = origin.get.bind(origin); - else { - this._originGetter = null; - this._output.origin = origin; - } - return this; - }; - - /** - * Set function, object, or numerical array to provide align, as [x,y], - * where x and y are in the range [0,1]. - * - * @method alignFrom - * - * @param {Object} align provider object - * @return {Modifier} this - */ - Modifier.prototype.alignFrom = function alignFrom(align) { - if (align instanceof Function) this._alignGetter = align; - else if (align instanceof Object && align.get) this._alignGetter = align.get.bind(align); - else { - this._alignGetter = null; - this._output.align = align; - } - return this; - }; - - /** - * Set function, object, or numerical array to provide size, as [width, height]. - * - * @method sizeFrom - * - * @param {Object} size provider object - * @return {Modifier} this - */ - Modifier.prototype.sizeFrom = function sizeFrom(size) { - if (size instanceof Function) this._sizeGetter = size; - else if (size instanceof Object && size.get) this._sizeGetter = size.get.bind(size); - else { - this._sizeGetter = null; - this._output.size = size; - } - return this; - }; - - /** - * Deprecated: Prefer transformFrom with static Transform, or use a TransitionableTransform. - * @deprecated - * @method setTransform - * - * @param {Transform} transform Transform to transition to - * @param {Transitionable} transition Valid transitionable object - * @param {Function} callback callback to call after transition completes - * @return {Modifier} this - */ - Modifier.prototype.setTransform = function setTransform(transform, transition, callback) { - if (transition || this._legacyStates.transform) { - if (!this._legacyStates.transform) { - this._legacyStates.transform = new TransitionableTransform(this._output.transform); - } - if (!this._transformGetter) this.transformFrom(this._legacyStates.transform); - - this._legacyStates.transform.set(transform, transition, callback); - return this; - } - else return this.transformFrom(transform); - }; - - /** - * Deprecated: Prefer opacityFrom with static opacity array, or use a Transitionable with that opacity. - * @deprecated - * @method setOpacity - * - * @param {Number} opacity Opacity value to transition to. - * @param {Transitionable} transition Valid transitionable object - * @param {Function} callback callback to call after transition completes - * @return {Modifier} this - */ - Modifier.prototype.setOpacity = function setOpacity(opacity, transition, callback) { - if (transition || this._legacyStates.opacity) { - if (!this._legacyStates.opacity) { - this._legacyStates.opacity = new Transitionable(this._output.opacity); - } - if (!this._opacityGetter) this.opacityFrom(this._legacyStates.opacity); - - return this._legacyStates.opacity.set(opacity, transition, callback); - } - else return this.opacityFrom(opacity); - }; - - /** - * Deprecated: Prefer originFrom with static origin array, or use a Transitionable with that origin. - * @deprecated - * @method setOrigin - * - * @param {Array.Number} origin 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 {Modifier} this - */ - Modifier.prototype.setOrigin = function setOrigin(origin, transition, callback) { - /* TODO: remove this if statement when deprecation complete */ - if (transition || this._legacyStates.origin) { - - if (!this._legacyStates.origin) { - this._legacyStates.origin = new Transitionable(this._output.origin || [0, 0]); - } - if (!this._originGetter) this.originFrom(this._legacyStates.origin); - - this._legacyStates.origin.set(origin, transition, callback); - return this; - } - else return this.originFrom(origin); - }; - - /** - * Deprecated: Prefer alignFrom with static align array, or use a Transitionable with that align. - * @deprecated - * @method setAlign - * - * @param {Array.Number} align 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 {Modifier} this - */ - Modifier.prototype.setAlign = function setAlign(align, transition, callback) { - /* TODO: remove this if statement when deprecation complete */ - if (transition || this._legacyStates.align) { - - if (!this._legacyStates.align) { - this._legacyStates.align = new Transitionable(this._output.align || [0, 0]); - } - if (!this._alignGetter) this.alignFrom(this._legacyStates.align); - - this._legacyStates.align.set(align, transition, callback); - return this; - } - else return this.alignFrom(align); - }; - - /** - * Deprecated: Prefer sizeFrom with static origin array, or use a Transitionable with that size. - * @deprecated - * @method setSize - * @param {Array.Number} size two element array of [width, height] - * @param {Transitionable} transition Valid transitionable object - * @param {Function} callback callback to call after transition completes - * @return {Modifier} this - */ - Modifier.prototype.setSize = function setSize(size, transition, callback) { - if (size && (transition || this._legacyStates.size)) { - if (!this._legacyStates.size) { - this._legacyStates.size = new Transitionable(this._output.size || [0, 0]); - } - if (!this._sizeGetter) this.sizeFrom(this._legacyStates.size); - - this._legacyStates.size.set(size, transition, callback); - return this; - } - else return this.sizeFrom(size); - }; - - /** - * Deprecated: Prefer to stop transform in your provider object. - * @deprecated - * @method halt - */ - Modifier.prototype.halt = function halt() { - if (this._legacyStates.transform) this._legacyStates.transform.halt(); - if (this._legacyStates.opacity) this._legacyStates.opacity.halt(); - if (this._legacyStates.origin) this._legacyStates.origin.halt(); - if (this._legacyStates.align) this._legacyStates.align.halt(); - if (this._legacyStates.size) this._legacyStates.size.halt(); - this._transformGetter = null; - this._opacityGetter = null; - this._originGetter = null; - this._alignGetter = null; - this._sizeGetter = null; - }; - - /** - * Deprecated: Prefer to use your provided transform or output of your transform provider. - * @deprecated - * @method getTransform - * @return {Object} transform provider object - */ - Modifier.prototype.getTransform = function getTransform() { - return this._transformGetter(); - }; - - /** - * Deprecated: Prefer to determine the end state of your transform from your transform provider - * @deprecated - * @method getFinalTransform - * @return {Transform} transform matrix - */ - Modifier.prototype.getFinalTransform = function getFinalTransform() { - return this._legacyStates.transform ? this._legacyStates.transform.getFinal() : this._output.transform; - }; - - /** - * Deprecated: Prefer to use your provided opacity or output of your opacity provider. - * @deprecated - * @method getOpacity - * @return {Object} opacity provider object - */ - Modifier.prototype.getOpacity = function getOpacity() { - return this._opacityGetter(); - }; - - /** - * Deprecated: Prefer to use your provided origin or output of your origin provider. - * @deprecated - * @method getOrigin - * @return {Object} origin provider object - */ - Modifier.prototype.getOrigin = function getOrigin() { - return this._originGetter(); - }; - - /** - * Deprecated: Prefer to use your provided align or output of your align provider. - * @deprecated - * @method getAlign - * @return {Object} align provider object - */ - Modifier.prototype.getAlign = function getAlign() { - return this._alignGetter(); - }; - - /** - * Deprecated: Prefer to use your provided size or output of your size provider. - * @deprecated - * @method getSize - * @return {Object} size provider object - */ - Modifier.prototype.getSize = function getSize() { - return this._sizeGetter ? this._sizeGetter() : this._output.size; - }; - - // call providers on tick to receive render spec elements to apply - function _update() { - if (this._transformGetter) this._output.transform = this._transformGetter(); - if (this._opacityGetter) this._output.opacity = this._opacityGetter(); - if (this._originGetter) this._output.origin = this._originGetter(); - if (this._alignGetter) this._output.align = this._alignGetter(); - if (this._sizeGetter) this._output.size = this._sizeGetter(); - } - - /** - * Return render spec for this Modifier, applying to the provided - * target component. This is similar to render() for Surfaces. - * - * @private - * @method modify - * - * @param {Object} target (already rendered) render spec to - * which to apply the transform. - * @return {Object} render spec for this Modifier, including the - * provided target - */ - Modifier.prototype.modify = function modify(target) { - _update.call(this); - this._output.target = target; - return this._output; - }; - - module.exports = Modifier; -}); - -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. - * - * Owner: mark@famo.us - * @license MPL 2.0 - * @copyright Famous Industries, Inc. 2014 - */ - -define('famous/core/Scene',['require','exports','module','./Transform','./Modifier','./RenderNode'],function(require, exports, module) { - var Transform = require('./Transform'); - var Modifier = require('./Modifier'); - var RenderNode = require('./RenderNode'); - - /** - * Builds and renders a scene graph based on a declarative structure definition. - * See the Scene examples in the examples distribution (http://github.com/Famous/examples.git). - * - * @class Scene - * @constructor - * @param {Object} definition in the format of a render spec. - */ - function Scene(definition) { - this.id = null; - this._objects = null; - - this.node = new RenderNode(); - this._definition = null; - - if (definition) this.load(definition); - } - - var _MATRIX_GENERATORS = { - 'translate': Transform.translate, - 'rotate': Transform.rotate, - 'rotateX': Transform.rotateX, - 'rotateY': Transform.rotateY, - 'rotateZ': Transform.rotateZ, - 'rotateAxis': Transform.rotateAxis, - 'scale': Transform.scale, - 'skew': Transform.skew, - 'matrix3d': function() { - return arguments; - } - }; - - /** - * Clone this scene - * - * @method create - * @return {Scene} deep copy of this scene - */ - Scene.prototype.create = function create() { - return new Scene(this._definition); - }; - - function _resolveTransformMatrix(matrixDefinition) { - for (var type in _MATRIX_GENERATORS) { - if (type in matrixDefinition) { - var args = matrixDefinition[type]; - if (!(args instanceof Array)) args = [args]; - return _MATRIX_GENERATORS[type].apply(this, args); - } - } - } - - // parse transform into tree of render nodes, doing matrix multiplication - // when available - function _parseTransform(definition) { - var transformDefinition = definition.transform; - var opacity = definition.opacity; - var origin = definition.origin; - var size = definition.size; - var transform = Transform.identity; - if (transformDefinition instanceof Array) { - if (transformDefinition.length === 16 && typeof transformDefinition[0] === 'number') { - transform = transformDefinition; - } - else { - for (var i = 0; i < transformDefinition.length; i++) { - transform = Transform.multiply(transform, _resolveTransformMatrix(transformDefinition[i])); - } - } - } - else if (transformDefinition instanceof Object) { - transform = _resolveTransformMatrix(transformDefinition); - } - - var result = new Modifier({ - transform: transform, - opacity: opacity, - origin: origin, - size: size - }); - return result; - } - - function _parseArray(definition) { - var result = new RenderNode(); - for (var i = 0; i < definition.length; i++) { - var obj = _parse.call(this, definition[i]); - if (obj) result.add(obj); - } - return result; - } - - // parse object directly into tree of RenderNodes - function _parse(definition) { - var result; - var id; - if (definition instanceof Array) { - result = _parseArray.call(this, definition); - } - else { - id = this._objects.length; - if (definition.render && (definition.render instanceof Function)) { - result = definition; - } - else if (definition.target) { - var targetObj = _parse.call(this, definition.target); - var obj = _parseTransform.call(this, definition); - - result = new RenderNode(obj); - result.add(targetObj); - if (definition.id) this.id[definition.id] = obj; - } - else if (definition.id) { - result = new RenderNode(); - this.id[definition.id] = result; - } - } - this._objects[id] = result; - return result; - } - - /** - * Builds and renders a scene graph based on a canonical declarative scene definition. - * See examples/Scene/example.js. - * - * @method load - * @param {Object} definition definition in the format of a render spec. - */ - Scene.prototype.load = function load(definition) { - this._definition = definition; - this.id = {}; - this._objects = []; - this.node.set(_parse.call(this, definition)); - }; - - /** - * Add renderables to this component's render tree - * - * @method add - * - * @param {Object} obj renderable object - * @return {RenderNode} Render wrapping provided object, if not already a RenderNode - */ - Scene.prototype.add = function add() { - return this.node.add.apply(this.node, arguments); - }; - - /** - * Generate a render spec from the contents of this component. - * - * @private - * @method render - * @return {number} Render spec for this component - */ - Scene.prototype.render = function render() { - return this.node.render.apply(this.node, arguments); - }; - - module.exports = Scene; -}); - -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. - * - * Owner: mark@famo.us - * @license MPL 2.0 - * @copyright Famous Industries, Inc. 2014 - */ - -define('famous/core/View',['require','exports','module','./EventHandler','./OptionsManager','./RenderNode'],function(require, exports, module) { - var EventHandler = require('./EventHandler'); - var OptionsManager = require('./OptionsManager'); - var RenderNode = require('./RenderNode'); - - /** - * Useful for quickly creating elements within applications - * with large event systems. Consists of a RenderNode paired with - * an input EventHandler and an output EventHandler. - * Meant to be extended by the developer. - * - * @class View - * @uses EventHandler - * @uses OptionsManager - * @uses RenderNode - * @constructor - */ - function View(options) { - this._node = new RenderNode(); - - this._eventInput = new EventHandler(); - this._eventOutput = new EventHandler(); - EventHandler.setInputHandler(this, this._eventInput); - EventHandler.setOutputHandler(this, this._eventOutput); - - this.options = Object.create(this.constructor.DEFAULT_OPTIONS || View.DEFAULT_OPTIONS); - this._optionsManager = new OptionsManager(this.options); - - if (options) this.setOptions(options); - } - - View.DEFAULT_OPTIONS = {}; // no defaults - - /** - * Look up options value by key - * @method getOptions - * - * @param {string} key key - * @return {Object} associated object - */ - View.prototype.getOptions = function getOptions() { - return this._optionsManager.value(); - }; - - /* - * Set internal options. - * No defaults options are set in View. - * - * @method setOptions - * @param {Object} options - */ - View.prototype.setOptions = function setOptions(options) { - this._optionsManager.patch(options); - }; - - /** - * Add a child renderable to the view. - * Note: This is meant to be used by an inheriting class - * rather than from outside the prototype chain. - * - * @method add - * @return {RenderNode} - * @protected - */ - View.prototype.add = function add() { - return this._node.add.apply(this._node, arguments); - }; - - /** - * Alias for add - * @method _add - */ - View.prototype._add = View.prototype.add; - - /** - * Generate a render spec from the contents of this component. - * - * @private - * @method render - * @return {number} Render spec for this component - */ - View.prototype.render = function render() { - return this._node.render(); - }; - - /** - * Return size of contained element. - * - * @method getSize - * @return {Array.Number} [width, height] - */ - View.prototype.getSize = function getSize() { - if (this._node && this._node.getSize) { - return this._node.getSize.apply(this._node, arguments) || this.options.size; - } - else return this.options.size; - }; - - module.exports = View; -}); - -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. - * - * Owner: mark@famo.us - * @license MPL 2.0 - * @copyright Famous Industries, Inc. 2014 - */ - -define('famous/core/ViewSequence',['require','exports','module'],function(require, exports, module) { - - /** - * Helper object used to iterate through items sequentially. Used in - * views that deal with layout. A ViewSequence object conceptually points - * to a node in a linked list. - * - * @class ViewSequence - * - * @constructor - * @param {Object|Array} options Options object, or content array. - * @param {Number} [options.index] starting index. - * @param {Number} [options.array] Array of elements to populate the ViewSequence - * @param {Object} [options._] Optional backing store (internal - * @param {Boolean} [options.loop] Whether to wrap when accessing elements just past the end - * (or beginning) of the sequence. - */ - function ViewSequence(options) { - if (!options) options = []; - if (options instanceof Array) options = {array: options}; - - this._ = null; - this.index = options.index || 0; - - if (options.array) this._ = new (this.constructor.Backing)(options.array); - else if (options._) this._ = options._; - - if (this.index === this._.firstIndex) this._.firstNode = this; - if (this.index === this._.firstIndex + this._.array.length - 1) this._.lastNode = this; - - if (options.loop !== undefined) this._.loop = options.loop; - - this._previousNode = null; - this._nextNode = null; - } - - // constructor for internal storage - ViewSequence.Backing = function Backing(array) { - this.array = array; - this.firstIndex = 0; - this.loop = false; - this.firstNode = null; - this.lastNode = null; - }; - - // Get value "i" slots away from the first index. - ViewSequence.Backing.prototype.getValue = function getValue(i) { - var _i = i - this.firstIndex; - if (_i < 0 || _i >= this.array.length) return null; - return this.array[_i]; - }; - - // Set value "i" slots away from the first index. - ViewSequence.Backing.prototype.setValue = function setValue(i, value) { - this.array[i - this.firstIndex] = value; - }; - - // After splicing into the backing store, restore the indexes of each node correctly. - ViewSequence.Backing.prototype.reindex = function reindex(start, removeCount, insertCount) { - if (!this.array[0]) return; - - var i = 0; - var index = this.firstIndex; - var indexShiftAmount = insertCount - removeCount; - var node = this.firstNode; - - // find node to begin - while (index < start - 1) { - node = node.getNext(); - index++; - } - // skip removed nodes - var spliceStartNode = node; - for (i = 0; i < removeCount; i++) { - node = node.getNext(); - if (node) node._previousNode = spliceStartNode; - } - var spliceResumeNode = node ? node.getNext() : null; - // generate nodes for inserted items - spliceStartNode._nextNode = null; - node = spliceStartNode; - for (i = 0; i < insertCount; i++) node = node.getNext(); - index += insertCount; - // resume the chain - if (node !== spliceResumeNode) { - node._nextNode = spliceResumeNode; - if (spliceResumeNode) spliceResumeNode._previousNode = node; - } - if (spliceResumeNode) { - node = spliceResumeNode; - index++; - while (node && index < this.array.length + this.firstIndex) { - if (node._nextNode) node.index += indexShiftAmount; - else node.index = index; - node = node.getNext(); - index++; - } - } - }; - - /** - * Return ViewSequence node previous to this node in the list, respecting looping if applied. - * - * @method getPrevious - * @return {ViewSequence} previous node. - */ - ViewSequence.prototype.getPrevious = function getPrevious() { - if (this.index === this._.firstIndex) { - if (this._.loop) { - this._previousNode = this._.lastNode || new (this.constructor)({_: this._, index: this._.firstIndex + this._.array.length - 1}); - this._previousNode._nextNode = this; - } - else { - this._previousNode = null; - } - } - else if (!this._previousNode) { - this._previousNode = new (this.constructor)({_: this._, index: this.index - 1}); - this._previousNode._nextNode = this; - } - return this._previousNode; - }; - - /** - * Return ViewSequence node next after this node in the list, respecting looping if applied. - * - * @method getNext - * @return {ViewSequence} previous node. - */ - ViewSequence.prototype.getNext = function getNext() { - if (this.index === this._.firstIndex + this._.array.length - 1) { - if (this._.loop) { - this._nextNode = this._.firstNode || new (this.constructor)({_: this._, index: this._.firstIndex}); - this._nextNode._previousNode = this; - } - else { - this._nextNode = null; - } - } - else if (!this._nextNode) { - this._nextNode = new (this.constructor)({_: this._, index: this.index + 1}); - this._nextNode._previousNode = this; - } - return this._nextNode; - }; - - /** - * Return index of this ViewSequence node. - * - * @method getIndex - * @return {Number} index - */ - ViewSequence.prototype.getIndex = function getIndex() { - return this.index; - }; - - /** - * Return printable version of this ViewSequence node. - * - * @method toString - * @return {string} this index as a string - */ - ViewSequence.prototype.toString = function toString() { - return '' + this.index; - }; - - /** - * Add one or more objects to the beginning of the sequence. - * - * @method unshift - * @param {...Object} value arguments array of objects - */ - ViewSequence.prototype.unshift = function unshift(value) { - this._.array.unshift.apply(this._.array, arguments); - this._.firstIndex -= arguments.length; - }; - - /** - * Add one or more objects to the end of the sequence. - * - * @method push - * @param {...Object} value arguments array of objects - */ - ViewSequence.prototype.push = function push(value) { - this._.array.push.apply(this._.array, arguments); - }; - - /** - * Remove objects from the sequence - * - * @method splice - * @param {Number} index starting index for removal - * @param {Number} howMany how many elements to remove - * @param {...Object} value arguments array of objects - */ - ViewSequence.prototype.splice = function splice(index, howMany) { - var values = Array.prototype.slice.call(arguments, 2); - this._.array.splice.apply(this._.array, [index - this._.firstIndex, howMany].concat(values)); - this._.reindex(index, howMany, values.length); - }; - - /** - * Exchange this element's sequence position with another's. - * - * @method swap - * @param {ViewSequence} other element to swap with. - */ - ViewSequence.prototype.swap = function swap(other) { - var otherValue = other.get(); - var myValue = this.get(); - this._.setValue(this.index, otherValue); - this._.setValue(other.index, myValue); - - var myPrevious = this._previousNode; - var myNext = this._nextNode; - var myIndex = this.index; - var otherPrevious = other._previousNode; - var otherNext = other._nextNode; - var otherIndex = other.index; - - this.index = otherIndex; - this._previousNode = (otherPrevious === this) ? other : otherPrevious; - if (this._previousNode) this._previousNode._nextNode = this; - this._nextNode = (otherNext === this) ? other : otherNext; - if (this._nextNode) this._nextNode._previousNode = this; - - other.index = myIndex; - other._previousNode = (myPrevious === other) ? this : myPrevious; - if (other._previousNode) other._previousNode._nextNode = other; - other._nextNode = (myNext === other) ? this : myNext; - if (other._nextNode) other._nextNode._previousNode = other; - - if (this.index === this._.firstIndex) this._.firstNode = this; - else if (this.index === this._.firstIndex + this._.array.length - 1) this._.lastNode = this; - if (other.index === this._.firstIndex) this._.firstNode = other; - else if (other.index === this._.firstIndex + this._.array.length - 1) this._.lastNode = other; - }; - - /** - * Return value of this ViewSequence node. - * - * @method get - * @return {Object} value of thiss - */ - ViewSequence.prototype.get = function get() { - return this._.getValue(this.index); - }; - - /** - * Call getSize() on the contained View. - * - * @method getSize - * @return {Array.Number} [width, height] - */ - ViewSequence.prototype.getSize = function getSize() { - var target = this.get(); - return target ? target.getSize() : null; - }; - - /** - * Generate a render spec from the contents of this component. - * Specifically, this will render the value at the current index. - * @private - * @method render - * @return {number} Render spec for this component - */ - ViewSequence.prototype.render = function render() { - var target = this.get(); - return target ? target.render.apply(target, arguments) : null; - }; - - module.exports = ViewSequence; -}); - -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. - * - * Owner: mark@famo.us - * @license MPL 2.0 - * @copyright Famous Industries, Inc. 2014 - */ - -define('famous/math/Utilities',['require','exports','module'],function(require, exports, module) { - /** - * A few static methods. - * - * @class Utilities - * @static - */ - var Utilities = {}; - - /** - * Constrain input to range. - * - * @method clamp - * @param {Number} value input - * @param {Array.Number} range [min, max] - * @static - */ - Utilities.clamp = function clamp(value, range) { - return Math.max(Math.min(value, range[1]), range[0]); - }; - - /** - * Euclidean length of numerical array. - * - * @method length - * @param {Array.Number} array array of numbers - * @static - */ - Utilities.length = function length(array) { - var distanceSquared = 0; - for (var i = 0; i < array.length; i++) { - distanceSquared += array[i] * array[i]; - } - return Math.sqrt(distanceSquared); - }; - - module.exports = Utilities; -}); - -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. - * - * Owner: mark@famo.us - * @license MPL 2.0 - * @copyright Famous Industries, Inc. 2014 - */ - -define('famous/inputs/GenericSync',['require','exports','module','famous/core/EventHandler'],function(require, exports, module) { - var EventHandler = require('famous/core/EventHandler'); - - /** - * Combines multiple types of sync classes (e.g. mouse, touch, - * scrolling) into one standardized interface for inclusion in widgets. - * - * Sync classes are first registered with a key, and then can be accessed - * globally by key. - * - * Emits 'start', 'update' and 'end' events as a union of the sync class - * providers. - * - * @class GenericSync - * @constructor - * @param syncs {Object|Array} object with fields {sync key : sync options} - * or an array of registered sync keys - * @param [options] {Object|Array} options object to set on all syncs - */ - function GenericSync(syncs, options) { - this._eventInput = new EventHandler(); - this._eventOutput = new EventHandler(); - - EventHandler.setInputHandler(this, this._eventInput); - EventHandler.setOutputHandler(this, this._eventOutput); - - this._syncs = {}; - if (syncs) this.addSync(syncs); - if (options) this.setOptions(options); - } - - GenericSync.DIRECTION_X = 0; - GenericSync.DIRECTION_Y = 1; - GenericSync.DIRECTION_Z = 2; - - // Global registry of sync classes. Append only. - var registry = {}; - - /** - * Register a global sync class with an identifying key - * - * @static - * @method register - * - * @param syncObject {Object} an object of {sync key : sync options} fields - */ - GenericSync.register = function register(syncObject) { - for (var key in syncObject){ - if (registry[key]){ - if (registry[key] === syncObject[key]) return; // redundant registration - else throw new Error('this key is registered to a different sync class'); - } - else registry[key] = syncObject[key]; - } - }; - - /** - * Helper to set options on all sync instances - * - * @method setOptions - * @param options {Object} options object - */ - GenericSync.prototype.setOptions = function(options) { - for (var key in this._syncs){ - this._syncs[key].setOptions(options); - } - }; - - /** - * Pipe events to a sync class - * - * @method pipeSync - * @param key {String} identifier for sync class - */ - GenericSync.prototype.pipeSync = function pipeToSync(key) { - var sync = this._syncs[key]; - this._eventInput.pipe(sync); - sync.pipe(this._eventOutput); - }; - - /** - * Unpipe events from a sync class - * - * @method unpipeSync - * @param key {String} identifier for sync class - */ - GenericSync.prototype.unpipeSync = function unpipeFromSync(key) { - var sync = this._syncs[key]; - this._eventInput.unpipe(sync); - sync.unpipe(this._eventOutput); - }; - - function _addSingleSync(key, options) { - if (!registry[key]) return; - this._syncs[key] = new (registry[key])(options); - this.pipeSync(key); - } - - /** - * Add a sync class to from the registered classes - * - * @method addSync - * @param syncs {Object|Array.String} an array of registered sync keys - * or an object with fields {sync key : sync options} - */ - GenericSync.prototype.addSync = function addSync(syncs) { - if (syncs instanceof Array) - for (var i = 0; i < syncs.length; i++) - _addSingleSync.call(this, syncs[i]); - else if (syncs instanceof Object) - for (var key in syncs) - _addSingleSync.call(this, key, syncs[key]); - }; - - module.exports = GenericSync; -}); - -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. - * - * Owner: mark@famo.us - * @license MPL 2.0 - * @copyright Famous Industries, Inc. 2014 - */ - -define('famous/inputs/MouseSync',['require','exports','module','famous/core/EventHandler'],function(require, exports, module) { - var EventHandler = require('famous/core/EventHandler'); - - /** - * Handles piped in mouse drag events. Outputs an object with two - * properties, position and velocity. - * Emits 'start', 'update' and 'end' events with DOM event passthroughs, - * with position, velocity, and a delta key. - * - * @class MouseSync - * @constructor - * - * @param [options] {Object} default options overrides - * @param [options.direction] {Number} read from a particular axis - * @param [options.rails] {Boolean} read from axis with greatest differential - * @param [options.propogate] {Boolean} add listened to document on mouseleave - */ - function MouseSync(options) { - this.options = Object.create(MouseSync.DEFAULT_OPTIONS); - if (options) this.setOptions(options); - - this._eventInput = new EventHandler(); - this._eventOutput = new EventHandler(); - - EventHandler.setInputHandler(this, this._eventInput); - EventHandler.setOutputHandler(this, this._eventOutput); - - this._eventInput.on('mousedown', _handleStart.bind(this)); - this._eventInput.on('mousemove', _handleMove.bind(this)); - this._eventInput.on('mouseup', _handleEnd.bind(this)); - - if (this.options.propogate) this._eventInput.on('mouseleave', _handleLeave.bind(this)); - else this._eventInput.on('mouseleave', _handleEnd.bind(this)); - - this._payload = { - delta : null, - position : null, - velocity : null, - clientX : 0, - clientY : 0, - offsetX : 0, - offsetY : 0 - }; - - this._position = null; // to be deprecated - this._prevCoord = undefined; - this._prevTime = undefined; - this._down = false; - this._moved = false; - } - - MouseSync.DEFAULT_OPTIONS = { - direction: undefined, - rails: false, - scale: 1, - propogate: true // events piped to document on mouseleave - }; - - MouseSync.DIRECTION_X = 0; - MouseSync.DIRECTION_Y = 1; - - var MINIMUM_TICK_TIME = 8; - - var _now = Date.now; - - function _handleStart(event) { - var delta; - var velocity; - event.preventDefault(); // prevent drag - - var x = event.clientX; - var y = event.clientY; - - this._prevCoord = [x, y]; - this._prevTime = _now(); - this._down = true; - this._move = false; - - if (this.options.direction !== undefined){ - this._position = 0; - delta = 0; - velocity = 0; - } - else { - this._position = [0, 0]; - delta = [0, 0]; - velocity = [0, 0]; - } - - var payload = this._payload; - payload.delta = delta; - payload.position = this._position; - payload.velocity = velocity; - payload.clientX = x; - payload.clientY = y; - payload.offsetX = event.offsetX; - payload.offsetY = event.offsetY; - - this._eventOutput.emit('start', payload); - } - - function _handleMove(event) { - if (!this._prevCoord) return; - - var prevCoord = this._prevCoord; - var prevTime = this._prevTime; - - var x = event.clientX; - var y = event.clientY; - - var currTime = _now(); - - var diffX = x - prevCoord[0]; - var diffY = y - prevCoord[1]; - - if (this.options.rails) { - if (Math.abs(diffX) > Math.abs(diffY)) diffY = 0; - else diffX = 0; - } - - var diffTime = Math.max(currTime - prevTime, MINIMUM_TICK_TIME); // minimum tick time - - var velX = diffX / diffTime; - var velY = diffY / diffTime; - - var scale = this.options.scale; - var nextVel; - var nextDelta; - - if (this.options.direction === MouseSync.DIRECTION_X) { - nextDelta = scale * diffX; - nextVel = scale * velX; - this._position += nextDelta; - } - else if (this.options.direction === MouseSync.DIRECTION_Y) { - nextDelta = scale * diffY; - nextVel = scale * velY; - this._position += nextDelta; - } - else { - nextDelta = [scale * diffX, scale * diffY]; - nextVel = [scale * velX, scale * velY]; - this._position[0] += nextDelta[0]; - this._position[1] += nextDelta[1]; - } - - var payload = this._payload; - payload.delta = nextDelta; - payload.position = this._position; - payload.velocity = nextVel; - payload.clientX = x; - payload.clientY = y; - payload.offsetX = event.offsetX; - payload.offsetY = event.offsetY; - - this._eventOutput.emit('update', payload); - - this._prevCoord = [x, y]; - this._prevTime = currTime; - this._move = true; - } - - function _handleEnd(event) { - if (!this._down) return; - - this._eventOutput.emit('end', this._payload); - this._prevCoord = undefined; - this._prevTime = undefined; - this._down = false; - this._move = false; - } - - function _handleLeave(event) { - if (!this._down || !this._move) return; - - var boundMove = _handleMove.bind(this); - var boundEnd = function(event) { - _handleEnd.call(this, event); - document.removeEventListener('mousemove', boundMove); - document.removeEventListener('mouseup', boundEnd); - }.bind(this, event); - - document.addEventListener('mousemove', boundMove); - document.addEventListener('mouseup', boundEnd); - } - - /** - * Return entire options dictionary, including defaults. - * - * @method getOptions - * @return {Object} configuration options - */ - MouseSync.prototype.getOptions = function getOptions() { - return this.options; - }; - - /** - * Set internal options, overriding any default options - * - * @method setOptions - * - * @param [options] {Object} default options overrides - * @param [options.direction] {Number} read from a particular axis - * @param [options.rails] {Boolean} read from axis with greatest differential - * @param [options.propogate] {Boolean} add listened to document on mouseleave - */ - 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; - }; - - module.exports = MouseSync; -}); - -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. - * - * Owner: mark@famo.us - * @license MPL 2.0 - * @copyright Famous Industries, Inc. 2014 - */ - -define('famous/inputs/TouchTracker',['require','exports','module','famous/core/EventHandler'],function(require, exports, module) { - var EventHandler = require('famous/core/EventHandler'); - - var _now = Date.now; - - function _timestampTouch(touch, event, history) { - return { - x: touch.clientX, - y: touch.clientY, - identifier : touch.identifier, - origin: event.origin, - timestamp: _now(), - count: event.touches.length, - history: history - }; - } - - function _handleStart(event) { - for (var i = 0; i < event.changedTouches.length; i++) { - var touch = event.changedTouches[i]; - var data = _timestampTouch(touch, event, null); - this.eventOutput.emit('trackstart', data); - if (!this.selective && !this.touchHistory[touch.identifier]) this.track(data); - } - } - - function _handleMove(event) { - for (var i = 0; i < event.changedTouches.length; i++) { - var touch = event.changedTouches[i]; - var history = this.touchHistory[touch.identifier]; - if (history) { - var data = _timestampTouch(touch, event, history); - this.touchHistory[touch.identifier].push(data); - this.eventOutput.emit('trackmove', data); - } - } - } - - function _handleEnd(event) { - for (var i = 0; i < event.changedTouches.length; i++) { - var touch = event.changedTouches[i]; - var history = this.touchHistory[touch.identifier]; - if (history) { - var data = _timestampTouch(touch, event, history); - this.eventOutput.emit('trackend', data); - delete this.touchHistory[touch.identifier]; - } - } - } - - function _handleUnpipe() { - for (var i in this.touchHistory) { - var history = this.touchHistory[i]; - this.eventOutput.emit('trackend', { - touch: history[history.length - 1].touch, - timestamp: Date.now(), - count: 0, - history: history - }); - delete this.touchHistory[i]; - } - } - - /** - * Helper to TouchSync – tracks piped in touch events, organizes touch - * events by ID, and emits track events back to TouchSync. - * Emits 'trackstart', 'trackmove', and 'trackend' events upstream. - * - * @class TouchTracker - * @constructor - * @param {Boolean} selective if false, save state for each touch. - */ - function TouchTracker(selective) { - this.selective = selective; - this.touchHistory = {}; - - this.eventInput = new EventHandler(); - this.eventOutput = new EventHandler(); - - EventHandler.setInputHandler(this, this.eventInput); - EventHandler.setOutputHandler(this, this.eventOutput); - - this.eventInput.on('touchstart', _handleStart.bind(this)); - this.eventInput.on('touchmove', _handleMove.bind(this)); - this.eventInput.on('touchend', _handleEnd.bind(this)); - this.eventInput.on('touchcancel', _handleEnd.bind(this)); - this.eventInput.on('unpipe', _handleUnpipe.bind(this)); - } - - /** - * Record touch data, if selective is false. - * @private - * @method track - * @param {Object} data touch data - */ - TouchTracker.prototype.track = function track(data) { - this.touchHistory[data.identifier] = [data]; - }; - - module.exports = TouchTracker; -}); - -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. - * - * Owner: mark@famo.us - * @license MPL 2.0 - * @copyright Famous Industries, Inc. 2014 - */ - -define('famous/inputs/TouchSync',['require','exports','module','./TouchTracker','famous/core/EventHandler'],function(require, exports, module) { - var TouchTracker = require('./TouchTracker'); - var EventHandler = require('famous/core/EventHandler'); - - /** - * Handles piped in touch events. Emits 'start', 'update', and 'events' - * events with position, velocity, acceleration, and touch id. - * Useful for dealing with inputs on touch devices. - * - * - * @class TouchSync - * @constructor - * - * @param [options] {Object} default options overrides - * @param [options.direction] {Number} read from a particular axis - * @param [options.rails] {Boolean} read from axis with greatest differential - * @param [options.scale] {Number} constant factor to scale velocity output - */ - function TouchSync(options) { - this.options = Object.create(TouchSync.DEFAULT_OPTIONS); - if (options) this.setOptions(options); - - this._eventOutput = new EventHandler(); - this._touchTracker = new TouchTracker(); - - EventHandler.setOutputHandler(this, this._eventOutput); - EventHandler.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)); - - this._payload = { - delta : null, - position : null, - velocity : null, - clientX : undefined, - clientY : undefined, - count : 0, - touch : undefined - }; - - this._position = null; // to be deprecated - } - - TouchSync.DEFAULT_OPTIONS = { - direction: undefined, - rails: false, - scale: 1 - }; - - TouchSync.DIRECTION_X = 0; - TouchSync.DIRECTION_Y = 1; - - var MINIMUM_TICK_TIME = 8; - - // handle 'trackstart' - function _handleStart(data) { - var velocity; - var delta; - if (this.options.direction !== undefined){ - this._position = 0; - velocity = 0; - delta = 0; - } - else { - this._position = [0, 0]; - velocity = [0, 0]; - delta = [0, 0]; - } - - var payload = this._payload; - payload.delta = delta; - payload.position = this._position; - payload.velocity = velocity; - payload.clientX = data.x; - payload.clientY = data.y; - payload.count = data.count; - payload.touch = data.identifier; - - this._eventOutput.emit('start', payload); - } - - // handle 'trackmove' - function _handleMove(data) { - var history = data.history; - - var currHistory = history[history.length - 1]; - var prevHistory = history[history.length - 2]; - - var prevTime = prevHistory.timestamp; - var currTime = currHistory.timestamp; - - var diffX = currHistory.x - prevHistory.x; - var diffY = currHistory.y - prevHistory.y; - - if (this.options.rails) { - if (Math.abs(diffX) > Math.abs(diffY)) diffY = 0; - else diffX = 0; - } - - var diffTime = Math.max(currTime - prevTime, MINIMUM_TICK_TIME); - - var velX = diffX / diffTime; - var velY = diffY / diffTime; - - var scale = this.options.scale; - var nextVel; - var nextDelta; - - if (this.options.direction === TouchSync.DIRECTION_X) { - nextDelta = scale * diffX; - nextVel = scale * velX; - this._position += nextDelta; - } - else if (this.options.direction === TouchSync.DIRECTION_Y) { - nextDelta = scale * diffY; - nextVel = scale * velY; - this._position += nextDelta; - } - else { - nextDelta = [scale * diffX, scale * diffY]; - nextVel = [scale * velX, scale * velY]; - this._position[0] += nextDelta[0]; - this._position[1] += nextDelta[1]; - } - - var payload = this._payload; - payload.delta = nextDelta; - payload.velocity = nextVel; - payload.position = this._position; - payload.clientX = data.x; - payload.clientY = data.y; - payload.count = data.count; - payload.touch = data.identifier; - - this._eventOutput.emit('update', payload); - } - - // handle 'trackend' - function _handleEnd(data) { - this._payload.count = data.count; - this._eventOutput.emit('end', this._payload); - } - - /** - * Set internal options, overriding any default options - * - * @method setOptions - * - * @param [options] {Object} default options overrides - * @param [options.direction] {Number} read from a particular axis - * @param [options.rails] {Boolean} read from axis with greatest differential - * @param [options.scale] {Number} constant factor to scale velocity output - */ - 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 entire options dictionary, including defaults. - * - * @method getOptions - * @return {Object} configuration options - */ - TouchSync.prototype.getOptions = function getOptions() { - return this.options; - }; - - module.exports = TouchSync; -}); - -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. - * - * Owner: david@famo.us - * @license MPL 2.0 - * @copyright Famous Industries, Inc. 2014 - */ - -define('famous/modifiers/Draggable',['require','exports','module','famous/core/Transform','famous/transitions/Transitionable','famous/core/EventHandler','famous/math/Utilities','famous/inputs/GenericSync','famous/inputs/MouseSync','famous/inputs/TouchSync'],function(require, exports, module) { - var Transform = require('famous/core/Transform'); - var Transitionable = require('famous/transitions/Transitionable'); - var EventHandler = require('famous/core/EventHandler'); - var Utilities = require('famous/math/Utilities'); - - var GenericSync = require('famous/inputs/GenericSync'); - var MouseSync = require('famous/inputs/MouseSync'); - var TouchSync = require('famous/inputs/TouchSync'); - GenericSync.register({'mouse': MouseSync, 'touch': TouchSync}); - - /** - * Makes added render nodes responsive to drag beahvior. - * Emits events 'start', 'update', 'end'. - * @class Draggable - * @constructor - * @param {Object} [options] options configuration object. - * @param {Number} [options.snapX] grid width for snapping during drag - * @param {Number} [options.snapY] grid height for snapping during drag - * @param {Array.Number} [options.xRange] maxmimum [negative, positive] x displacement from start of drag - * @param {Array.Number} [options.yRange] maxmimum [negative, positive] y displacement from start of drag - * @param {Number} [options.scale] one pixel of input motion translates to this many pixels of output drag motion - * @param {Number} [options.projection] User should set to Draggable._direction.x or - * Draggable._direction.y to constrain to one axis. - * - */ - function Draggable(options) { - this.options = Object.create(Draggable.DEFAULT_OPTIONS); - if (options) this.setOptions(options); - - this._positionState = new Transitionable([0,0]); - this._differential = [0,0]; - this._active = true; - - this.sync = new GenericSync(['mouse', 'touch'], {scale : this.options.scale}); - this.eventOutput = new EventHandler(); - EventHandler.setInputHandler(this, this.sync); - EventHandler.setOutputHandler(this, this.eventOutput); - - _bindEvents.call(this); - } - - //binary representation of directions for bitwise operations - var _direction = { - x : 0x01, //001 - y : 0x02 //010 - }; - - Draggable.DIRECTION_X = _direction.x; - Draggable.DIRECTION_Y = _direction.y; - - var _clamp = Utilities.clamp; - - Draggable.DEFAULT_OPTIONS = { - projection : _direction.x | _direction.y, - scale : 1, - xRange : null, - yRange : null, - snapX : 0, - snapY : 0, - transition : {duration : 0} - }; - - function _mapDifferential(differential) { - var opts = this.options; - var projection = opts.projection; - var snapX = opts.snapX; - var snapY = opts.snapY; - - //axes - var tx = (projection & _direction.x) ? differential[0] : 0; - var ty = (projection & _direction.y) ? differential[1] : 0; - - //snapping - if (snapX > 0) tx -= tx % snapX; - if (snapY > 0) ty -= ty % snapY; - - return [tx, ty]; - } - - function _handleStart() { - if (!this._active) return; - if (this._positionState.isActive()) this._positionState.halt(); - this.eventOutput.emit('start', {position : this.getPosition()}); - } - - function _handleMove(event) { - if (!this._active) return; - - var options = this.options; - this._differential = event.position; - var newDifferential = _mapDifferential.call(this, this._differential); - - //buffer the differential if snapping is set - this._differential[0] -= newDifferential[0]; - this._differential[1] -= newDifferential[1]; - - var pos = this.getPosition(); - - //modify position, retain reference - pos[0] += newDifferential[0]; - pos[1] += newDifferential[1]; - - //handle bounding box - if (options.xRange){ - var xRange = [options.xRange[0] + 0.5 * options.snapX, options.xRange[1] - 0.5 * options.snapX]; - pos[0] = _clamp(pos[0], xRange); - } - - if (options.yRange){ - var yRange = [options.yRange[0] + 0.5 * options.snapY, options.yRange[1] - 0.5 * options.snapY]; - pos[1] = _clamp(pos[1], yRange); - } - - this.eventOutput.emit('update', {position : pos}); - } - - function _handleEnd() { - if (!this._active) return; - this.eventOutput.emit('end', {position : this.getPosition()}); - } - - function _bindEvents() { - this.sync.on('start', _handleStart.bind(this)); - this.sync.on('update', _handleMove.bind(this)); - this.sync.on('end', _handleEnd.bind(this)); - } - - /** - * Set internal options, overriding any default options - * - * @method setOptions - * - * @param {Object} [options] overrides of default options. See constructor. - */ - Draggable.prototype.setOptions = function setOptions(options) { - var currentOptions = this.options; - if (options.projection !== undefined) { - var proj = options.projection; - this.options.projection = 0; - ['x', 'y'].forEach(function(val) { - if (proj.indexOf(val) !== -1) currentOptions.projection |= _direction[val]; - }); - } - if (options.scale !== undefined) { - currentOptions.scale = options.scale; - this.sync.setOptions({ - scale: options.scale - }); - } - if (options.xRange !== undefined) currentOptions.xRange = options.xRange; - if (options.yRange !== undefined) currentOptions.yRange = options.yRange; - if (options.snapX !== undefined) currentOptions.snapX = options.snapX; - if (options.snapY !== undefined) currentOptions.snapY = options.snapY; - }; - - /** - * Get current delta in position from where this draggable started. - * - * @method getPosition - * - * @return {array} [x, y] position delta from start. - */ - Draggable.prototype.getPosition = function getPosition() { - return this._positionState.get(); - }; - - /** - * Transition the element to the desired relative position via provided transition. - * For example, calling this with [0,0] will not change the position. - * Callback will be executed on completion. - * - * @method setRelativePosition - * - * @param {array} position end state to which we interpolate - * @param {transition} transition transition object specifying how object moves to new position - * @param {function} callback zero-argument function to call on observed completion - */ - Draggable.prototype.setRelativePosition = function setRelativePosition(position, transition, callback) { - var currPos = this.getPosition(); - var relativePosition = [currPos[0] + position[0], currPos[1] + position[1]]; - this.setPosition(relativePosition, transition, callback); - }; - - /** - * Transition the element to the desired absolute position via provided transition. - * Callback will be executed on completion. - * - * @method setPosition - * - * @param {array} position end state to which we interpolate - * @param {transition} transition transition object specifying how object moves to new position - * @param {function} callback zero-argument function to call on observed completion - */ - Draggable.prototype.setPosition = function setPosition(position, transition, callback) { - if (this._positionState.isActive()) this._positionState.halt(); - this._positionState.set(position, transition, callback); - }; - - /** - * Set this draggable to respond to user input. - * - * @method activate - * - */ - Draggable.prototype.activate = function activate() { - this._active = true; - }; - - /** - * Set this draggable to ignore user input. - * - * @method deactivate - * - */ - Draggable.prototype.deactivate = function deactivate() { - this._active = false; - }; - - /** - * Switch the input response stage between active and inactive. - * - * @method toggle - * - */ - Draggable.prototype.toggle = function toggle() { - this._active = !this._active; - }; - - /** - * Return render spec for this Modifier, applying to the provided - * target component. This is similar to render() for Surfaces. - * - * @private - * @method modify - * - * @param {Object} target (already rendered) render spec to - * which to apply the transform. - * @return {Object} render spec for this Modifier, including the - * provided target - */ - Draggable.prototype.modify = function modify(target) { - var pos = this.getPosition(); - return { - transform: Transform.translate(pos[0], pos[1]), - target: target - }; - }; - - module.exports = Draggable; -}); - -define('famous/modifiers/Fader',['require','exports','module','famous/transitions/Transitionable','famous/core/OptionsManager'],function(require, exports, module) { - var Transitionable = require('famous/transitions/Transitionable'); - var OptionsManager = require('famous/core/OptionsManager'); - - /** - * Modifier that allows you to fade the opacity of affected renderables in and out. - * @class Fader - * @constructor - * @param {Object} [options] options configuration object. - * @param {Boolean} [options.cull=false] Stops returning affected renderables up the tree when they're fully faded when true. - * @param {Transition} [options.transition=true] The main transition for showing and hiding. - * @param {Transition} [options.pulseInTransition=true] Controls the transition to a pulsed state when the Fader instance's pulse - * method is called. - * @param {Transition} [options.pulseOutTransition=true]Controls the transition back from a pulsed state when the Fader instance's pulse - * method is called. - * - */ - function Fader(options, startState) { - this.options = Object.create(Fader.DEFAULT_OPTIONS); - this._optionsManager = new OptionsManager(this.options); - - if (options) this.setOptions(options); - - if (!startState) startState = 0; - this.transitionHelper = new Transitionable(startState); - } - - Fader.DEFAULT_OPTIONS = { - cull: false, - transition: true, - pulseInTransition: true, - pulseOutTransition: true - }; - - /** - * Set internal options, overriding any default options - * - * @method setOptions - * - * @param {Object} [options] overrides of default options. See constructor. - */ - Fader.prototype.setOptions = function setOptions(options) { - return this._optionsManager.setOptions(options); - }; - - /** - * Fully displays the Fader instance's associated renderables. - * - * @method show - * @param {Transition} [transition] The transition that coordinates setting to the new state. - * @param {Function} [callback] A callback that executes once you've transitioned to the fully shown state. - */ - Fader.prototype.show = function show(transition, callback) { - transition = transition || this.options.transition; - this.set(1, transition, callback); - }; - - /** - * Fully fades the Fader instance's associated renderables. - * - * @method hide - * @param {Transition} [transition] The transition that coordinates setting to the new state. - * @param {Function} [callback] A callback that executes once you've transitioned to the fully faded state. - */ - Fader.prototype.hide = function hide(transition, callback) { - transition = transition || this.options.transition; - this.set(0, transition, callback); - }; - - /** - * Manually sets the opacity state of the fader to the passed-in one. Executes with an optional - * transition and callback. - * - * @method set - * @param {Number} state A number from zero to one: the amount of opacity you want to set to. - * @param {Transition} [transition] The transition that coordinates setting to the new state. - * @param {Function} [callback] A callback that executes once you've finished executing the pulse. - */ - Fader.prototype.set = function set(state, transition, callback) { - this.halt(); - this.transitionHelper.set(state, transition, callback); - }; - - /** - * Halt the transition - * - * @method halt - */ - Fader.prototype.halt = function halt() { - this.transitionHelper.halt(); - }; - - /** - * Tells you if your Fader instance is above its visibility threshold. - * - * @method isVisible - * @return {Boolean} Whether or not your Fader instance is visible. - */ - Fader.prototype.isVisible = function isVisible() { - return (this.transitionHelper.get() > 0); - }; - - /** - * Return render spec for this Modifier, applying to the provided - * target component. This is similar to render() for Surfaces. - * - * @private - * @method modify - * - * @param {Object} target (already rendered) render spec to - * which to apply the transform. - * @return {Object} render spec for this Modifier, including the - * provided target - */ - Fader.prototype.modify = function modify(target) { - var currOpacity = this.transitionHelper.get(); - if (this.options.cull && !currOpacity) return undefined; - else return {opacity: currOpacity, target: target}; - }; - - module.exports = Fader; -}); - -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. - * - * Owner: david@famo.us - * @license MPL 2.0 - * @copyright Famous Industries, Inc. 2014 - */ - -define('famous/modifiers/ModifierChain',['require','exports','module'],function(require, exports, module) { - - /** - * A class to add and remove a chain of modifiers - * at a single point in the render tree - * - * @class ModifierChain - * @constructor - */ - function ModifierChain() { - this._chain = []; - if (arguments.length) this.addModifier.apply(this, arguments); - } - - /** - * Add a modifier, or comma separated modifiers, to the modifier chain. - * - * @method addModifier - * - * @param {...Modifier*} varargs args list of Modifiers - */ - ModifierChain.prototype.addModifier = function addModifier(varargs) { - Array.prototype.push.apply(this._chain, arguments); - }; - - /** - * Remove a modifier from the modifier chain. - * - * @method removeModifier - * - * @param {Modifier} modifier - */ - ModifierChain.prototype.removeModifier = function removeModifier(modifier) { - var index = this._chain.indexOf(modifier); - if (index < 0) return; - this._chain.splice(index, 1); - }; - - /** - * Return render spec for this Modifier, applying to the provided - * target component. This is similar to render() for Surfaces. - * - * @private - * @method modify - * - * @param {Object} input (already rendered) render spec to - * which to apply the transform. - * @return {Object} render spec for this Modifier, including the - * provided target - */ - ModifierChain.prototype.modify = function modify(input) { - var chain = this._chain; - var result = input; - for (var i = 0; i < chain.length; i++) { - result = chain[i].modify(result); - } - return result; - }; - - module.exports = ModifierChain; -}); - -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. - * - * Owner: mark@famo.us - * @license MPL 2.0 - * @copyright Famous Industries, Inc. 2014 - */ - -define('famous/modifiers/StateModifier',['require','exports','module','famous/core/Modifier','famous/core/Transform','famous/transitions/Transitionable','famous/transitions/TransitionableTransform'],function(require, exports, module) { - var Modifier = require('famous/core/Modifier'); - var Transform = require('famous/core/Transform'); - var Transitionable = require('famous/transitions/Transitionable'); - var TransitionableTransform = require('famous/transitions/TransitionableTransform'); - - /** - * A collection of visual changes to be - * applied to another renderable component, strongly coupled with the state that defines - * those changes. This collection includes a - * transform matrix, an opacity constant, a size, an origin specifier, and an alignment specifier. - * StateModifier objects can be added to any RenderNode or object - * capable of displaying renderables. The StateModifier's children and descendants - * are transformed by the amounts specified in the modifier's properties. - * - * @class StateModifier - * @constructor - * @param {Object} [options] overrides of default options - * @param {Transform} [options.transform] affine transformation matrix - * @param {Number} [options.opacity] - * @param {Array.Number} [options.origin] origin adjustment - * @param {Array.Number} [options.align] align adjustment - * @param {Array.Number} [options.size] size to apply to descendants - */ - function StateModifier(options) { - this._transformState = new TransitionableTransform(Transform.identity); - this._opacityState = new Transitionable(1); - this._originState = new Transitionable([0, 0]); - this._alignState = new Transitionable([0, 0]); - this._sizeState = new Transitionable([0, 0]); - - this._modifier = new Modifier({ - transform: this._transformState, - opacity: this._opacityState, - origin: null, - align: null, - size: null - }); - - this._hasOrigin = false; - this._hasAlign = false; - this._hasSize = false; - - if (options) { - if (options.transform) this.setTransform(options.transform); - if (options.opacity !== undefined) this.setOpacity(options.opacity); - if (options.origin) this.setOrigin(options.origin); - if (options.align) this.setAlign(options.align); - if (options.size) this.setSize(options.size); - } - } - - /** - * Set the transform matrix of this modifier, either statically or - * through a provided Transitionable. - * - * @method setTransform - * - * @param {Transform} transform Transform to transition to. - * @param {Transitionable} [transition] Valid transitionable object - * @param {Function} [callback] callback to call after transition completes - * @return {StateModifier} this - */ - StateModifier.prototype.setTransform = function setTransform(transform, transition, callback) { - this._transformState.set(transform, transition, callback); - return this; - }; - - /** - * Set the opacity of this modifier, either statically or - * through a provided Transitionable. - * - * @method setOpacity - * - * @param {Number} opacity Opacity value to transition to. - * @param {Transitionable} transition Valid transitionable object - * @param {Function} callback callback to call after transition completes - * @return {StateModifier} this - */ - StateModifier.prototype.setOpacity = function setOpacity(opacity, transition, callback) { - this._opacityState.set(opacity, transition, callback); - return this; - }; - - /** - * Set the origin of this modifier, either statically or - * through a provided Transitionable. - * - * @method setOrigin - * - * @param {Array.Number} origin 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.setOrigin = function setOrigin(origin, transition, callback) { - if (origin === null) { - if (this._hasOrigin) { - this._modifier.originFrom(null); - this._hasOrigin = false; - } - return this; - } - else if (!this._hasOrigin) { - this._hasOrigin = true; - this._modifier.originFrom(this._originState); - } - this._originState.set(origin, transition, callback); - return this; - }; - - /** - * Set the alignment of this modifier, either statically or - * through a provided Transitionable. - * - * @method setAlign - * - * @param {Array.Number} align 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.setAlign = function setOrigin(align, transition, callback) { - if (align === null) { - if (this._hasAlign) { - this._modifier.alignFrom(null); - this._hasAlign = false; - } - return this; - } - else if (!this._hasAlign) { - this._hasAlign = true; - this._modifier.alignFrom(this._alignState); - } - this._alignState.set(align, transition, callback); - return this; - }; - - /** - * Set the size of this modifier, either statically or - * through a provided Transitionable. - * - * @method setSize - * - * @param {Array.Number} size 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.setSize = function setSize(size, transition, callback) { - if (size === null) { - if (this._hasSize) { - this._modifier.sizeFrom(null); - this._hasSize = false; - } - return this; - } - else if (!this._hasSize) { - this._hasSize = true; - this._modifier.sizeFrom(this._sizeState); - } - this._sizeState.set(size, transition, callback); - return this; - }; - - /** - * Stop the transition. - * - * @method halt - */ - StateModifier.prototype.halt = function halt() { - this._transformState.halt(); - this._opacityState.halt(); - this._originState.halt(); - this._alignState.halt(); - this._sizeState.halt(); - }; - - /** - * Get the current state of the transform matrix component. - * - * @method getTransform - * @return {Object} transform provider object - */ - StateModifier.prototype.getTransform = function getTransform() { - return this._transformState.get(); - }; - - /** - * Get the destination state of the transform component. - * - * @method getFinalTransform - * @return {Transform} transform matrix - */ - StateModifier.prototype.getFinalTransform = function getFinalTransform() { - return this._transformState.getFinal(); - }; - - /** - * Get the current state of the opacity component. - * - * @method getOpacity - * @return {Object} opacity provider object - */ - StateModifier.prototype.getOpacity = function getOpacity() { - return this._opacityState.get(); - }; - - /** - * Get the current state of the origin component. - * - * @method getOrigin - * @return {Object} origin provider object - */ - StateModifier.prototype.getOrigin = function getOrigin() { - return this._hasOrigin ? this._originState.get() : null; - }; - - /** - * Get the current state of the align component. - * - * @method getAlign - * @return {Object} align provider object - */ - StateModifier.prototype.getAlign = function getAlign() { - return this._hasAlign ? this._alignState.get() : null; - }; - - /** - * Get the current state of the size component. - * - * @method getSize - * @return {Object} size provider object - */ - StateModifier.prototype.getSize = function getSize() { - return this._hasSize ? this._sizeState.get() : null; - }; - - /** - * Return render spec for this StateModifier, applying to the provided - * target component. This is similar to render() for Surfaces. - * - * @private - * @method modify - * - * @param {Object} target (already rendered) render spec to - * which to apply the transform. - * @return {Object} render spec for this StateModifier, including the - * provided target - */ - StateModifier.prototype.modify = function modify(target) { - return this._modifier.modify(target); - }; - - module.exports = StateModifier; -}); - -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. - * - * Owner: david@famo.us - * @license MPL 2.0 - * @copyright Famous Industries, Inc. 2014 - */ - -define('famous/math/Vector',['require','exports','module'],function(require, exports, module) { - - /** - * Three-element floating point vector. - * - * @class Vector - * @constructor - * - * @param {number} x x element value - * @param {number} y y element value - * @param {number} z z element value - */ - function Vector(x,y,z) { - if (arguments.length === 1) this.set(x); - else { - this.x = x || 0; - this.y = y || 0; - this.z = z || 0; - } - return this; - } - - var _register = new Vector(0,0,0); - - /** - * Add this element-wise to another Vector, element-wise. - * Note: This sets the internal result register, so other references to that vector will change. - * - * @method add - * @param {Vector} v addend - * @return {Vector} vector sum - */ - Vector.prototype.add = function add(v) { - return _setXYZ.call(_register, - this.x + v.x, - this.y + v.y, - this.z + v.z - ); - }; - - /** - * Subtract another vector from this vector, element-wise. - * Note: This sets the internal result register, so other references to that vector will change. - * - * @method sub - * @param {Vector} v subtrahend - * @return {Vector} vector difference - */ - Vector.prototype.sub = function sub(v) { - return _setXYZ.call(_register, - this.x - v.x, - this.y - v.y, - this.z - v.z - ); - }; - - /** - * Scale Vector by floating point r. - * Note: This sets the internal result register, so other references to that vector will change. - * - * @method mult - * - * @param {number} r scalar - * @return {Vector} vector result - */ - Vector.prototype.mult = function mult(r) { - return _setXYZ.call(_register, - r * this.x, - r * this.y, - r * this.z - ); - }; - - /** - * Scale Vector by floating point 1/r. - * Note: This sets the internal result register, so other references to that vector will change. - * - * @method div - * - * @param {number} r scalar - * @return {Vector} vector result - */ - Vector.prototype.div = function div(r) { - return this.mult(1 / r); - }; - - /** - * Given another vector v, return cross product (v)x(this). - * Note: This sets the internal result register, so other references to that vector will change. - * - * @method cross - * @param {Vector} v Left Hand Vector - * @return {Vector} vector result - */ - Vector.prototype.cross = function cross(v) { - var x = this.x; - var y = this.y; - var z = this.z; - var vx = v.x; - var vy = v.y; - var vz = v.z; - - return _setXYZ.call(_register, - z * vy - y * vz, - x * vz - z * vx, - y * vx - x * vy - ); - }; - - /** - * Component-wise equality test between this and Vector v. - * @method equals - * @param {Vector} v vector to compare - * @return {boolean} - */ - Vector.prototype.equals = function equals(v) { - return (v.x === this.x && v.y === this.y && v.z === this.z); - }; - - /** - * Rotate clockwise around x-axis by theta radians. - * Note: This sets the internal result register, so other references to that vector will change. - * @method rotateX - * @param {number} theta radians - * @return {Vector} rotated vector - */ - Vector.prototype.rotateX = function rotateX(theta) { - var x = this.x; - var y = this.y; - var z = this.z; - - var cosTheta = Math.cos(theta); - var sinTheta = Math.sin(theta); - - return _setXYZ.call(_register, - x, - y * cosTheta - z * sinTheta, - y * sinTheta + z * cosTheta - ); - }; - - /** - * Rotate clockwise around y-axis by theta radians. - * Note: This sets the internal result register, so other references to that vector will change. - * @method rotateY - * @param {number} theta radians - * @return {Vector} rotated vector - */ - Vector.prototype.rotateY = function rotateY(theta) { - var x = this.x; - var y = this.y; - var z = this.z; - - var cosTheta = Math.cos(theta); - var sinTheta = Math.sin(theta); - - return _setXYZ.call(_register, - z * sinTheta + x * cosTheta, - y, - z * cosTheta - x * sinTheta - ); - }; - - /** - * Rotate clockwise around z-axis by theta radians. - * Note: This sets the internal result register, so other references to that vector will change. - * @method rotateZ - * @param {number} theta radians - * @return {Vector} rotated vector - */ - Vector.prototype.rotateZ = function rotateZ(theta) { - var x = this.x; - var y = this.y; - var z = this.z; - - var cosTheta = Math.cos(theta); - var sinTheta = Math.sin(theta); - - return _setXYZ.call(_register, - x * cosTheta - y * sinTheta, - x * sinTheta + y * cosTheta, - z - ); - }; - - /** - * Return dot product of this with a second Vector - * @method dot - * @param {Vector} v second vector - * @return {number} dot product - */ - Vector.prototype.dot = function dot(v) { - return this.x * v.x + this.y * v.y + this.z * v.z; - }; - - /** - * Return squared length of this vector - * @method normSquared - * @return {number} squared length - */ - Vector.prototype.normSquared = function normSquared() { - return this.dot(this); - }; - - /** - * Return length of this vector - * @method norm - * @return {number} length - */ - Vector.prototype.norm = function norm() { - return Math.sqrt(this.normSquared()); - }; - - /** - * Scale Vector to specified length. - * If length is less than internal tolerance, set vector to [length, 0, 0]. - * Note: This sets the internal result register, so other references to that vector will change. - * @method normalize - * - * @param {number} length target length, default 1.0 - * @return {Vector} - */ - Vector.prototype.normalize = function normalize(length) { - if (arguments.length === 0) length = 1; - var norm = this.norm(); - - if (norm > 1e-7) return _setFromVector.call(_register, this.mult(length / norm)); - else return _setXYZ.call(_register, length, 0, 0); - }; - - /** - * Make a separate copy of the Vector. - * - * @method clone - * - * @return {Vector} - */ - Vector.prototype.clone = function clone() { - return new Vector(this); - }; - - /** - * True if and only if every value is 0 (or falsy) - * - * @method isZero - * - * @return {boolean} - */ - Vector.prototype.isZero = function isZero() { - return !(this.x || this.y || this.z); - }; - - function _setXYZ(x,y,z) { - this.x = x; - this.y = y; - this.z = z; - return this; - } - - function _setFromArray(v) { - return _setXYZ.call(this,v[0],v[1],v[2] || 0); - } - - function _setFromVector(v) { - return _setXYZ.call(this, v.x, v.y, v.z); - } - - function _setFromNumber(x) { - return _setXYZ.call(this,x,0,0); - } - - /** - * Set this Vector to the values in the provided Array or Vector. - * - * @method set - * @param {object} v array, Vector, or number - * @return {Vector} this - */ - Vector.prototype.set = function set(v) { - if (v instanceof Array) return _setFromArray.call(this, v); - if (v instanceof Vector) return _setFromVector.call(this, v); - if (typeof v === 'number') return _setFromNumber.call(this, v); - }; - - Vector.prototype.setXYZ = function(x,y,z) { - return _setXYZ.apply(this, arguments); - }; - - Vector.prototype.set1D = function(x) { - return _setFromNumber.call(this, x); - }; - - /** - * Put result of last internal register calculation in specified output vector. - * - * @method put - * @param {Vector} v destination vector - * @return {Vector} destination vector - */ - - Vector.prototype.put = function put(v) { - _setFromVector.call(v, _register); - }; - - /** - * Set this vector to [0,0,0] - * - * @method clear - */ - Vector.prototype.clear = function clear() { - return _setXYZ.call(this,0,0,0); - }; - - /** - * Scale this Vector down to specified "cap" length. - * If Vector shorter than cap, or cap is Infinity, do nothing. - * Note: This sets the internal result register, so other references to that vector will change. - * - * @method cap - * @return {Vector} capped vector - */ - Vector.prototype.cap = function cap(cap) { - if (cap === Infinity) return _setFromVector.call(_register, this); - var norm = this.norm(); - if (norm > cap) return _setFromVector.call(_register, this.mult(cap / norm)); - else return _setFromVector.call(_register, this); - }; - - /** - * Return projection of this Vector onto another. - * Note: This sets the internal result register, so other references to that vector will change. - * - * @method project - * @param {Vector} n vector to project upon - * @return {Vector} projected vector - */ - Vector.prototype.project = function project(n) { - return n.mult(this.dot(n)); - }; - - /** - * Reflect this Vector across provided vector. - * Note: This sets the internal result register, so other references to that vector will change. - * - * @method reflectAcross - * @param {Vector} n vector to reflect across - * @return {Vector} reflected vector - */ - Vector.prototype.reflectAcross = function reflectAcross(n) { - n.normalize().put(n); - return _setFromVector(_register, this.sub(this.project(n).mult(2))); - }; - - /** - * Convert Vector to three-element array. - * - * @method get - * @return {array} three-element array - */ - Vector.prototype.get = function get() { - return [this.x, this.y, this.z]; - }; - - Vector.prototype.get1D = function() { - return this.x; - }; - - module.exports = Vector; - -}); - -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. - * - * Owner: david@famo.us - * @license MPL 2.0 - * @copyright Famous Industries, Inc. 2014 - */ - -define('famous/math/Matrix',['require','exports','module','./Vector'],function(require, exports, module) { - var Vector = require('./Vector'); - - /** - * A library for using a 3x3 numerical matrix, represented as a two-level array. - * - * @class Matrix - * @constructor - * - * @param {Array.Array} values array of rows - */ - function Matrix(values) { - this.values = values || - [ - [1,0,0], - [0,1,0], - [0,0,1] - ]; - - return this; - } - - var _register = new Matrix(); - var _vectorRegister = new Vector(); - - /** - * Return the values in the matrix as an array of numerical row arrays - * - * @method get - * - * @return {Array.array} matrix values as array of rows. - */ - Matrix.prototype.get = function get() { - return this.values; - }; - - /** - * Set the nested array of rows in the matrix. - * - * @method set - * - * @param {Array.array} values matrix values as array of rows. - */ - Matrix.prototype.set = function set(values) { - this.values = values; - }; - - /** - * Take this matrix as A, input vector V as a column vector, and return matrix product (A)(V). - * Note: This sets the internal vector register. Current handles to the vector register - * will see values changed. - * - * @method vectorMultiply - * - * @param {Vector} v input vector V - * @return {Vector} result of multiplication, as a handle to the internal vector register - */ - Matrix.prototype.vectorMultiply = function vectorMultiply(v) { - var M = this.get(); - var v0 = v.x; - var v1 = v.y; - var v2 = v.z; - - var M0 = M[0]; - var M1 = M[1]; - var M2 = M[2]; - - var M00 = M0[0]; - var M01 = M0[1]; - var M02 = M0[2]; - var M10 = M1[0]; - var M11 = M1[1]; - var M12 = M1[2]; - var M20 = M2[0]; - var M21 = M2[1]; - var M22 = M2[2]; - - return _vectorRegister.setXYZ( - M00*v0 + M01*v1 + M02*v2, - M10*v0 + M11*v1 + M12*v2, - M20*v0 + M21*v1 + M22*v2 - ); - }; - - /** - * Multiply the provided matrix M2 with this matrix. Result is (this) * (M2). - * Note: This sets the internal matrix register. Current handles to the register - * will see values changed. - * - * @method multiply - * - * @param {Matrix} M2 input matrix to multiply on the right - * @return {Matrix} result of multiplication, as a handle to the internal register - */ - Matrix.prototype.multiply = function multiply(M2) { - var M1 = this.get(); - var result = [[]]; - for (var i = 0; i < 3; i++) { - result[i] = []; - for (var j = 0; j < 3; j++) { - var sum = 0; - for (var k = 0; k < 3; k++) { - sum += M1[i][k] * M2[k][j]; - } - result[i][j] = sum; - } - } - return _register.set(result); - }; - - /** - * Creates a Matrix which is the transpose of this matrix. - * Note: This sets the internal matrix register. Current handles to the register - * will see values changed. - * - * @method transpose - * - * @return {Matrix} result of transpose, as a handle to the internal register - */ - Matrix.prototype.transpose = function transpose() { - var result = []; - var M = this.get(); - for (var row = 0; row < 3; row++) { - for (var col = 0; col < 3; col++) { - result[row][col] = M[col][row]; - } - } - return _register.set(result); - }; - - /** - * Clones the matrix - * - * @method clone - * @return {Matrix} New copy of the original matrix - */ - Matrix.prototype.clone = function clone() { - var values = this.get(); - var M = []; - for (var row = 0; row < 3; row++) - M[row] = values[row].slice(); - return new Matrix(M); - }; - - module.exports = Matrix; -}); - -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. - * - * Owner: david@famo.us - * @license MPL 2.0 - * @copyright Famous Industries, Inc. 2014 - */ - -define('famous/math/Quaternion',['require','exports','module','./Matrix'],function(require, exports, module) { - var Matrix = require('./Matrix'); - - /** - * @class Quaternion - * @constructor - * - * @param {Number} w - * @param {Number} x - * @param {Number} y - * @param {Number} z - */ - function Quaternion(w,x,y,z) { - if (arguments.length === 1) this.set(w); - else { - this.w = (w !== undefined) ? w : 1; //Angle - this.x = (x !== undefined) ? x : 0; //Axis.x - this.y = (y !== undefined) ? y : 0; //Axis.y - this.z = (z !== undefined) ? z : 0; //Axis.z - } - return this; - } - - var register = new Quaternion(1,0,0,0); - - /** - * Doc: TODO - * @method add - * @param {Quaternion} q - * @return {Quaternion} - */ - Quaternion.prototype.add = function add(q) { - return register.setWXYZ( - this.w + q.w, - this.x + q.x, - this.y + q.y, - this.z + q.z - ); - }; - - /* - * Docs: TODO - * - * @method sub - * @param {Quaternion} q - * @return {Quaternion} - */ - Quaternion.prototype.sub = function sub(q) { - return register.setWXYZ( - this.w - q.w, - this.x - q.x, - this.y - q.y, - this.z - q.z - ); - }; - - /** - * Doc: TODO - * - * @method scalarDivide - * @param {Number} s - * @return {Quaternion} - */ - Quaternion.prototype.scalarDivide = function scalarDivide(s) { - return this.scalarMultiply(1/s); - }; - - /* - * Docs: TODO - * - * @method scalarMultiply - * @param {Number} s - * @return {Quaternion} - */ - Quaternion.prototype.scalarMultiply = function scalarMultiply(s) { - return register.setWXYZ( - this.w * s, - this.x * s, - this.y * s, - this.z * s - ); - }; - - /* - * Docs: TODO - * - * @method multiply - * @param {Quaternion} q - * @return {Quaternion} - */ - Quaternion.prototype.multiply = function multiply(q) { - //left-handed coordinate system multiplication - var x1 = this.x; - var y1 = this.y; - var z1 = this.z; - var w1 = this.w; - var x2 = q.x; - var y2 = q.y; - var z2 = q.z; - var w2 = q.w || 0; - - return register.setWXYZ( - w1*w2 - x1*x2 - y1*y2 - z1*z2, - x1*w2 + x2*w1 + y2*z1 - y1*z2, - y1*w2 + y2*w1 + x1*z2 - x2*z1, - z1*w2 + z2*w1 + x2*y1 - x1*y2 - ); - }; - - var conj = new Quaternion(1,0,0,0); - - /* - * Docs: TODO - * - * @method rotateVector - * @param {Vector} v - * @return {Quaternion} - */ - Quaternion.prototype.rotateVector = function rotateVector(v) { - conj.set(this.conj()); - return register.set(this.multiply(v).multiply(conj)); - }; - - /* - * Docs: TODO - * - * @method inverse - * @return {Quaternion} - */ - Quaternion.prototype.inverse = function inverse() { - return register.set(this.conj().scalarDivide(this.normSquared())); - }; - - /* - * Docs: TODO - * - * @method negate - * @return {Quaternion} - */ - Quaternion.prototype.negate = function negate() { - return this.scalarMultiply(-1); - }; - - /* - * Docs: TODO - * - * @method conj - * @return {Quaternion} - */ - Quaternion.prototype.conj = function conj() { - return register.setWXYZ( - this.w, - -this.x, - -this.y, - -this.z - ); - }; - - /* - * Docs: TODO - * - * @method normalize - * @param {Number} length - * @return {Quaternion} - */ - Quaternion.prototype.normalize = function normalize(length) { - length = (length === undefined) ? 1 : length; - return this.scalarDivide(length * this.norm()); - }; - - /* - * Docs: TODO - * - * @method makeFromAngleAndAxis - * @param {Number} angle - * @param {Vector} v - * @return {Quaternion} - */ - Quaternion.prototype.makeFromAngleAndAxis = function makeFromAngleAndAxis(angle, v) { - //left handed quaternion creation: theta -> -theta - var n = v.normalize(); - var ha = angle*0.5; - var s = -Math.sin(ha); - this.x = s*n.x; - this.y = s*n.y; - this.z = s*n.z; - this.w = Math.cos(ha); - return this; - }; - - /* - * Docs: TODO - * - * @method setWXYZ - * @param {Number} w - * @param {Number} x - * @param {Number} y - * @param {Number} z - * @return {Quaternion} - */ - Quaternion.prototype.setWXYZ = function setWXYZ(w,x,y,z) { - register.clear(); - this.w = w; - this.x = x; - this.y = y; - this.z = z; - return this; - }; - - /* - * Docs: TODO - * - * @method set - * @param {Array|Quaternion} v - * @return {Quaternion} - */ - Quaternion.prototype.set = function set(v) { - if (v instanceof Array) { - this.w = v[0]; - this.x = v[1]; - this.y = v[2]; - this.z = v[3]; - } - else { - this.w = v.w; - this.x = v.x; - this.y = v.y; - this.z = v.z; - } - if (this !== register) register.clear(); - return this; - }; - - /** - * Docs: TODO - * - * @method put - * @param {Quaternion} q - * @return {Quaternion} - */ - Quaternion.prototype.put = function put(q) { - q.set(register); - }; - - /** - * Doc: TODO - * - * @method clone - * @return {Quaternion} - */ - Quaternion.prototype.clone = function clone() { - return new Quaternion(this); - }; - - /** - * Doc: TODO - * - * @method clear - * @return {Quaternion} - */ - Quaternion.prototype.clear = function clear() { - this.w = 1; - this.x = 0; - this.y = 0; - this.z = 0; - return this; - }; - - /** - * Doc: TODO - * - * @method isEqual - * @param {Quaternion} q - * @return {Boolean} - */ - Quaternion.prototype.isEqual = function isEqual(q) { - return q.w === this.w && q.x === this.x && q.y === this.y && q.z === this.z; - }; - - /** - * Doc: TODO - * - * @method dot - * @param {Quaternion} q - * @return {Number} - */ - Quaternion.prototype.dot = function dot(q) { - return this.w * q.w + this.x * q.x + this.y * q.y + this.z * q.z; - }; - - /** - * Doc: TODO - * - * @method normSquared - * @return {Number} - */ - Quaternion.prototype.normSquared = function normSquared() { - return this.dot(this); - }; - - /** - * Doc: TODO - * - * @method norm - * @return {Number} - */ - Quaternion.prototype.norm = function norm() { - return Math.sqrt(this.normSquared()); - }; - - /** - * Doc: TODO - * - * @method isZero - * @return {Boolean} - */ - Quaternion.prototype.isZero = function isZero() { - return !(this.x || this.y || this.z); - }; - - /** - * Doc: TODO - * - * @method getTransform - * @return {Transform} - */ - Quaternion.prototype.getTransform = function getTransform() { - var temp = this.normalize(1); - var x = temp.x; - var y = temp.y; - var z = temp.z; - var w = temp.w; - - //LHC system flattened to column major = RHC flattened to row major - return [ - 1 - 2*y*y - 2*z*z, - 2*x*y - 2*z*w, - 2*x*z + 2*y*w, - 0, - 2*x*y + 2*z*w, - 1 - 2*x*x - 2*z*z, - 2*y*z - 2*x*w, - 0, - 2*x*z - 2*y*w, - 2*y*z + 2*x*w, - 1 - 2*x*x - 2*y*y, - 0, - 0, - 0, - 0, - 1 - ]; - }; - - var matrixRegister = new Matrix(); - - /** - * Doc: TODO - * - * @method getMatrix - * @return {Transform} - */ - Quaternion.prototype.getMatrix = function getMatrix() { - var temp = this.normalize(1); - var x = temp.x; - var y = temp.y; - var z = temp.z; - var w = temp.w; - - //LHC system flattened to row major - return matrixRegister.set([ - [ - 1 - 2*y*y - 2*z*z, - 2*x*y + 2*z*w, - 2*x*z - 2*y*w - ], - [ - 2*x*y - 2*z*w, - 1 - 2*x*x - 2*z*z, - 2*y*z + 2*x*w - ], - [ - 2*x*z + 2*y*w, - 2*y*z - 2*x*w, - 1 - 2*x*x - 2*y*y - ] - ]); - }; - - var epsilon = 1e-5; - - /** - * Doc: TODO - * - * @method slerp - * @param {Quaternion} q - * @param {Number} t - * @return {Transform} - */ - Quaternion.prototype.slerp = function slerp(q, t) { - var omega; - var cosomega; - var sinomega; - var scaleFrom; - var scaleTo; - - cosomega = this.dot(q); - if ((1.0 - cosomega) > epsilon) { - omega = Math.acos(cosomega); - sinomega = Math.sin(omega); - scaleFrom = Math.sin((1.0 - t) * omega) / sinomega; - scaleTo = Math.sin(t * omega) / sinomega; - } - else { - scaleFrom = 1.0 - t; - scaleTo = t; - } - return register.set(this.scalarMultiply(scaleFrom/scaleTo).add(q).multiply(scaleTo)); - }; - - module.exports = Quaternion; - -}); - -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. - * - * Owner: david@famo.us - * @license MPL 2.0 - * @copyright Famous Industries, Inc. 2014 - */ - -define('famous/math/Random',['require','exports','module'],function(require, exports, module) { - - var RAND = Math.random; - - function _randomFloat(min,max) { - return min + RAND() * (max - min); - } - - function _randomInteger(min,max) { - return (min + RAND() * (max - min + 1)) >> 0; - } - - /** - * Very simple uniform random number generator library wrapping Math.random(). - * - * @class Random - * @static - */ - var Random = {}; - - /** - * Get single random integer between min and max (inclusive), or array - * of size dim if specified. - * - * @method integer - * - * @param {Number} min lower bound, default 0 - * @param {Number} max upper bound, default 1 - * @param {Number} dim (optional) dimension of output array, if specified - * @return {number | array} random integer, or optionally, an array of random integers - */ - Random.integer = function integer(min,max,dim) { - min = (min !== undefined) ? min : 0; - max = (max !== undefined) ? max : 1; - if (dim !== undefined) { - var result = []; - for (var i = 0; i < dim; i++) result.push(_randomInteger(min,max)); - return result; - } - else return _randomInteger(min,max); - }; - - /** - * Get single random float between min and max (inclusive), or array - * of size dim if specified - * - * @method range - * - * @param {Number} min lower bound, default 0 - * @param {Number} max upper bound, default 1 - * @param {Number} [dim] dimension of output array, if specified - * @return {Number} random float, or optionally an array - */ - Random.range = function range(min,max,dim) { - min = (min !== undefined) ? min : 0; - max = (max !== undefined) ? max : 1; - if (dim !== undefined) { - var result = []; - for (var i = 0; i < dim; i++) result.push(_randomFloat(min,max)); - return result; - } - else return _randomFloat(min,max); - }; - - /** - * Return random number among the set {-1 ,1} - * - * @method sign - * - * @param {Number} prob probability of returning 1, default 0.5 - * @return {Number} random sign (-1 or 1) - */ - Random.sign = function sign(prob) { - prob = (prob !== undefined) ? prob : 0.5; - return (RAND() < prob) ? 1 : -1; - }; - - /** - * Return random boolean value, true or false. - * - * @method bool - * - * @param {Number} prob probability of returning true, default 0.5 - * @return {Boolean} random boolean - */ - Random.bool = function bool(prob) { - prob = (prob !== undefined) ? prob : 0.5; - return RAND() < prob; - }; - - module.exports = Random; -}); - -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. - * - * Owner: david@famo.us - * @license MPL 2.0 - * @copyright Famous Industries, Inc. 2014 - */ - -define('famous/events/EventArbiter',['require','exports','module','famous/core/EventHandler'],function(require, exports, module) { - var EventHandler = require('famous/core/EventHandler'); - - /** - * A switch which wraps several event destinations and - * redirects received events to at most one of them. - * Setting the 'mode' of the object dictates which one - * of these destinations will receive events. - * - * @class EventArbiter - * @constructor - * - * @param {Number | string} startMode initial setting of switch, - */ - function EventArbiter(startMode) { - this.dispatchers = {}; - this.currMode = undefined; - this.setMode(startMode); - } - - /** - * Set switch to this mode, passing events to the corresponding - * EventHandler. If mode has changed, emits 'change' event, - * emits 'unpipe' event to the old mode's handler, and emits 'pipe' - * event to the new mode's handler. - * - * @method setMode - * - * @param {string | number} mode indicating which event handler to send to. - */ - EventArbiter.prototype.setMode = function setMode(mode) { - if (mode !== this.currMode) { - var startMode = this.currMode; - - if (this.dispatchers[this.currMode]) this.dispatchers[this.currMode].trigger('unpipe'); - this.currMode = mode; - if (this.dispatchers[mode]) this.dispatchers[mode].emit('pipe'); - this.emit('change', {from: startMode, to: mode}); - } - }; - - /** - * Return the existing EventHandler corresponding to this - * mode, creating one if it doesn't exist. - * - * @method forMode - * - * @param {string | number} mode mode to which this eventHandler corresponds - * - * @return {EventHandler} eventHandler corresponding to this mode - */ - EventArbiter.prototype.forMode = function forMode(mode) { - if (!this.dispatchers[mode]) this.dispatchers[mode] = new EventHandler(); - return this.dispatchers[mode]; - }; - - /** - * Trigger an event, sending to currently selected handler, if - * it is listening for provided 'type' key. - * - * @method emit - * - * @param {string} eventType event type key (for example, 'click') - * @param {Object} event event data - * @return {EventHandler} this - */ - EventArbiter.prototype.emit = function emit(eventType, event) { - if (this.currMode === undefined) return false; - if (!event) event = {}; - var dispatcher = this.dispatchers[this.currMode]; - if (dispatcher) return dispatcher.trigger(eventType, event); - }; - - module.exports = EventArbiter; -}); - -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. - * - * Owner: david@famo.us - * @license MPL 2.0 - * @copyright Famous Industries, Inc. 2014 - */ - -define('famous/events/EventFilter',['require','exports','module','famous/core/EventHandler'],function(require, exports, module) { - var EventHandler = require('famous/core/EventHandler'); - - /** - * EventFilter regulates the broadcasting of events based on - * a specified condition function of standard event type: function(type, data). - * - * @class EventFilter - * @constructor - * - * @param {function} condition function to determine whether or not - * events are emitted. - */ - function EventFilter(condition) { - EventHandler.call(this); - this._condition = condition; - } - EventFilter.prototype = Object.create(EventHandler.prototype); - EventFilter.prototype.constructor = EventFilter; - - /** - * If filter condition is met, trigger an event, sending to all downstream handlers - * listening for provided 'type' key. - * - * @method emit - * - * @param {string} type event type key (for example, 'click') - * @param {Object} data event data - * @return {EventHandler} this - */ - EventFilter.prototype.emit = function emit(type, data) { - if (this._condition(type, data)) - return EventHandler.prototype.emit.apply(this, arguments); - }; - - /** - * An alias of emit. Trigger determines whether to send - * events based on the return value of it's condition function - * when passed the event type and associated data. - * - * @method trigger - * @param {string} type name of the event - * @param {object} data associated data - */ - EventFilter.prototype.trigger = EventFilter.prototype.emit; - - module.exports = EventFilter; -}); - -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. - * - * Owner: david@famo.us - * @license MPL 2.0 - * @copyright Famous Industries, Inc. 2014 - */ - -define('famous/events/EventMapper',['require','exports','module','famous/core/EventHandler'],function(require, exports, module) { - var EventHandler = require('famous/core/EventHandler'); - - /** - * EventMapper routes events to various event destinations - * based on custom logic. The function signature is arbitrary. - * - * @class EventMapper - * @constructor - * - * @param {function} mappingFunction function to determine where - * events are routed to. - */ - function EventMapper(mappingFunction) { - EventHandler.call(this); - this._mappingFunction = mappingFunction; - } - EventMapper.prototype = Object.create(EventHandler.prototype); - EventMapper.prototype.constructor = EventMapper; - - EventMapper.prototype.subscribe = null; - EventMapper.prototype.unsubscribe = null; - - /** - * Trigger an event, sending to all mapped downstream handlers - * listening for provided 'type' key. - * - * @method emit - * - * @param {string} type event type key (for example, 'click') - * @param {Object} data event data - * @return {EventHandler} this - */ - EventMapper.prototype.emit = function emit(type, data) { - var target = this._mappingFunction.apply(this, arguments); - if (target && (target.emit instanceof Function)) target.emit(type, data); - }; - - /** - * Alias of emit. - * @method trigger - */ - EventMapper.prototype.trigger = EventMapper.prototype.emit; - - module.exports = EventMapper; -}); - -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. - * - * @license MPL 2.0 - * @copyright Famous Industries, Inc. 2014 - */ -define('famous/physics/PhysicsEngine',['require','exports','module','famous/core/EventHandler'],function(require, exports, module) { - var EventHandler = require('famous/core/EventHandler'); - - /** - * 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. - * - * @class PhysicsEngine - * @constructor - * @param options {Object} options - */ - function PhysicsEngine(options) { - this.options = Object.create(PhysicsEngine.DEFAULT_OPTIONS); - if (options) this.setOptions(options); - - this._particles = []; //list of managed particles - 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._buffer = 0.0; - this._prevTime = now(); - this._isSleeping = false; - this._eventHandler = null; - this._currAgentId = 0; - this._hasBodies = false; - } - - var TIMESTEP = 17; - var MIN_TIME_STEP = 1000 / 120; - var MAX_TIME_STEP = 17; - - /** - * @property PhysicsEngine.DEFAULT_OPTIONS - * @type Object - * @protected - * @static - */ - PhysicsEngine.DEFAULT_OPTIONS = { - - /** - * The number of iterations the engine takes to resolve constraints - * @attribute constraintSteps - * @type Number - */ - constraintSteps : 1, - - /** - * The energy threshold before the Engine stops updating - * @attribute sleepTolerance - * @type Number - */ - sleepTolerance : 1e-7 - }; - - var now = (function() { - return Date.now; - })(); - - /** - * Options setter - * @method setOptions - * @param options {Object} - */ - PhysicsEngine.prototype.setOptions = function setOptions(opts) { - for (var key in opts) if (this.options[key]) this.options[key] = opts[key]; - }; - - /** - * Method to add a physics body to the engine. Necessary to update the - * body over time. - * - * @method addBody - * @param body {Body} - * @return body {Body} - */ - PhysicsEngine.prototype.addBody = function addBody(body) { - body._engine = this; - if (body.isBody) { - this._bodies.push(body); - this._hasBodies = true; - } - else this._particles.push(body); - return body; - }; - - /** - * Remove a body from the engine. Detaches body from all forces and - * constraints. - * - * @method removeBody - * @param body {Body} - */ - PhysicsEngine.prototype.removeBody = function removeBody(body) { - var array = (body.isBody) ? this._bodies : this._particles; - var index = array.indexOf(body); - if (index > -1) { - for (var i = 0; i < Object.keys(this._agents).length; i++) this.detachFrom(i, body); - array.splice(index,1); - } - if (this.getBodies().length === 0) this._hasBodies = false; - }; - - function _mapAgentArray(agent) { - if (agent.applyForce) return this._forces; - if (agent.applyConstraint) return this._constraints; - } - - function _attachOne(agent, targets, source) { - if (targets === undefined) targets = this.getParticlesAndBodies(); - if (!(targets instanceof Array)) targets = [targets]; - - this._agents[this._currAgentId] = { - agent : agent, - targets : targets, - source : source - }; - - _mapAgentArray.call(this, agent).push(this._currAgentId); - return this._currAgentId++; - } - - /** - * Attaches a force or constraint to a Body. Returns an AgentId of the - * attached agent which can be used to detach the agent. - * - * @method attach - * @param agent {Agent|Array.Agent} A force, constraint, or array of them. - * @param [targets=All] {Body|Array.Body} The Body or Bodies affected by the agent - * @param [source] {Body} The source of the agent - * @return AgentId {Number} - */ - PhysicsEngine.prototype.attach = function attach(agents, targets, source) { - if (agents instanceof Array) { - var agentIDs = []; - for (var i = 0; i < agents.length; i++) - agentIDs[i] = _attachOne.call(this, agents[i], targets, source); - return agentIDs; - } - else return _attachOne.call(this, agents, targets, source); - }; - - /** - * Append a body to the targets of a previously defined physics agent. - * - * @method attachTo - * @param agentID {AgentId} The agentId of a previously defined agent - * @param target {Body} The Body affected by the agent - */ - PhysicsEngine.prototype.attachTo = function attachTo(agentID, target) { - _getBoundAgent.call(this, agentID).targets.push(target); - }; - - /** - * Undoes PhysicsEngine.attach. Removes an agent and its associated - * effect on its affected Bodies. - * - * @method detach - * @param agentID {AgentId} The agentId of a previously defined agent - */ - PhysicsEngine.prototype.detach = function detach(id) { - // detach from forces/constraints array - var agent = this.getAgent(id); - var agentArray = _mapAgentArray.call(this, agent); - var index = agentArray.indexOf(id); - agentArray.splice(index,1); - - // detach agents array - delete this._agents[id]; - }; - - /** - * Remove a single Body from a previously defined agent. - * - * @method detach - * @param agentID {AgentId} The agentId of a previously defined agent - * @param target {Body} The body to remove from the agent - */ - PhysicsEngine.prototype.detachFrom = function detachFrom(id, target) { - var boundAgent = _getBoundAgent.call(this, id); - if (boundAgent.source === target) this.detach(id); - else { - var targets = boundAgent.targets; - var index = targets.indexOf(target); - if (index > -1) targets.splice(index,1); - } - }; - - /** - * A convenience method to give the Physics Engine a clean slate of - * agents. Preserves all added Body objects. - * - * @method detachAll - */ - PhysicsEngine.prototype.detachAll = function detachAll() { - this._agents = {}; - this._forces = []; - this._constraints = []; - this._currAgentId = 0; - }; - - function _getBoundAgent(id) { - return this._agents[id]; - } - - /** - * Returns the corresponding agent given its agentId. - * - * @method getAgent - * @param id {AgentId} - */ - PhysicsEngine.prototype.getAgent = function getAgent(id) { - return _getBoundAgent.call(this, id).agent; - }; - - /** - * Returns all particles that are currently managed by the Physics Engine. - * - * @method getParticles - * @return particles {Array.Particles} - */ - PhysicsEngine.prototype.getParticles = function getParticles() { - return this._particles; - }; - - /** - * Returns all bodies, except particles, that are currently managed by the Physics Engine. - * - * @method getBodies - * @return bodies {Array.Bodies} - */ - PhysicsEngine.prototype.getBodies = function getBodies() { - return this._bodies; - }; - - /** - * Returns all bodies that are currently managed by the Physics Engine. - * - * @method getBodies - * @return bodies {Array.Bodies} - */ - PhysicsEngine.prototype.getParticlesAndBodies = function getParticlesAndBodies() { - return this.getParticles().concat(this.getBodies()); - }; - - /** - * Iterates over every Particle and applies a function whose first - * argument is the Particle - * - * @method forEachParticle - * @param fn {Function} Function to iterate over - * @param [dt] {Number} Delta time - */ - PhysicsEngine.prototype.forEachParticle = function forEachParticle(fn, dt) { - var particles = this.getParticles(); - for (var index = 0, len = particles.length; index < len; index++) - fn.call(this, particles[index], dt); - }; - - /** - * Iterates over every Body that isn't a Particle and applies - * a function whose first argument is the Body - * - * @method forEachBody - * @param fn {Function} Function to iterate over - * @param [dt] {Number} Delta time - */ - PhysicsEngine.prototype.forEachBody = function forEachBody(fn, dt) { - if (!this._hasBodies) return; - var bodies = this.getBodies(); - for (var index = 0, len = bodies.length; index < len; index++) - fn.call(this, bodies[index], dt); - }; - - /** - * Iterates over every Body and applies a function whose first - * argument is the Body - * - * @method forEach - * @param fn {Function} Function to iterate over - * @param [dt] {Number} Delta time - */ - PhysicsEngine.prototype.forEach = function forEach(fn, dt) { - this.forEachParticle(fn, dt); - this.forEachBody(fn, dt); - }; - - function _updateForce(index) { - var boundAgent = _getBoundAgent.call(this, this._forces[index]); - boundAgent.agent.applyForce(boundAgent.targets, boundAgent.source); - } - - function _updateForces() { - for (var index = this._forces.length - 1; index > -1; index--) - _updateForce.call(this, index); - } - - function _updateConstraint(index, dt) { - var boundAgent = this._agents[this._constraints[index]]; - return boundAgent.agent.applyConstraint(boundAgent.targets, boundAgent.source, dt); - } - - function _updateConstraints(dt) { - var iteration = 0; - while (iteration < this.options.constraintSteps) { - for (var index = this._constraints.length - 1; index > -1; index--) - _updateConstraint.call(this, index, dt); - iteration++; - } - } - - function _updateVelocities(particle, dt) { - particle.integrateVelocity(dt); - } - - function _updateAngularVelocities(body, dt) { - body.integrateAngularMomentum(dt); - body.updateAngularVelocity(); - } - - function _updateOrientations(body, dt) { - body.integrateOrientation(dt); - } - - function _updatePositions(particle, dt) { - particle.integratePosition(dt); - particle.emit('update', particle); - } - - function _integrate(dt) { - _updateForces.call(this, dt); - this.forEach(_updateVelocities, dt); - this.forEachBody(_updateAngularVelocities, dt); - _updateConstraints.call(this, dt); - this.forEachBody(_updateOrientations, dt); - this.forEach(_updatePositions, dt); - } - - function _getEnergyParticles() { - var energy = 0.0; - var particleEnergy = 0.0; - this.forEach(function(particle) { - particleEnergy = particle.getEnergy(); - energy += particleEnergy; - if (particleEnergy < particle.sleepTolerance) particle.sleep(); - }); - return energy; - } - - function _getEnergyForces() { - var energy = 0; - for (var index = this._forces.length - 1; index > -1; index--) - energy += this._forces[index].getEnergy() || 0.0; - 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 kinetic energy of all Body objects and potential energy - * of all attached agents. - * - * TODO: implement. - * @method getEnergy - * @return energy {Number} - */ - PhysicsEngine.prototype.getEnergy = function getEnergy() { - return _getEnergyParticles.call(this) + _getEnergyForces.call(this) + _getEnergyConstraints.call(this); - }; - - /** - * Updates all Body objects managed by the physics engine over the - * time duration since the last time step was called. - * - * @method step - */ - PhysicsEngine.prototype.step = function step() { -// if (this.getEnergy() < this.options.sleepTolerance) { -// this.sleep(); -// return; -// }; - - //set current frame's time - var currTime = now(); - - //milliseconds elapsed since last frame - var dtFrame = currTime - this._prevTime; - - this._prevTime = currTime; - - if (dtFrame < MIN_TIME_STEP) return; - if (dtFrame > MAX_TIME_STEP) dtFrame = MAX_TIME_STEP; - - //robust integration -// this._buffer += dtFrame; -// while (this._buffer > this._timestep){ -// _integrate.call(this, this._timestep); -// this._buffer -= this._timestep; -// }; -// _integrate.call(this, this._buffer); -// this._buffer = 0.0; - _integrate.call(this, TIMESTEP); - -// this.emit('update', this); - }; - - /** - * Tells whether the Physics Engine is sleeping or awake. - * @method isSleeping - * @return {Boolean} - */ - PhysicsEngine.prototype.isSleeping = function isSleeping() { - return this._isSleeping; - }; - - /** - * Stops the Physics Engine from updating. Emits an 'end' event. - * @method sleep - */ - PhysicsEngine.prototype.sleep = function sleep() { - this.emit('end', this); - this._isSleeping = true; - }; - - /** - * Starts the Physics Engine from updating. Emits an 'start' event. - * @method wake - */ - PhysicsEngine.prototype.wake = function wake() { - this._prevTime = now(); - this.emit('start', this); - this._isSleeping = false; - }; - - PhysicsEngine.prototype.emit = function emit(type, data) { - if (this._eventHandler === null) return; - this._eventHandler.emit(type, data); - }; - - PhysicsEngine.prototype.on = function on(event, fn) { - if (this._eventHandler === null) this._eventHandler = new EventHandler(); - this._eventHandler.on(event, fn); - }; - - module.exports = PhysicsEngine; -}); - -define('famous/inputs/Accumulator',['require','exports','module','famous/core/EventHandler','famous/transitions/Transitionable'],function(require, exports, module) { - var EventHandler = require('famous/core/EventHandler'); - var Transitionable = require('famous/transitions/Transitionable'); - - /** - * Accumulates differentials of event sources that emit a `delta` - * attribute taking a Number or Array of Number types. The accumulated - * value is stored in a getter/setter. - * - * @class Accumulator - * @constructor - * @param value {Number|Array|Transitionable} Initializing value - * @param [eventName='update'] {String} Name of update event - */ - function Accumulator(value, eventName) { - if (eventName === undefined) eventName = 'update'; - - this._state = (value && value.get && value.set) - ? value - : new Transitionable(value || 0); - - this._eventInput = new EventHandler(); - EventHandler.setInputHandler(this, this._eventInput); - - this._eventInput.on(eventName, _handleUpdate.bind(this)); - } - - function _handleUpdate(data) { - var delta = data.delta; - var state = this.get(); - - if (delta.constructor === state.constructor){ - var newState = (delta instanceof Array) - ? [state[0] + delta[0], state[1] + delta[1]] - : state + delta; - this.set(newState); - } - } - - /** - * Basic getter - * - * @method get - * @return {Number|Array} current value - */ - Accumulator.prototype.get = function get() { - return this._state.get(); - }; - - /** - * Basic setter - * - * @method set - * @param value {Number|Array} new value - */ - Accumulator.prototype.set = function set(value) { - this._state.set(value); - }; - - module.exports = Accumulator; -}); - -define('famous/inputs/DesktopEmulationMode',['require','exports','module'],function(require, exports, module) { - var hasTouch = 'ontouchstart' in window; - - function kill(type) { - window.addEventListener(type, function(event) { - event.stopPropagation(); - return false; - }, true); - } - - if (hasTouch) { - kill('mousedown'); - kill('mousemove'); - kill('mouseup'); - kill('mouseleave'); - } -}); - -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. - * - * Owner: mark@famo.us - * @license MPL 2.0 - * @copyright Famous Industries, Inc. 2014 - */ - -define('famous/inputs/FastClick',['require','exports','module'],function(require, exports, module) { - /** - * FastClick is an override shim which maps event pairs of - * 'touchstart' and 'touchend' which differ by less than a certain - * threshold to the 'click' event. - * This is used to speed up clicks on some browsers. - */ - 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('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, - 'details': 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); -}); - -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. - * - * Owner: mark@famo.us - * @license MPL 2.0 - * @copyright Famous Industries, Inc. 2014 - */ - -define('famous/inputs/TwoFingerSync',['require','exports','module','famous/core/EventHandler'],function(require, exports, module) { - var EventHandler = require('famous/core/EventHandler'); - - /** - * Helper to PinchSync, RotateSync, and ScaleSync. Generalized handling of - * two-finger touch events. - * This class is meant to be overridden and not used directly. - * - * @class TwoFingerSync - * @constructor - */ - function TwoFingerSync() { - this._eventInput = new EventHandler(); - this._eventOutput = new EventHandler(); - - EventHandler.setInputHandler(this, this._eventInput); - EventHandler.setOutputHandler(this, this._eventOutput); - - this.touchAEnabled = false; - this.touchAId = 0; - this.posA = null; - this.timestampA = 0; - this.touchBEnabled = false; - this.touchBId = 0; - this.posB = null; - this.timestampB = 0; - - this._eventInput.on('touchstart', this.handleStart.bind(this)); - this._eventInput.on('touchmove', this.handleMove.bind(this)); - this._eventInput.on('touchend', this.handleEnd.bind(this)); - this._eventInput.on('touchcancel', this.handleEnd.bind(this)); - } - - TwoFingerSync.calculateAngle = function(posA, posB) { - var diffX = posB[0] - posA[0]; - var diffY = posB[1] - posA[1]; - return Math.atan2(diffY, diffX); - }; - - TwoFingerSync.calculateDistance = function(posA, posB) { - var diffX = posB[0] - posA[0]; - var diffY = posB[1] - posA[1]; - return Math.sqrt(diffX * diffX + diffY * diffY); - }; - - TwoFingerSync.calculateCenter = function(posA, posB) { - return [(posA[0] + posB[0]) / 2.0, (posA[1] + posB[1]) / 2.0]; - }; - - var _now = Date.now; - - // private - TwoFingerSync.prototype.handleStart = function handleStart(event) { - for (var i = 0; i < event.changedTouches.length; i++) { - var touch = event.changedTouches[i]; - if (!this.touchAEnabled) { - this.touchAId = touch.identifier; - this.touchAEnabled = true; - this.posA = [touch.pageX, touch.pageY]; - this.timestampA = _now(); - } - else if (!this.touchBEnabled) { - this.touchBId = touch.identifier; - this.touchBEnabled = true; - this.posB = [touch.pageX, touch.pageY]; - this.timestampB = _now(); - this._startUpdate(event); - } - } - }; - - // private - TwoFingerSync.prototype.handleMove = function handleMove(event) { - if (!(this.touchAEnabled && this.touchBEnabled)) return; - var prevTimeA = this.timestampA; - var prevTimeB = this.timestampB; - var diffTime; - for (var i = 0; i < event.changedTouches.length; i++) { - var touch = event.changedTouches[i]; - if (touch.identifier === this.touchAId) { - this.posA = [touch.pageX, touch.pageY]; - this.timestampA = _now(); - diffTime = this.timestampA - prevTimeA; - } - else if (touch.identifier === this.touchBId) { - this.posB = [touch.pageX, touch.pageY]; - this.timestampB = _now(); - diffTime = this.timestampB - prevTimeB; - } - } - if (diffTime) this._moveUpdate(diffTime); - }; - - // private - TwoFingerSync.prototype.handleEnd = function handleEnd(event) { - for (var i = 0; i < event.changedTouches.length; i++) { - var touch = event.changedTouches[i]; - if (touch.identifier === this.touchAId || touch.identifier === this.touchBId) { - if (this.touchAEnabled && this.touchBEnabled) { - this._eventOutput.emit('end', { - touches : [this.touchAId, this.touchBId], - angle : this._angle - }); - } - this.touchAEnabled = false; - this.touchAId = 0; - this.touchBEnabled = false; - this.touchBId = 0; - } - } - }; - - module.exports = TwoFingerSync; -}); - -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. - * - * Owner: mark@famo.us - * @license MPL 2.0 - * @copyright Famous Industries, Inc. 2014 - */ - -define('famous/inputs/PinchSync',['require','exports','module','./TwoFingerSync'],function(require, exports, module) { - var TwoFingerSync = require('./TwoFingerSync'); - - /** - * Handles piped in two-finger touch events to change position via pinching / expanding. - * Emits 'start', 'update' and 'end' events with - * position, velocity, touch ids, and distance between fingers. - * - * @class PinchSync - * @extends TwoFingerSync - * @constructor - * @param {Object} options default options overrides - * @param {Number} [options.scale] scale velocity by this factor - */ - function PinchSync(options) { - TwoFingerSync.call(this); - - this.options = Object.create(PinchSync.DEFAULT_OPTIONS); - if (options) this.setOptions(options); - - this._displacement = 0; - this._previousDistance = 0; - } - - PinchSync.prototype = Object.create(TwoFingerSync.prototype); - PinchSync.prototype.constructor = PinchSync; - - PinchSync.DEFAULT_OPTIONS = { - scale : 1 - }; - - PinchSync.prototype._startUpdate = function _startUpdate(event) { - this._previousDistance = TwoFingerSync.calculateDistance(this.posA, this.posB); - this._displacement = 0; - - this._eventOutput.emit('start', { - count: event.touches.length, - touches: [this.touchAId, this.touchBId], - distance: this._dist, - center: TwoFingerSync.calculateCenter(this.posA, this.posB) - }); - }; - - PinchSync.prototype._moveUpdate = function _moveUpdate(diffTime) { - var currDist = TwoFingerSync.calculateDistance(this.posA, this.posB); - var center = TwoFingerSync.calculateCenter(this.posA, this.posB); - - var scale = this.options.scale; - var delta = scale * (currDist - this._previousDistance); - var velocity = delta / diffTime; - - this._previousDistance = currDist; - this._displacement += delta; - - this._eventOutput.emit('update', { - delta : delta, - velocity: velocity, - distance: currDist, - displacement: this._displacement, - center: center, - touches: [this.touchAId, this.touchBId] - }); - }; - - /** - * Return entire options dictionary, including defaults. - * - * @method getOptions - * @return {Object} configuration options - */ - PinchSync.prototype.getOptions = function getOptions() { - return this.options; - }; - - /** - * Set internal options, overriding any default options - * - * @method setOptions - * - * @param {Object} [options] overrides of default options - * @param {Number} [options.scale] scale velocity by this factor - */ - PinchSync.prototype.setOptions = function setOptions(options) { - if (options.scale !== undefined) this.options.scale = options.scale; - }; - - module.exports = PinchSync; -}); - -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. - * - * Owner: mark@famo.us - * @license MPL 2.0 - * @copyright Famous Industries, Inc. 2014 - */ - -define('famous/inputs/RotateSync',['require','exports','module','./TwoFingerSync'],function(require, exports, module) { - var TwoFingerSync = require('./TwoFingerSync'); - - /** - * Handles piped in two-finger touch events to increase or decrease scale via pinching / expanding. - * Emits 'start', 'update' and 'end' events an object with position, velocity, touch ids, and angle. - * Useful for determining a rotation factor from initial two-finger touch. - * - * @class RotateSync - * @extends TwoFingerSync - * @constructor - * @param {Object} options default options overrides - * @param {Number} [options.scale] scale velocity by this factor - */ - function RotateSync(options) { - TwoFingerSync.call(this); - - this.options = Object.create(RotateSync.DEFAULT_OPTIONS); - if (options) this.setOptions(options); - - this._angle = 0; - this._previousAngle = 0; - } - - RotateSync.prototype = Object.create(TwoFingerSync.prototype); - RotateSync.prototype.constructor = RotateSync; - - RotateSync.DEFAULT_OPTIONS = { - scale : 1 - }; - - RotateSync.prototype._startUpdate = function _startUpdate(event) { - this._angle = 0; - this._previousAngle = TwoFingerSync.calculateAngle(this.posA, this.posB); - var center = TwoFingerSync.calculateCenter(this.posA, this.posB); - this._eventOutput.emit('start', { - count: event.touches.length, - angle: this._angle, - center: center, - touches: [this.touchAId, this.touchBId] - }); - }; - - RotateSync.prototype._moveUpdate = function _moveUpdate(diffTime) { - var scale = this.options.scale; - - var currAngle = TwoFingerSync.calculateAngle(this.posA, this.posB); - var center = TwoFingerSync.calculateCenter(this.posA, this.posB); - - var diffTheta = scale * (currAngle - this._previousAngle); - var velTheta = diffTheta / diffTime; - - this._angle += diffTheta; - - this._eventOutput.emit('update', { - delta : diffTheta, - velocity: velTheta, - angle: this._angle, - center: center, - touches: [this.touchAId, this.touchBId] - }); - - this._previousAngle = currAngle; - }; - - /** - * Return entire options dictionary, including defaults. - * - * @method getOptions - * @return {Object} configuration options - */ - RotateSync.prototype.getOptions = function getOptions() { - return this.options; - }; - - /** - * Set internal options, overriding any default options - * - * @method setOptions - * - * @param {Object} [options] overrides of default options - * @param {Number} [options.scale] scale velocity by this factor - */ - RotateSync.prototype.setOptions = function setOptions(options) { - if (options.scale !== undefined) this.options.scale = options.scale; - }; - - module.exports = RotateSync; -}); - -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. - * - * Owner: mark@famo.us - * @license MPL 2.0 - * @copyright Famous Industries, Inc. 2014 - */ - -define('famous/inputs/ScaleSync',['require','exports','module','./TwoFingerSync'],function(require, exports, module) { - var TwoFingerSync = require('./TwoFingerSync'); - - /** - * Handles piped in two-finger touch events to increase or decrease scale via pinching / expanding. - * Emits 'start', 'update' and 'end' events an object with position, velocity, touch ids, distance, and scale factor. - * Useful for determining a scaling factor from initial two-finger touch. - * - * @class ScaleSync - * @extends TwoFingerSync - * @constructor - * @param {Object} options default options overrides - * @param {Number} [options.scale] scale velocity by this factor - */ - function ScaleSync(options) { - TwoFingerSync.call(this); - - this.options = Object.create(ScaleSync.DEFAULT_OPTIONS); - if (options) this.setOptions(options); - - this._scaleFactor = 1; - this._startDist = 0; - this._eventInput.on('pipe', _reset.bind(this)); - } - - ScaleSync.prototype = Object.create(TwoFingerSync.prototype); - ScaleSync.prototype.constructor = ScaleSync; - - ScaleSync.DEFAULT_OPTIONS = { - scale : 1 - }; - - function _reset() { - this.touchAId = undefined; - this.touchBId = undefined; - } - - // handles initial touch of two fingers - ScaleSync.prototype._startUpdate = function _startUpdate(event) { - this._scaleFactor = 1; - this._startDist = TwoFingerSync.calculateDistance(this.posA, this.posB); - this._eventOutput.emit('start', { - count: event.touches.length, - touches: [this.touchAId, this.touchBId], - distance: this._startDist, - center: TwoFingerSync.calculateCenter(this.posA, this.posB) - }); - }; - - // handles movement of two fingers - ScaleSync.prototype._moveUpdate = function _moveUpdate(diffTime) { - var scale = this.options.scale; - - var currDist = TwoFingerSync.calculateDistance(this.posA, this.posB); - var center = TwoFingerSync.calculateCenter(this.posA, this.posB); - - var delta = (currDist - this._startDist) / this._startDist; - var newScaleFactor = Math.max(1 + scale * delta, 0); - var veloScale = (newScaleFactor - this._scaleFactor) / diffTime; - - this._eventOutput.emit('update', { - delta : delta, - scale: newScaleFactor, - velocity: veloScale, - distance: currDist, - center : center, - touches: [this.touchAId, this.touchBId] - }); - - this._scaleFactor = newScaleFactor; - }; - - /** - * Return entire options dictionary, including defaults. - * - * @method getOptions - * @return {Object} configuration options - */ - ScaleSync.prototype.getOptions = function getOptions() { - return this.options; - }; - - /** - * Set internal options, overriding any default options - * - * @method setOptions - * - * @param {Object} [options] overrides of default options - * @param {Number} [options.scale] scale velocity by this factor - */ - ScaleSync.prototype.setOptions = function setOptions(options) { - if (options.scale !== undefined) this.options.scale = options.scale; - }; - - module.exports = ScaleSync; -}); - -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. - * - * Owner: mark@famo.us - * @license MPL 2.0 - * @copyright Famous Industries, Inc. 2014 - */ - -define('famous/inputs/ScrollSync',['require','exports','module','famous/core/EventHandler','famous/core/Engine'],function(require, exports, module) { - var EventHandler = require('famous/core/EventHandler'); - var Engine = require('famous/core/Engine'); - - /** - * Handles piped in mousewheel events. - * Emits 'start', 'update', and 'end' events with payloads including: - * delta: change since last position, - * position: accumulated deltas, - * velocity: speed of change in pixels per ms, - * slip: true (unused). - * - * Can be used as delegate of GenericSync. - * - * @class ScrollSync - * @constructor - * @param {Object} [options] overrides of default options - * @param {Number} [options.direction] Pay attention to x changes (ScrollSync.DIRECTION_X), - * y changes (ScrollSync.DIRECTION_Y) or both (undefined) - * @param {Number} [options.minimumEndSpeed] End speed calculation floors at this number, in pixels per ms - * @param {boolean} [options.rails] whether to snap position calculations to nearest axis - * @param {Number | Array.Number} [options.scale] scale outputs in by scalar or pair of scalars - * @param {Number} [options.stallTime] reset time for velocity calculation in ms - */ - function ScrollSync(options) { - this.options = Object.create(ScrollSync.DEFAULT_OPTIONS); - if (options) this.setOptions(options); - - this._payload = { - delta : null, - position : null, - velocity : null, - slip : true - }; - - this._eventInput = new EventHandler(); - this._eventOutput = new EventHandler(); - - EventHandler.setInputHandler(this, this._eventInput); - EventHandler.setOutputHandler(this, this._eventOutput); - - this._position = (this.options.direction === undefined) ? [0,0] : 0; - this._prevTime = undefined; - this._prevVel = undefined; - this._eventInput.on('mousewheel', _handleMove.bind(this)); - this._eventInput.on('wheel', _handleMove.bind(this)); - this._inProgress = false; - this._loopBound = false; - } - - ScrollSync.DEFAULT_OPTIONS = { - direction: undefined, - minimumEndSpeed: Infinity, - rails: false, - scale: 1, - stallTime: 50, - lineHeight: 40 - }; - - ScrollSync.DIRECTION_X = 0; - ScrollSync.DIRECTION_Y = 1; - - var MINIMUM_TICK_TIME = 8; - - var _now = Date.now; - - function _newFrame() { - if (this._inProgress && (_now() - this._prevTime) > this.options.stallTime) { - this._position = (this.options.direction === undefined) ? [0,0] : 0; - this._inProgress = false; - - var finalVel = (Math.abs(this._prevVel) >= this.options.minimumEndSpeed) - ? this._prevVel - : 0; - - var payload = this._payload; - payload.position = this._position; - payload.velocity = finalVel; - payload.slip = true; - - this._eventOutput.emit('end', payload); - } - } - - function _handleMove(event) { - event.preventDefault(); - - if (!this._inProgress) { - this._inProgress = true; - - payload = this._payload; - payload.slip = true; - payload.position = this._position; - payload.clientX = event.clientX; - payload.clientY = event.clientY; - payload.offsetX = event.offsetX; - payload.offsetY = event.offsetY; - this._eventOutput.emit('start', payload); - if (!this._loopBound) { - Engine.on('prerender', _newFrame.bind(this)); - this._loopBound = true; - } - } - - var currTime = _now(); - var prevTime = this._prevTime || currTime; - - var diffX = (event.wheelDeltaX !== undefined) ? event.wheelDeltaX : -event.deltaX; - var diffY = (event.wheelDeltaY !== undefined) ? event.wheelDeltaY : -event.deltaY; - - if (event.deltaMode === 1) { // units in lines, not pixels - diffX *= this.options.lineHeight; - diffY *= this.options.lineHeight; - } - - if (this.options.rails) { - if (Math.abs(diffX) > Math.abs(diffY)) diffY = 0; - else diffX = 0; - } - - var diffTime = Math.max(currTime - prevTime, MINIMUM_TICK_TIME); // minimum tick time - - var velX = diffX / diffTime; - var velY = diffY / diffTime; - - var scale = this.options.scale; - var nextVel; - var nextDelta; - - if (this.options.direction === ScrollSync.DIRECTION_X) { - nextDelta = scale * diffX; - nextVel = scale * velX; - this._position += nextDelta; - } - else if (this.options.direction === ScrollSync.DIRECTION_Y) { - nextDelta = scale * diffY; - nextVel = scale * velY; - this._position += nextDelta; - } - else { - nextDelta = [scale * diffX, scale * diffY]; - nextVel = [scale * velX, scale * velY]; - this._position[0] += nextDelta[0]; - this._position[1] += nextDelta[1]; - } - - var payload = this._payload; - payload.delta = nextDelta; - payload.velocity = nextVel; - payload.position = this._position; - payload.slip = true; - - this._eventOutput.emit('update', payload); - - this._prevTime = currTime; - this._prevVel = nextVel; - } - - /** - * Return entire options dictionary, including defaults. - * - * @method getOptions - * @return {Object} configuration options - */ - ScrollSync.prototype.getOptions = function getOptions() { - return this.options; - }; - - /** - * Set internal options, overriding any default options - * - * @method setOptions - * - * @param {Object} [options] overrides of default options - * @param {Number} [options.minimimEndSpeed] If final velocity smaller than this, round down to 0. - * @param {Number} [options.stallTime] ms of non-motion before 'end' emitted - * @param {Number} [options.rails] whether to constrain to nearest axis. - * @param {Number} [options.direction] ScrollSync.DIRECTION_X, DIRECTION_Y - - * pay attention to one specific direction. - * @param {Number} [options.scale] constant factor to scale velocity output - */ - 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; - }; - - module.exports = ScrollSync; -}); - -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. - * - * Owner: david@famo.us - * @license MPL 2.0 - * @copyright Famous Industries, Inc. 2014 - */ - -define('famous/transitions/CachedMap',['require','exports','module'],function(require, exports, module) { - /** - * A simple in-memory object cache. Used as a helper for Views with - * provider functions. - * @class CachedMap - * @constructor - */ - function CachedMap(mappingFunction) { - this._map = mappingFunction || null; - this._cachedOutput = null; - this._cachedInput = Number.NaN; //never valid as input - } - - /** - * Creates a mapping function with a cache. - * This is the main entrypoint for this object. - * @static - * @method create - * @param {function} mappingFunction mapping - * @return {function} memoized mapping function - */ - CachedMap.create = function create(mappingFunction) { - var instance = new CachedMap(mappingFunction); - return instance.get.bind(instance); - }; - - /** - * Retrieve items from cache or from mapping functin. - * - * @method get - * @param {Object} input input key - */ - CachedMap.prototype.get = function get(input) { - if (input !== this._cachedInput) { - this._cachedInput = input; - this._cachedOutput = this._map(input); - } - return this._cachedOutput; - }; - - module.exports = CachedMap; -}); - -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. - * - * Owner: david@famo.us - * @license MPL 2.0 - * @copyright Famous Industries, Inc. 2014 - */ - -define('famous/transitions/Easing',['require','exports','module'],function(require, exports, module) { - - /* - * A library of curves which map an animation explicitly as a function of time. - * - * @class Easing - */ - var Easing = { - - /** - * @property inQuad - * @static - */ - inQuad: function(t) { - return t*t; - }, - - /** - * @property outQuad - * @static - */ - outQuad: function(t) { - return -(t-=1)*t+1; - }, - - /** - * @property inOutQuad - * @static - */ - inOutQuad: function(t) { - if ((t/=.5) < 1) return .5*t*t; - return -.5*((--t)*(t-2) - 1); - }, - - /** - * @property inCubic - * @static - */ - inCubic: function(t) { - return t*t*t; - }, - - /** - * @property outCubic - * @static - */ - outCubic: function(t) { - return ((--t)*t*t + 1); - }, - - /** - * @property inOutCubic - * @static - */ - inOutCubic: function(t) { - if ((t/=.5) < 1) return .5*t*t*t; - return .5*((t-=2)*t*t + 2); - }, - - /** - * @property inQuart - * @static - */ - inQuart: function(t) { - return t*t*t*t; - }, - - /** - * @property outQuart - * @static - */ - outQuart: function(t) { - return -((--t)*t*t*t - 1); - }, - - /** - * @property inOutQuart - * @static - */ - inOutQuart: function(t) { - if ((t/=.5) < 1) return .5*t*t*t*t; - return -.5 * ((t-=2)*t*t*t - 2); - }, - - /** - * @property inQuint - * @static - */ - inQuint: function(t) { - return t*t*t*t*t; - }, - - /** - * @property outQuint - * @static - */ - outQuint: function(t) { - return ((--t)*t*t*t*t + 1); - }, - - /** - * @property inOutQuint - * @static - */ - inOutQuint: function(t) { - if ((t/=.5) < 1) return .5*t*t*t*t*t; - return .5*((t-=2)*t*t*t*t + 2); - }, - - /** - * @property inSine - * @static - */ - inSine: function(t) { - return -1.0*Math.cos(t * (Math.PI/2)) + 1.0; - }, - - /** - * @property outSine - * @static - */ - outSine: function(t) { - return Math.sin(t * (Math.PI/2)); - }, - - /** - * @property inOutSine - * @static - */ - inOutSine: function(t) { - return -.5*(Math.cos(Math.PI*t) - 1); - }, - - /** - * @property inExpo - * @static - */ - inExpo: function(t) { - return (t===0) ? 0.0 : Math.pow(2, 10 * (t - 1)); - }, - - /** - * @property outExpo - * @static - */ - outExpo: function(t) { - return (t===1.0) ? 1.0 : (-Math.pow(2, -10 * t) + 1); - }, - - /** - * @property inOutExpo - * @static - */ - inOutExpo: function(t) { - if (t===0) return 0.0; - if (t===1.0) return 1.0; - if ((t/=.5) < 1) return .5 * Math.pow(2, 10 * (t - 1)); - return .5 * (-Math.pow(2, -10 * --t) + 2); - }, - - /** - * @property inCirc - * @static - */ - inCirc: function(t) { - return -(Math.sqrt(1 - t*t) - 1); - }, - - /** - * @property outCirc - * @static - */ - outCirc: function(t) { - return Math.sqrt(1 - (--t)*t); - }, - - /** - * @property inOutCirc - * @static - */ - inOutCirc: function(t) { - if ((t/=.5) < 1) return -.5 * (Math.sqrt(1 - t*t) - 1); - return .5 * (Math.sqrt(1 - (t-=2)*t) + 1); - }, - - /** - * @property inElastic - * @static - */ - inElastic: function(t) { - var s=1.70158;var p=0;var a=1.0; - if (t===0) return 0.0; if (t===1) return 1.0; if (!p) p=.3; - s = p/(2*Math.PI) * Math.asin(1.0/a); - return -(a*Math.pow(2,10*(t-=1)) * Math.sin((t-s)*(2*Math.PI)/ p)); - }, - - /** - * @property outElastic - * @static - */ - outElastic: function(t) { - var s=1.70158;var p=0;var a=1.0; - if (t===0) return 0.0; if (t===1) return 1.0; if (!p) p=.3; - s = p/(2*Math.PI) * Math.asin(1.0/a); - return a*Math.pow(2,-10*t) * Math.sin((t-s)*(2*Math.PI)/p) + 1.0; - }, - - /** - * @property inOutElastic - * @static - */ - inOutElastic: function(t) { - var s=1.70158;var p=0;var a=1.0; - if (t===0) return 0.0; if ((t/=.5)===2) return 1.0; if (!p) p=(.3*1.5); - s = p/(2*Math.PI) * Math.asin(1.0/a); - if (t < 1) return -.5*(a*Math.pow(2,10*(t-=1)) * Math.sin((t-s)*(2*Math.PI)/p)); - return a*Math.pow(2,-10*(t-=1)) * Math.sin((t-s)*(2*Math.PI)/p)*.5 + 1.0; - }, - - /** - * @property inBack - * @static - */ - inBack: function(t, s) { - if (s === undefined) s = 1.70158; - return t*t*((s+1)*t - s); - }, - - /** - * @property outBack - * @static - */ - outBack: function(t, s) { - if (s === undefined) s = 1.70158; - return ((--t)*t*((s+1)*t + s) + 1); - }, - - /** - * @property inOutBack - * @static - */ - inOutBack: function(t, s) { - if (s === undefined) s = 1.70158; - if ((t/=.5) < 1) return .5*(t*t*(((s*=(1.525))+1)*t - s)); - return .5*((t-=2)*t*(((s*=(1.525))+1)*t + s) + 2); - }, - - /** - * @property inBounce - * @static - */ - inBounce: function(t) { - return 1.0 - Easing.outBounce(1.0-t); - }, - - /** - * @property outBounce - * @static - */ - outBounce: function(t) { - if (t < (1/2.75)) { - return (7.5625*t*t); - } else if (t < (2/2.75)) { - return (7.5625*(t-=(1.5/2.75))*t + .75); - } else if (t < (2.5/2.75)) { - return (7.5625*(t-=(2.25/2.75))*t + .9375); - } else { - return (7.5625*(t-=(2.625/2.75))*t + .984375); - } - }, - - /** - * @property inOutBounce - * @static - */ - inOutBounce: function(t) { - if (t < .5) return Easing.inBounce(t*2) * .5; - return Easing.outBounce(t*2-1.0) * .5 + .5; - } - }; - - module.exports = Easing; -}); - -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. - * - * Owner: david@famo.us - * @license MPL 2.0 - * @copyright Famous Industries, Inc. 2014 - */ - -define('famous/physics/integrators/SymplecticEuler',['require','exports','module','famous/core/OptionsManager'],function(require, exports, module) { - var OptionsManager = require('famous/core/OptionsManager'); - - /** - * Ordinary Differential Equation (ODE) Integrator. - * Manages updating a physics body's state over time. - * - * p = position, v = velocity, m = mass, f = force, dt = change in time - * - * v <- v + dt * f / m - * p <- p + dt * v - * - * q = orientation, w = angular velocity, L = angular momentum - * - * L <- L + dt * t - * q <- q + dt/2 * q * w - * - * @class SymplecticEuler - * @constructor - * @param {Object} options Options to set - */ - function SymplecticEuler(options) { - this.options = Object.create(SymplecticEuler.DEFAULT_OPTIONS); - this._optionsManager = new OptionsManager(this.options); - - 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. - * v <- v + dt * f / m - * - * @method integrateVelocity - * @param {Body} physics body - * @param {Number} dt delta time - */ - SymplecticEuler.prototype.integrateVelocity = function integrateVelocity(body, dt) { - var v = body.velocity; - var w = body.inverseMass; - var f = body.force; - - if (f.isZero()) return; - - v.add(f.mult(dt * w)).put(v); - f.clear(); - }; - - /* - * Updates the position of a physics body from its velocity. - * p <- p + dt * v - * - * @method integratePosition - * @param {Body} physics body - * @param {Number} dt delta time - */ - SymplecticEuler.prototype.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); - }; - - /* - * Updates the angular momentum of a physics body from its accumuled torque. - * L <- L + dt * t - * - * @method integrateAngularMomentum - * @param {Body} physics body (except a particle) - * @param {Number} dt delta time - */ - SymplecticEuler.prototype.integrateAngularMomentum = function integrateAngularMomentum(body, dt) { - var L = body.angularMomentum; - var t = body.torque; - - if (t.isZero()) return; - - if (this.options.angularVelocityCap) t.cap(this.options.angularVelocityCap).put(t); - L.add(t.mult(dt)).put(L); - t.clear(); - }; - - /* - * Updates the orientation of a physics body from its angular velocity. - * q <- q + dt/2 * q * w - * - * @method integrateOrientation - * @param {Body} physics body (except a particle) - * @param {Number} dt delta time - */ - SymplecticEuler.prototype.integrateOrientation = function integrateOrientation(body, dt) { - var q = body.orientation; - var w = body.angularVelocity; - - if (w.isZero()) return; - q.add(q.multiply(w).scalarMultiply(0.5 * dt)).put(q); -// q.normalize.put(q); - }; - - module.exports = SymplecticEuler; -}); - -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. - * - * Owner: david@famo.us - * @license MPL 2.0 - * @copyright Famous Industries, Inc. 2014 - */ - -define('famous/physics/bodies/Particle',['require','exports','module','famous/math/Vector','famous/core/Transform','famous/core/EventHandler','../integrators/SymplecticEuler'],function(require, exports, module) { - var Vector = require('famous/math/Vector'); - var Transform = require('famous/core/Transform'); - var EventHandler = require('famous/core/EventHandler'); - var Integrator = require('../integrators/SymplecticEuler'); - - /** - * A point body that is controlled by the Physics Engine. A particle has - * 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. - * - * @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 - * - */ - function Particle(options) { - options = options || {}; - - // registers - this.position = new Vector(); - this.velocity = new Vector(); - this.force = new Vector(); - - var defaults = Particle.DEFAULT_OPTIONS; - - // set vectors - this.setPosition(options.position || defaults.position); - this.setVelocity(options.velocity || defaults.velocity); - this.force.set(options.force || [0,0,0]); - - // set scalars - this.mass = (options.mass !== undefined) - ? options.mass - : defaults.mass; - - 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; - - this.transform = Transform.identity.slice(); - - // cached _spec - this._spec = { - transform : this.transform, - target : null - }; - } - - Particle.DEFAULT_OPTIONS = { - position : [0,0,0], - velocity : [0,0,0], - mass : 1, - axis : undefined - }; - - /** - * Kinetic energy threshold needed to update the body - * - * @property SLEEP_TOLERANCE - * @type Number - * @static - * @default 1e-7 - */ - Particle.SLEEP_TOLERANCE = 1e-7; - - /** - * Axes by which a body can translate - * - * @property AXES - * @type Hexadecimal - * @static - * @default 1e-7 - */ - Particle.AXES = { - X : 0x00, // hexadecimal for 0 - Y : 0x01, // hexadecimal for 1 - Z : 0x02 // hexadecimal for 2 - }; - - // 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 - */ - Particle.prototype.sleep = function sleep() { - if (this._isSleeping) return; - this.emit(_events.end, this); - this._isSleeping = true; - }; - - /** - * Starts the particle update - * @method wake - */ - Particle.prototype.wake = function wake() { - if (!this._isSleeping) return; - this.emit(_events.start, this); - this._isSleeping = false; - this._prevTime = now(); - }; - - /** - * @attribute isBody - * @type Boolean - * @static - */ - Particle.prototype.isBody = false; - - /** - * Basic setter for position - * @method getPosition - * @param position {Array|Vector} - */ - Particle.prototype.setPosition = function setPosition(position) { - this.position.set(position); - }; - - /** - * 1-dimensional setter for position - * @method setPosition1D - * @param value {Number} - */ - Particle.prototype.setPosition1D = function setPosition1D(x) { - this.position.x = x; - }; - - /** - * Basic getter function for position - * @method getPosition - * @return position {Array} - */ - Particle.prototype.getPosition = function getPosition() { - if (this._positionGetter instanceof Function) - this.setPosition(this._positionGetter()); - - this._engine.step(); - - return this.position.get(); - }; - - /** - * 1-dimensional getter for position - * @method getPosition1D - * @return value {Number} - */ - Particle.prototype.getPosition1D = function getPosition1D() { - this._engine.step(); - return this.position.x; - }; - - /** - * 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 - * @function - */ - Particle.prototype.setVelocity = function setVelocity(velocity) { - this.velocity.set(velocity); - this.wake(); - }; - - /** - * 1-dimensional setter for velocity - * @method setVelocity1D - * @param velocity {Number} - */ - Particle.prototype.setVelocity1D = function setVelocity1D(x) { - this.velocity.x = x; - this.wake(); - }; - - /** - * Basic getter function for velocity Vector - * @method getVelocity - * @return velocity {Array} - */ - Particle.prototype.getVelocity = function getVelocity() { - return this.velocity.get(); - }; - - /** - * 1-dimensional getter for velocity - * @method getVelocity1D - * @return velocity {Number} - */ - Particle.prototype.getVelocity1D = function getVelocity1D() { - return this.velocity.x; - }; - - /** - * Basic setter function for mass quantity - * @method setMass - * @param mass {Number} mass - */ - Particle.prototype.setMass = function setMass(mass) { - this.mass = mass; - this.inverseMass = 1 / mass; - }; - - /** - * Basic getter function for mass quantity - * @method getMass - * @return mass {Number} - */ - Particle.prototype.getMass = function getMass() { - return this.mass; - }; - - /** - * Reset position and velocity - * @method reset - * @param position {Array|Vector} - * @param velocity {Array|Vector} - */ - Particle.prototype.reset = function reset(position, velocity) { - this.setPosition(position || [0,0,0]); - this.setVelocity(velocity || [0,0,0]); - }; - - /** - * Add force vector to existing internal force Vector - * @method applyForce - * @param force {Vector} - */ - Particle.prototype.applyForce = function applyForce(force) { - if (force.isZero()) return; - this.force.add(force).put(this.force); - this.wake(); - }; - - /** - * Add impulse (change in velocity) Vector to this Vector's velocity. - * @method applyImpulse - * @param impulse {Vector} - */ - Particle.prototype.applyImpulse = function applyImpulse(impulse) { - if (impulse.isZero()) return; - var velocity = this.velocity; - velocity.add(impulse.mult(this.inverseMass)).put(velocity); - }; - - /** - * Update a particle's velocity from its force accumulator - * @method integrateVelocity - * @param dt {Number} Time differential - */ - Particle.prototype.integrateVelocity = function integrateVelocity(dt) { - Particle.INTEGRATOR.integrateVelocity(this, dt); - }; - - /** - * Update a particle's position from its velocity - * @method integratePosition - * @param dt {Number} Time differential - */ - Particle.prototype.integratePosition = function integratePosition(dt) { - Particle.INTEGRATOR.integratePosition(this, dt); - }; - - /** - * Update the position and velocity of the particle - * @method _integrate - * @protected - * @param dt {Number} Time differential - */ - Particle.prototype._integrate = function _integrate(dt) { - this.integrateVelocity(dt); - this.integratePosition(dt); - }; - - /** - * Get kinetic energy of the particle. - * @method getEnergy - * @function - */ - Particle.prototype.getEnergy = function getEnergy() { - return 0.5 * this.mass * this.velocity.normSquared(); - }; - - /** - * Generate transform from the current position state - * @method getTransform - * @return Transform {Transform} - */ - Particle.prototype.getTransform = function getTransform() { - this._engine.step(); - - 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; - }; - - /** - * The modify interface of a Modifier - * @method modify - * @param target {Spec} - * @return Spec {Spec} - */ - Particle.prototype.modify = function modify(target) { - var _spec = this._spec; - _spec.transform = this.getTransform(); - _spec.target = target; - return _spec; - }; - - // private - function _createEventOutput() { - this._eventOutput = new EventHandler(); - this._eventOutput.bindThis(this); - //overrides on/removeListener/pipe/unpipe methods - EventHandler.setOutputHandler(this, this._eventOutput); - } - - Particle.prototype.emit = function emit(type, data) { - if (!this._eventOutput) return; - this._eventOutput.emit(type, data); - }; - - Particle.prototype.on = function on() { - _createEventOutput.call(this); - return this.on.apply(this, arguments); - }; - Particle.prototype.removeListener = function removeListener() { - _createEventOutput.call(this); - return this.removeListener.apply(this, arguments); - }; - Particle.prototype.pipe = function pipe() { - _createEventOutput.call(this); - return this.pipe.apply(this, arguments); - }; - Particle.prototype.unpipe = function unpipe() { - _createEventOutput.call(this); - return this.unpipe.apply(this, arguments); - }; - - module.exports = Particle; -}); - -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. - * - * Owner: david@famo.us - * @license MPL 2.0 - * @copyright Famous Industries, Inc. 2014 - */ - -define('famous/physics/constraints/Constraint',['require','exports','module','famous/core/EventHandler'],function(require, exports, module) { - var EventHandler = require('famous/core/EventHandler'); - - /** - * Allows for two circular bodies to collide and bounce off each other. - * - * @class Constraint - * @constructor - * @uses EventHandler - * @param options {Object} - */ - function Constraint() { - this.options = this.options || {}; - this._energy = 0.0; - this._eventOutput = null; - } - - /* - * Setter for options. - * - * @method setOptions - * @param options {Objects} - */ - Constraint.prototype.setOptions = function setOptions(options) { - for (var key in options) this.options[key] = options[key]; - }; - - /** - * Adds an impulse to a physics body's velocity due to the constraint - * - * @method applyConstraint - */ - Constraint.prototype.applyConstraint = function applyConstraint() {}; - - /** - * Getter for energy - * - * @method getEnergy - * @return energy {Number} - */ - Constraint.prototype.getEnergy = function getEnergy() { - return this._energy; - }; - - /** - * 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; -}); - -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. - * - * Owner: david@famo.us - * @license MPL 2.0 - * @copyright Famous Industries, Inc. 2014 - */ - -define('famous/physics/constraints/Snap',['require','exports','module','./Constraint','famous/math/Vector'],function(require, exports, module) { - var Constraint = require('./Constraint'); - var Vector = require('famous/math/Vector'); - - /** - * A spring constraint is like a spring force, except that it is always - * numerically stable (even for low periods), at the expense of introducing - * damping (even with dampingRatio set to 0). - * - * Use this if you need fast spring-like behavior, e.g., snapping - * - * @class Snap - * @constructor - * @extends Constraint - * @param {Options} [options] An object of configurable options. - * @param {Number} [options.period] The amount of time in milliseconds taken for one complete oscillation when there is no damping. Range : [150, Infinity] - * @param {Number} [options.dampingRatio] Additional damping of the spring. Range : [0, 1]. At 0 this spring will still be damped, at 1 the spring will be critically damped (the spring will never oscillate) - * @param {Number} [options.length] The rest length of the spring. Range: [0, Infinity]. - * @param {Array} [options.anchor] The location of the spring's anchor, if not another physics body. - * - */ - function Snap(options) { - this.options = Object.create(this.constructor.DEFAULT_OPTIONS); - if (options) this.setOptions(options); - - //registers - this.pDiff = new Vector(); - this.vDiff = new Vector(); - this.impulse1 = new Vector(); - this.impulse2 = new Vector(); - - Constraint.call(this); - } - - Snap.prototype = Object.create(Constraint.prototype); - Snap.prototype.constructor = Snap; - - Snap.DEFAULT_OPTIONS = { - period : 300, - dampingRatio : 0.1, - length : 0, - anchor : undefined - }; - - /** const */ var pi = Math.PI; - - function _calcEnergy(impulse, disp, dt) { - return Math.abs(impulse.dot(disp)/dt); - } - - /** - * Basic options setter - * - * @method setOptions - * @param options {Objects} options - */ - Snap.prototype.setOptions = function setOptions(options) { - if (options.anchor !== undefined) { - if (options.anchor instanceof Vector) this.options.anchor = options.anchor; - if (options.anchor.position instanceof Vector) this.options.anchor = options.anchor.position; - if (options.anchor instanceof Array) this.options.anchor = new Vector(options.anchor); - } - if (options.length !== undefined) this.options.length = options.length; - if (options.dampingRatio !== undefined) this.options.dampingRatio = options.dampingRatio; - if (options.period !== undefined) this.options.period = options.period; - }; - - /** - * 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 - * @return energy {Number} - */ - Snap.prototype.getEnergy = function getEnergy(target, source) { - var options = this.options; - var restLength = options.length; - var anchor = options.anchor || source.position; - var strength = Math.pow(2 * pi / options.period, 2); - - var dist = anchor.sub(target.position).norm() - restLength; - - return 0.5 * strength * dist * dist; - }; - - /** - * Adds a spring impulse to a physics body's velocity due to the constraint - * - * @method applyConstraint - * @param targets {Array.Body} Array of bodies to apply the constraint to - * @param source {Body} The source of the constraint - * @param dt {Number} Delta time - */ - Snap.prototype.applyConstraint = function applyConstraint(targets, source, dt) { - var options = this.options; - var pDiff = this.pDiff; - var vDiff = this.vDiff; - var impulse1 = this.impulse1; - var impulse2 = this.impulse2; - var length = options.length; - var anchor = options.anchor || source.position; - var period = options.period; - var dampingRatio = options.dampingRatio; - - for (var i = 0; i < targets.length ; i++) { - var target = targets[i]; - - var p1 = target.position; - var v1 = target.velocity; - var m1 = target.mass; - var w1 = target.inverseMass; - - pDiff.set(p1.sub(anchor)); - var dist = pDiff.norm() - length; - var effMass; - - if (source) { - var w2 = source.inverseMass; - var v2 = source.velocity; - vDiff.set(v1.sub(v2)); - effMass = 1/(w1 + w2); - } - else { - vDiff.set(v1); - effMass = m1; - } - - var gamma; - var beta; - - if (this.options.period === 0) { - gamma = 0; - beta = 1; - } - else { - var k = 4 * effMass * pi * pi / (period * period); - var c = 4 * effMass * pi * dampingRatio / period; - - beta = dt * k / (c + dt * k); - gamma = 1 / (c + dt*k); - } - - var antiDrift = beta/dt * dist; - pDiff.normalize(-antiDrift) - .sub(vDiff) - .mult(dt / (gamma + dt/effMass)) - .put(impulse1); - - // var n = new Vector(); - // n.set(pDiff.normalize()); - // var lambda = -(n.dot(vDiff) + antiDrift) / (gamma + dt/effMass); - // impulse2.set(n.mult(dt*lambda)); - - target.applyImpulse(impulse1); - - if (source) { - impulse1.mult(-1).put(impulse2); - source.applyImpulse(impulse2); - } - - this.setEnergy(_calcEnergy(impulse1, pDiff, dt)); - } - }; - - module.exports = Snap; -}); - -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. - * - * Owner: david@famo.us - * @license MPL 2.0 - * @copyright Famous Industries, Inc. 2014 - */ - -define('famous/transitions/SnapTransition',['require','exports','module','famous/physics/PhysicsEngine','famous/physics/bodies/Particle','famous/physics/constraints/Snap','famous/math/Vector'],function(require, exports, module) { - var PE = require('famous/physics/PhysicsEngine'); - var Particle = require('famous/physics/bodies/Particle'); - var Spring = require('famous/physics/constraints/Snap'); - var Vector = require('famous/math/Vector'); - - /** - * SnapTransition is a method of transitioning between two values (numbers, - * or arrays of numbers). It is similar to SpringTransition except - * the transition can be much faster and always has a damping effect. - * - * @class SnapTransition - * @constructor - * - * @param [state=0] {Number|Array} Initial state - */ - function SnapTransition(state) { - state = state || 0; - - this.endState = new Vector(state); - this.initState = new Vector(); - - this._dimensions = 1; - this._restTolerance = 1e-10; - this._absRestTolerance = this._restTolerance; - this._callback = undefined; - - this.PE = new PE(); - this.particle = new Particle(); - this.spring = new Spring({anchor : this.endState}); - - this.PE.addBody(this.particle); - this.PE.attach(this.spring, this.particle); - } - - SnapTransition.SUPPORTS_MULTIPLE = 3; - - /** - * @property SnapTransition.DEFAULT_OPTIONS - * @type Object - * @protected - * @static - */ - SnapTransition.DEFAULT_OPTIONS = { - - /** - * The amount of time in milliseconds taken for one complete oscillation - * when there is no damping - * Range : [0, Infinity] - * - * @attribute period - * @type Number - * @default 100 - */ - period : 100, - - /** - * The damping of the snap. - * Range : [0, 1] - * - * @attribute dampingRatio - * @type Number - * @default 0.2 - */ - dampingRatio : 0.2, - - /** - * The initial velocity of the transition. - * - * @attribute velocity - * @type Number|Array - * @default 0 - */ - velocity : 0 - }; - - function _getEnergy() { - return this.particle.getEnergy() + this.spring.getEnergy(this.particle); - } - - function _setAbsoluteRestTolerance() { - var distance = this.endState.sub(this.initState).normSquared(); - this._absRestTolerance = (distance === 0) - ? this._restTolerance - : this._restTolerance * distance; - } - - function _setTarget(target) { - this.endState.set(target); - _setAbsoluteRestTolerance.call(this); - } - - function _wake() { - this.PE.wake(); - } - - function _sleep() { - this.PE.sleep(); - } - - function _setParticlePosition(p) { - this.particle.position.set(p); - } - - function _setParticleVelocity(v) { - this.particle.velocity.set(v); - } - - function _getParticlePosition() { - return (this._dimensions === 0) - ? this.particle.getPosition1D() - : this.particle.getPosition(); - } - - function _getParticleVelocity() { - return (this._dimensions === 0) - ? this.particle.getVelocity1D() - : this.particle.getVelocity(); - } - - function _setCallback(callback) { - this._callback = callback; - } - - function _setupDefinition(definition) { - var defaults = SnapTransition.DEFAULT_OPTIONS; - if (definition.period === undefined) definition.period = defaults.period; - if (definition.dampingRatio === undefined) definition.dampingRatio = defaults.dampingRatio; - if (definition.velocity === undefined) definition.velocity = defaults.velocity; - - //setup spring - this.spring.setOptions({ - period : definition.period, - dampingRatio : definition.dampingRatio - }); - - //setup particle - _setParticleVelocity.call(this, definition.velocity); - } - - function _update() { - if (this.PE.isSleeping()) { - if (this._callback) { - var cb = this._callback; - this._callback = undefined; - cb(); - } - return; - } - - if (_getEnergy.call(this) < this._absRestTolerance) { - _setParticlePosition.call(this, this.endState); - _setParticleVelocity.call(this, [0,0,0]); - _sleep.call(this); - } - } - - /** - * Resets the state and velocity - * - * @method reset - * - * @param state {Number|Array} State - * @param [velocity] {Number|Array} Velocity - */ - SnapTransition.prototype.reset = function reset(state, velocity) { - this._dimensions = (state instanceof Array) - ? state.length - : 0; - - this.initState.set(state); - _setParticlePosition.call(this, state); - _setTarget.call(this, state); - if (velocity) _setParticleVelocity.call(this, velocity); - _setCallback.call(this, undefined); - }; - - /** - * Getter for velocity - * - * @method getVelocity - * - * @return velocity {Number|Array} - */ - SnapTransition.prototype.getVelocity = function getVelocity() { - return _getParticleVelocity.call(this); - }; - - /** - * Setter for velocity - * - * @method setVelocity - * - * @return velocity {Number|Array} - */ - SnapTransition.prototype.setVelocity = function setVelocity(velocity) { - this.call(this, _setParticleVelocity(velocity)); - }; - - /** - * Detects whether a transition is in progress - * - * @method isActive - * - * @return {Boolean} - */ - SnapTransition.prototype.isActive = function isActive() { - return !this.PE.isSleeping(); - }; - - /** - * Halt the transition - * - * @method halt - */ - SnapTransition.prototype.halt = function halt() { - this.set(this.get()); - }; - - /** - * Get the current position of the transition -s * - * @method get - * - * @return state {Number|Array} - */ - SnapTransition.prototype.get = function get() { - _update.call(this); - return _getParticlePosition.call(this); - }; - - /** - * Set the end position and transition, with optional callback on completion. - * - * @method set - * - * @param state {Number|Array} Final state - * @param [definition] {Object} Transition definition - * @param [callback] {Function} Callback - */ - SnapTransition.prototype.set = function set(state, definition, callback) { - if (!definition) { - this.reset(state); - if (callback) callback(); - return; - } - - this._dimensions = (state instanceof Array) - ? state.length - : 0; - - _wake.call(this); - _setupDefinition.call(this, definition); - _setTarget.call(this, state); - _setCallback.call(this, callback); - }; - - module.exports = SnapTransition; -}); - -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. - * - * Owner: david@famo.us - * @license MPL 2.0 - * @copyright Famous Industries, Inc. 2014 - */ - -define('famous/physics/forces/Force',['require','exports','module','famous/math/Vector','famous/core/EventHandler'],function(require, exports, module) { - var Vector = require('famous/math/Vector'); - var EventHandler = require('famous/core/EventHandler'); - - /** - * Force base class. - * - * @class Force - * @uses EventHandler - * @constructor - */ - function Force(force) { - this.force = new Vector(force); - this._energy = 0.0; - this._eventOutput = null; - } - - /** - * Basic setter for options - * - * @method setOptions - * @param options {Objects} - */ - Force.prototype.setOptions = function setOptions(options) { - for (var key in options) this.options[key] = options[key]; - }; - - /** - * Adds a force to a physics body's force accumulator. - * - * @method applyForce - * @param body {Body} - */ - Force.prototype.applyForce = function applyForce(body) { - body.applyForce(this.force); - }; - - /** - * Getter for a force's potential energy. - * - * @method getEnergy - * @return energy {Number} - */ - Force.prototype.getEnergy = function getEnergy() { - return this._energy; - }; - - /* - * 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; -}); - -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. - * - * Owner: david@famo.us - * @license MPL 2.0 - * @copyright Famous Industries, Inc. 2014 - */ - -define('famous/physics/forces/Spring',['require','exports','module','./Force','famous/math/Vector'],function(require, exports, module) { - var Force = require('./Force'); - var Vector = require('famous/math/Vector'); - - /** - * A force that moves a physics body to a location with a spring motion. - * The body can be moved to another physics body, or an anchor point. - * - * @class Spring - * @constructor - * @extends Force - * @param {Object} options options to set on drag - */ - function Spring(options) { - this.options = Object.create(this.constructor.DEFAULT_OPTIONS); - if (options) this.setOptions(options); - - //registers - this.disp = new Vector(0,0,0); - - _init.call(this); - Force.call(this); - } - - Spring.prototype = Object.create(Force.prototype); - Spring.prototype.constructor = Spring; - - /** @const */ var pi = Math.PI; - - /** - * @property Spring.FORCE_FUNCTIONS - * @type Object - * @protected - * @static - */ - Spring.FORCE_FUNCTIONS = { - - /** - * A FENE (Finitely Extensible Nonlinear Elastic) spring force - * see: http://en.wikipedia.org/wiki/FENE - * @attribute FENE - * @type Function - * @param {Number} dist current distance target is from source body - * @param {Number} rMax maximum range of influence - * @return {Number} unscaled force - */ - FENE : function(dist, rMax) { - var rMaxSmall = rMax * .99; - var r = Math.max(Math.min(dist, rMaxSmall), -rMaxSmall); - return r / (1 - r * r/(rMax * rMax)); - }, - - /** - * A Hookean spring force, linear in the displacement - * see: http://en.wikipedia.org/wiki/FENE - * @attribute FENE - * @type Function - * @param {Number} dist current distance target is from source body - * @return {Number} unscaled force - */ - HOOK : function(dist) { - return dist; - } - }; - - /** - * @property Spring.DEFAULT_OPTIONS - * @type Object - * @protected - * @static - */ - Spring.DEFAULT_OPTIONS = { - - /** - * The amount of time in milliseconds taken for one complete oscillation - * when there is no damping - * Range : [150, Infinity] - * @attribute period - * @type Number - * @default 300 - */ - period : 300, - - /** - * The damping of the spring. - * Range : [0, 1] - * 0 = no damping, and the spring will oscillate forever - * 1 = critically damped (the spring will never oscillate) - * @attribute dampingRatio - * @type Number - * @default 0.1 - */ - dampingRatio : 0.1, - - /** - * The rest length of the spring - * Range : [0, Infinity] - * @attribute length - * @type Number - * @default 0 - */ - length : 0, - - /** - * The maximum length of the spring (for a FENE spring) - * Range : [0, Infinity] - * @attribute length - * @type Number - * @default Infinity - */ - maxLength : Infinity, - - /** - * The location of the spring's anchor, if not another physics body - * - * @attribute anchor - * @type Array - * @optional - */ - anchor : undefined, - - /** - * The type of spring force - * @attribute forceFunction - * @type Function - */ - forceFunction : Spring.FORCE_FUNCTIONS.HOOK - }; - - function _setForceFunction(fn) { - this.forceFunction = fn; - } - - 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 _calcEnergy(strength, dist) { - return 0.5 * strength * dist * dist; - } - - function _init() { - _setForceFunction.call(this, this.options.forceFunction); - _calcStiffness.call(this); - _calcDamping.call(this); - } - - /** - * Basic options setter - * - * @method setOptions - * @param options {Objects} - */ - Spring.prototype.setOptions = function setOptions(options) { - 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.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); - }; - - /** - * Adds a spring force to a physics body's force accumulator. - * - * @method applyForce - * @param targets {Array.Body} Array of bodies to apply force to. - */ - Spring.prototype.applyForce = function applyForce(targets, source) { - 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; - - for (var i = 0; i < targets.length; i++) { - var target = targets[i]; - var p2 = target.position; - var v2 = target.velocity; - - anchor.sub(p2).put(disp); - var dist = disp.norm() - restLength; - - if (dist === 0) return; - - //if dampingRatio specified, then override strength and damping - var m = target.mass; - stiffness *= m; - damping *= m; - - disp.normalize(stiffness * this.forceFunction(dist, lMax)) - .put(force); - - if (damping) - if (source) force.add(v2.sub(source.velocity).mult(-damping)).put(force); - else force.add(v2.mult(-damping)).put(force); - - target.applyForce(force); - if (source) source.applyForce(force.mult(-1)); - - this.setEnergy(_calcEnergy(stiffness, dist)); - } - }; - - /** - * Calculates the potential energy of the spring. - * - * @method getEnergy - * @param target {Body} The physics body attached to the spring - * @return energy {Number} - */ - Spring.prototype.getEnergy = function getEnergy(target) { - var options = this.options; - var restLength = options.length; - var anchor = options.anchor; - var strength = options.stiffness; - - var dist = anchor.sub(target.position).norm() - restLength; - return 0.5 * strength * dist * dist; - }; - - /** - * 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; -}); - -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. - * - * Owner: david@famo.us - * @license MPL 2.0 - * @copyright Famous Industries, Inc. 2014 - */ - -/*global console*/ - -define('famous/transitions/SpringTransition',['require','exports','module','famous/physics/PhysicsEngine','famous/physics/bodies/Particle','famous/physics/forces/Spring','famous/math/Vector'],function(require, exports, module) { - var PE = require('famous/physics/PhysicsEngine'); - var Particle = require('famous/physics/bodies/Particle'); - var Spring = require('famous/physics/forces/Spring'); - var Vector = require('famous/math/Vector'); - - /** - * SpringTransition is a method of transitioning between two values (numbers, - * or arrays of numbers) with a bounce. The transition will overshoot the target - * state depending on the parameters of the transition. - * - * @class SpringTransition - * @constructor - * - * @param {Number|Array} [state=0] Initial state - */ - function SpringTransition(state) { - state = state || 0; - this.endState = new Vector(state); - this.initState = new Vector(); - - this._dimensions = undefined; - this._restTolerance = 1e-10; - this._absRestTolerance = this._restTolerance; - this._callback = undefined; - - this.PE = new PE(); - this.spring = new Spring({anchor : this.endState}); - this.particle = new Particle(); - - this.PE.addBody(this.particle); - this.PE.attach(this.spring, this.particle); - } - - SpringTransition.SUPPORTS_MULTIPLE = 3; - - /** - * @property SpringTransition.DEFAULT_OPTIONS - * @type Object - * @protected - * @static - */ - SpringTransition.DEFAULT_OPTIONS = { - - /** - * The amount of time in milliseconds taken for one complete oscillation - * when there is no damping - * Range : [0, Infinity] - * - * @attribute period - * @type Number - * @default 300 - */ - period : 300, - - /** - * The damping of the snap. - * Range : [0, 1] - * 0 = no damping, and the spring will oscillate forever - * 1 = critically damped (the spring will never oscillate) - * - * @attribute dampingRatio - * @type Number - * @default 0.5 - */ - dampingRatio : 0.5, - - /** - * The initial velocity of the transition. - * - * @attribute velocity - * @type Number|Array - * @default 0 - */ - velocity : 0 - }; - - function _getEnergy() { - return this.particle.getEnergy() + this.spring.getEnergy(this.particle); - } - - function _setParticlePosition(p) { - this.particle.setPosition(p); - } - - function _setParticleVelocity(v) { - this.particle.setVelocity(v); - } - - function _getParticlePosition() { - return (this._dimensions === 0) - ? this.particle.getPosition1D() - : this.particle.getPosition(); - } - - function _getParticleVelocity() { - return (this._dimensions === 0) - ? this.particle.getVelocity1D() - : this.particle.getVelocity(); - } - - function _setCallback(callback) { - this._callback = callback; - } - - function _wake() { - this.PE.wake(); - } - - function _sleep() { - this.PE.sleep(); - } - - function _update() { - if (this.PE.isSleeping()) { - if (this._callback) { - var cb = this._callback; - this._callback = undefined; - cb(); - } - return; - } - - if (_getEnergy.call(this) < this._absRestTolerance) { - _setParticlePosition.call(this, this.endState); - _setParticleVelocity.call(this, [0,0,0]); - _sleep.call(this); - } - } - - function _setupDefinition(definition) { - // TODO fix no-console error - /* eslint no-console: 0 */ - var defaults = SpringTransition.DEFAULT_OPTIONS; - if (definition.period === undefined) definition.period = defaults.period; - if (definition.dampingRatio === undefined) definition.dampingRatio = defaults.dampingRatio; - if (definition.velocity === undefined) definition.velocity = defaults.velocity; - - if (definition.period < 150) { - definition.period = 150; - console.warn('The period of a SpringTransition is capped at 150 ms. Use a SnapTransition for faster transitions'); - } - - //setup spring - this.spring.setOptions({ - period : definition.period, - dampingRatio : definition.dampingRatio - }); - - //setup particle - _setParticleVelocity.call(this, definition.velocity); - } - - function _setAbsoluteRestTolerance() { - var distance = this.endState.sub(this.initState).normSquared(); - this._absRestTolerance = (distance === 0) - ? this._restTolerance - : this._restTolerance * distance; - } - - function _setTarget(target) { - this.endState.set(target); - _setAbsoluteRestTolerance.call(this); - } - - /** - * Resets the position and velocity - * - * @method reset - * - * @param {Number|Array.Number} pos positional state - * @param {Number|Array} vel velocity - */ - SpringTransition.prototype.reset = function reset(pos, vel) { - this._dimensions = (pos instanceof Array) - ? pos.length - : 0; - - this.initState.set(pos); - _setParticlePosition.call(this, pos); - _setTarget.call(this, pos); - if (vel) _setParticleVelocity.call(this, vel); - _setCallback.call(this, undefined); - }; - - /** - * Getter for velocity - * - * @method getVelocity - * - * @return {Number|Array} velocity - */ - SpringTransition.prototype.getVelocity = function getVelocity() { - return _getParticleVelocity.call(this); - }; - - /** - * Setter for velocity - * - * @method setVelocity - * - * @return {Number|Array} velocity - */ - SpringTransition.prototype.setVelocity = function setVelocity(v) { - this.call(this, _setParticleVelocity(v)); - }; - - /** - * Detects whether a transition is in progress - * - * @method isActive - * - * @return {Boolean} - */ - SpringTransition.prototype.isActive = function isActive() { - return !this.PE.isSleeping(); - }; - - /** - * Halt the transition - * - * @method halt - */ - SpringTransition.prototype.halt = function halt() { - this.set(this.get()); - }; - - /** - * Get the current position of the transition - * - * @method get - * - * @return {Number|Array} state - */ - SpringTransition.prototype.get = function get() { - _update.call(this); - return _getParticlePosition.call(this); - }; - - /** - * Set the end position and transition, with optional callback on completion. - * - * @method set - * - * @param {Number|Array} endState Final state - * @param {Object} definition Transition definition - * @param {Function} callback Callback - */ - SpringTransition.prototype.set = function set(endState, definition, callback) { - if (!definition) { - this.reset(endState); - if (callback) callback(); - return; - } - - this._dimensions = (endState instanceof Array) - ? endState.length - : 0; - - _wake.call(this); - _setupDefinition.call(this, definition); - _setTarget.call(this, endState); - _setCallback.call(this, callback); - }; - - module.exports = SpringTransition; -}); - -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. - * - * Owner: david@famo.us - * @license MPL 2.0 - * @copyright Famous Industries, Inc. 2014 - */ - -define('famous/physics/constraints/Wall',['require','exports','module','./Constraint','famous/math/Vector'],function(require, exports, module) { - var Constraint = require('./Constraint'); - var Vector = require('famous/math/Vector'); - - /** - * A wall describes an infinite two-dimensional plane that physics bodies - * can collide with. To define a wall, you must give it a distance (from - * the center of the physics engine's origin, and a normal defining the plane - * of the wall. - * - * (wall) - * | - * | (normal) (origin) - * | ---> * - * | - * | (distance) - * ................... - * (100px) - * - * e.g., Wall({normal : [1,0,0], distance : 100}) - * would be a wall 100 pixels to the left, whose normal points right - * - * @class Wall - * @constructor - * @extends Constraint - * @param {Options} [options] An object of configurable options. - * @param {Number} [options.restitution] The energy ratio lost in a collision (0 = stick, 1 = elastic). Range : [0, 1] - * @param {Number} [options.drift] Baumgarte stabilization parameter. Makes constraints "loosely" (0) or "tightly" (1) enforced. Range : [0, 1] - * @param {Number} [options.slop] Amount of penetration in pixels to ignore before collision event triggers. - * @param {Array} [options.normal] The normal direction to the wall. - * @param {Number} [options.distance] The distance from the origin that the wall is placed. - * @param {onContact} [options.onContact] How to handle collision against the wall. - * - */ - function Wall(options) { - this.options = Object.create(Wall.DEFAULT_OPTIONS); - if (options) this.setOptions(options); - - //registers - this.diff = new Vector(); - this.impulse = new Vector(); - - Constraint.call(this); - } - - Wall.prototype = Object.create(Constraint.prototype); - Wall.prototype.constructor = Wall; - - /** - * @property Wall.ON_CONTACT - * @type Object - * @protected - * @static - */ - Wall.ON_CONTACT = { - - /** - * Physical bodies bounce off the wall - * @attribute REFLECT - */ - REFLECT : 0, - - /** - * Physical bodies are unaffected. Usecase is to fire events on contact. - * @attribute SILENT - */ - SILENT : 1 - }; - - Wall.DEFAULT_OPTIONS = { - restitution : 0.5, - drift : 0.5, - slop : 0, - normal : [1, 0, 0], - distance : 0, - onContact : Wall.ON_CONTACT.REFLECT - }; - - /* - * Setter for options. - * - * @method setOptions - * @param options {Objects} - */ - Wall.prototype.setOptions = function setOptions(options) { - if (options.normal !== undefined) { - if (options.normal instanceof Vector) this.options.normal = options.normal.clone(); - if (options.normal instanceof Array) this.options.normal = new Vector(options.normal); - } - if (options.restitution !== undefined) this.options.restitution = options.restitution; - if (options.drift !== undefined) this.options.drift = options.drift; - if (options.slop !== undefined) this.options.slop = options.slop; - if (options.distance !== undefined) this.options.distance = options.distance; - if (options.onContact !== undefined) this.options.onContact = options.onContact; - }; - - function _getNormalVelocity(n, v) { - return v.dot(n); - } - - function _getDistanceFromOrigin(p) { - var n = this.options.normal; - var d = this.options.distance; - return p.dot(n) + d; - } - - function _onEnter(particle, overlap, dt) { - var p = particle.position; - var v = particle.velocity; - var m = particle.mass; - var n = this.options.normal; - var action = this.options.onContact; - var restitution = this.options.restitution; - var impulse = this.impulse; - - var drift = this.options.drift; - var slop = -this.options.slop; - var gamma = 0; - - if (this._eventOutput) { - var data = {particle : particle, wall : this, overlap : overlap, normal : n}; - this._eventOutput.emit('preCollision', data); - this._eventOutput.emit('collision', data); - } - - switch (action) { - case Wall.ON_CONTACT.REFLECT: - var lambda = (overlap < slop) - ? -((1 + restitution) * n.dot(v) + drift / dt * (overlap - slop)) / (m * dt + gamma) - : -((1 + restitution) * n.dot(v)) / (m * dt + gamma); - - impulse.set(n.mult(dt * lambda)); - particle.applyImpulse(impulse); - particle.setPosition(p.add(n.mult(-overlap))); - break; - } - - if (this._eventOutput) this._eventOutput.emit('postCollision', data); - } - - function _onExit(particle, overlap, dt) { - var action = this.options.onContact; - var p = particle.position; - var n = this.options.normal; - - if (action === Wall.ON_CONTACT.REFLECT) { - particle.setPosition(p.add(n.mult(-overlap))); - } - } - - /** - * Adds an impulse to a physics body's velocity due to the wall constraint - * - * @method applyConstraint - * @param targets {Array.Body} Array of bodies to apply the constraint to - * @param source {Body} The source of the constraint - * @param dt {Number} Delta time - */ - Wall.prototype.applyConstraint = function applyConstraint(targets, source, dt) { - var n = this.options.normal; - - for (var i = 0; i < targets.length; i++) { - var particle = targets[i]; - var p = particle.position; - var v = particle.velocity; - var r = particle.radius || 0; - - var overlap = _getDistanceFromOrigin.call(this, p.add(n.mult(-r))); - var nv = _getNormalVelocity.call(this, n, v); - - if (overlap <= 0) { - if (nv < 0) _onEnter.call(this, particle, overlap, dt); - else _onExit.call(this, particle, overlap, dt); - } - } - }; - - module.exports = Wall; -}); - -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. - * - * Owner: david@famo.us - * @license MPL 2.0 - * @copyright Famous Industries, Inc. 2014 - */ - -define('famous/transitions/WallTransition',['require','exports','module','famous/physics/PhysicsEngine','famous/physics/bodies/Particle','famous/physics/forces/Spring','famous/physics/constraints/Wall','famous/math/Vector'],function(require, exports, module) { - var PE = require('famous/physics/PhysicsEngine'); - var Particle = require('famous/physics/bodies/Particle'); - var Spring = require('famous/physics/forces/Spring'); - var Wall = require('famous/physics/constraints/Wall'); - var Vector = require('famous/math/Vector'); - - /** - * WallTransition is a method of transitioning between two values (numbers, - * or arrays of numbers) with a bounce. Unlike a SpringTransition - * The transition will not overshoot the target, but bounce back against it. - * The behavior of the bounce is specified by the transition options. - * - * @class WallTransition - * @constructor - * - * @param {Number|Array} [state=0] Initial state - */ - function WallTransition(state) { - state = state || 0; - - this.endState = new Vector(state); - this.initState = new Vector(); - - this.spring = new Spring({anchor : this.endState}); - this.wall = new Wall(); - - this._restTolerance = 1e-10; - this._dimensions = 1; - this._absRestTolerance = this._restTolerance; - this._callback = undefined; - - this.PE = new PE(); - this.particle = new Particle(); - - this.PE.addBody(this.particle); - this.PE.attach([this.wall, this.spring], this.particle); - } - - WallTransition.SUPPORTS_MULTIPLE = 3; - - /** - * @property WallTransition.DEFAULT_OPTIONS - * @type Object - * @protected - * @static - */ - WallTransition.DEFAULT_OPTIONS = { - - /** - * The amount of time in milliseconds taken for one complete oscillation - * when there is no damping - * Range : [0, Infinity] - * - * @attribute period - * @type Number - * @default 300 - */ - period : 300, - - /** - * The damping of the snap. - * Range : [0, 1] - * 0 = no damping, and the spring will oscillate forever - * 1 = critically damped (the spring will never oscillate) - * - * @attribute dampingRatio - * @type Number - * @default 0.5 - */ - dampingRatio : 0.5, - - /** - * The initial velocity of the transition. - * - * @attribute velocity - * @type Number|Array - * @default 0 - */ - velocity : 0, - - /** - * The percentage of momentum transferred to the wall - * - * @attribute restitution - * @type Number - * @default 0.5 - */ - resitution : 0.5 - }; - - function _getEnergy() { - return this.particle.getEnergy() + this.spring.getEnergy(this.particle); - } - - function _setAbsoluteRestTolerance() { - var distance = this.endState.sub(this.initState).normSquared(); - this._absRestTolerance = (distance === 0) - ? this._restTolerance - : this._restTolerance * distance; - } - - function _wake() { - this.PE.wake(); - } - - function _sleep() { - this.PE.sleep(); - } - - function _setTarget(target) { - this.endState.set(target); - - var dist = this.endState.sub(this.initState).norm(); - - this.wall.setOptions({ - distance : this.endState.norm(), - normal : (dist === 0) - ? this.particle.velocity.normalize(-1) - : this.endState.sub(this.initState).normalize(-1) - }); - - _setAbsoluteRestTolerance.call(this); - } - - function _setParticlePosition(p) { - this.particle.position.set(p); - } - - function _setParticleVelocity(v) { - this.particle.velocity.set(v); - } - - function _getParticlePosition() { - return (this._dimensions === 0) - ? this.particle.getPosition1D() - : this.particle.getPosition(); - } - - function _getParticleVelocity() { - return (this._dimensions === 0) - ? this.particle.getVelocity1D() - : this.particle.getVelocity(); - } - - function _setCallback(callback) { - this._callback = callback; - } - - function _update() { - if (this.PE.isSleeping()) { - if (this._callback) { - var cb = this._callback; - this._callback = undefined; - cb(); - } - return; - } - var energy = _getEnergy.call(this); - if (energy < this._absRestTolerance) { - _sleep.call(this); - _setParticlePosition.call(this, this.endState); - _setParticleVelocity.call(this, [0,0,0]); - } - } - - function _setupDefinition(def) { - var defaults = WallTransition.DEFAULT_OPTIONS; - if (def.period === undefined) def.period = defaults.period; - if (def.dampingRatio === undefined) def.dampingRatio = defaults.dampingRatio; - if (def.velocity === undefined) def.velocity = defaults.velocity; - if (def.restitution === undefined) def.restitution = defaults.restitution; - - //setup spring - this.spring.setOptions({ - period : def.period, - dampingRatio : def.dampingRatio - }); - - //setup wall - this.wall.setOptions({ - restitution : def.restitution - }); - - //setup particle - _setParticleVelocity.call(this, def.velocity); - } - - /** - * Resets the state and velocity - * - * @method reset - * - * @param {Number|Array} state State - * @param {Number|Array} [velocity] Velocity - */ - WallTransition.prototype.reset = function reset(state, velocity) { - this._dimensions = (state instanceof Array) - ? state.length - : 0; - - this.initState.set(state); - _setParticlePosition.call(this, state); - if (velocity) _setParticleVelocity.call(this, velocity); - _setTarget.call(this, state); - _setCallback.call(this, undefined); - }; - - /** - * Getter for velocity - * - * @method getVelocity - * - * @return velocity {Number|Array} - */ - WallTransition.prototype.getVelocity = function getVelocity() { - return _getParticleVelocity.call(this); - }; - - /** - * Setter for velocity - * - * @method setVelocity - * - * @return velocity {Number|Array} - */ - WallTransition.prototype.setVelocity = function setVelocity(velocity) { - this.call(this, _setParticleVelocity(velocity)); - }; - - /** - * Detects whether a transition is in progress - * - * @method isActive - * - * @return {Boolean} - */ - WallTransition.prototype.isActive = function isActive() { - return !this.PE.isSleeping(); - }; - - /** - * Halt the transition - * - * @method halt - */ - WallTransition.prototype.halt = function halt() { - this.set(this.get()); - }; - - /** - * Getter - * - * @method get - * - * @return state {Number|Array} - */ - WallTransition.prototype.get = function get() { - _update.call(this); - return _getParticlePosition.call(this); - }; - - /** - * Set the end position and transition, with optional callback on completion. - * - * @method set - * - * @param state {Number|Array} Final state - * @param [definition] {Object} Transition definition - * @param [callback] {Function} Callback - */ - WallTransition.prototype.set = function set(state, definition, callback) { - if (!definition) { - this.reset(state); - if (callback) callback(); - return; - } - - this._dimensions = (state instanceof Array) - ? state.length - : 0; - - _wake.call(this); - _setupDefinition.call(this, definition); - _setTarget.call(this, state); - _setCallback.call(this, callback); - }; - - module.exports = WallTransition; -}); - -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. - * - * Owner: mark@famo.us - * @license MPL 2.0 - * @copyright Famous Industries, Inc. 2014 - */ - -define('famous/surfaces/CanvasSurface',['require','exports','module','famous/core/Surface'],function(require, exports, module) { - var Surface = require('famous/core/Surface'); - - /** - * A surface containing an HTML5 Canvas element. - * This extends the Surface class. - * - * @class CanvasSurface - * @extends Surface - * @constructor - * @param {Object} [options] overrides of default options - * @param {Array.Number} [options.canvasSize] [width, height] for document element - */ - function CanvasSurface(options) { - if (options && options.canvasSize) this._canvasSize = options.canvasSize; - Surface.apply(this, arguments); - if (!this._canvasSize) this._canvasSize = this.getSize(); - this._backBuffer = document.createElement('canvas'); - if (this._canvasSize) { - this._backBuffer.width = this._canvasSize[0]; - this._backBuffer.height = this._canvasSize[1]; - } - this._contextId = undefined; - } - - CanvasSurface.prototype = Object.create(Surface.prototype); - CanvasSurface.prototype.constructor = CanvasSurface; - CanvasSurface.prototype.elementType = 'canvas'; - CanvasSurface.prototype.elementClass = 'famous-surface'; - - /** - * Set inner document content. Note that this is a noop for CanvasSurface. - * - * @method setContent - * - */ - CanvasSurface.prototype.setContent = function setContent() {}; - - /** - * Place the document element this component manages into the document. - * This will draw the content to the document. - * - * @private - * @method deploy - * @param {Node} target document parent of this container - */ - CanvasSurface.prototype.deploy = function deploy(target) { - if (this._canvasSize) { - target.width = this._canvasSize[0]; - target.height = this._canvasSize[1]; - } - if (this._contextId === '2d') { - target.getContext(this._contextId).drawImage(this._backBuffer, 0, 0); - this._backBuffer.width = 0; - this._backBuffer.height = 0; - } - }; - - /** - * Remove this component and contained content from the document - * - * @private - * @method recall - * - * @param {Node} target node to which the component was deployed - */ - CanvasSurface.prototype.recall = function recall(target) { - var size = this.getSize(); - - this._backBuffer.width = target.width; - this._backBuffer.height = target.height; - - if (this._contextId === '2d') { - this._backBuffer.getContext(this._contextId).drawImage(target, 0, 0); - target.width = 0; - target.height = 0; - } - }; - - /** - * Returns the canvas element's context - * - * @method getContext - * @param {string} contextId context identifier - */ - CanvasSurface.prototype.getContext = function getContext(contextId) { - this._contextId = contextId; - return this._currTarget ? this._currTarget.getContext(contextId) : this._backBuffer.getContext(contextId); - }; - - /** - * Set the size of the surface and canvas element. - * - * @method setSize - * @param {Array.number} size [width, height] of surface - * @param {Array.number} canvasSize [width, height] of canvas surface - */ - CanvasSurface.prototype.setSize = function setSize(size, canvasSize) { - Surface.prototype.setSize.apply(this, arguments); - if (canvasSize) this._canvasSize = [canvasSize[0], canvasSize[1]]; - if (this._currTarget) { - this._currTarget.width = this._canvasSize[0]; - this._currTarget.height = this._canvasSize[1]; - } - }; - - module.exports = CanvasSurface; -}); - - -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. - * - * Owner: mark@famo.us - * @license MPL 2.0 - * @copyright Famous Industries, Inc. 2014 - */ - -define('famous/surfaces/ContainerSurface',['require','exports','module','famous/core/Surface','famous/core/Context'],function(require, exports, module) { - var Surface = require('famous/core/Surface'); - var Context = require('famous/core/Context'); - - /** - * ContainerSurface is an object designed to contain surfaces and - * set properties to be applied to all of them at once. - * This extends the Surface class. - * A container surface will enforce these properties on the - * surfaces it contains: - * - * size (clips contained surfaces to its own width and height); - * - * origin; - * - * its own opacity and transform, which will be automatically - * applied to all Surfaces contained directly and indirectly. - * - * @class ContainerSurface - * @extends Surface - * @constructor - * @param {Array.Number} [options.size] [width, height] in pixels - * @param {Array.string} [options.classes] CSS classes to set on all inner content - * @param {Array} [options.properties] string dictionary of HTML attributes to set on target div - * @param {string} [options.content] inner (HTML) content of surface (should not be used) - */ - function ContainerSurface(options) { - Surface.call(this, options); - this._container = document.createElement('div'); - this._container.classList.add('famous-group'); - this._container.classList.add('famous-container-group'); - this._shouldRecalculateSize = false; - this.context = new Context(this._container); - this.setContent(this._container); - } - - ContainerSurface.prototype = Object.create(Surface.prototype); - ContainerSurface.prototype.constructor = ContainerSurface; - ContainerSurface.prototype.elementType = 'div'; - ContainerSurface.prototype.elementClass = 'famous-surface'; - - /** - * Add renderables to this object's render tree - * - * @method add - * - * @param {Object} obj renderable object - * @return {RenderNode} RenderNode wrapping this object, if not already a RenderNode - */ - ContainerSurface.prototype.add = function add() { - return this.context.add.apply(this.context, arguments); - }; - - /** - * Return spec for this surface. Note: Can result in a size recalculation. - * - * @private - * @method render - * - * @return {Object} render spec for this surface (spec id) - */ - ContainerSurface.prototype.render = function render() { - if (this._sizeDirty) this._shouldRecalculateSize = true; - return Surface.prototype.render.apply(this, arguments); - }; - - /** - * Place the document element this component manages into the document. - * - * @private - * @method deploy - * @param {Node} target document parent of this container - */ - ContainerSurface.prototype.deploy = function deploy() { - this._shouldRecalculateSize = true; - return Surface.prototype.deploy.apply(this, arguments); - }; - - /** - * Apply changes from this component to the corresponding document element. - * This includes changes to classes, styles, size, content, opacity, origin, - * and matrix transforms. - * - * @private - * @method commit - * @param {Context} context commit context - * @param {Transform} transform unused TODO - * @param {Number} opacity unused TODO - * @param {Array.Number} origin unused TODO - * @param {Array.Number} size unused TODO - * @return {undefined} TODO returns an undefined value - */ - ContainerSurface.prototype.commit = function commit(context, transform, opacity, origin, size) { - var previousSize = this._size ? [this._size[0], this._size[1]] : null; - var result = Surface.prototype.commit.apply(this, arguments); - if (this._shouldRecalculateSize || (previousSize && (this._size[0] !== previousSize[0] || this._size[1] !== previousSize[1]))) { - this.context.setSize(); - this._shouldRecalculateSize = false; - } - this.context.update(); - return result; - }; - - module.exports = ContainerSurface; -}); - -define('famous/surfaces/FormContainerSurface',['require','exports','module','./ContainerSurface'],function(require, exports, module) { - var ContainerSurface = require('./ContainerSurface'); - - function FormContainerSurface(options) { - if (options) this._method = options.method || ''; - ContainerSurface.apply(this, arguments); - } - - FormContainerSurface.prototype = Object.create(ContainerSurface.prototype); - FormContainerSurface.prototype.constructor = FormContainerSurface; - - FormContainerSurface.prototype.elementType = 'form'; - - FormContainerSurface.prototype.deploy = function deploy(target) { - if (this._method) target.method = this._method; - return ContainerSurface.prototype.deploy.apply(this, arguments); - }; - - module.exports = FormContainerSurface; -}); - - -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. - * - * Owner: mark@famo.us - * @license MPL 2.0 - * @copyright Famous Industries, Inc. 2014 - */ - -define('famous/surfaces/ImageSurface',['require','exports','module','famous/core/Surface'],function(require, exports, module) { - var Surface = require('famous/core/Surface'); - - /** - * A surface containing image content. - * This extends the Surface class. - * - * @class ImageSurface - * - * @extends Surface - * @constructor - * @param {Object} [options] overrides of default options - */ - function ImageSurface(options) { - this._imageUrl = undefined; - Surface.apply(this, arguments); - } - - ImageSurface.prototype = Object.create(Surface.prototype); - ImageSurface.prototype.constructor = ImageSurface; - ImageSurface.prototype.elementType = 'img'; - ImageSurface.prototype.elementClass = 'famous-surface'; - - /** - * Set content URL. This will cause a re-rendering. - * @method setContent - * @param {string} imageUrl - */ - ImageSurface.prototype.setContent = function setContent(imageUrl) { - this._imageUrl = imageUrl; - this._contentDirty = true; - }; - - /** - * Place the document element that this component manages into the document. - * - * @private - * @method deploy - * @param {Node} target document parent of this container - */ - ImageSurface.prototype.deploy = function deploy(target) { - target.src = this._imageUrl || ''; - }; - - /** - * Remove this component and contained content from the document - * - * @private - * @method recall - * - * @param {Node} target node to which the component was deployed - */ - ImageSurface.prototype.recall = function recall(target) { - target.src = ''; - }; - - module.exports = ImageSurface; -}); - -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. - * - * Owner: mark@famo.us - * @license MPL 2.0 - * @copyright Famous Industries, Inc. 2014 - */ - -define('famous/surfaces/InputSurface',['require','exports','module','famous/core/Surface'],function(require, exports, module) { - var Surface = require('famous/core/Surface'); - - /** - * A Famo.us surface in the form of an HTML input element. - * This extends the Surface class. - * - * @class InputSurface - * @extends Surface - * @constructor - * @param {Object} [options] overrides of default options - * @param {string} [options.placeholder] placeholder text hint that describes the expected value of an element - * @param {string} [options.type] specifies the type of element to display (e.g. 'datetime', 'text', 'button', etc.) - * @param {string} [options.value] value of text - */ - function InputSurface(options) { - this._placeholder = options.placeholder || ''; - this._value = options.value || ''; - this._type = options.type || 'text'; - this._name = options.name || ''; - - Surface.apply(this, arguments); - - this.on('click', this.focus.bind(this)); - window.addEventListener('click', function(event) { - if (event.target !== this._currTarget) this.blur(); - }.bind(this)); - } - InputSurface.prototype = Object.create(Surface.prototype); - InputSurface.prototype.constructor = InputSurface; - - InputSurface.prototype.elementType = 'input'; - InputSurface.prototype.elementClass = 'famous-surface'; - - /** - * Set placeholder text. Note: Triggers a repaint. - * - * @method setPlaceholder - * @param {string} str Value to set the placeholder to. - * @return {InputSurface} this, allowing method chaining. - */ - InputSurface.prototype.setPlaceholder = function setPlaceholder(str) { - this._placeholder = str; - this._contentDirty = true; - return this; - }; - - /** - * Focus on the current input, pulling up the keyboard on mobile. - * - * @method focus - * @return {InputSurface} this, allowing method chaining. - */ - InputSurface.prototype.focus = function focus() { - if (this._currTarget) this._currTarget.focus(); - return this; - }; - - /** - * Blur the current input, hiding the keyboard on mobile. - * - * @method blur - * @return {InputSurface} this, allowing method chaining. - */ - InputSurface.prototype.blur = function blur() { - if (this._currTarget) this._currTarget.blur(); - return this; - }; - - /** - * Set the placeholder conent. - * Note: Triggers a repaint next tick. - * - * @method setValue - * @param {string} str Value to set the main input value to. - * @return {InputSurface} this, allowing method chaining. - */ - InputSurface.prototype.setValue = function setValue(str) { - this._value = str; - this._contentDirty = true; - return this; - }; - - /** - * Set the type of element to display conent. - * Note: Triggers a repaint next tick. - * - * @method setType - * @param {string} str type of the input surface (e.g. 'button', 'text') - * @return {InputSurface} this, allowing method chaining. - */ - InputSurface.prototype.setType = function setType(str) { - this._type = str; - this._contentDirty = true; - return this; - }; - - /** - * Get the value of the inner content of the element (e.g. the entered text) - * - * @method getValue - * @return {string} value of element - */ - InputSurface.prototype.getValue = function getValue() { - if (this._currTarget) { - return this._currTarget.value; - } - else { - return this._value; - } - }; - - /** - * Set the name attribute of the element. - * Note: Triggers a repaint next tick. - * - * @method setName - * @param {string} str element name - * @return {InputSurface} this, allowing method chaining. - */ - InputSurface.prototype.setName = function setName(str) { - this._name = str; - this._contentDirty = true; - return this; - }; - - /** - * Get the name attribute of the element. - * - * @method getName - * @return {string} name of element - */ - InputSurface.prototype.getName = function getName() { - return this._name; - }; - - /** - * Place the document element this component manages into the document. - * - * @private - * @method deploy - * @param {Node} target document parent of this container - */ - InputSurface.prototype.deploy = function deploy(target) { - if (this._placeholder !== '') target.placeholder = this._placeholder; - target.value = this._value; - target.type = this._type; - target.name = this._name; - }; - - module.exports = InputSurface; -}); - -define('famous/surfaces/SubmitInputSurface',['require','exports','module','./InputSurface'],function(require, exports, module) { - var InputSurface = require('./InputSurface'); - - function SubmitInputSurface(options) { - InputSurface.apply(this, arguments); - this._type = 'submit'; - if (options && options.onClick) this.setOnClick(options.onClick); - } - - SubmitInputSurface.prototype = Object.create(InputSurface.prototype); - SubmitInputSurface.prototype.constructor = SubmitInputSurface; - - SubmitInputSurface.prototype.setOnClick = function(onClick) { - this.onClick = onClick; - }; - - SubmitInputSurface.prototype.deploy = function deploy(target) { - if (this.onclick) target.onClick = this.onClick; - InputSurface.prototype.deploy.apply(this, arguments); - }; - - module.exports = SubmitInputSurface; -}); - -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. - * - * Owner: mark@famo.us - * @license MPL 2.0 - * @copyright Famous Industries, Inc. 2014 - */ - -define('famous/surfaces/TextareaSurface',['require','exports','module','famous/core/Surface'],function(require, exports, module) { - var Surface = require('famous/core/Surface'); - - /** - * A Famo.us surface in the form of an HTML textarea element. - * This extends the Surface class. - * - * @class TextareaSurface - * @extends Surface - * @constructor - * @param {Object} [options] overrides of default options - * @param {string} [options.placeholder] placeholder text hint that describes the expected value of an textarea element - * @param {string} [options.value] value of text - * @param {string} [options.name] specifies the name of textarea - * @param {string} [options.wrap] specify 'hard' or 'soft' wrap for textarea - * @param {number} [options.cols] number of columns in textarea - * @param {number} [options.rows] number of rows in textarea - */ - function TextareaSurface(options) { - this._placeholder = options.placeholder || ''; - this._value = options.value || ''; - this._name = options.name || ''; - this._wrap = options.wrap || ''; - this._cols = options.cols || ''; - this._rows = options.rows || ''; - - Surface.apply(this, arguments); - this.on('click', this.focus.bind(this)); - } - TextareaSurface.prototype = Object.create(Surface.prototype); - TextareaSurface.prototype.constructor = TextareaSurface; - - TextareaSurface.prototype.elementType = 'textarea'; - TextareaSurface.prototype.elementClass = 'famous-surface'; - - /** - * Set placeholder text. Note: Triggers a repaint. - * - * @method setPlaceholder - * @param {string} str Value to set the placeholder to. - * @return {TextareaSurface} this, allowing method chaining. - */ - TextareaSurface.prototype.setPlaceholder = function setPlaceholder(str) { - this._placeholder = str; - this._contentDirty = true; - return this; - }; - - /** - * Focus on the current input, pulling up the keyboard on mobile. - * - * @method focus - * @return {TextareaSurface} this, allowing method chaining. - */ - TextareaSurface.prototype.focus = function focus() { - if (this._currTarget) this._currTarget.focus(); - return this; - }; - - /** - * Blur the current input, hiding the keyboard on mobile. - * - * @method focus - * @return {TextareaSurface} this, allowing method chaining. - */ - TextareaSurface.prototype.blur = function blur() { - if (this._currTarget) this._currTarget.blur(); - return this; - }; - - /** - * Set the value of textarea. - * Note: Triggers a repaint next tick. - * - * @method setValue - * @param {string} str Value to set the main textarea value to. - * @return {TextareaSurface} this, allowing method chaining. - */ - TextareaSurface.prototype.setValue = function setValue(str) { - this._value = str; - this._contentDirty = true; - return this; - }; - - /** - * Get the value of the inner content of the textarea (e.g. the entered text) - * - * @method getValue - * @return {string} value of element - */ - TextareaSurface.prototype.getValue = function getValue() { - if (this._currTarget) { - return this._currTarget.value; - } - else { - return this._value; - } - }; - - /** - * Set the name attribute of the element. - * Note: Triggers a repaint next tick. - * - * @method setName - * @param {string} str element name - * @return {TextareaSurface} this, allowing method chaining. - */ - TextareaSurface.prototype.setName = function setName(str) { - this._name = str; - this._contentDirty = true; - return this; - }; - - /** - * Get the name attribute of the element. - * - * @method getName - * @return {string} name of element - */ - TextareaSurface.prototype.getName = function getName() { - return this._name; - }; - - /** - * Set the wrap of textarea. - * Note: Triggers a repaint next tick. - * - * @method setWrap - * @param {string} str wrap of the textarea surface (e.g. 'soft', 'hard') - * @return {TextareaSurface} this, allowing method chaining. - */ - TextareaSurface.prototype.setWrap = function setWrap(str) { - this._wrap = str; - this._contentDirty = true; - return this; - }; - - /** - * Set the number of columns visible in the textarea. - * Note: Overridden by surface size; set width to true. (eg. size: [true, *]) - * Triggers a repaint next tick. - * - * @method setColumns - * @param {number} num columns in textarea surface - * @return {TextareaSurface} this, allowing method chaining. - */ - TextareaSurface.prototype.setColumns = function setColumns(num) { - this._cols = num; - this._contentDirty = true; - return this; - }; - - /** - * Set the number of rows visible in the textarea. - * Note: Overridden by surface size; set height to true. (eg. size: [*, true]) - * Triggers a repaint next tick. - * - * @method setRows - * @param {number} num rows in textarea surface - * @return {TextareaSurface} this, allowing method chaining. - */ - TextareaSurface.prototype.setRows = function setRows(num) { - this._rows = num; - this._contentDirty = true; - return this; - }; - - /** - * Place the document element this component manages into the document. - * - * @private - * @method deploy - * @param {Node} target document parent of this container - */ - TextareaSurface.prototype.deploy = function deploy(target) { - if (this._placeholder !== '') target.placeholder = this._placeholder; - if (this._value !== '') target.value = this._value; - if (this._name !== '') target.name = this._name; - if (this._wrap !== '') target.wrap = this._wrap; - if (this._cols !== '') target.cols = this._cols; - if (this._rows !== '') target.rows = this._rows; - }; - - module.exports = TextareaSurface; -}); - -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. - * - * Owner: mark@famo.us - * @license MPL 2.0 - * @copyright Famous Industries, Inc. 2014 - */ - -define('famous/surfaces/VideoSurface',['require','exports','module','famous/core/Surface'],function(require, exports, module) { - var Surface = require('famous/core/Surface'); - - /** - * Creates a famous surface containing video content. Currently adding - * controls and manipulating the video are not supported through the - * surface interface, but can be accomplished via standard JavaScript - * manipulation of the video DOM element. - * This extends the Surface class. - * - * @class VideoSurface - * @extends Surface - * @constructor - * @param {Object} [options] default option overrides - * @param {Array.Number} [options.size] [width, height] in pixels - * @param {Array.string} [options.classes] CSS classes to set on inner content - * @param {Array} [options.properties] string dictionary of HTML attributes to set on target div - * @param {string} [options.content] inner (HTML) content of surface - * @param {boolean} [options.autoplay] autoplay - */ - function VideoSurface(options) { - this._videoUrl = undefined; - this.options = Object.create(VideoSurface.DEFAULT_OPTIONS); - if (options) this.setOptions(options); - - Surface.apply(this, arguments); - } - VideoSurface.prototype = Object.create(Surface.prototype); - VideoSurface.prototype.constructor = VideoSurface; - - VideoSurface.DEFAULT_OPTIONS = { - autoplay: false - }; - - VideoSurface.prototype.elementType = 'video'; - VideoSurface.prototype.elementClass = 'famous-surface'; - - /** - * Set internal options, overriding any default options - * - * @method setOptions - * - * @param {Object} [options] overrides of default options - * @param {Boolean} [options.autoplay] HTML autoplay - */ - VideoSurface.prototype.setOptions = function setOptions(options) { - for (var key in VideoSurface.DEFAULT_OPTIONS) { - if (options[key] !== undefined) this.options[key] = options[key]; - } - }; - - /** - * Set url of the video. - * - * @method setContent - * @param {string} videoUrl URL - */ - VideoSurface.prototype.setContent = function setContent(videoUrl) { - this._videoUrl = videoUrl; - this._contentDirty = true; - }; - - /** - * Place the document element this component manages into the document. - * Note: In the case of VideoSurface, simply changes the options on the target. - * - * @private - * @method deploy - * @param {Node} target document parent of this container - */ - VideoSurface.prototype.deploy = function deploy(target) { - target.src = this._videoUrl; - target.autoplay = this.options.autoplay; - }; - - /** - * Remove this component and contained content from the document. - * Note: This doesn't actually remove the