mousedown事件未在平板电脑/移动设备上启动,HTML5 Canvas

mousedown event not firing on tablet / mobile, HTML5 Canvas

本文关键字:启动 Canvas HTML5 移动 事件 平板电脑 mousedown      更新时间:2023-09-26

我遇到了canvas没有在平板电脑上注册mousedown事件的问题,我已经尝试了一段时间,但什么都不起作用,甚至在代码中将mousedown更改为touchstart,实现hammer.js,jquery mobile,任何帮助都将不胜感激,一切都可以在桌面上运行,只是不需要触摸手势

var gestures = function(config){
var conf = {
    debug: true,
    draw: true,
    drawColor: "##f8f07e",
    drawWidth: 5,
    autoTrack: true,
    allowRotation: true,
    inverseShape: true,
    points: 33
};
var d;
var ctx;
var tracking = false;
var ob = this;
this.gestures = [];
this.points = [];
this.construct = function(){
    d = doc_size();
    //copying configuration
    for(var opt in config){
        conf[opt] = config[opt];
    }
    if(document.getElementById("gestures_canvas"))
    {
        ctx = document.getElementById("gestures_canvas").getContext("2d");
    }
    else if(conf.draw)
    {
        //create canvas for drawing
        var canvas = document.createElement("canvas");
        canvas.setAttribute("width", d.width + "px");
        canvas.setAttribute("height", d.height + "px");
        canvas.style.position = "fixed";
        canvas.style.top = "0px";
        canvas.style.left = "0px";
        canvas.id = "gestures_canvas";
        ctx = canvas.getContext("2d");
        document.body.appendChild(canvas);
    }
    if(conf.autoTrack || conf.draw)
    {
        add_event(document.body, "mousedown", this.Down);
        add_event(document.body, "mouseup", this.Up);


        tracking = true;
    }
    this.reset();
};


this.pauseTracking = function(){
    tracking = false;
};
this.resumeTracking = function(){
    tracking = true;
};
this.addGesture = function(name, points, callback){
    if(conf.inverseShape){
        var inverse = [];
        for(var i = points.length-1; i >= 0; i--)
        {
            inverse.push(points[i]);
        }
        var gesture = {};
        gesture.name = name;
        gesture.callback = callback;
        var map = resample(inverse, inverse.length, conf);
        gesture.map = vectorize(map, conf.allowRotation);
        this.gestures.push(gesture);
    }
    var gesture = {};
    gesture.name = name;
    gesture.callback = callback;
    var map = resample(points, points.length, conf);
    gesture.map = vectorize(map, conf.allowRotation);
    this.gestures.push(gesture);
};
this.resolve = function(points){
    if(points.length > 1)
    {
        this.reset();
        var map = resample(points, points.length, conf);
        var ivect = vectorize(map, conf.allowRotation);
        var maxScore = 0;
        var match = "none";
        for(var i = 0; i < this.gestures.length; i++)
        {
            var dist = optCosDist(this.gestures[i].map, ivect);
            var score = 1/dist;
            if(score > maxScore)
            {
                maxScore = score;
                match = this.gestures[i];
            }
        }
        if(match.callback)
        {
            match.callback(match.name);
        }
    }
};
this.reset = function(){
    this.points = [];
};
this.clear = function(){
    ctx.clearRect(0, 0, d.width, d.height);
};
//gesture auto tracking
//mouse down
this.Down = function(event){
    ob.reset();
    if(conf.draw)
    {
        ctx.clearRect(0, 0, d.width, d.height);
        ctx.lineWidth = conf.drawWidth;
        ctx.strokeStyle = conf.drawColor;
        ctx.lastX = event.clientX;
        ctx.lastY = event.clientY;
    }
    if(conf.autoTrack && tracking)
    {
        var point = {};
        point.x = event.clientX;
        point.y = event.clientY;
        ob.points.push(point);
    }
    add_event(document.body, "mousedown", ob.Move);
};
//mouse move
this.Move = function(event){
    if(conf.draw)
    {
        ctx.beginPath();
        ctx.moveTo(ctx.lastX, ctx.lastY);
        ctx.lineTo(event.clientX, event.clientY);
        ctx.stroke();
        ctx.lastX = event.clientX;
        ctx.lastY = event.clientY;
    }
    if(conf.autoTrack && tracking)
    {
        var point = {};
        point.x = event.clientX;
        point.y = event.clientY;
        ob.points.push(point);
    }
};
//mouse up
this.Up = function(event){
    if(conf.autoTrack && tracking)
    {
        ob.resolve(ob.points);
    }
    remove_event(document.body, "mousemove", ob.Move);
};

//some helping internal functions
var optCosDist = function(gestureV, inputV){
    var a = 0;
    var b = 0;
    for(i = 0; i < gestureV.length; i += 2)
    {
        a = a + gestureV[i]*inputV[i] + gestureV[i+1]*inputV[i+1];
        b = b + gestureV[i]*inputV[i+1] - gestureV[i+1]*inputV[i];
    }
    var angle = Math.atan2(b,a);
    return Math.acos(a*Math.cos(angle) + b*Math.sin(angle));
};
//distance [PROTRACTOR]
var Distance = function(u, v){
    var x = (u.x - v.x);
    var y = (u.y - v.y);
    return Math.sqrt((x*x)+(y*y));
};
var pathLength = function(points, n){
    var distance = 0;
    for(i = 1; i < n; i++)
    {
        distance = distance + Distance(points[i-1], points[i]);
    }
    return distance;
};
var resample = function(points, n){
    var subLength = pathLength(points, n)/(conf.points-1);
    var distance = 0;
    var newpoints = [];
    var elem ={};
    elem.x = points[0].x;
    elem.y = points[0].y;
    newpoints.push(elem);
    var i = 1;
    while (i < points.length && newpoints.length < (conf.points-1))
    {
        var subdist = Distance(points[i-1], points[i]);
        if((distance + subdist) >= subLength)
        {
            var elem2 = {};
            elem2.x = points[i-1].x + ((subLength - distance)/subdist)*(points[i].x - points[i-1].x);
            elem2.y = points[i-1].y + ((subLength - distance)/subdist)*(points[i].y - points[i-1].y);
            //add point
            newpoints.push(elem2);
            points.splice(i,0,elem2);
            distance = 0;
        }
        else
        {
            distance = distance + subdist;
        }
        i = i + 1;
    }
    var elem3 = {};
    //adding last point
    elem3.x = points[points.length-1].x;
    elem3.y = points[points.length-1].y;
    newpoints.push(elem3);
    return newpoints;
};
var centroid = function(points){
    var center = {};
    center.x = 0;
    center.y = 0;
    for(i = 0; i < points.length; i++)
    {
        center.x = center.x + points[i].x;
        center.y = center.y + points[i].y;
    }
    center.x = center.x/(points.length-1);
    center.y = center.y/(points.length-1);
    return center;
};
var translate = function(points,center){
    for(var i = 0; i < points.length; i++)
    {
        points[i].x = points[i].x - center.x;
        points[i].y = points[i].y - center.y;
    }
    return points;
};
var vectorize = function(points, sensit){
    var vector = [];
    var center = centroid(points);
    var points = translate(points, center);
    var lenkis = Math.atan2(points[1].x, points[1].y);
    var delta = lenkis;
    if(sensit)
    {
        var base = (Math.PI/4)*Math.floor((lenkis+(Math.PI/8))*(4/Math.PI));
        delta = base-lenkis;
    }
    var summa = 0;
    for(var i = 0; i < points.length; i++)
    {
        var newx = points[i].x*Math.cos(delta) - points[i].y*Math.sin(delta);
        var newy = points[i].x*Math.sin(delta) + points[i].y*Math.cos(delta);
        vector.push(newx);
        vector.push(newy);
        summa = summa + newx*newx + newy*newy;
    }
    var magnitude = Math.sqrt(summa);
    for(var i = 0; i < vector.length; i++)
    {
        vector[i] = vector[i]/magnitude;
    }
    return vector;
};
//get document dimensions
var doc_size = function(){
    var docsize = new Object();
    docsize.width = 0;
    docsize.height = 0;
    docsize.width = Math.max(
        Math.max(document.body.scrollWidth, document.documentElement.scrollWidth),
        Math.max(document.body.offsetWidth, document.documentElement.offsetWidth),
        Math.max(document.body.clientWidth, document.documentElement.clientWidth)
    );
    docsize.height = Math.max(
        Math.max(document.body.scrollHeight, document.documentElement.scrollHeight),
        Math.max(document.body.offsetHeight, document.documentElement.offsetHeight),
        Math.max(document.body.clientHeight, document.documentElement.clientHeight)
    );
    return docsize;
};
//add event
var add_event = function(element, type, listener){
    if(element.addEventListener)
    {
        element.addEventListener(type, listener, false);
    }
    else
    {
        element.attachEvent('on' +  type, listener);
    }
};
//remove event
var remove_event = function(element, type, listener){
    if(element.removeEventListener)
        element.removeEventListener(type, listener, false);
    else
        element.detachEvent('on' +  type, listener);
};
this.construct();

}

