Why this plugin:I am developing a mobile app - at some point, I felt like this would be a good idea to give the users the possibility to control everything in the app with touch gestures, hence the need for a plugin able to recognize more than the basic swipe events.What it does:When the user starts touching the screen and moving his finger (or mouse on desktop btw), the code tries to identify his move as one of the eight cardinal directions (North, South, West, East, NorthWest, SouthWest, SouthEast, NorthEast). If he changes direction, then the next direction he takes is added to the list to produce an output like : North->East->South...Why I am posting here:This code is going to be run quite a lot of times in the app (every time the user moves his finger on the screen), and I would love to be sure that it is not going to pose performance issues, or if I overlooked some best practices I am not aware of, and of course, any constructive feedback is very welcome.The part of the code to attach the event and handle touchStart and touchStop is not mine, it is taken from here, but I am including it for plugin completeness (also modified some very minor things).The code:// jquerymobile-unicorn_swipe// ----------------------------------// Copyright (c)2012 Donnovan Lewis// Copyright (c)2014 Romain Le Bail// Distributed under MIT license (http://opensource.org/licenses/MIT)////credits to Donnovan Lewis for the material taken from https://github.com/blackdynamo/jquerymobile-swipeupdown(function () { // initializes touch events    var supportTouch = $.support.touch,        touchStartEvent = supportTouch ? touchstart : mousedown,        touchStopEvent = supportTouch ? touchend : mouseup,        touchMoveEvent = supportTouch ? touchmove : mousemove;$.event.special.unicorn = {     setup: function () {        var thisObject = this;        var $this = $(thisObject);        $this.bind(touchStartEvent, function (event) {               var path = []; var derived_path = []; var segs = [[]]; var seg_types =[[]]; var max_freqs = [[]];            var data = event.originalEvent.touches ?                    event.originalEvent.touches[ 0 ] :                    event,                start = {                    time: (new Date).getTime(),                    coords: [ data.pageX, data.pageY ],                    origin: $(event.target)                },                stop = false;            var n = 0;            path[n]=[ data.pageX, data.pageY ]; /* starting point */            function moveHandler(event) {                if (!start) {                    return;                }                var data = event.originalEvent.touches ?                    event.originalEvent.touches[ 0 ] :                    event;                stop = {                    time: (new Date).getTime(),                    coords: [ data.pageX, data.pageY ]                };                n++;                path[n]=[ data.pageX, data.pageY ];                // prevent scrolling                //if (Math.abs(start.coords[1] - stop.coords[1]) > 10) {event.preventDefault();}            }            $this                .bind(touchMoveEvent, moveHandler)                .one(touchStopEvent, function (event) {                      $this.unbind(touchMoveEvent, moveHandler);    /* now we stopped moving */                    var l = path.length;                     var min_length = 8; /* min length is to have enough points to perform consistent recognition */                     var fire = false;                    if(l>min_length && stop.time - start.time < 10000)                     {                    for(var i=1;i<l-1;++i)                    {                        var d_i = (path[i+1][1]-path[i-1][1]) / (path[i+1][0]-path[i-1][0]); /* maybe use x'(t) and y'(t) in addition to y'(x)*/                        var x_sig_i = path[i+1][0]-path[i-1][0]<0 ? -1 : 1;                         derived_path[i-1] = d_i==Infinity ? 1000 : d_i==-Infinity ? -1000 : d_i>3 ? 1000*x_sig_i : d_i<-3 ? -1000*x_sig_i /* vertical moves */                                : d_i>=-2 && d_i<=-0.5 ? -1 : d_i>=0.5 && d_i<=2 ? 1 /* diagonal moves */                                : Math.abs(d_i)<=0.5 ? 0 : d_i; /* horizontal moves */                    };                    for(var i=0;i<=l-min_length;++i) /* create sub paths of min_length-2 points */                    {                        segs[i]=derived_path.slice(i,i+min_length-2);                        seg_types[i]=[0,0];                        if(path[i+7][1]<path[i][1]){seg_types[i][1]=1;}; /* four quadrants */                        if(path[i+7][1]>path[i][1]){seg_types[i][1]=-1;};                        if(path[i+7][0]>path[i][0]){seg_types[i][0]=1;};                        if(path[i+7][0]<path[i][0]){seg_types[i][0]=-1;};                    }                    for(var i=0;i<=l-min_length;++i)                    {                         segs[i].sort(function(a,b){return a - b;});  /* sorting to count duplicates */                        var previous = segs[i][0];                        var popular = segs[i][0];                        var count = 1;                        var max_count = 1;                        for (var j=1; j<8; j++)                         {                             if (segs[i][j] == previous)                            {count++;}                            else                             {                                if (count > max_count)                                 {                                    popular = segs[i][j-1];                                    max_count = count;                                };                                previous = segs[i][j];                                count = 1;                            };                        var pop = count > max_count ? segs[i][min_length-3] : popular;                        var cnt = count > max_count ? count : max_count;                        max_freqs[i]=[pop,cnt];                        }                    }                    for(var i=max_freqs.length-1; i>=0; i--)                    {                            if(max_freqs[i][1]<=4){max_freqs.splice(i,1);seg_types.splice(i,1);};  /* eliminate sub paths without clear direction */                    }                    var previous = max_freqs[max_freqs.length-1];                    var previous_type = seg_types[max_freqs.length-1];                    for(var i=max_freqs.length-2; i>=0; i--)                    {                            if(previous[0]==max_freqs[i][0] && (previous_type[0]==seg_types[i][0] && previous_type[1]==seg_types[i][1] /* merge consecutive sub paths */                            || Math.abs(max_freqs[i][0])>500)                            || (max_freqs[i][0]==0 && previous_type[0]==seg_types[i][0]))                        {                            if(previous[1]>max_freqs[i][1]){max_freqs.splice(i,1);seg_types.splice(i,1);}                            else{max_freqs.splice(i+1,1);seg_types.splice(i,1);};                        }                        previous = max_freqs[i];                        previous_type = seg_types[i];                    }                    var typezor=;                    for(var i=0;i<max_freqs.length;++i)                    {                        var p_i = max_freqs[i][0];                        var t_x_i = seg_types[i][0];                        var t_y_i = seg_types[i][1];                        if(i>0){typezor += ->;};                        typezor += p_i==-1000 ? North : p_i==1000 ? South : p_i==0 ? (t_x_i > 0 ? East : West) :                             p_i == -1 ? (t_y_i > 0 ? NorthEast : SouthWest) : (t_y_i > 0 ? NorthWest : SouthEast);                    }                    if(i!=0){fire=true;};                    }                    if (start && stop) {                        if (fire) {                              start.origin.trigger({type:unicorn,typezor:typezor});                        }                    }                    start = stop = false;                });        });    }};})();How to test:If anyone finds this funny, you can test it on desktop PC by adding an event handler:$(document).on('unicorn', function(event, ui){ console.warn(event.typezor); });or simply by replacing the start.origin.trigger({type:unicorn,typezor:typezor}); line by an alert/console.log.
Small jQuery mobile plugin to handle touch events
javascript;jquery;event handling;plugin;touch
Interesting plugin,some observations:Use JsHint, there are a ton of minor issues with this code that you should clean upUse JsBeautifier, there is quite a bit of inconsistent formatting'unicorn' sounds like fun, 'typezor' not so muchIt seems this code does not handle simultaneous touch events ?From a style perspective,Too much horizontal stretching, why ?var path = []; var derived_path = []; var segs = [[]]; var seg_types =[[]]; var max_freqs = [[]];Naming is often too cryptic, plus JavaScript should use lowerCamelCase ( max_count -> maxCount )Nested ternary operators are too hackishif(i!=0){fire=true;}; could be fire = fire || !i; though I might have considered that too hackish if you had actually written that ;)Commenting : simply stuff is commented like /* starting point */ but the harder part ( for me ) where you derive a direction does not have enough commentsAll in all, I think this code needs some more polishing before I would use it in a project.