diff --git a/.project b/.project
new file mode 100644
index 0000000..eae200c
--- /dev/null
+++ b/.project
@@ -0,0 +1,11 @@
+
+
+ molecular-control-toolkit-js
+
+
+
+
+
+
+
+
diff --git a/README.md b/README.md
index edc9840..ffefa7d 100644
--- a/README.md
+++ b/README.md
@@ -2,3 +2,49 @@ molecular-control-toolkit-js
============================
A javascript adapter to the molecular control toolkit.
+
+see https://github.com/Traksewt/molecular-control-toolkit
+
+This toolkit can be used to transfer Leap Motion events in the browser direct to an applet.
+
+in the browser JS:
+
+ var leapToolkit = new molecularControlToolkitJS.leap(gestures());
+
+ var gestures = function () {
+ var functions = ['triggerPan', 'triggerRotate', 'triggerZoom', 'point', 'reset', 'zoomToSelection', 'selectMouseCursor'];
+ var ret = {};
+ functions.forEach(function (funcName) {
+ ret[funcName] = function () {
+ var newArgs = [funcName];
+ newArgs.push(Array.prototype.slice.call(arguments));
+ if (document.applets[0]) {
+ document.applets[0].molecularControlToolkit.apply(document.applets[0], newArgs);
+ }
+ }
+ })
+ return ret;
+ }
+
+ leapToolkit.start()
+
+
+in the applet:
+
+TunnellingConnector connector = null;
+
+ public void initialise() {
+ MolecularControlToolkit molecularControlToolkit = new MolecularControlToolkit();
+ this.connector = (TunnellingConnector) molecularControlToolkit.addConnector(ConnectorType.LeapMotionJS);
+ MyDispatcher dispatcher = new MyDispatcher();
+ molecularControlToolkit.setListeners(dispatcher);
+ }
+
+ /** The entry point for the browser events */
+ public void molecularControlToolkit(String methodName, float[] arguments) {
+ System.out.println("Method: " + methodName + ", args: " + Arrays.asList(arguments).toString());
+ if (this.connector != null) {
+ this.connector.tunnel(methodName, arguments);
+ }
+ }
+
diff --git a/index.js b/index.js
new file mode 100644
index 0000000..7957c0f
--- /dev/null
+++ b/index.js
@@ -0,0 +1,4 @@
+var leapConnector = require('./src/leapConnector');
+
+
+module.exports.leap = leapConnector;
\ No newline at end of file
diff --git a/package.json b/package.json
new file mode 100644
index 0000000..c204b76
--- /dev/null
+++ b/package.json
@@ -0,0 +1,24 @@
+{
+ "name": "molecular-control-toolkit-js",
+ "version": "0.0.2",
+ "description": "A javascript adapter to the molecular control toolkit",
+ "main": "index.js",
+ "repository": {
+ "type": "git",
+ "url": "git://github.com/Traksewt/molecular-control-toolkit-js.git"
+ },
+ "keywords": [
+ "LeapMotion",
+ "Gesture",
+ "Device",
+ "MolecularControlToolkit"
+ ],
+ "author": "Kenny Sabir",
+ "license": "BSD",
+ "bugs": {
+ "url": "https://github.com/Traksewt/molecular-control-toolkit-js/issues"
+ },
+ "dependencies": {
+ "leapjs": "*"
+ }
+}
diff --git a/src/leapConnector.js b/src/leapConnector.js
new file mode 100644
index 0000000..683bdc7
--- /dev/null
+++ b/src/leapConnector.js
@@ -0,0 +1,144 @@
+var Leap = require('leapjs');
+var Pointer = require('./pointer')
+
+/** constant for scaling pointing in the x axis */
+var X_SCALE = 150;
+
+/** constant for scaling pointing in the y axis */
+var Y_SCALE = -400;
+
+/** constant for offsetting pointing in the y axis */
+var Y_OFFSET = 400;
+
+var ROTATION_SCALE = 500;
+
+var MAX_ROTATION = 30;
+
+var MIN_ROTATION = 3;
+
+var LeapConnector = function(gestureDispatcher) {
+ this.gestureDispatcher = gestureDispatcher;
+
+
+ /** Store the lastX for custom pointing algorithm */
+ this.lastX = -1;
+
+ /** Store the lastY for custom pointing algorithm */
+ this.lastY = -1;
+
+};
+
+LeapConnector.prototype.start = function() {
+ var that = this;
+ this.controller = Leap.loop({
+// frameEventName: 'deviceFrame',
+ enableGestures : false
+ }, function(frame) {
+ return that.onFrame(frame);
+ });
+ return that;
+}
+
+LeapConnector.prototype.limitRotation = function(r) {
+ r *= ROTATION_SCALE;
+ r = Math.max(-MAX_ROTATION, r);
+ r = Math.min(MAX_ROTATION, r);
+ if (Math.abs(r) < MIN_ROTATION) {
+ r = 0;
+ }
+ return r;
+}
+
+LeapConnector.prototype.onFrame = function(frame) {
+ var that = this;
+ if (frame.hands.length == 1) {
+ if (frame.fingers.length > 3) {
+ var lastFrame = this.controller.frame(1);
+ if (lastFrame && lastFrame.hands.length == 1) {
+
+ // rotate
+ that.lastY = -1;
+ that.lastX = -1;
+
+ var hand = frame.hands[0];
+ var translation = hand.translation(lastFrame);
+ // comment out for the moment until JS Leap Motion rotation bugs are fixed.
+// that.gestureDispatcher.triggerPan(translation[0], -translation[1]);
+// that.gestureDispatcher.triggerZoom(-translation[2]);
+
+ // yaw pitch roll are slightly better, but there still seems to be an issue.
+// var xRotation = this.limitRotation(hand.pitch() - lastFrame.hands[0].pitch());
+// var yRotation = this.limitRotation(hand.yaw() - lastFrame.hands[0].yaw());
+// var zRotation = this.limitRotation(hand.roll() - lastFrame.hands[0].roll());
+
+ // these rotations have an issue where changes aren't updated properly.
+ // see https://github.com/leapmotion/leapjs/issues/188
+ var xRotation = this.limitRotation(hand.rotationAngle(lastFrame, [ 1, 0, 0 ]));
+ var yRotation = this.limitRotation(hand.rotationAngle(lastFrame, [ 0, 1, 0 ]));
+ var zRotation = this.limitRotation(hand.rotationAngle(lastFrame, [ 0, 0, 1 ]));
+ // console.log('lastframe1: ' + that.lastFrame);
+ if (Math.abs(xRotation) > MIN_ROTATION ||
+ Math.abs(yRotation) > MIN_ROTATION ||
+ Math.abs(zRotation) > MIN_ROTATION) {
+ that.gestureDispatcher.triggerRotate((xRotation),
+ -(yRotation), (zRotation));
+ }
+ }
+ } else if (frame.fingers.length > 0) {
+
+ try {
+ var finger = frame.fingers[0];
+ var hit = Pointer(finger);
+ // Vector hit =
+ // controller.locatedScreens().closestScreenHit(finger).intersect(finger,true);
+ var zVel = finger.tipVelocity.getZ[2];
+ var absZVel = Math.abs(zVel);
+ var y = hit.getY();
+ var x = hit.getX();
+
+ if (absZVel > 50 && that.lastY != -1) {
+ var scale = 2500 / (absZVel * absZVel);
+ x = (hit.x - that.lastX) * scale + that.lastX;
+ y = (hit.y - that.lastY) * scale + that.lastY;
+ }
+ that.lastY = y;
+ that.lastX = x;
+ if (!isNaN(x) && !isNaN(y)) {
+ // that.gestureDispatcher.point(x, y);
+ }
+ } catch (e) {
+ console.log('error occurred when pointing: ' + e);
+ }
+ } else {
+ that.lastY = -1;
+ that.lastX = -1;
+
+ }
+ var i;
+ if (frame.gestures) {
+
+ frame.gestures.forEach(function(gesture) {
+ switch (gesture.type) {
+ case 'swipe':
+ that.gestureDispatcher.reset();
+ break;
+ case 'screenTap':
+
+ that.gestureDispatcher.selectMouseCursor();
+ // add a delay so the app can process the mouse clicks.
+ setTimeout(that.gestureDispatcher.zoomToSelection, 100);
+ break;
+ case 'keyTap':
+ that.gestureDispatcher.zoomToSelection();
+ break;
+ default:
+ console.log("Unknown gesture type: " + gesture.type);
+ break;
+ }
+ });
+ }
+ }
+ // console.log('lastframe2: ' + that.lastFrame);
+}
+
+module.exports = LeapConnector;
diff --git a/src/pointer.js b/src/pointer.js
new file mode 100644
index 0000000..870fd61
--- /dev/null
+++ b/src/pointer.js
@@ -0,0 +1,172 @@
+// adapted from a forum post by cabbibo:
+// https://github.com/leapmotion/leapjs/issues/31
+// http://cabbibo.com/leap/lmlab/mouse/test.html
+
+/*
+
+Below are all of the starting parameters for the different
+Pointer Acceleration Functions.
+
+Additionally the look and feel of the graph is created here.
+
+*/
+var PARAMS = function(){
+
+
+ //Function Type that we are starting with
+ this.functionType = 'atan'
+
+
+ //power function
+ this.power = {
+ division:300,
+ divisionRange:[1,10000],
+ power:1,
+ powerRange:[0,3]
+
+ }
+
+
+ this.atan = {
+ division1:660,
+ division1Range:[0,10000],
+ division2:0.5,
+ division2Range:[0,1]
+ }
+
+ this.asymp1 = {
+ max:0.5,
+ maxRange:[0,1],
+ min:0.001,
+ minRange:[0,.1],
+ Vo:200,
+ VoRange:[1,10000]
+ }
+
+ this.asymp2 = {
+ max:0.001,
+ maxRange:[0,.01],
+ min:0.001,
+ minRange:[0,.01],
+ Vo:1500,
+ VoRange:[0,3000],
+ }
+
+
+
+ //Look and Feel Section
+ this.mouseSize = 10
+ this.frameOpacity = 800
+
+ this.gainGraphFrames = 200
+
+
+
+
+
+ //Moves Cursor to the center of the screen
+ this.resetPosition = function(){
+ curPos.x = window.innerWidth/2
+ curPos.y = window.innerHeight/2
+ }
+}
+
+//Initialize params
+var params = new PARAMS();
+
+
+//setting up the current position to be in the very center of the screen
+var curPos = {
+ x:window.innerWidth/2,
+ y:window.innerHeight/2
+}
+
+
+var point = function (pointer) {
+
+ //get the amount to be added by calling the 'convert' function.
+ //The convert function will basically use whatever equation that we have selected
+ //In order to create Pointer Acceleration
+ var addAmount = convert(pointer.tipVelocity[0],pointer.tipVelocity[1], params.functionType)
+
+
+ //Add the altered velocity to the current Position
+ var newPos = {
+ x:(curPos.x + addAmount.x),
+ y:(curPos.y + addAmount.y)
+ }
+
+
+ /*
+ Setting up the bounding box
+ */
+ if(newPos.x >= window.innerWidth){
+ newPos.x = window.innerWidth
+ }
+
+ if(newPos.x <= 0 ){
+ newPos.x = 0
+ }
+
+ if(newPos.y >= window.innerHeight){
+ newPos.y = window.innerHeight
+ }
+
+ if(newPos.y <= 0 ){
+ newPos.y = 0
+ }
+
+ //Assign the current position to the be the new position for use in the next frame
+ curPos = newPos;
+ return newPos;
+}
+
+
+//Function to convert the velocity to something useful
+function convert(velocityX, velocityY, type){
+
+ //Gets the magnitude outside the individual functions
+ //Becasue it will be the same for every function type
+ var magnitude = Math.sqrt((velocityX*velocityX)+(velocityY*velocityY))
+
+ //CD or Control Display Gain, is the amount that
+ var cdGain = 1
+
+
+
+
+
+ if(type == 'power'){
+
+ cdGain = Math.pow(magnitude,params.power.power) / Math.pow(params.power.division,params.power.power)
+
+ }else if (type == 'atan'){
+
+ cdGain = Math.atan(magnitude/params.atan.division1) / params.atan.division2
+
+ }else if(type == 'asymp1'){
+
+ cdGain = ((params.asymp1.max) *(1- Math.exp(-magnitude/params.asymp1.Vo))+params.asymp1.min)
+
+ }else if(type == 'asymp2'){
+
+ cdGain = (((params.asymp2.max) * magnitude * Math.exp(-magnitude/params.asymp2.Vo))+params.asymp2.min)
+
+ }
+
+ //The amount that we are going to be adding to the current position
+ //is simply the Control Display Gain Multiplied by the Velocity
+ //the velocityY is negated becasue of the change of Axis direction in browser
+ toReturn = {
+ x:cdGain*velocityX,
+ y:-cdGain*velocityY
+ }
+
+ //console.log(toReturn.x)
+ return toReturn
+
+}
+
+
+module.exports = point;
+module.exports.reset = params.resetPosition;
\ No newline at end of file