我最近不得不这么做,所以你可以在这里追随我的脚步。

要使您的游戏在移动设备上运行,您必须遵循两个步骤:

  • A)将所有mousedownmousemovemouseup事件更改为touchstarttouchmovetouchend(通过查找和替换在记事本中直接替换它们)
  • B)用以下内容替换event.clientXevent.clientY的每个实例:

clientX↓

(event.targetTouches[0] ? event.targetTouches[0].pageX : event.changedTouches[event.changedTouches.length-1].pageX)

客户Y↓

(event.targetTouches[0] ? event.targetTouches[0].pageY : event.changedTouches[event.changedTouches.length-1].pageY)

同样,只需使用Find&代替

以上命令很长/很复杂,因为ontouchend不包含targetTouches对象,并且可以通过Find&替换并将适用于所有Android版本。

最后一件事,您可能还必须在每个touchstart/touchmove事件处理程序的最后放入event.preventDefault(),以防止移动浏览器认为页面正在滚动。

希望这能有所帮助!

我设法做到了这一点,在头上贴了一些代码来检测手机并使用手势脚本,然后桌面使用鼠标脚本,有点像偷工减料的代码,但它可以工作,如果有人能帮我做得很好,请联系

if(/(android|bb'd+|meego).+mobile|avantgo|bada'/|blackberry|blazer|compal|elaine|fennec|hiptop|iemobile|ip(hone|od)|ipad|iris|kindle|Android|Silk|lge |maemo|midp|mmp|netfront|opera m(ob|in)i|palm( os)?|phone|p(ixi|re)'/|plucker|pocket|psp|series(4|6)0|symbian|treo|up'.(browser|link)|vodafone|wap|windows (ce|phone)|xda|xiino/i.test(navigator.userAgent) 
|| /1207|6310|6590|3gso|4thp|50[1-6]i|770s|802s|a wa|abac|ac(er|oo|s'-)|ai(ko|rn)|al(av|ca|co)|amoi|an(ex|ny|yw)|aptu|ar(ch|go)|as(te|us)|attw|au(di|'-m|r |s )|avan|be(ck|ll|nq)|bi(lb|rd)|bl(ac|az)|br(e|v)w|bumb|bw'-(n|u)|c55'/|capi|ccwa|cdm'-|cell|chtm|cldc|cmd'-|co(mp|nd)|craw|da(it|ll|ng)|dbte|dc'-s|devi|dica|dmob|do(c|p)o|ds(12|'-d)|el(49|ai)|em(l2|ul)|er(ic|k0)|esl8|ez([4-7]0|os|wa|ze)|fetc|fly('-|_)|g1 u|g560|gene|gf'-5|g'-mo|go('.w|od)|gr(ad|un)|haie|hcit|hd'-(m|p|t)|hei'-|hi(pt|ta)|hp( i|ip)|hs'-c|ht(c('-| |_|a|g|p|s|t)|tp)|hu(aw|tc)|i'-(20|go|ma)|i230|iac( |'-|'/)|ibro|idea|ig01|ikom|im1k|inno|ipaq|iris|ja(t|v)a|jbro|jemu|jigs|kddi|keji|kgt( |'/)|klon|kpt |kwc'-|kyo(c|k)|le(no|xi)|lg( g|'/(k|l|u)|50|54|'-[a-w])|libw|lynx|m1'-w|m3ga|m50'/|ma(te|ui|xo)|mc(01|21|ca)|m'-cr|me(rc|ri)|mi(o8|oa|ts)|mmef|mo(01|02|bi|de|do|t('-| |o|v)|zz)|mt(50|p1|v )|mwbp|mywa|n10[0-2]|n20[2-3]|n30(0|2)|n50(0|2|5)|n7(0(0|1)|10)|ne((c|m)'-|on|tf|wf|wg|wt)|nok(6|i)|nzph|o2im|op(ti|wv)|oran|owg1|p800|pan(a|d|t)|pdxg|pg(13|'-([1-8]|c))|phil|pire|pl(ay|uc)|pn'-2|po(ck|rt|se)|prox|psio|pt'-g|qa'-a|qc(07|12|21|32|60|'-[2-7]|i'-)|qtek|r380|r600|raks|rim9|ro(ve|zo)|s55'/|sa(ge|ma|mm|ms|ny|va)|sc(01|h'-|oo|p'-)|sdk'/|se(c('-|0|1)|47|mc|nd|ri)|sgh'-|shar|sie('-|m)|sk'-0|sl(45|id)|sm(al|ar|b3|it|t5)|so(ft|ny)|sp(01|h'-|v'-|v )|sy(01|mb)|t2(18|50)|t6(00|10|18)|ta(gt|lk)|tcl'-|tdg'-|tel(i|m)|tim'-|t'-mo|to(pl|sh)|ts(70|m'-|m3|m5)|tx'-9|up('.b|g1|si)|utst|v400|v750|veri|vi(rg|te)|vk(40|5[0-3]|'-v)|vm40|voda|vulc|vx(52|53|60|61|70|80|81|83|85|98)|w3c('-| )|webc|whit|wi(g |nc|nw)|wmlb|wonu|x700|yas'-|your|zeto|zte'-/i.test(navigator.userAgent.substr(0,4))){ isMobile = true;}
----------end of head code---------------
 if(isMobile==true){
var gestures = function(config){
var conf = {
    debug: true,
    draw: true,
    drawColor: "#000000",
    drawWidth: 5,
    autoTrack: true,
    allowRotation: true,
    inverseShape: true,
    points: 33
};
var d;
var ctx;
var tracking = false;
var ob = this;
this.gestures = [];
this.points = [];
this.construct = function(){
    d = doc_size();
    //copying configuration
    for(var opt in config){
        conf[opt] = config[opt];
    }
    if(document.getElementById("gestures_canvas"))
    {
        ctx = document.getElementById("gestures_canvas").getContext("2d");
    }
    else if(conf.draw)
    {
        //create canvas for drawing
        var canvas = document.createElement("canvas");
        canvas.setAttribute("width", d.width + "px");
        canvas.setAttribute("height", d.height + "px");
        canvas.style.position = "absolute";
        canvas.style.top = "0px";
        canvas.style.left = "0px";
        canvas.id = "gestures_canvas";
        ctx = canvas.getContext("2d");
        document.body.appendChild(canvas);
    }
    if(conf.autoTrack || conf.draw)
    {
        add_event(document.body, "touchstart", this.Down);
        add_event(document.body, "touchend", this.Up);
        tracking = true;
    }
    this.reset();
};
this.pauseTracking = function(){
    tracking = false;
};
this.resumeTracking = function(){
    tracking = true;
};
this.addGesture = function(name, points, callback){
    if(conf.inverseShape){
        var inverse = [];
        for(var i = points.length-1; i >= 0; i--)
        {
            inverse.push(points[i]);
        }
        var gesture = {};
        gesture.name = name;
        gesture.callback = callback;
        var map = resample(inverse, inverse.length, conf);
        gesture.map = vectorize(map, conf.allowRotation);
        this.gestures.push(gesture);
    }
    var gesture = {};
    gesture.name = name;
    gesture.callback = callback;
    var map = resample(points, points.length, conf);
    gesture.map = vectorize(map, conf.allowRotation);
    this.gestures.push(gesture);
};
this.resolve = function(points){
    if(points.length > 1)
    {
        this.reset();
        var map = resample(points, points.length, conf);
        var ivect = vectorize(map, conf.allowRotation);
        var maxScore = 0;
        var match = "none";
        for(var i = 0; i < this.gestures.length; i++)
        {
            var dist = optCosDist(this.gestures[i].map, ivect);
            var score = 1/dist;
            if(score > maxScore)
            {
                maxScore = score;
                match = this.gestures[i];
            }
        }
        if(match.callback)
        {
            match.callback(match.name);
        }
    }
};
this.reset = function(){
    this.points = [];
};
this.clear = function(){
    ctx.clearRect(0, 0, d.width, d.height);
};
//gesture auto tracking
//mouse down
this.Down = function(event){
    ob.reset();
    if(conf.draw)
    {
        ctx.clearRect(0, 0, d.width, d.height);
        ctx.lineWidth = conf.drawWidth;
        ctx.strokeStyle = conf.drawColor;
        ctx.lastX = (event.targetTouches[0] ? event.targetTouches[0].pageX :        event.changedTouches[event.changedTouches.length-1].pageX)
;ctx.lastY = (event.targetTouches[0] ? event.targetTouches[0].pageY :     event.changedTouches[event.changedTouches.length-1].pageY)
;
    }
    if(conf.autoTrack && tracking)
    {
        var point = {};
        point.x = (event.targetTouches[0] ? event.targetTouches[0].pageX : event.changedTouches[event.changedTouches.length-1].pageX)
;
        point.y = (event.targetTouches[0] ? event.targetTouches[0].pageY : event.changedTouches[event.changedTouches.length-1].pageY)
;
        ob.points.push(point);
    }
    add_event(document.body, "touchmove", ob.Move);
};
//mouse move
this.Move = function(event){
    if(conf.draw)
    {
        ctx.beginPath();
        ctx.moveTo(ctx.lastX, ctx.lastY);
        ctx.lineTo((event.targetTouches[0] ? event.targetTouches[0].pageX :     event.changedTouches[event.changedTouches.length-1].pageX)
, (event.targetTouches[0] ? event.targetTouches[0].pageY : event.changedTouches[event.changedTouches.length-1].pageY)
);
            ctx.stroke();
        ctx.lastX = (event.targetTouches[0] ? event.targetTouches[0].pageX : event.changedTouches[event.changedTouches.length-1].pageX)
;
        ctx.lastY = (event.targetTouches[0] ? event.targetTouches[0].pageY : event.changedTouches[event.changedTouches.length-1].pageY)
;
    }
    if(conf.autoTrack && tracking)
    {
        var point = {};
        point.x = (event.targetTouches[0] ? event.targetTouches[0].pageX : event.changedTouches[event.changedTouches.length-1].pageX)
;
        point.y = (event.targetTouches[0] ? event.targetTouches[0].pageY : event.changedTouches[event.changedTouches.length-1].pageY)
  ;
        ob.points.push(point);
    }
};
//mouse up
this.Up = function(event){
    if(conf.autoTrack && tracking)
    {
        ob.resolve(ob.points);
    }
    remove_event(document.body, "touchmove", ob.Move);
};

//some helping internal functions
var optCosDist = function(gestureV, inputV){
    var a = 0;
    var b = 0;
    for(i = 0; i < gestureV.length; i += 2)
    {
        a = a + gestureV[i]*inputV[i] + gestureV[i+1]*inputV[i+1];
        b = b + gestureV[i]*inputV[i+1] - gestureV[i+1]*inputV[i];
    }
    var angle = Math.atan2(b,a);
    return Math.acos(a*Math.cos(angle) + b*Math.sin(angle));
};
//distance [PROTRACTOR]
var Distance = function(u, v){
    var x = (u.x - v.x);
    var y = (u.y - v.y);
    return Math.sqrt((x*x)+(y*y));
};
var pathLength = function(points, n){
    var distance = 0;
    for(i = 1; i < n; i++)
    {
        distance = distance + Distance(points[i-1], points[i]);
    }
    return distance;
};
var resample = function(points, n){
    var subLength = pathLength(points, n)/(conf.points-1);
    var distance = 0;
    var newpoints = [];
    var elem ={};
    elem.x = points[0].x;
    elem.y = points[0].y;
    newpoints.push(elem);
    var i = 1;
    while (i < points.length && newpoints.length < (conf.points-1))
    {
        var subdist = Distance(points[i-1], points[i]);
        if((distance + subdist) >= subLength)
        {
            var elem2 = {};
            elem2.x = points[i-1].x + ((subLength - distance)/subdist)*(points[i].x - points[i-1].x);
            elem2.y = points[i-1].y + ((subLength - distance)/subdist)*(points[i].y - points[i-1].y);
            //add point
            newpoints.push(elem2);
            points.splice(i,0,elem2);
            distance = 0;
        }
        else
        {
            distance = distance + subdist;
        }
        i = i + 1;
    }
    var elem3 = {};
    //adding last point
    elem3.x = points[points.length-1].x;
    elem3.y = points[points.length-1].y;
    newpoints.push(elem3);
    return newpoints;
};
var centroid = function(points){
    var center = {};
    center.x = 0;
    center.y = 0;
    for(i = 0; i < points.length; i++)
    {
        center.x = center.x + points[i].x;
        center.y = center.y + points[i].y;
    }
    center.x = center.x/(points.length-1);
    center.y = center.y/(points.length-1);
    return center;
};
var translate = function(points,center){
    for(var i = 0; i < points.length; i++)
    {
        points[i].x = points[i].x - center.x;
        points[i].y = points[i].y - center.y;
    }
    return points;
};
var vectorize = function(points, sensit){
    var vector = [];
    var center = centroid(points);
    var points = translate(points, center);
    var lenkis = Math.atan2(points[1].x, points[1].y);
    var delta = lenkis;
    if(sensit)
    {
        var base = (Math.PI/4)*Math.floor((lenkis+(Math.PI/8))*(4/Math.PI));
        delta = base-lenkis;
    }
    var summa = 0;
    for(var i = 0; i < points.length; i++)
    {
        var newx = points[i].x*Math.cos(delta) - points[i].y*Math.sin(delta);
        var newy = points[i].x*Math.sin(delta) + points[i].y*Math.cos(delta);
        vector.push(newx);
        vector.push(newy);
        summa = summa + newx*newx + newy*newy;
    }
    var magnitude = Math.sqrt(summa);
    for(var i = 0; i < vector.length; i++)
    {
        vector[i] = vector[i]/magnitude;
    }
    return vector;
};
//get document dimensions
var doc_size = function(){
    var docsize = new Object();
    docsize.width = 0;
    docsize.height = 0;
    docsize.width = Math.max(
        Math.max(document.body.scrollWidth, document.documentElement.scrollWidth),
        Math.max(document.body.offsetWidth, document.documentElement.offsetWidth),
        Math.max(document.body.clientWidth, document.documentElement.clientWidth)
    );
    docsize.height = Math.max(
        Math.max(document.body.scrollHeight, document.documentElement.scrollHeight),
        Math.max(document.body.offsetHeight, document.documentElement.offsetHeight),
        Math.max(document.body.clientHeight, document.documentElement.clientHeight)
    );
    return docsize;
};
//add event
var add_event = function(element, type, listener){
    if(element.addEventListener)
    {
        element.addEventListener(type, listener, false);
    }
    else
    {
        element.attachEvent('on' +  type, listener);
    }
};
//remove event
var remove_event = function(element, type, listener){
    if(element.removeEventListener)
        element.removeEventListener(type, listener, false);
    else
        element.detachEvent('on' +  type, listener);
};
this.construct();
}
} else { 
var gestures = function(config){
var conf = {
    debug: true,
    draw: true,
    drawColor: "#000000",
    drawWidth: 5,
    autoTrack: true,
    allowRotation: true,
    inverseShape: true,
    points: 33
};
var d;
var ctx;
var tracking = false;
var ob = this;
this.gestures = [];
this.points = [];
this.construct = function(){
    d = doc_size();
    //copying configuration
    for(var opt in config){
        conf[opt] = config[opt];
    }
    if(document.getElementById("gestures_canvas"))
    {
        ctx = document.getElementById("gestures_canvas").getContext("2d");
    }
    else if(conf.draw)
    {
        //create canvas for drawing
        var canvas = document.createElement("canvas");
        canvas.setAttribute("width", d.width + "px");
        canvas.setAttribute("height", d.height + "px");
        canvas.style.position = "absolute";
        canvas.style.top = "0px";
        canvas.style.left = "0px";
        canvas.id = "gestures_canvas";
        ctx = canvas.getContext("2d");
        document.body.appendChild(canvas);
    }
    if(conf.autoTrack || conf.draw)
    {
        add_event(document.body, "mousedown", this.Down);
        add_event(document.body, "mouseup", this.Up);
        tracking = true;
    }
    this.reset();
};
this.pauseTracking = function(){
    tracking = false;
};
this.resumeTracking = function(){
    tracking = true;
};
this.addGesture = function(name, points, callback){
    if(conf.inverseShape){
        var inverse = [];
        for(var i = points.length-1; i >= 0; i--)
        {
            inverse.push(points[i]);
        }
        var gesture = {};
        gesture.name = name;
        gesture.callback = callback;
        var map = resample(inverse, inverse.length, conf);
        gesture.map = vectorize(map, conf.allowRotation);
        this.gestures.push(gesture);
    }
    var gesture = {};
    gesture.name = name;
    gesture.callback = callback;
    var map = resample(points, points.length, conf);
    gesture.map = vectorize(map, conf.allowRotation);
    this.gestures.push(gesture);
};
this.resolve = function(points){
    if(points.length > 1)
    {
        this.reset();
        var map = resample(points, points.length, conf);
        var ivect = vectorize(map, conf.allowRotation);
        var maxScore = 0;
        var match = "none";
        for(var i = 0; i < this.gestures.length; i++)
        {
            var dist = optCosDist(this.gestures[i].map, ivect);
            var score = 1/dist;
            if(score > maxScore)
            {
                maxScore = score;
                match = this.gestures[i];
            }
        }
        if(match.callback)
        {
            match.callback(match.name);
        }
    }
};
this.reset = function(){
    this.points = [];
};
this.clear = function(){
    ctx.clearRect(0, 0, d.width, d.height);
};
//gesture auto tracking
//mouse down
this.Down = function(event){
    ob.reset();
    if(conf.draw)
    {
        ctx.clearRect(0, 0, d.width, d.height);
        ctx.lineWidth = conf.drawWidth;
        ctx.strokeStyle = conf.drawColor;
        ctx.lastX = event.clientX;
        ctx.lastY = event.clientY;
    }
    if(conf.autoTrack && tracking)
    {
        var point = {};
        point.x = event.clientX;
        point.y = event.clientY;
        ob.points.push(point);
    }
    add_event(document.body, "mousemove", ob.Move);
};
//mouse move
this.Move = function(event){
    if(conf.draw)
    {
        ctx.beginPath();
        ctx.moveTo(ctx.lastX, ctx.lastY);
        ctx.lineTo(event.clientX, event.clientY);
        ctx.stroke();
        ctx.lastX = event.clientX;
        ctx.lastY = event.clientY;
    }
    if(conf.autoTrack && tracking)
    {
        var point = {};
        point.x = event.clientX;
        point.y = event.clientY;
        ob.points.push(point);
    }
};
//mouse up
this.Up = function(event){
    if(conf.autoTrack && tracking)
    {
        ob.resolve(ob.points);
    }
    remove_event(document.body, "mousemove", ob.Move);
};

//some helping internal functions
var optCosDist = function(gestureV, inputV){
    var a = 0;
    var b = 0;
    for(i = 0; i < gestureV.length; i += 2)
    {
        a = a + gestureV[i]*inputV[i] + gestureV[i+1]*inputV[i+1];
        b = b + gestureV[i]*inputV[i+1] - gestureV[i+1]*inputV[i];
    }
    var angle = Math.atan2(b,a);
    return Math.acos(a*Math.cos(angle) + b*Math.sin(angle));
};
//distance [PROTRACTOR]
var Distance = function(u, v){
    var x = (u.x - v.x);
    var y = (u.y - v.y);
    return Math.sqrt((x*x)+(y*y));
};
var pathLength = function(points, n){
    var distance = 0;
    for(i = 1; i < n; i++)
    {
        distance = distance + Distance(points[i-1], points[i]);
    }
    return distance;
};
var resample = function(points, n){
    var subLength = pathLength(points, n)/(conf.points-1);
    var distance = 0;
    var newpoints = [];
    var elem ={};
    elem.x = points[0].x;
    elem.y = points[0].y;
    newpoints.push(elem);
    var i = 1;
    while (i < points.length && newpoints.length < (conf.points-1))
    {
        var subdist = Distance(points[i-1], points[i]);
        if((distance + subdist) >= subLength)
        {
            var elem2 = {};
            elem2.x = points[i-1].x + ((subLength - distance)/subdist)*(points[i].x - points[i-1].x);
            elem2.y = points[i-1].y + ((subLength - distance)/subdist)*(points[i].y - points[i-1].y);
            //add point
            newpoints.push(elem2);
            points.splice(i,0,elem2);
            distance = 0;
        }
        else
        {
            distance = distance + subdist;
        }
        i = i + 1;
    }
    var elem3 = {};
    //adding last point
    elem3.x = points[points.length-1].x;
    elem3.y = points[points.length-1].y;
    newpoints.push(elem3);
    return newpoints;
};
var centroid = function(points){
    var center = {};
    center.x = 0;
    center.y = 0;
    for(i = 0; i < points.length; i++)
    {
        center.x = center.x + points[i].x;
        center.y = center.y + points[i].y;
    }
    center.x = center.x/(points.length-1);
    center.y = center.y/(points.length-1);
    return center;
};
var translate = function(points,center){
    for(var i = 0; i < points.length; i++)
    {
        points[i].x = points[i].x - center.x;
        points[i].y = points[i].y - center.y;
    }
    return points;
};
var vectorize = function(points, sensit){
    var vector = [];
    var center = centroid(points);
    var points = translate(points, center);
    var lenkis = Math.atan2(points[1].x, points[1].y);
    var delta = lenkis;
    if(sensit)
    {
        var base = (Math.PI/4)*Math.floor((lenkis+(Math.PI/8))*(4/Math.PI));
        delta = base-lenkis;
    }
    var summa = 0;
    for(var i = 0; i < points.length; i++)
    {
        var newx = points[i].x*Math.cos(delta) - points[i].y*Math.sin(delta);
        var newy = points[i].x*Math.sin(delta) + points[i].y*Math.cos(delta);
        vector.push(newx);
        vector.push(newy);
        summa = summa + newx*newx + newy*newy;
    }
    var magnitude = Math.sqrt(summa);
    for(var i = 0; i < vector.length; i++)
    {
        vector[i] = vector[i]/magnitude;
    }
    return vector;
};
//get document dimensions
var doc_size = function(){
    var docsize = new Object();
    docsize.width = 0;
    docsize.height = 0;
    docsize.width = Math.max(
        Math.max(document.body.scrollWidth, document.documentElement.scrollWidth),
        Math.max(document.body.offsetWidth, document.documentElement.offsetWidth),
        Math.max(document.body.clientWidth, document.documentElement.clientWidth)
    );
    docsize.height = Math.max(
        Math.max(document.body.scrollHeight, document.documentElement.scrollHeight),
        Math.max(document.body.offsetHeight, document.documentElement.offsetHeight),
        Math.max(document.body.clientHeight, document.documentElement.clientHeight)
    );
    return docsize;
};
//add event
var add_event = function(element, type, listener){
    if(element.addEventListener)
    {
        element.addEventListener(type, listener, false);
    }
    else
    {
        element.attachEvent('on' +  type, listener);
    }
};
//remove event
var remove_event = function(element, type, listener){
    if(element.removeEventListener)
        element.removeEventListener(type, listener, false);
    else
        element.detachEvent('on' +  type, listener);
};
this.construct();
}
}