{"action":"created","issue":{"url":"https://api.github.com/repos/garris/TremulaJS/issues/17","labels_url":"https://api.github.com/repos/garris/TremulaJS/issues/17/labels{/name}","comments_url":"https://api.github.com/repos/garris/TremulaJS/issues/17/comments","events_url":"https://api.github.com/repos/garris/TremulaJS/issues/17/events","html_url":"https://github.com/garris/TremulaJS/issues/17","id":60707813,"number":17,"title":"Hammer.js Exception","user":{"login":"vko-online","id":4560099,"avatar_url":"https://avatars.githubusercontent.com/u/4560099?v=3","gravatar_id":"","url":"https://api.github.com/users/vko-online","html_url":"https://github.com/vko-online","followers_url":"https://api.github.com/users/vko-online/followers","following_url":"https://api.github.com/users/vko-online/following{/other_user}","gists_url":"https://api.github.com/users/vko-online/gists{/gist_id}","starred_url":"https://api.github.com/users/vko-online/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/vko-online/subscriptions","organizations_url":"https://api.github.com/users/vko-online/orgs","repos_url":"https://api.github.com/users/vko-online/repos","events_url":"https://api.github.com/users/vko-online/events{/privacy}","received_events_url":"https://api.github.com/users/vko-online/received_events","type":"User","site_admin":false},"labels":[],"state":"open","locked":false,"assignee":null,"milestone":null,"comments":4,"created_at":"2015-03-11T18:34:20Z","updated_at":"2015-03-12T04:24:43Z","closed_at":null,"body":"`Uncaught TypeError: Cannot read property 'stopDetect' of undefined` when dragging, in \r\n\r\n```json\r\n    \"jquery\": \"~1.7.1\",\r\n    \"tremulajs\": \"~1.2.4\",\r\n    \"hammer.js\": \"~2.0.4\",\r\n    \"jsbezier\": \"*\"\r\n```\r\n```js\r\nswitch(ev.type) {\r\n\t\t\tcase 'mousewheel':\r\n\t\t\tcase 'DOMMouseScroll':\r\n\t\t\tcase 'wheel':\r\n\t\t\t\t_mw.call(this,ev);\r\n\t\t\t\t//dont break here -- keep evaluation...\r\n\t\t\tcase '_mw': //map events over for processing by dragleft\r\n\t\t\t\tvar wheelEvent = ev;//ev.originalEvent;\r\n\t\t\t\tvar //wheel events for webkit|| new moz || old moz\r\n\t\t\t\t\tdy = wheelEvent.wheelDeltaY*.5||-wheelEvent.deltaY||-wheelEvent.detail*3,\r\n\t\t\t\t\tdx = wheelEvent.wheelDeltaX*.5||-wheelEvent.deltaX||-wheelEvent.detail*3;\r\n\t\t\t\tvar nextScrollPos = this.scrollPos + (this.sx)?dx:dy;\r\n\t\t\t\tvar maxScroll = this.trailingEdgeScrollPos;\r\n\t\t\t\t//isNextHeadMargin and isNextTailMargin add massive drag to input to simulate rubberband tension in scrollFrame\r\n\t\t\t\tvar isNextHeadMargin = !this.hasMediumGridDimsSi && nextScrollPos>this.firstItemPos;\r\n\t\t\t\tvar isNextTailMargin = !this.hasMediumGridDimsSi && nextScrollPos<maxScroll;\r\n\t\t\t\t//   || this.isInHeadMargin\r\n\t\t\t\t//add scroll tension if looping is OFF and the very next tick is going to put us beyound the first item or the last item\r\n\t\t\t\tif(!this.isLooping && (isNextHeadMargin||isNextTailMargin) ){\r\n\t\t\t\t\tif(this.sx){\r\n\t\t\t\t\t\tdx=Math.min(dx*.1,100);\r\n\t\t\t\t\t}else{\r\n\t\t\t\t\t\tdy=Math.min(dy*.1,100);\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\t\t\t\tev.gesture                  = ev.gesture || {};\r\n\t\t\t\tev.gesture.deltaX           = dx;\r\n\t\t\t\tev.gesture.deltaY           = dy;\r\n\t\t\t\tev.gesture.center           = ev.gesture.center || {};\r\n\t\t\t\tev.gesture.center.pageX = ev.pageX;//ev.originalEvent.pageX;\r\n\t\t\t\tev.gesture.center.pageY = ev.pageY;//ev.originalEvent.pageY;\r\n\t\t\t\t//fingeredOffset = this.scrollPos; moved below...\r\n\t\t\t\t// if(this.isInHeadMargin){ev.gesture.deltaX = dx*.01}\r\n\t\t\t\t// ===>  NOTE: THERE IS NO BREAK HERE. MW EVENTS ARE NORMALIZED (as ev.gesture.*) ABOVE AND THEN PROCESSED AS DRAG EVENTS BELOW vvv\r\n\t\t\t\t\r\n\t\t\tcase 'dragup':\r\n\t\t\tcase 'dragdown':\r\n\t\t\tcase 'dragright':\r\n\t\t\tcase 'dragleft':\r\n\t\t\t// === manually block page scroll ===\r\n\t\t\t// if in horizontal config and the user is scrolling horizontally\r\n\t\t\t// or if in vertical config and the user is scrolling vertically\r\n\t\t\tif(ev.pointerType==\"mouse\"){\r\n\t\t\t\tev.gesture.preventDefault();\r\n\t\t\t\tev.gesture.stopPropagation();\r\n\t\t\t}else if(this.sx){//is horizontal config\r\n\t\t\t\t// if(ev.gesture.deltaX != 0){//this old bit was recently disabled\r\n\t\t\t\t\tif(Math.abs(ev.gesture.deltaY/ev.gesture.deltaX) <= 1){ // if this ratio is 1 or less then the user is scrolling the scroll axis: so block native events\r\n\t\t\t\t\t\tshuntEvent(ev);\r\n\t\t\t\t\t}\r\n\t\t\t\t// }\r\n\t\t\t}else{// is vertical config\r\n\t\t\t\t// if(ev.gesture.deltaY != 0){//this old bit was recently disabled -- not needed now?\r\n\t\t\t\t\tif(Math.abs(ev.gesture.deltaX/ev.gesture.deltaY) <= 1){ // if this ratio is 1 or less then the user is scrolling the scroll axis: so block native events\r\n\t\t\t\t\t\tshuntEvent(ev);\r\n\t\t\t\t\t}\r\n\t\t\t\t// }\r\n\t\t\t}// config case\r\n\t\t\t// === END: manually block page scroll  === \r\n\t\t\t\tthis.isTouching=true;\r\n\t\t\t\t//incase we are at the begining of a touch event or incase this is a fallthrough WheelEvent\r\n\t\t\t\tif(fingeredOffset==0 || /wheel|scroll/.test(ev.type)){\r\n\t\t\t\t\tfingeredOffset = this.scrollPos;\r\n\t\t\t\t\tlastD = 0;\r\n\t\t\t\t}\r\n\t\t\t\t// //incase we are at the begining of a touch event or incase this is a fallthrough WheelEvent\r\n\t\t\t\t// if(fingeredOffset_==0 ||  /wheel|scroll/.test(ev.type)){\r\n\t\t\t\t// \tfingeredOffset_ = this.parentParentE.scrollTop;\r\n\t\t\t\t// \tlastD_ = 0;\r\n\t\t\t\t// }\r\n\t\t\t\tvar D = (this.sx)?ev.gesture.deltaX:ev.gesture.deltaY;\r\n\t\t\t\tvar D_ = (!this.sx)?ev.gesture.deltaX:ev.gesture.deltaY;\r\n\t\t\t\t//if we are scrolling along the scrollaxis\r\n\t\t\t\tif(Math.abs(D)>Math.abs(D_)){\r\n\t\t\t\t\tthis.setScrollPos( D-lastD, true );\r\n\t\t\t\t\tlastD = D;\r\n\t\t\t\t\tthis.oneShotPaint(ev);\r\n\t\t\t\t}\r\n\t\t\t\tthis.tagLastUserEvent(ev);\r\n\t\t\t\tbreak;\r\n\t\t\t\t\r\n\t\t\tcase 'swipeleft':\r\n\t\t\t\tif(!this.sx){return}\r\n\t\t\t\tev.gesture.stopDetect();\r\n\t\t\t\tthis.isTouching=false;\r\n\t\t\t\t//var m = this.momentum = -this.dMomentum;\r\n\t\t\t\tvar m = -ev.gesture.velocityX;\r\n\t\t\t\tif(this.steppedScrolling)\r\n\t\t\t\t\tthis.easeToNextStepItem();\r\n\t\t\t\telse\r\n\t\t\t\t\tthis.startEasing(m,ev)\r\n\t\t\t\tthis.tagLastUserEvent(ev);\r\n\t\t\t\tbreak;\r\n\r\n\t\t\tcase 'swiperight':\r\n\t\t\t\tif(!this.sx){return}\r\n\t\t\t\tev.gesture.stopDetect();\r\n\t\t\t\tthis.isTouching=false;\r\n\t\t\t\tvar m = ev.gesture.velocityX;\r\n\t\t\t\tif(this.steppedScrolling)\r\n\t\t\t\t\tthis.easeToPrevStepItem();\r\n\t\t\t\telse\r\n\t\t\t\t\tthis.startEasing(m,ev)\r\n\t\t\t\tthis.tagLastUserEvent(ev);\r\n\t\t\t\tbreak;\r\n\t\t\t\t\r\n\t\t\tcase 'swipeup':\r\n\t\t\t\tif(this.sx){return}\r\n\t\t\t\tev.gesture.stopDetect();\r\n\t\t\t\tthis.isTouching=false;\r\n\t\t\t\tvar m = -ev.gesture.velocityY;\r\n\t\t\t\tif(this.steppedScrolling)\r\n\t\t\t\t\tthis.easeToNextStepItem();\r\n\t\t\t\telse\r\n\t\t\t\t\tthis.startEasing(m,ev)\r\n\t\t\t\tthis.tagLastUserEvent(ev);\r\n\t\t\t\tbreak;\r\n\r\n\t\t\tcase 'swipedown':\r\n\t\t\t\tif(this.sx){return}\r\n\t\t\t\tev.gesture.stopDetect();\r\n\t\t\t\tthis.isTouching=false;\r\n\t\t\t\t//var m = this.momentum = this.dMomentum;\r\n\t\t\t\tvar m = ev.gesture.velocityY;\r\n\t\t\t\tif(this.steppedScrolling)\r\n\t\t\t\t\tthis.easeToPrevStepItem();\r\n\t\t\t\telse\r\n\t\t\t\t\tthis.startEasing(m,ev)\r\n\t\t\t\tthis.tagLastUserEvent(ev);\r\n\t\t\t\tbreak;\r\n\t\t\r\n\t\t\tcase 'touch':\r\n\t\t\t\t//u.log('touch: '+new Date().getMilliseconds())\r\n\t\t\t\tfingeredOffset = 0;\r\n\t\t\t\tfingeredOffset_ = 0;\r\n\t\t\t\tthis.isTouching=true;\r\n\t\t\t\tthis.oneShotPaint(ev);\r\n\t\t\t\tthis.tagLastUserEvent(ev);\r\n\t\t\t\tbreak;\r\n\t\t\tcase 'release':\r\n\t\t\t\t//u.log('release: '+new Date().getMilliseconds())\r\n\t\t\t\t//test for last event being a touch AND being OVER x ms ago.  Also make sure we're not in the middle of easing.\r\n\t\t\t\tvar lastUserEvtMs = new Date() - this.lastUserEvent.time;\r\n\t\t\t\tvar lastWasTouch = /touch/.test(this.lastUserEvent.evt.type,'i');\r\n\t\t\t\tif(!this.isEasing && lastWasTouch && lastUserEvtMs < 1000){\r\n\t\t\t\t\tthis.$e.trigger('tremulaItemSelect',ev);\r\n\t\t\t\t}\r\n\t\t\t\tthis.isTouching=false;\r\n\t\t\t\tif(this.steppedScrolling){\r\n\t\t\t\t\tvar lastWasLegalTouch =  lastWasTouch && ev.target && ev.target.className && !/\\bgridBox\\b/.test(ev.target.className);\r\n\r\n\t\t\t\t\tif(!lastWasTouch || lastWasLegalTouch){\r\n\t\t\t\t\t\tthis.easeToClosestStepItem();\r\n\t\t\t\t\t};\r\n\t\t\t\t}else{\r\n\t\t\t\t\tthis.oneShotPaint();\r\n\t\t\t\t}\r\n\t\t\t\tthis.tagLastUserEvent(ev);\r\n\t\t\t\tbreak;          \r\n\t\t}//switch\r\n```\r\n`ev` doesn't have property `gesture` in 'swipe***' case. `ev.gesture.stopDetect(); ` causes error\r\n\r\ncopied from tremula codepen demo\r\n\r\n```js\r\n    (function(){\r\n\r\n  'use strict';\r\n\r\n  angular.module('tremula', []).directive('tremula', function($timeout){\r\n\r\n    return{\r\n      restrict: 'EA',\r\n      link: function($scope, elem){\r\n        var tremulaBase;\r\n        function createTremula(){\r\n\r\n          var $tremulaContainer = elem;\r\n          var tremula = new Tremula();\r\n          var config = {\r\n            itemConstraint      :150,//px\r\n            itemMargins         :[10,10],//x (left & right), y (top & bottom) in px\r\n            staticAxisOffset    :0,//px\r\n            scrollAxisOffset    :20,//px\r\n            scrollAxis          :'x',//'x'|'y'\r\n            surfaceMap          :tremula.projections.xyPlain,\r\n            staticAxisCount     :2,//zero based\r\n            defaultLayout       :tremula.layouts.xyPlain,\r\n            itemPreloading      :true,\r\n            itemEasing          :false,\r\n            isLooping         \t:false,\r\n            itemEasingParams    :{\r\n              touchCurve          :tremula.easings.easeOutCubic,\r\n              swipeCurve          :tremula.easings.easeOutCubic,\r\n              transitionCurve     :tremula.easings.easeOutElastic,\r\n              easeTime            :500,\r\n              springLimit         :40 //in px\r\n            },\r\n            onChangePub\t\t\t\t\t: doScrollEvents,\r\n            data                : null,\r\n            lastContentBlock \t\t: {\r\n              template :'<div class=\"lastContentItem\"></div>',\r\n              layoutType :'tremulaBlockItem',\r\n              noScaling:true,\r\n              w:300,\r\n              h:300,\r\n              isLastContentBlock:true,\r\n              adapter:tremula.dataAdapters.TremulaItem\r\n            },\r\n            adapter             :null\r\n\r\n          };\r\n          tremula.init($tremulaContainer,config,this);\r\n          return tremula;\r\n        }\r\n        function doScrollEvents(o){\r\n          if(o.scrollProgress>.7){\r\n            if(!tremula.cache.endOfScrollFlag){\r\n              tremula.cache.endOfScrollFlag = true;\r\n              pageCtr++;\r\n              loadFlickr();\r\n              console.log('END OF SCROLL!')\r\n            }\r\n          }\r\n        }\r\n\r\n        var pageCtr = 1;\r\n        function loadFlickr(){\r\n          var dataUrl = 'https://api.flickr.com/services/rest/?method=flickr.photos.search&api_key=c149b994c54c114bd7836b61539eec2e&tags=street+art&format=json&page='+pageCtr+'&extras=url_n';\r\n          $.ajax({\r\n            url:dataUrl\r\n            ,dataType: 'jsonp'\r\n            ,jsonp: 'jsoncallback'\r\n          })\r\n            .done(function(res){\r\n              if (res.stat=='fail')alert('Dang. Looks like Flickr has lost its pancakes... '+res.message);\r\n              var rs = res.photos.photo.filter(function(o,i){return o.height_n > o.width_n * .5});//filter out any with a really wide aspect ratio.\r\n              tremulaBase.appendData(rs,flickrDataAdapter);//flicker\r\n              tremulaBase.cache.endOfScrollFlag = false;\r\n            })\r\n            .fail( function(d,config,err){console.log('API FAIL. '+err) })}\r\n\r\n        function flickrDataAdapter(data,env){\r\n          this.data = data;\r\n          this.w = this.width = data.width_n;\r\n          this.h = this.height = data.height_n;\r\n          this.imgUrl = data.url_n;\r\n          this.auxClassList = \"flickrRS\";//stamp each mapped item with map ID\r\n          this.template = this.data.template||('<img draggable=\"false\" class=\"moneyShot\" onload=\"imageLoaded(this)\" src=\"\"/><span class=\"span\">desc </span>');\r\n        }\r\n        function applyBoxClick(){\r\n          elem.on('tremulaItemSelect',function(gestureEvt,domEvt){\r\n            console.log(gestureEvt,domEvt)\r\n            var\r\n              $e = $(domEvt.target);\r\n            if($e.closest('.gridBox')[0]){\r\n              var data = $.data(t).model.model.data;\r\n            }\r\n            if(data)alert(JSON.stringify(data));\r\n          })\r\n        }\r\n        $timeout(function(){\r\n          tremulaBase = createTremula();\r\n          applyBoxClick();\r\n          loadFlickr()\r\n        }, 1);\r\n      }\r\n    }\r\n  });\r\n\r\n})();\r\n\r\n```\r\nMaybe `hammer.js` events not attached to DOM?"},"comment":{"url":"https://api.github.com/repos/garris/TremulaJS/issues/comments/78421897","html_url":"https://github.com/garris/TremulaJS/issues/17#issuecomment-78421897","issue_url":"https://api.github.com/repos/garris/TremulaJS/issues/17","id":78421897,"user":{"login":"vko-online","id":4560099,"avatar_url":"https://avatars.githubusercontent.com/u/4560099?v=3","gravatar_id":"","url":"https://api.github.com/users/vko-online","html_url":"https://github.com/vko-online","followers_url":"https://api.github.com/users/vko-online/followers","following_url":"https://api.github.com/users/vko-online/following{/other_user}","gists_url":"https://api.github.com/users/vko-online/gists{/gist_id}","starred_url":"https://api.github.com/users/vko-online/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/vko-online/subscriptions","organizations_url":"https://api.github.com/users/vko-online/orgs","repos_url":"https://api.github.com/users/vko-online/repos","events_url":"https://api.github.com/users/vko-online/events{/privacy}","received_events_url":"https://api.github.com/users/vko-online/received_events","type":"User","site_admin":false},"created_at":"2015-03-12T04:24:42Z","updated_at":"2015-03-12T04:24:42Z","body":"Also, `jquery` dependency is redundant, few usages, basically \r\n`$.extend, $.each, $(), addClass/removeClass` but maybe hammerjs still requires jquery (and maybe jsbezier) \r\nAlso i think whole convertion to angular would pass easily. \r\n`hammerjs => angular-touch`, and i think you could get rid if jsbezier, you already have them in `src/Easing.js`"}}