forked from roboleary/LeapTrainer.js
-
Notifications
You must be signed in to change notification settings - Fork 0
/
leaptrainer-ui.min.js
52 lines (52 loc) · 17.9 KB
/
leaptrainer-ui.min.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
/*
* The MIT License (MIT)
*
* Copyright (c) 2013 Robert O'Leary
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
* ------------------------------ NOTE ----------------------------------
*
* The positionPalm and positionFinger functions, as well as the structure of the leap
* controller listener below, are based on code from jestPlay (also under the MIT license), by Theo Armour:
*
* http://jaanga.github.io/gestification/cookbook/jest-play/r1/jest-play.html
*
* Thanks Theo!
*
* ----------------------------------------------------------------------
*
*
* Table of contents
* ---------------------------
*
* 1. Basic Initialization
* 2. Setting up the options panel
* 3. Setting up the overlay
* 4. Handling window resize events
* 5. Setting up the gesture creation form
* 6. Utility interface modification functions
* 7. Training event listeners
* 8. Leap controller event listeners
* 9. WebGL rendering functions
* 10. And finally...
*
* ---------------------------
*/
jQuery(document).ready(function($){var controller=new Leap.Controller();var trainer=new LeapTrainer.Controller({controller:controller});var win=$(window),body=$("body"),gestureCreationArea=$("#gesture-creation-area"),creationForm=$("#new-gesture-form"),existingGestureList=$("#existing-gestures"),newGestureName=$("#new-gesture-name"),renderArea=$("#render-area"),main=$("#main"),overlayArea=$("#overlay"),overlayShade=$("#overlay-shade"),exportingName=$("#exporting-gesture-name"),exportingSampleText=$("#exporting-gesture-sample-text"),exportText=$("#export-text"),retrainButton=$("#retrain-gesture"),closeOverlayButton=$("#close-overlay"),outputText=$("#output-text"),optionsButton=$("#options-button"),optionsArea=$("#options"),recordingTriggers=$("#recording-triggers"),recordingStrategies=$("#recording-strategies"),recogStrategies=$("#recognition-strategies"),updateConfirmation=$("#options-update-confirmation"),openConfiguration=$("#open-configuration"),closeConfiguration=$("#close-configuration"),wegGlWarning=$("#webgl-warning"),versionTag=$("#version-tag"),forkMe=$("#fork-me"),webGl=Detector.webgl,renderer=webGl?new THREE.WebGLRenderer({antialias:true}):new THREE.CanvasRenderer(),red="#EE5A40",green="#2ECC71",yellow="#EEE738",blue="#AFDFF1",white="#FFFFFF",material=new THREE.MeshBasicMaterial({color:white}),recordingMaterial=new THREE.MeshBasicMaterial({color:yellow}),palmGeometry=new THREE.CubeGeometry(60,10,60),fingerGeometry=webGl?new THREE.SphereGeometry(5,20,10):new THREE.TorusGeometry(1,5,5,5),camera=new THREE.PerspectiveCamera(45,2/1,1,3000),cameraInitialPos=new THREE.Vector3(0,0,450),scene=new THREE.Scene(),controls=new THREE.OrbitControls(camera,renderer.domElement),gestureRenderInterval=webGl?3:6,windowHeight,windowWidth,gestureEntries={},progressBars={},gestureLabels={},gestureArrows={},optionsOpen=false,overlayOpen=false,training=false,data;if(webGl){wegGlWarning.remove();}else{wegGlWarning.css({display:"block"});}controls.noPan=true;function openOptions(evt){if(optionsOpen){return;}if(evt){evt.stopPropagation();}optionsOpen=true;recordingTriggers.focus();main.animate({left:-340});}function closeOptions(evt){if(!optionsOpen){return;}if(evt){evt.stopPropagation();}optionsOpen=false;main.animate({left:0});}optionsButton.click(function(evt){optionsOpen?closeOptions(evt):openOptions(evt);});win.touchwipe({wipeRight:closeOptions,wipeLeft:openOptions,preventDefaultEvents:false});main.click(closeOptions);function optionsUpdated(){updateConfirmation.show();setTimeout(function(){updateConfirmation.hide();},3000);}var impl,t=[],s=[],cs=[];function setupOptionList(rt,t,list,implName){if(rt){rt=rt();if(t.indexOf(rt)==-1){t.push(rt);list.append('<option value="'+implName+'">'+rt+"</option>");}}}for(var implName in LeapTrainer){impl=LeapTrainer[implName].prototype;setupOptionList(impl.getRecordingTriggerStrategy,t,recordingTriggers,implName);setupOptionList(impl.getFrameRecordingStrategy,s,recordingStrategies,implName);setupOptionList(impl.getRecognitionStrategy,cs,recogStrategies,implName);}function modifyController(replacementController){replacementController=LeapTrainer[replacementController];var fields=replacementController.overidden;var func;for(var field in fields){func=replacementController.prototype[field];if(func){if(func.bind){func.bind(trainer);}trainer[field]=func;}}optionsUpdated();}recordingTriggers.change(function(){modifyController(recordingTriggers.val());});recordingStrategies.change(function(){modifyController(recordingStrategies.val());});recogStrategies.change(function(){modifyController(recogStrategies.val());});function setupOptionInput(binding){var input=$("#"+binding);input.val(trainer[binding]);input.blur(function(){var val=input.val();if(val!=trainer[binding]){trainer[binding]=val;optionsUpdated();}});}setupOptionInput("minRecordingVelocity");setupOptionInput("minGestureFrames");setupOptionInput("hitThreshold");setupOptionInput("trainingGestures");setupOptionInput("convolutionFactor");setupOptionInput("downtime");var openConfigGesture=null,closeConfigGesture=null;function registerUIGesture(oldGesture,newGesture,func){trainer.off(oldGesture,func);trainer.on(newGesture,func);optionsUpdated();return newGesture;}openConfiguration.change(function(){openConfigGesture=registerUIGesture(openConfigGesture,openConfiguration.val(),openOptions);});closeConfiguration.change(function(){closeConfigGesture=registerUIGesture(closeConfigGesture,closeConfiguration.val(),closeOptions);});function openExportOverlay(listItem,gestureName){if(overlayOpen||training){return;}trainer.pause();main.css({position:"inherit"});var bar=progressBars[gestureName];bar.css({width:"100%",background:blue});setGestureLabel(gestureName,"");existingGestureList.find("li").removeClass("selected");listItem.addClass("selected");exportingName.html(gestureName);var json=trainer.toJSON(gestureName);exportingSampleText.html((json.length>60?json.substring(0,60):json)+"...");exportText.html(json);body.addClass("overlay-open");overlayOpen=true;exportText.css({height:overlayArea.height()-(overlayArea.children()[0].clientHeight+150)});}function closeExportOverlay(){if(!overlayOpen){return;}trainer.resume();main.css({position:"fixed"});unselectAllGestures(true);existingGestureList.find("li").removeClass("selected");body.removeClass("overlay-open");overlayOpen=false;}retrainButton.click(function(){closeExportOverlay();trainer.retrain(exportingName.html());});closeOverlayButton.click(closeExportOverlay);overlayShade.on("click",function(e){if(body.hasClass("overlay-open")){closeExportOverlay();}});$(document).on("keydown",function(e){if(e.keyCode===27){closeExportOverlay();}});exportText.click(function(){this.focus();this.select();});function updateDimensions(){windowHeight=win.innerHeight();windowWidth=win.innerWidth();overlayShade.css({height:windowHeight});optionsArea.css({height:windowHeight});main.css({height:windowHeight});var renderHeight=windowHeight-5;renderArea.css({width:windowWidth,height:renderHeight});renderer.setSize(windowWidth,renderHeight);var outputTextLeft=(windowWidth<1000)?100:22;outputText.css({left:outputTextLeft,width:windowWidth-outputTextLeft-22,fontSize:Math.max(22,windowWidth/55)});overlayArea.css({width:windowWidth-480,height:windowHeight*0.88});exportText.css({height:overlayArea.height()-(overlayArea.children()[0].clientHeight+150)});}updateDimensions();win.resize(updateDimensions);newGestureName.data("default-text",newGestureName.val());newGestureName.focus(function(){if($(this).val()!=""&&$(this).val()==$(this).data("default-text")){$(this).val("");}}).blur(function(){if($(this).val()==""){$(this).val($(this).data("default-text"));}});creationForm.submit(function(){var name=newGestureName.val().trim();if(name.length==0||name==newGestureName.data("default-text")||trainer.gestures[name]!=null){return false;}trainer.create(name.toUpperCase());return false;});function setOutputText(text){outputText.html(text?text:"");}function unselectAllGestures(resetProgressBars){if(resetProgressBars){for(arrow in gestureArrows){gestureArrows[arrow].css({background:"transparent"});}var bar;for(barName in progressBars){bar=progressBars[barName];bar.css({width:"0%",background:blue});bar.parent().removeClass("selected");}}for(label in gestureLabels){gestureLabels[label].html(" ");}}function setGestureScale(gestureName,val,color,arrowColor){gestureArrows[gestureName].css({display:arrowColor=="transparent"?"none":"block",background:arrowColor});var bar=progressBars[gestureName];bar.css({background:color});bar.animate({width:val+"%"},200,"swing");}function setAllGestureScales(allHits,excluding){for(var gestureName in allHits){if(gestureName==excluding){continue;}setGestureLabel(gestureName);setGestureScale(gestureName,Math.min(parseInt(100*allHits[gestureName]),100),blue,"transparent");}}function setGestureLabel(gestureName,val){gestureLabels[gestureName].html(val?val:" ");}function disableUI(color,message){main.css({background:color});gestureCreationArea.css({display:"none"});optionsButton.css({display:"none"});versionTag.css({display:"none"});forkMe.css({display:"none"});outputText.css({background:"transparent"});setOutputText(message);}function enableUI(message){main.css({background:""});gestureCreationArea.css({display:""});optionsButton.css({display:""});versionTag.css({display:""});forkMe.css({display:""});outputText.css({background:""});setOutputText(message);}trainer.on("gesture-created",function(gestureName,trainingSkipped){var gesture=$("<li"+(trainingSkipped?"":' class="selected"')+'><div class="progress"><span class="gesture-name">'+gestureName+'</span><img class="arrow" src="./trainer-ui/images/training-arrow.png" /></div>'+'<img class="export-arrow" src="./trainer-ui/images/export-arrow.png" />'+'<span class="label"> </span></li>');gesture.click(function(){openExportOverlay(gesture,gestureName);});var items=existingGestureList.find("li");if(items.length==0){existingGestureList.append(gesture);}else{unselectAllGestures(true);$("#existing-gestures li").first().before(gesture);}gestureEntries[gestureName]=$(existingGestureList.find("li.selected")[0]);progressBars[gestureName]=$(existingGestureList.find("li.selected .progress")[0]);gestureLabels[gestureName]=$(existingGestureList.find("li.selected .label")[0]);gestureArrows[gestureName]=$(existingGestureList.find("li.selected .progress .arrow")[0]);newGestureName.val("");newGestureName.blur();openConfiguration.append('<option value="'+gestureName+'">'+gestureName+"</option>");closeConfiguration.append('<option value="'+gestureName+'">'+gestureName+"</option>");});trainer.on("training-countdown",function(countdown){training=true;setOutputText("Starting training in "+countdown+" second"+(countdown>1?"s":""));});trainer.on("training-started",function(gestureName){gestureArrows[gestureName].css({display:"block"});var trainingGestureCount=trainer.trainingGestures;setOutputText("Perform the "+gestureName+" gesture "+(trainingGestureCount>1?trainingGestureCount+" times":""));gestureEntries[gestureName].css({background:"transparent"});setGestureLabel(gestureName);setGestureScale(gestureName,1,yellow,yellow);});trainer.on("training-gesture-saved",function(gestureName,trainingSet){var trainingGestures=trainer.trainingGestures;renderGesture();var remaining=(trainingGestures-trainingSet.length);setGestureScale(gestureName,100-((100/trainingGestures)*remaining),yellow,yellow);setOutputText("Perform the "+gestureName+" gesture "+(remaining==1?" once more":remaining+" more times"));});trainer.on("training-complete",function(gestureName,trainingSet){training=false;renderGesture();setOutputText(gestureName+" learned!");setGestureLabel(gestureName,"Learned");setGestureScale(gestureName,100,green,green);});trainer.on("gesture-recognized",function(hit,gestureName,allHits){unselectAllGestures(false);setAllGestureScales(allHits,gestureName);renderGesture();var hitPercentage=Math.min(parseInt(100*hit),100);setGestureScale(gestureName,hitPercentage,green,green);setOutputText('<span style="font-weight: bold">'+gestureName+"</span> : "+hitPercentage+"% MATCH");});trainer.on("gesture-unknown",function(allHits){unselectAllGestures(false);setOutputText();setAllGestureScales(allHits);clearGesture();});controller.on("connect",function(){setOutputText("Create a gesture to get started");});controller.on("deviceDisconnected",function(){disableUI(red,"DISCONNECTED! Check the connection to your Leap Motion");});controller.on("deviceConnected",function(){enableUI("Connection restored!");});camera.position.set(cameraInitialPos.x,cameraInitialPos.y,cameraInitialPos.z);renderArea.append(renderer.domElement);function createPalm(){return new THREE.Mesh(palmGeometry,material);}function createFinger(){return new THREE.Mesh(fingerGeometry,material);}var palms=[createPalm(),createPalm()];palms[1].visible=false;scene.add(palms[0]);scene.add(palms[1]);var finger,fingers=[];for(var j=0;j<10;j++){finger=new THREE.Mesh(fingerGeometry,material);finger.visible=j<5;scene.add(finger);fingers.push(finger);}var defaultHandPosition=true;palms[0].position.set(-5.62994,-37.67400000000001,96.368);palms[0].rotation.set(-2.0921488149553125,0.051271951412566935,-2.6597446090413466);fingers[0].position.set(34.179,24.22,28.7022);fingers[0].rotation.set(-2.777879785829599,0.02183472660404244,3.133282166633954);fingers[0].scale.z=8;fingers[1].position.set(53.8033,-15.913000000000011,32.6661);fingers[1].rotation.set(-2.7753644328170965,0.22532594370921782,3.056111568660471);fingers[1].scale.z=5;fingers[2].position.set(4.69965,49.19499999999999,31.643);fingers[2].rotation.set(-2.600622653205929,0.033504548426940645,3.121471314695975);fingers[2].scale.z=9;fingers[3].position.set(-23.7075,50.976,50.363);fingers[3].rotation.set(-2.543443897235925,0.04106473211751575,3.113625377842598);fingers[3].scale.z=8;fingers[4].position.set(-80.6532,-33.772999999999996,84.7031);fingers[4].rotation.set(-2.589002343898949,-0.4631619960981157,-2.872745378807403);fingers[4].scale.z=6;function setHandMaterial(m){palms[0].material=m;palms[1].material=m;for(var i=0,l=fingers.length;i<l;i++){fingers[i].material=m;}}trainer.on("started-recording",function(){setHandMaterial(recordingMaterial);}).on("stopped-recording",function(){setHandMaterial(material);});window.requestAnimFrame=(function(){return window.requestAnimationFrame||window.webkitRequestAnimationFrame||window.mozRequestAnimationFrame||function(callback){window.setTimeout(callback,1000/60);};})();function updateRender(){controls.update();TWEEN.update();renderer.render(scene,camera);requestAnimFrame(updateRender);}requestAnimFrame(updateRender);var hand,palm,position,direction,normal,handFingers,handFingerCount,finger,handCount,palmCount=palms.length;var yOffset=-170;function positionPalm(hand,palm){position=hand.stabilizedPalmPosition||hand.position;palm.position.set(position[0],position[1]+yOffset,position[2]);direction=hand.direction;palm.lookAt(new THREE.Vector3(direction[0],direction[1],direction[2]).add(palm.position));normal=hand.palmNormal||hand.normal;palm.rotation.z=Math.atan2(normal[0],normal[1]);}function positionFinger(handFinger,finger){position=handFinger.stabilizedTipPosition||handFinger.position;finger.position.set(position[0],position[1]+yOffset,position[2]);direction=handFinger.direction;finger.lookAt(new THREE.Vector3(direction[0],direction[1],direction[2]).add(finger.position));finger.scale.z=0.1*handFinger.length;}var clock=new THREE.Clock();clock.previousTime=1000000;controller.on("frame",function(frame){if(clock.previousTime===1000000){handCount=frame.hands.length;for(var i=0;i<palmCount;i++){palm=palms[i];if(i>=handCount){if(!defaultHandPosition){palm.visible=false;for(var j=0,k=5,p;j<k;j++){p=(i*5)+j;fingers[p].visible=false;}}}else{defaultHandPosition=false;hand=frame.hands[i];positionPalm(hand,palm);palm.visible=true;handFingers=hand.fingers;handFingerCount=handFingers.length;for(var j=0,k=5;j<k;j++){finger=fingers[(i*5)+j];if(j>=handFingerCount){finger.visible=false;}else{positionFinger(handFingers[j],finger);finger.visible=true;}}}}}});var renderedHands=[];function clearGesture(){new TWEEN.Tween(camera.position).to({x:cameraInitialPos.x,y:cameraInitialPos.y,z:cameraInitialPos.z}).easing(TWEEN.Easing.Exponential.Out).start();new TWEEN.Tween(camera.rotation).to({x:0,y:0,z:0}).easing(TWEEN.Easing.Exponential.Out).start();for(var i=0,l=renderedHands.length;i<l;i++){scene.remove(renderedHands[i]);}renderedHands=[];}function renderGesture(){if(!webGl){return;}clearGesture();var gestureFrames=trainer.renderableGesture;if(!gestureFrames||gestureFrames.length==0){return;}var frame,hand,handObject,palm,fingers,finger,fingerMesh,material;for(var i=0,l=gestureFrames.length;i<l;i+=gestureRenderInterval){frame=gestureFrames[i];material=new THREE.MeshBasicMaterial({wireframe:true,color:white,transparent:true,opacity:Math.min(0.02*i,0.5)});for(var j=0,k=frame.length;j<k;j++){hand=frame[j];handObject=new THREE.Object3D();palm=createPalm();palm.material=material;positionPalm(hand,palm);handObject.add(palm);fingers=hand.fingers;for(var p=0,q=fingers.length;p<q;p++){finger=fingers[p];fingerMesh=createFinger();fingerMesh.material=material;positionFinger(finger,fingerMesh);handObject.add(fingerMesh);}renderedHands.push(handObject);scene.add(handObject);}}}controller.connect();});