1 /****************************************************************************
  2  Copyright (c) 2010-2012 cocos2d-x.org
  3  Copyright (c) 2008-2010 Ricardo Quesada
  4  Copyright (c) 2011      Zynga Inc.
  5 
  6  http://www.cocos2d-x.org
  7 
  8  Permission is hereby granted, free of charge, to any person obtaining a copy
  9  of this software and associated documentation files (the "Software"), to deal
 10  in the Software without restriction, including without limitation the rights
 11  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 12  copies of the Software, and to permit persons to whom the Software is
 13  furnished to do so, subject to the following conditions:
 14 
 15  The above copyright notice and this permission notice shall be included in
 16  all copies or substantial portions of the Software.
 17 
 18  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 19  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 20  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 21  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 22  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 23  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 24  THE SOFTWARE.
 25  ****************************************************************************/
 26 
 27 /**
 28  * @constant
 29  * @type Number
 30  */
 31 cc.TouchSelectorBeganBit = 1 << 0;
 32 
 33 /**
 34  * @constant
 35  * @type Number
 36  */
 37 cc.TouchSelectorMovedBit = 1 << 1;
 38 
 39 /**
 40  * @constant
 41  * @type Number
 42  */
 43 cc.TouchSelectorEndedBit = 1 << 2;
 44 
 45 /**
 46  * @constant
 47  * @type Number
 48  */
 49 cc.TouchSelectorCancelledBit = 1 << 3;
 50 
 51 /**
 52  * @constant
 53  * @type Number
 54  */
 55 cc.TouchSelectorAllBits = ( cc.TouchSelectorBeganBit | cc.TouchSelectorMovedBit | cc.TouchSelectorEndedBit | cc.TouchSelectorCancelledBit);
 56 
 57 /**
 58  * @constant
 59  * @type Number
 60  */
 61 cc.TOUCH_BEGAN = 0;
 62 
 63 /**
 64  * @constant
 65  * @type Number
 66  */
 67 cc.TOUCH_MOVED = 1;
 68 
 69 /**
 70  * @constant
 71  * @type Number
 72  */
 73 cc.TOUCH_ENDED = 2;
 74 
 75 /**
 76  * @constant
 77  * @type Number
 78  */
 79 cc.TOUCH_CANCELLED = 3;
 80 
 81 /**
 82  * @constant
 83  * @type Number
 84  */
 85 cc.TouchMax = 4;
 86 
 87 /**
 88  * @function
 89  * @param {cc.TouchHandler} p1
 90  * @param {cc.TouchHandler} p2
 91  * @return {Boolean}
 92  */
 93 cc.less = function (p1, p2) {
 94     return p1.getPriority() > p2.getPriority();
 95 };
 96 
 97 /**
 98  * @param {Number} type
 99  * Constructor
100  */
101 cc.TouchHandlerHelperData = function (type) {
102     // we only use the type
103     this.type = type;
104 };
105 
106 /**
107  * cc.TouchDispatcher.
108  * Singleton that handles all the touch events.
109  * The dispatcher dispatches events to the registered TouchHandlers.
110  * There are 2 different type of touch handlers:
111  * - Standard Touch Handlers
112  * - Targeted Touch Handlers
113  *
114  * The Standard Touch Handlers work like the CocoaTouch touch handler: a set of touches is passed to the delegate.
115  * On the other hand, the Targeted Touch Handlers only receive 1 touch at the time, and they can "swallow" touches (avoid the propagation of the event).
116  *
117  * Firstly, the dispatcher sends the received touches to the targeted touches.
118  * These touches can be swallowed by the Targeted Touch Handlers. If there are still remaining touches, then the remaining touches will be sent
119  * to the Standard Touch Handlers.
120  * @class
121  * @extends cc.Class
122  */
123 cc.TouchDispatcher = cc.Class.extend(/** @lends cc.TouchDispatcher# */{
124     _mousePressed:false,
125     _targetedHandlers:null,
126     _standardHandlers:null,
127     _locked:false,
128     _toAdd:false,
129     _toRemove:false,
130     _handlersToAdd:null,
131     _handlersToRemove:null,
132     _toQuit:false,
133     _dispatchEvents:false,
134     _handlerHelperData:[new cc.TouchHandlerHelperData(cc.TOUCH_BEGAN), new cc.TouchHandlerHelperData(cc.TOUCH_MOVED),
135         new cc.TouchHandlerHelperData(cc.TOUCH_ENDED), new cc.TouchHandlerHelperData(cc.TOUCH_CANCELLED)],
136 
137     /**
138      * @return {Boolean}
139      */
140     init:function () {
141         this._dispatchEvents = true;
142         this._targetedHandlers = [];
143         this._standardHandlers = [];
144         this._handlersToAdd = [];
145         this._handlersToRemove = [];
146         this._toRemove = false;
147         this._toAdd = false;
148         this._toQuit = false;
149         this._locked = false;
150         this._mousePressed = false;
151         cc.TouchDispatcher.registerHtmlElementEvent(cc.canvas);
152         return true;
153     },
154 
155     _setMousePressed:function (pressed) {
156         this._mousePressed = pressed;
157     },
158 
159     _getMousePressed:function () {
160         return this._mousePressed;
161     },
162 
163     /**
164      * Whether or not the events are going to be dispatched. Default: true
165      * @return {Boolean}
166      */
167     isDispatchEvents:function () {
168         return this._dispatchEvents;
169     },
170 
171     /**
172      * @param {Boolean} dispatchEvents
173      */
174     setDispatchEvents:function (dispatchEvents) {
175         this._dispatchEvents = dispatchEvents;
176     },
177 
178     /**
179      * Adds a standard touch delegate to the dispatcher's list.
180      * See StandardTouchDelegate description.
181      * IMPORTANT: The delegate will be retained.
182      * @param {cc.TouchDelegate} delegate
183      * @param {Number} priority
184      */
185     addStandardDelegate:function (delegate, priority) {
186         var handler = cc.StandardTouchHandler.handlerWithDelegate(delegate, priority);
187 
188         if (!this._locked) {
189             this._standardHandlers = this.forceAddHandler(handler, this._standardHandlers);
190         } else {
191             /* If handler is contained in m_pHandlersToRemove, if so remove it from m_pHandlersToRemove and retrun.
192              * Refer issue #752(cocos2d-x)
193              */
194             if (this._handlersToRemove.indexOf(delegate) != -1) {
195                 cc.ArrayRemoveObject(this._handlersToRemove, delegate);
196                 return;
197             }
198 
199             this._handlersToAdd.push(handler);
200             this._toAdd = true;
201         }
202     },
203 
204     /**
205      * @param {cc.TouchDelegate} delegate
206      * @param {Number} priority
207      * @param {Boolean} swallowsTouches
208      */
209     addTargetedDelegate:function (delegate, priority, swallowsTouches) {
210         var handler = cc.TargetedTouchHandler.handlerWithDelegate(delegate, priority, swallowsTouches);
211         if (!this._locked) {
212             this._targetedHandlers = this.forceAddHandler(handler, this._targetedHandlers);
213         } else {
214             /* If handler is contained in m_pHandlersToRemove, if so remove it from m_pHandlersToRemove and retrun.
215              * Refer issue #752(cocos2d-x)
216              */
217             if (this._handlersToRemove.indexOf(delegate) != -1) {
218                 cc.ArrayRemoveObject(this._handlersToRemove, delegate);
219                 return;
220             }
221 
222             this._handlersToAdd.push(handler);
223             this._toAdd = true;
224         }
225     },
226 
227     /**
228      *  Force add handler
229      * @param {cc.TouchHandler} handler
230      * @param {Array} array
231      * @return {Array}
232      */
233     forceAddHandler:function (handler, array) {
234         var u = 0;
235 
236         for (var i = 0; i < array.length; i++) {
237             var h = array[i];
238             if (h) {
239                 if (h.getPriority() < handler.getPriority()) {
240                     ++u;
241                 }
242                 if (h.getDelegate() == handler.getDelegate()) {
243                     cc.Assert(0, "TouchDispatcher.forceAddHandler()");
244                     return array;
245                 }
246             }
247         }
248         return cc.ArrayAppendObjectToIndex(array, handler, u);
249     },
250 
251     /**
252      *  Force remove all delegates
253      */
254     forceRemoveAllDelegates:function () {
255         this._standardHandlers.length = 0;
256         this._targetedHandlers.length = 0;
257     },
258 
259     /**
260      * Removes a touch delegate.
261      * The delegate will be released
262      * @param {cc.TouchDelegate} delegate
263      */
264     removeDelegate:function (delegate) {
265         if (delegate == null) {
266             return;
267         }
268 
269         if (!this._locked) {
270             this.forceRemoveDelegate(delegate);
271         } else {
272             /*
273              * If handler is contained in m_pHandlersToAdd, if so remove it from m_pHandlersToAdd and return.
274              */
275             var handler = this.findHandler(this._handlersToAdd, delegate);
276             if (handler) {
277                 cc.ArrayRemoveObject(this._handlersToAdd, handler);
278                 return;
279             }
280 
281             this._handlersToRemove.push(delegate);
282             this._toRemove = true;
283         }
284     },
285 
286     /**
287      * Removes all touch delegates, releasing all the delegates
288      */
289     removeAllDelegates:function () {
290         if (!this._locked) {
291             this.forceRemoveAllDelegates();
292         } else {
293             this._toQuit = true;
294         }
295     },
296 
297     /**
298      * Changes the priority of a previously added delegate. The lower the number,  the higher the priority
299      * @param {Number} priority
300      * @param {cc.TouchDelegate} delegate
301      */
302     setPriority:function (priority, delegate) {
303         cc.Assert(delegate != null, "TouchDispatcher.setPriority():Arguments is null");
304 
305         var handler = this.findHandler(delegate);
306 
307         cc.Assert(handler != null, "TouchDispatcher.setPriority():Cant find TouchHandler");
308 
309         if (handler.getPriority() != priority) {
310             handler.setPriority(priority);
311 
312             this.rearrangeHandlers(this._targetedHandlers);
313             this.rearrangeHandlers(this._standardHandlers);
314         }
315     },
316 
317     /**
318      * @param {Array} touches
319      * @param {event} event
320      * @param {Number} index
321      */
322     touches:function (touches, event, index) {
323         cc.Assert(index >= 0 && index < 4, "TouchDispatcher.touches()");
324 
325         this._locked = true;
326 
327         // optimization to prevent a mutable copy when it is not necessary
328         var targetedHandlersCount = this._targetedHandlers.length;
329         var standardHandlersCount = this._standardHandlers.length;
330         var needsMutableSet = (targetedHandlersCount && standardHandlersCount);
331 
332         var mutableTouches = (needsMutableSet ? touches.slice() : touches);
333         var helper = this._handlerHelperData[index];
334         //
335         // process the target handlers 1st
336         //
337         if (targetedHandlersCount > 0) {
338             var touch;
339             for (var i = 0; i < touches.length; i++) {
340                 touch = touches[i];
341                 var handler;
342 
343                 for (var j = 0; j < this._targetedHandlers.length; j++) {
344                     handler = this._targetedHandlers[j];
345 
346                     if (!handler) {
347                         break;
348                     }
349 
350                     var claimed = false;
351                     if (index == cc.TOUCH_BEGAN) {
352                         if (handler.getDelegate().onTouchBegan) {
353                             claimed = handler.getDelegate().onTouchBegan(touch, event);
354 
355                             if (claimed) {
356                                 handler.getClaimedTouches().push(touch);
357                             }
358                         }
359                         //} else if (handler.getClaimedTouches().indexOf(touch)> -1){
360                     } else if (handler.getClaimedTouches().length > 0) {
361                         // moved ended cancelled
362                         claimed = true;
363                         switch (helper.type) {
364                             case cc.TOUCH_MOVED:
365                                 if (cc.Browser.isMobile) {
366                                     if (handler.getDelegate().onTouchMoved)
367                                         handler.getDelegate().onTouchMoved(touch, event);
368                                 } else {
369                                     if (this._mousePressed)
370                                         if (handler.getDelegate().onTouchMoved)
371                                             handler.getDelegate().onTouchMoved(touch, event);
372                                 }
373                                 break;
374                             case cc.TOUCH_ENDED:
375                                 if (handler.getDelegate().onTouchEnded)
376                                     handler.getDelegate().onTouchEnded(touch, event);
377                                 handler.getClaimedTouches().length = 0;
378                                 //cc.ArrayRemoveObject(handler.getClaimedTouches(),touch);
379                                 break;
380                             case cc.TOUCH_CANCELLED:
381                                 if (handler.getDelegate().onTouchCancelled)
382                                     handler.getDelegate().onTouchCancelled(touch, event);
383                                 handler.getClaimedTouches().length = 0;
384                                 //cc.ArrayRemoveObject(handler.getClaimedTouches(),touch);
385                                 break;
386                         }
387                     }
388 
389                     if (claimed && handler.isSwallowsTouches()) {
390                         if (needsMutableSet) {
391                             cc.ArrayRemoveObject(mutableTouches, touch);
392                         }
393                         break;
394                     }
395                 }
396             }
397         }
398 
399         //
400         // process standard handlers 2nd
401         //
402         if (standardHandlersCount > 0) {
403             for (i = 0; i < this._standardHandlers.length; i++) {
404                 handler = this._standardHandlers[i];
405 
406                 if (!handler) {
407                     break;
408                 }
409 
410                 switch (helper.type) {
411                     case cc.TOUCH_BEGAN:
412                         if (mutableTouches.length > 0) {
413                             if (handler.getDelegate().onTouchesBegan)
414                                 handler.getDelegate().onTouchesBegan(mutableTouches, event);
415                         }
416                         break;
417                     case cc.TOUCH_MOVED:
418                         if (mutableTouches.length > 0) {
419                             if (cc.Browser.isMobile) {
420                                 if (handler.getDelegate().onTouchesMoved)
421                                     handler.getDelegate().onTouchesMoved(mutableTouches, event);
422                             } else {
423                                 if (this._mousePressed)
424                                     if (handler.getDelegate().onTouchesMoved)
425                                         handler.getDelegate().onTouchesMoved(mutableTouches, event);
426                             }
427                         }
428                         break;
429                     case cc.TOUCH_ENDED:
430                         if (handler.getDelegate().onTouchesEnded)
431                             handler.getDelegate().onTouchesEnded(mutableTouches, event);
432                         break;
433                     case cc.TOUCH_CANCELLED:
434                         if (handler.getDelegate().onTouchesCancelled)
435                             handler.getDelegate().onTouchesCancelled(mutableTouches, event);
436                         break;
437                 }
438             }
439         }
440 
441         if (needsMutableSet) {
442             mutableTouches = null;
443         }
444 
445         //
446         // Optimization. To prevent a [handlers copy] which is expensive
447         // the add/removes/quit is done after the iterations
448         //
449         this._locked = false;
450         if (this._toRemove) {
451             this._toRemove = false;
452             for (i = 0; i < this._handlersToRemove.length; i++) {
453                 this.forceRemoveDelegate(this._handlersToRemove[i]);
454             }
455             this._handlersToRemove.length = 0;
456         }
457 
458         if (this._toAdd) {
459             this._toAdd = false;
460 
461             for (i = 0; i < this._handlersToAdd.length; i++) {
462                 handler = this._handlersToAdd[i];
463                 if (!handler) {
464                     break;
465                 }
466 
467                 if (handler  instanceof cc.TargetedTouchHandler) {
468                     this._targetedHandlers = this.forceAddHandler(handler, this._targetedHandlers);
469                 } else {
470                     this._standardHandlers = this.forceAddHandler(handler, this._standardHandlers);
471                 }
472             }
473             this._handlersToAdd.length = 0;
474         }
475 
476         if (this._toQuit) {
477             this._toQuit = false;
478             this.forceRemoveAllDelegates();
479         }
480     },
481 
482     /**
483      * @param {Array} touches
484      * @param {event} event
485      */
486     touchesBegan:function (touches, event) {
487         if (this._dispatchEvents) {
488             this.touches(touches, event, cc.TOUCH_BEGAN);
489         }
490     },
491 
492     /**
493      * @param {Array} touches
494      * @param {event} event
495      */
496     touchesMoved:function (touches, event) {
497         if (this._dispatchEvents) {
498             this.touches(touches, event, cc.TOUCH_MOVED);
499         }
500     },
501 
502     /**
503      * @param {Array} touches
504      * @param {event} event
505      */
506     touchesEnded:function (touches, event) {
507         if (this._dispatchEvents) {
508             this.touches(touches, event, cc.TOUCH_ENDED);
509         }
510     },
511 
512     /**
513      * @param {Array} touches
514      * @param {event} event
515      */
516     touchesCancelled:function (touches, event) {
517         if (this._dispatchEvents) {
518             this.touches(touches, event, cc.TOUCH_CANCELLED);
519         }
520     },
521 
522     /**
523      * @param {Array||cc.TouchDelegate} array array or delegate
524      * @param {cc.TouchDelegate} delegate
525      * @return {cc.TargetedTouchHandler|cc.StandardTouchHandler|Null}
526      */
527     findHandler:function (array, delegate) {
528         switch (arguments.length) {
529             case 1:
530                 delegate = arguments[0];
531                 for (var i = 0; i < this._targetedHandlers.length; i++) {
532                     if (this._targetedHandlers[i].getDelegate() == delegate) {
533                         return this._targetedHandlers[i];
534                     }
535                 }
536                 for (i = 0; i < this._standardHandlers.length; i++) {
537                     if (this._standardHandlers[i].getDelegate() == delegate) {
538                         return this._standardHandlers[i];
539                     }
540                 }
541                 return null;
542                 break;
543             case 2:
544                 cc.Assert(array != null && delegate != null, "TouchDispatcher.findHandler():Arguments is null");
545 
546                 for (i = 0; i < array.length; i++) {
547                     if (array[i].getDelegate() == delegate) {
548                         return array[i];
549                     }
550                 }
551 
552                 return null;
553                 break;
554             default:
555                 throw "Argument must be non-nil ";
556                 break;
557         }
558     },
559 
560     /**
561      * @param {cc.TouchDelegate} delegate
562      */
563     forceRemoveDelegate:function (delegate) {
564         var handler;
565         // XXX: remove it from both handlers ???
566         // remove handler from m_pStandardHandlers
567         for (var i = 0; i < this._standardHandlers.length; i++) {
568             handler = this._standardHandlers[i];
569             if (handler && handler.getDelegate() == delegate) {
570                 cc.ArrayRemoveObject(this._standardHandlers, handler);
571                 break;
572             }
573         }
574 
575         for (i = 0; i < this._targetedHandlers.length; i++) {
576             handler = this._targetedHandlers[i];
577             if (handler && handler.getDelegate() == delegate) {
578                 cc.ArrayRemoveObject(this._targetedHandlers, handler);
579                 break;
580             }
581         }
582     },
583 
584     /**
585      * @param {Array} array
586      */
587     rearrangeHandlers:function (array) {
588         array.sort(cc.less);
589     }
590 });
591 
592 /**
593  * @type {cc.Point}
594  */
595 cc.TouchDispatcher.preTouchPoint = cc.p(0, 0);
596 
597 cc.TouchDispatcher.isRegisterEvent = false;
598 
599 cc.getHTMLElementPosition = function (element) {
600     var pos = null;
601     if (element instanceof HTMLCanvasElement) {
602         pos = {left:0, top:0, width:element.width, height:element.height};
603     } else {
604         pos = {left:0, top:0, width:parseInt(element.style.width), height:parseInt(element.style.height)};
605     }
606     while (element != null) {
607         pos.left += element.offsetLeft;
608         pos.top += element.offsetTop;
609         element = element.offsetParent;
610     }
611     return pos;
612 };
613 
614 cc.ProcessMouseupEvent = function (element, event) {
615     var pos = cc.getHTMLElementPosition(element);
616 
617     var tx = event.pageX;
618     var ty = event.pageY;
619 
620     var mouseX = (tx - pos.left) / cc.Director.getInstance().getContentScaleFactor();
621     var mouseY = (pos.height - (ty - pos.top)) / cc.Director.getInstance().getContentScaleFactor();
622 
623     var touch = new cc.Touch(mouseX, mouseY);
624     touch._setPrevPoint(cc.TouchDispatcher.preTouchPoint.x, cc.TouchDispatcher.preTouchPoint.y);
625     cc.TouchDispatcher.preTouchPoint.x = mouseX;
626     cc.TouchDispatcher.preTouchPoint.y = mouseY;
627 
628     var posArr = [];
629     posArr.push(touch);
630     cc.Director.getInstance().getTouchDispatcher().touchesEnded(posArr, null);
631 };
632 /**
633  * @param {HTMLCanvasElement|HTMLDivElement} element
634  */
635 cc.TouchDispatcher.registerHtmlElementEvent = function (element) {
636     if (cc.TouchDispatcher.isRegisterEvent)
637         return;
638 
639     if (!cc.Browser.isMobile) {
640         window.addEventListener('mousedown', function (event) {
641             cc.Director.getInstance().getTouchDispatcher()._setMousePressed(true);
642         });
643 
644         window.addEventListener('mouseup', function (event) {
645             cc.Director.getInstance().getTouchDispatcher()._setMousePressed(false);
646 
647             var pos = cc.getHTMLElementPosition(element);
648 
649             var tx = event.pageX;
650             var ty = event.pageY;
651 
652             if (!cc.rectContainsPoint(new cc.Rect(pos.left, pos.top, pos.width, pos.height), cc.p(tx, ty))) {
653                 var mouseX = (tx - pos.left) / cc.Director.getInstance().getContentScaleFactor();
654                 var mouseY = (pos.height - (ty - pos.top)) / cc.Director.getInstance().getContentScaleFactor();
655 
656                 var touch = new cc.Touch(mouseX, mouseY);
657                 touch._setPrevPoint(cc.TouchDispatcher.preTouchPoint.x, cc.TouchDispatcher.preTouchPoint.y);
658                 cc.TouchDispatcher.preTouchPoint.x = mouseX;
659                 cc.TouchDispatcher.preTouchPoint.y = mouseY;
660 
661                 var posArr = [];
662                 posArr.push(touch);
663                 cc.Director.getInstance().getTouchDispatcher().touchesEnded(posArr, null);
664             }
665         });
666 
667         //register canvas mouse event
668         element.addEventListener("mousedown", function (event) {
669             var pos = cc.getHTMLElementPosition(element);
670 
671             var tx = event.pageX;
672             var ty = event.pageY;
673 
674             var mouseX = (tx - pos.left) / cc.Director.getInstance().getContentScaleFactor();
675             var mouseY = (pos.height - (ty - pos.top)) / cc.Director.getInstance().getContentScaleFactor();
676 
677             var touch = new cc.Touch(mouseX, mouseY);
678             touch._setPrevPoint(cc.TouchDispatcher.preTouchPoint.x, cc.TouchDispatcher.preTouchPoint.y);
679             cc.TouchDispatcher.preTouchPoint.x = mouseX;
680             cc.TouchDispatcher.preTouchPoint.y = mouseY;
681 
682             var posArr = [];
683             posArr.push(touch);
684             cc.Director.getInstance().getTouchDispatcher().touchesBegan(posArr, null);
685         });
686 
687         element.addEventListener("mouseup", function (event) {
688             cc.ProcessMouseupEvent(element, event);
689         });
690 
691         element.addEventListener("mousemove", function (event) {
692             var pos = cc.getHTMLElementPosition(element);
693 
694             var tx = event.pageX;
695             var ty = event.pageY;
696 
697             var mouseX = (tx - pos.left) / cc.Director.getInstance().getContentScaleFactor();
698             var mouseY = (pos.height - (ty - pos.top)) / cc.Director.getInstance().getContentScaleFactor();
699 
700             var touch = new cc.Touch(mouseX, mouseY);
701 
702             //TODO this feature only chrome support
703             //if((event.button == 0) && (event.which == 1))
704             //    touch._setPressed(true);
705 
706             touch._setPrevPoint(cc.TouchDispatcher.preTouchPoint.x, cc.TouchDispatcher.preTouchPoint.y);
707             cc.TouchDispatcher.preTouchPoint.x = mouseX;
708             cc.TouchDispatcher.preTouchPoint.y = mouseY;
709 
710             var posArr = [];
711             posArr.push(touch);
712 
713             cc.Director.getInstance().getTouchDispatcher().touchesMoved(posArr, null);
714         });
715     } else {
716         //register canvas touch event
717         element.addEventListener("touchstart", function (event) {
718             if (!event.touches)
719                 return;
720 
721             var posArr = [];
722             var pos = cc.getHTMLElementPosition(element);
723 
724             pos.left -= document.body.scrollLeft;
725             pos.top -= document.body.scrollTop;
726             for (var i = 0; i < event.touches.length; i++) {
727                 var tx = event.touches[i].pageX;
728                 var ty = event.touches[i].pageY;
729                 if (event.touches[i]) {
730                     tx = event.touches[i].clientX;
731                     ty = event.touches[i].clientY;
732                 }
733                 var mouseX = (tx - pos.left) / cc.Director.getInstance().getContentScaleFactor();
734                 var mouseY = (pos.height - (ty - pos.top)) / cc.Director.getInstance().getContentScaleFactor();
735                 var touch = null;
736                 if (event.touches[i].hasOwnProperty("identifier"))
737                     touch = new cc.Touch(mouseX, mouseY, event.touches[i].identifier);
738                 else
739                     touch = new cc.Touch(mouseX, mouseY);
740 
741                 touch._setPrevPoint(cc.TouchDispatcher.preTouchPoint.x, cc.TouchDispatcher.preTouchPoint.y);
742                 cc.TouchDispatcher.preTouchPoint.x = mouseX;
743                 cc.TouchDispatcher.preTouchPoint.y = mouseY;
744 
745                 posArr.push(touch);
746             }
747             cc.Director.getInstance().getTouchDispatcher().touchesBegan(posArr, null);
748             event.stopPropagation();
749             event.preventDefault();
750         }, false);
751 
752         element.addEventListener("touchmove", function (event) {
753             if (!event.touches)
754                 return;
755 
756             var posArr = [];
757             var pos = cc.getHTMLElementPosition(element);
758 
759             pos.left -= document.body.scrollLeft;
760             pos.top -= document.body.scrollTop;
761             for (var i = 0; i < event.touches.length; i++) {
762                 var tx = event.touches[i].pageX;
763                 var ty = event.touches[i].pageY;
764                 if (event.touches[i]) {
765                     tx = event.touches[i].clientX;
766                     ty = event.touches[i].clientY;
767                 }
768                 var mouseX = (tx - pos.left) / cc.Director.getInstance().getContentScaleFactor();
769                 var mouseY = (pos.height - (ty - pos.top)) / cc.Director.getInstance().getContentScaleFactor();
770 
771                 var touch = null;
772                 if (event.touches[i].hasOwnProperty("identifier"))
773                     touch = new cc.Touch(mouseX, mouseY, event.touches[i].identifier);
774                 else
775                     touch = new cc.Touch(mouseX, mouseY);
776                 touch._setPrevPoint(cc.TouchDispatcher.preTouchPoint.x, cc.TouchDispatcher.preTouchPoint.y);
777                 cc.TouchDispatcher.preTouchPoint.x = mouseX;
778                 cc.TouchDispatcher.preTouchPoint.y = mouseY;
779 
780                 posArr.push(touch);
781             }
782             cc.Director.getInstance().getTouchDispatcher().touchesMoved(posArr, null);
783             event.stopPropagation();
784             event.preventDefault();
785         }, false);
786 
787         element.addEventListener("touchend", function (event) {
788             if (!event.touches)
789                 return;
790 
791             var posArr = [];
792             var pos = cc.getHTMLElementPosition(element);
793 
794             pos.left -= document.body.scrollLeft;
795             pos.top -= document.body.scrollTop;
796 
797             var fireTouches = event.touches;
798             if (!fireTouches || (fireTouches.length == 0)) {
799                 fireTouches = event.changedTouches;
800             }
801             for (var i = 0; i < fireTouches.length; i++) {
802                 var tx = fireTouches[i].pageX;
803                 var ty = fireTouches[i].pageY;
804                 if (fireTouches[i]) {
805                     tx = fireTouches[i].clientX;
806                     ty = fireTouches[i].clientY;
807                 }
808 
809                 var mouseX = (tx - pos.left) / cc.Director.getInstance().getContentScaleFactor();
810                 var mouseY = (pos.height - (ty - pos.top)) / cc.Director.getInstance().getContentScaleFactor();
811 
812                 var touch = null;
813                 if (fireTouches[i].hasOwnProperty("identifier"))
814                     touch = new cc.Touch(mouseX, mouseY, fireTouches[i].identifier);
815                 else
816                     touch = new cc.Touch(mouseX, mouseY);
817 
818                 touch._setPrevPoint(cc.TouchDispatcher.preTouchPoint.x, cc.TouchDispatcher.preTouchPoint.y);
819                 cc.TouchDispatcher.preTouchPoint.x = mouseX;
820                 cc.TouchDispatcher.preTouchPoint.y = mouseY;
821 
822                 posArr.push(touch);
823             }
824             cc.Director.getInstance().getTouchDispatcher().touchesEnded(posArr, null);
825             event.stopPropagation();
826             event.preventDefault();
827         }, false);
828 
829         element.addEventListener("touchcancel", function (event) {
830             if (!event.touches)
831                 return;
832 
833             var posArr = [];
834             var pos = cc.getHTMLElementPosition(element);
835 
836             pos.left -= document.body.scrollLeft;
837             pos.top -= document.body.scrollTop;
838 
839             for (var i = 0; i < event.touches.length; i++) {
840                 var tx = event.touches[i].pageX;
841                 var ty = event.touches[i].pageY;
842                 if (event.touches[i]) {
843                     tx = event.touches[i].clientX;
844                     ty = event.touches[i].clientY;
845                 }
846                 var mouseX = (tx - pos.left) / cc.Director.getInstance().getContentScaleFactor();
847                 var mouseY = (pos.height - (ty - pos.top)) / cc.Director.getInstance().getContentScaleFactor();
848 
849                 var touch = null;
850                 if (event.touches[i].hasOwnProperty("identifier"))
851                     touch = new cc.Touch(mouseX, mouseY, event.touches[i].identifier);
852                 else
853                     touch = new cc.Touch(mouseX, mouseY);
854                 touch._setPrevPoint(cc.TouchDispatcher.preTouchPoint.x, cc.TouchDispatcher.preTouchPoint.y);
855                 cc.TouchDispatcher.preTouchPoint.x = mouseX;
856                 cc.TouchDispatcher.preTouchPoint.y = mouseY;
857 
858                 posArr.push(touch);
859             }
860             cc.Director.getInstance().getTouchDispatcher().touchesCancelled(posArr, null);
861             event.stopPropagation();
862             event.preventDefault();
863         }, false);
864     }
865 
866     cc.TouchDispatcher.isRegisterEvent = true;
867 };
868